mirror of
https://github.com/aseprite/aseprite.git
synced 2024-09-02 04:59:24 +00:00
Put playback options into Frame > Playback submenu
This menu was accessible right-clicking the Play button in the Timeline (and in the Preview window, with specific options for the Preview). This change includes some changes: 1. Now if a menu <item> in gui.xml doesn't specify a text field, the text of the command is used (to avoid double translation, the bad side is that we don't have a mnemonic specified). 2. Menu::showPopup() can be used with submenus from the root menu, to do this we have to remove the menu item owner temporarily before we show the menu as popup (see the change in Menu::showPopup()) 3. We can specify a special active DocView for commands with UIContext::SetTargetView, this is used to set the Preview editor as active view for commands like TogglePlayOnce, etc.
This commit is contained in:
parent
0dbcdc8159
commit
30a88c8e3d
20
data/gui.xml
20
data/gui.xml
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Aseprite -->
|
<!-- Aseprite -->
|
||||||
<!-- Copyright (C) 2018-2022 Igara Studio S.A. -->
|
<!-- Copyright (C) 2018-2023 Igara Studio S.A. -->
|
||||||
<!-- Copyright (C) 2001-2018 David Capello -->
|
<!-- Copyright (C) 2001-2018 David Capello -->
|
||||||
<gui>
|
<gui>
|
||||||
<!-- Keyboard shortcuts -->
|
<!-- Keyboard shortcuts -->
|
||||||
@ -911,6 +911,23 @@
|
|||||||
</item>
|
</item>
|
||||||
<item command="RemoveFrame" text="@.frame_delete_frame" group="cel_delete" />
|
<item command="RemoveFrame" text="@.frame_delete_frame" group="cel_delete" />
|
||||||
<separator />
|
<separator />
|
||||||
|
<menu text="@.frame_playback" id="animation_menu" group="cel_animation">
|
||||||
|
<item command="PlayAnimation" />
|
||||||
|
<item command="PlayPreviewAnimation" />
|
||||||
|
<separator />
|
||||||
|
<item command="SetPlaybackSpeed"><param name="multiplier" value="0.25" /></item>
|
||||||
|
<item command="SetPlaybackSpeed"><param name="multiplier" value="0.5" /></item>
|
||||||
|
<item command="SetPlaybackSpeed"><param name="multiplier" value="1.0" /></item>
|
||||||
|
<item command="SetPlaybackSpeed"><param name="multiplier" value="1.5" /></item>
|
||||||
|
<item command="SetPlaybackSpeed"><param name="multiplier" value="2.0" /></item>
|
||||||
|
<item command="SetPlaybackSpeed"><param name="multiplier" value="3.0" /></item>
|
||||||
|
<separator />
|
||||||
|
<item command="TogglePlayOnce" />
|
||||||
|
<item command="TogglePlayAll" />
|
||||||
|
<item command="TogglePlaySubtags" />
|
||||||
|
<separator />
|
||||||
|
<item command="ToggleRewindOnStop" />
|
||||||
|
</menu>
|
||||||
<menu text="@.frame_tags">
|
<menu text="@.frame_tags">
|
||||||
<item command="FrameTagProperties" text="@.frame_tags_tag_properties" />
|
<item command="FrameTagProperties" text="@.frame_tags_tag_properties" />
|
||||||
<separator />
|
<separator />
|
||||||
@ -928,7 +945,6 @@
|
|||||||
<separator />
|
<separator />
|
||||||
<item command="GotoFrame" text="@.frame_go_to_frame" />
|
<item command="GotoFrame" text="@.frame_go_to_frame" />
|
||||||
</menu>
|
</menu>
|
||||||
<item command="PlayAnimation" text="@.frame_play_animation" group="cel_animation" />
|
|
||||||
<separator />
|
<separator />
|
||||||
<item command="FrameProperties" text="@.frame_constant_frame_rate">
|
<item command="FrameProperties" text="@.frame_constant_frame_rate">
|
||||||
<param name="frame" value="all" />
|
<param name="frame" value="all" />
|
||||||
|
@ -549,6 +549,7 @@ SetInkType = Set Ink Type: {0}
|
|||||||
SetLoopSection = Set Loop Section
|
SetLoopSection = Set Loop Section
|
||||||
SetPalette = Set Palette
|
SetPalette = Set Palette
|
||||||
SetPaletteEntrySize = Set Palette Entry Size
|
SetPaletteEntrySize = Set Palette Entry Size
|
||||||
|
SetPlaybackSpeed = Playback Speed {0}x
|
||||||
SetSameInk = Same Ink in All Tools
|
SetSameInk = Same Ink in All Tools
|
||||||
ShowAutoGuides = Show Auto Guides
|
ShowAutoGuides = Show Auto Guides
|
||||||
ShowBrushPreview = Show Brush Preview
|
ShowBrushPreview = Show Brush Preview
|
||||||
@ -577,13 +578,17 @@ SwitchNonactiveLayersOpacity = Switch Nonactive Layers Opacity
|
|||||||
SymmetryMode = Symmetry Mode
|
SymmetryMode = Symmetry Mode
|
||||||
TiledMode = Tiled Mode
|
TiledMode = Tiled Mode
|
||||||
Timeline = Switch Timeline
|
Timeline = Switch Timeline
|
||||||
|
TogglePlayAll = Play All Frames (Ignore Tags)
|
||||||
|
TogglePlayOnce = Play Once
|
||||||
|
TogglePlaySubtags = Play Subtags & Repetitions
|
||||||
TogglePreview = Toggle Preview
|
TogglePreview = Toggle Preview
|
||||||
|
ToggleRewindOnStop = Rewind on Stop
|
||||||
ToggleTilesMode = Toggle Tiles Mode
|
ToggleTilesMode = Toggle Tiles Mode
|
||||||
|
ToggleTimelineThumbnails = Toggle Timeline Thumbnails
|
||||||
TilesetMode = Tileset Mode: {}
|
TilesetMode = Tileset Mode: {}
|
||||||
TilesetMode_Manual = Manual
|
TilesetMode_Manual = Manual
|
||||||
TilesetMode_Auto = Auto
|
TilesetMode_Auto = Auto
|
||||||
TilesetMode_Stack = Stack
|
TilesetMode_Stack = Stack
|
||||||
ToggleTimelineThumbnails = Toggle Timeline Thumbnails
|
|
||||||
Undo = Undo
|
Undo = Undo
|
||||||
UndoHistory = Undo History
|
UndoHistory = Undo History
|
||||||
UnlinkCel = Unlink Cel
|
UnlinkCel = Unlink Cel
|
||||||
@ -1244,13 +1249,14 @@ layer_merge_down = &Merge Down
|
|||||||
layer_flatten = &Flatten
|
layer_flatten = &Flatten
|
||||||
layer_flatten_visible = Flatten Vi&sible
|
layer_flatten_visible = Flatten Vi&sible
|
||||||
frame = F&rame
|
frame = F&rame
|
||||||
frame_properties = Frame &Properties...
|
frame_properties = &Frame Properties...
|
||||||
frame_cel_properties = &Cel Properties...
|
frame_cel_properties = &Cel Properties...
|
||||||
frame_new_frame = &New Frame
|
frame_new_frame = &New Frame
|
||||||
frame_new_empty_frame = New &Empty Frame
|
frame_new_empty_frame = New &Empty Frame
|
||||||
frame_duplicate_cels = &Duplicate Cel(s)
|
frame_duplicate_cels = &Duplicate Cel(s)
|
||||||
frame_duplicate_linked_cels = Duplicate &Linked Cel(s)
|
frame_duplicate_linked_cels = Duplicate &Linked Cel(s)
|
||||||
frame_delete_frame = Delete F&rame
|
frame_delete_frame = Delete F&rame
|
||||||
|
frame_playback = &Playback
|
||||||
frame_tags = &Tags
|
frame_tags = &Tags
|
||||||
frame_tags_tag_properties = Tag &Properties...
|
frame_tags_tag_properties = Tag &Properties...
|
||||||
frame_tags_new_tag = New &Tag
|
frame_tags_new_tag = New &Tag
|
||||||
@ -1263,7 +1269,6 @@ frame_jump_to_last_frame = &Last Frame
|
|||||||
frame_jump_to_first_frame_in_tag = First Frame In Tag
|
frame_jump_to_first_frame_in_tag = First Frame In Tag
|
||||||
frame_jump_to_last_frame_in_tag = Last Frame In Tag
|
frame_jump_to_last_frame_in_tag = Last Frame In Tag
|
||||||
frame_go_to_frame = &Go to Frame
|
frame_go_to_frame = &Go to Frame
|
||||||
frame_play_animation = &Play Animation
|
|
||||||
frame_constant_frame_rate = Constant Frame Rate
|
frame_constant_frame_rate = Constant Frame Rate
|
||||||
frame_reverse_frames = Re&verse Frames
|
frame_reverse_frames = Re&verse Frames
|
||||||
select = Selec&t
|
select = Selec&t
|
||||||
@ -1799,11 +1804,6 @@ antialias_tooltip = Smooth font edges
|
|||||||
|
|
||||||
[preview]
|
[preview]
|
||||||
title = Preview
|
title = Preview
|
||||||
speed_x = Speed x{}
|
|
||||||
play_once = Play Once
|
|
||||||
play_all_no_tags = Play All Frames (Ignore Tags)
|
|
||||||
play_subtags_and_repeats = Play Subtags & Repetitions
|
|
||||||
rewind_on_stop = Rewind on Stop
|
|
||||||
|
|
||||||
[recover_files]
|
[recover_files]
|
||||||
title = Recover Files
|
title = Recover Files
|
||||||
|
@ -323,8 +323,10 @@ if(ENABLE_UI)
|
|||||||
commands/filters/filter_target_buttons.cpp
|
commands/filters/filter_target_buttons.cpp
|
||||||
commands/filters/filter_window.cpp
|
commands/filters/filter_window.cpp
|
||||||
commands/screenshot.cpp
|
commands/screenshot.cpp
|
||||||
|
commands/set_playback_speed.cpp
|
||||||
commands/show_menu.cpp
|
commands/show_menu.cpp
|
||||||
commands/tileset_mode.cpp
|
commands/tileset_mode.cpp
|
||||||
|
commands/toggle_play_option.cpp
|
||||||
file_selector.cpp
|
file_selector.cpp
|
||||||
modules/gfx.cpp
|
modules/gfx.cpp
|
||||||
modules/gui.cpp
|
modules/gui.cpp
|
||||||
|
@ -608,6 +608,16 @@ bool AppMenus::rebuildRecentList()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Menu* AppMenus::getAnimationMenu()
|
||||||
|
{
|
||||||
|
auto menuItem =
|
||||||
|
dynamic_cast<MenuItem*>(m_rootMenu->findItemById("animation_menu"));
|
||||||
|
if (menuItem)
|
||||||
|
return menuItem->getSubmenu();
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void AppMenus::addMenuGroup(const std::string& groupId,
|
void AppMenus::addMenuGroup(const std::string& groupId,
|
||||||
MenuItem* menuItem)
|
MenuItem* menuItem)
|
||||||
{
|
{
|
||||||
@ -766,10 +776,10 @@ Widget* AppMenus::convertXmlelemToMenuitem(TiXmlElement* elem, Menu* menu)
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* command_id = elem->Attribute("command");
|
const char* commandId = elem->Attribute("command");
|
||||||
Command* command =
|
Command* command =
|
||||||
command_id ? Commands::instance()->byId(command_id):
|
(commandId ? Commands::instance()->byId(commandId):
|
||||||
nullptr;
|
nullptr);
|
||||||
|
|
||||||
// load params
|
// load params
|
||||||
Params params;
|
Params params;
|
||||||
@ -793,8 +803,17 @@ Widget* AppMenus::convertXmlelemToMenuitem(TiXmlElement* elem, Menu* menu)
|
|||||||
if (!menuitem)
|
if (!menuitem)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
// Get menu item text from command friendly name
|
||||||
|
if (command && menuitem->text().empty()) {
|
||||||
|
command->loadParams(params);
|
||||||
|
menuitem->setText(command->friendlyName());
|
||||||
|
}
|
||||||
|
// If the menu item has a specific text, process its mnemonic
|
||||||
|
else {
|
||||||
|
menuitem->processMnemonicFromText();
|
||||||
|
}
|
||||||
|
|
||||||
if (id) menuitem->setId(id);
|
if (id) menuitem->setId(id);
|
||||||
menuitem->processMnemonicFromText();
|
|
||||||
if (group) {
|
if (group) {
|
||||||
m_groups[group].menu = menu;
|
m_groups[group].menu = menu;
|
||||||
m_groups[group].end = menuitem;
|
m_groups[group].end = menuitem;
|
||||||
|
@ -54,6 +54,7 @@ namespace app {
|
|||||||
Menu* getSlicePopupMenu() { return m_slicePopupMenu.get(); }
|
Menu* getSlicePopupMenu() { return m_slicePopupMenu.get(); }
|
||||||
Menu* getPalettePopupMenu() { return m_palettePopupMenu.get(); }
|
Menu* getPalettePopupMenu() { return m_palettePopupMenu.get(); }
|
||||||
Menu* getInkPopupMenu() { return m_inkPopupMenu.get(); }
|
Menu* getInkPopupMenu() { return m_inkPopupMenu.get(); }
|
||||||
|
Menu* getAnimationMenu();
|
||||||
|
|
||||||
void applyShortcutToMenuitemsWithCommand(Command* command, const Params& params,
|
void applyShortcutToMenuitemsWithCommand(Command* command, const Params& params,
|
||||||
const KeyPtr& key);
|
const KeyPtr& key);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2022 Igara Studio S.A.
|
// Copyright (C) 2022-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -29,8 +29,9 @@ public:
|
|||||||
PlayAnimationCommand();
|
PlayAnimationCommand();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool onEnabled(Context* context) override;
|
bool onEnabled(Context* ctx) override;
|
||||||
void onExecute(Context* context) override;
|
bool onChecked(Context* ctx) override;
|
||||||
|
void onExecute(Context* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
PlayAnimationCommand::PlayAnimationCommand()
|
PlayAnimationCommand::PlayAnimationCommand()
|
||||||
@ -38,17 +39,23 @@ PlayAnimationCommand::PlayAnimationCommand()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayAnimationCommand::onEnabled(Context* context)
|
bool PlayAnimationCommand::onEnabled(Context* ctx)
|
||||||
{
|
{
|
||||||
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
return ctx->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
||||||
ContextFlags::HasActiveSprite);
|
ContextFlags::HasActiveSprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayAnimationCommand::onExecute(Context* context)
|
bool PlayAnimationCommand::onChecked(Context* ctx)
|
||||||
|
{
|
||||||
|
auto editor = Editor::activeEditor();
|
||||||
|
return (editor && editor->isPlaying());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayAnimationCommand::onExecute(Context* ctx)
|
||||||
{
|
{
|
||||||
// Do not play one-frame images
|
// Do not play one-frame images
|
||||||
{
|
{
|
||||||
ContextReader writer(context);
|
ContextReader writer(ctx);
|
||||||
Sprite* sprite(writer.sprite());
|
Sprite* sprite(writer.sprite());
|
||||||
if (!sprite || sprite->totalFrames() < 2)
|
if (!sprite || sprite->totalFrames() < 2)
|
||||||
return;
|
return;
|
||||||
@ -74,8 +81,9 @@ public:
|
|||||||
PlayPreviewAnimationCommand();
|
PlayPreviewAnimationCommand();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool onEnabled(Context* context) override;
|
bool onEnabled(Context* ctx) override;
|
||||||
void onExecute(Context* context) override;
|
bool onChecked(Context* ctx) override;
|
||||||
|
void onExecute(Context* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
PlayPreviewAnimationCommand::PlayPreviewAnimationCommand()
|
PlayPreviewAnimationCommand::PlayPreviewAnimationCommand()
|
||||||
@ -83,13 +91,19 @@ PlayPreviewAnimationCommand::PlayPreviewAnimationCommand()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayPreviewAnimationCommand::onEnabled(Context* context)
|
bool PlayPreviewAnimationCommand::onEnabled(Context* ctx)
|
||||||
{
|
{
|
||||||
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
return ctx->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
||||||
ContextFlags::HasActiveSprite);
|
ContextFlags::HasActiveSprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayPreviewAnimationCommand::onExecute(Context* context)
|
bool PlayPreviewAnimationCommand::onChecked(Context* ctx)
|
||||||
|
{
|
||||||
|
PreviewEditorWindow* preview = App::instance()->mainWindow()->getPreviewEditor();
|
||||||
|
return (preview && preview->previewEditor()->isPlaying());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayPreviewAnimationCommand::onExecute(Context* ctx)
|
||||||
{
|
{
|
||||||
PreviewEditorWindow* preview = App::instance()->mainWindow()->getPreviewEditor();
|
PreviewEditorWindow* preview = App::instance()->mainWindow()->getPreviewEditor();
|
||||||
if (!preview->isPreviewEnabled())
|
if (!preview->isPreviewEnabled())
|
||||||
|
@ -146,6 +146,7 @@ FOR_EACH_COMMAND(SetInkType)
|
|||||||
FOR_EACH_COMMAND(SetLoopSection)
|
FOR_EACH_COMMAND(SetLoopSection)
|
||||||
FOR_EACH_COMMAND(SetPalette)
|
FOR_EACH_COMMAND(SetPalette)
|
||||||
FOR_EACH_COMMAND(SetPaletteEntrySize)
|
FOR_EACH_COMMAND(SetPaletteEntrySize)
|
||||||
|
FOR_EACH_COMMAND(SetPlaybackSpeed)
|
||||||
FOR_EACH_COMMAND(SetSameInk)
|
FOR_EACH_COMMAND(SetSameInk)
|
||||||
FOR_EACH_COMMAND(ShowAutoGuides)
|
FOR_EACH_COMMAND(ShowAutoGuides)
|
||||||
FOR_EACH_COMMAND(ShowBrushPreview)
|
FOR_EACH_COMMAND(ShowBrushPreview)
|
||||||
@ -167,7 +168,11 @@ FOR_EACH_COMMAND(SymmetryMode)
|
|||||||
FOR_EACH_COMMAND(TiledMode)
|
FOR_EACH_COMMAND(TiledMode)
|
||||||
FOR_EACH_COMMAND(TilesetMode)
|
FOR_EACH_COMMAND(TilesetMode)
|
||||||
FOR_EACH_COMMAND(Timeline)
|
FOR_EACH_COMMAND(Timeline)
|
||||||
|
FOR_EACH_COMMAND(TogglePlayAll)
|
||||||
|
FOR_EACH_COMMAND(TogglePlayOnce)
|
||||||
|
FOR_EACH_COMMAND(TogglePlaySubtags)
|
||||||
FOR_EACH_COMMAND(TogglePreview)
|
FOR_EACH_COMMAND(TogglePreview)
|
||||||
|
FOR_EACH_COMMAND(ToggleRewindOnStop)
|
||||||
FOR_EACH_COMMAND(ToggleTilesMode)
|
FOR_EACH_COMMAND(ToggleTilesMode)
|
||||||
FOR_EACH_COMMAND(ToggleTimelineThumbnails)
|
FOR_EACH_COMMAND(ToggleTimelineThumbnails)
|
||||||
FOR_EACH_COMMAND(UndoHistory)
|
FOR_EACH_COMMAND(UndoHistory)
|
||||||
|
66
src/app/commands/set_playback_speed.cpp
Normal file
66
src/app/commands/set_playback_speed.cpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (c) 2023 Igara Studio S.A.
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "app/commands/new_params.h"
|
||||||
|
#include "app/ui_context.h"
|
||||||
|
#include "app/ui/editor/editor.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
struct SetPlaybackSpeedParams : public NewParams {
|
||||||
|
Param<double> multiplier { this, 1.0, "multiplier" };
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetPlaybackSpeedCommand : public CommandWithNewParams<SetPlaybackSpeedParams> {
|
||||||
|
public:
|
||||||
|
SetPlaybackSpeedCommand();
|
||||||
|
protected:
|
||||||
|
bool onChecked(Context* ctx) override;
|
||||||
|
void onExecute(Context* ctx) override;
|
||||||
|
std::string onGetFriendlyName() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
SetPlaybackSpeedCommand::SetPlaybackSpeedCommand()
|
||||||
|
: CommandWithNewParams(CommandId::SetPlaybackSpeed(), CmdUIOnlyFlag)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetPlaybackSpeedCommand::onChecked(Context* ctx)
|
||||||
|
{
|
||||||
|
Editor* editor = nullptr;
|
||||||
|
if (ctx->isUIAvailable())
|
||||||
|
editor = static_cast<UIContext*>(ctx)->activeEditor();
|
||||||
|
if (editor)
|
||||||
|
return (params().multiplier() == editor->getAnimationSpeedMultiplier());
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPlaybackSpeedCommand::onExecute(Context* ctx)
|
||||||
|
{
|
||||||
|
Editor* editor = nullptr;
|
||||||
|
if (ctx->isUIAvailable())
|
||||||
|
editor = static_cast<UIContext*>(ctx)->activeEditor();
|
||||||
|
if (editor)
|
||||||
|
editor->setAnimationSpeedMultiplier(params().multiplier());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SetPlaybackSpeedCommand::onGetFriendlyName() const
|
||||||
|
{
|
||||||
|
return fmt::format(getBaseFriendlyName(), params().multiplier());
|
||||||
|
}
|
||||||
|
|
||||||
|
Command* CommandFactory::createSetPlaybackSpeedCommand()
|
||||||
|
{
|
||||||
|
return new SetPlaybackSpeedCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
116
src/app/commands/toggle_play_option.cpp
Normal file
116
src/app/commands/toggle_play_option.cpp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (c) 2023 Igara Studio S.A.
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "app/commands/command.h"
|
||||||
|
#include "app/pref/preferences.h"
|
||||||
|
#include "app/ui/doc_view.h"
|
||||||
|
#include "app/ui_context.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
class TogglePlayOptionCommand : public Command {
|
||||||
|
public:
|
||||||
|
TogglePlayOptionCommand(const char* id,
|
||||||
|
Option<bool>* general,
|
||||||
|
Option<bool>* preview);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DocView* docView(Context* ctx) {
|
||||||
|
if (ctx->isUIAvailable())
|
||||||
|
return static_cast<UIContext*>(ctx)->activeView();
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool onEnabled(Context* ctx) override;
|
||||||
|
bool onChecked(Context* ctx) override;
|
||||||
|
void onExecute(Context* ctx) override;
|
||||||
|
|
||||||
|
Option<bool>* m_general;
|
||||||
|
Option<bool>* m_preview;
|
||||||
|
};
|
||||||
|
|
||||||
|
TogglePlayOptionCommand::TogglePlayOptionCommand(
|
||||||
|
const char* id,
|
||||||
|
Option<bool>* general,
|
||||||
|
Option<bool>* preview)
|
||||||
|
: Command(id, CmdUIOnlyFlag)
|
||||||
|
, m_general(general)
|
||||||
|
, m_preview(preview)
|
||||||
|
{
|
||||||
|
ASSERT(m_general);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TogglePlayOptionCommand::onEnabled(Context* ctx)
|
||||||
|
{
|
||||||
|
if (auto docView = this->docView(ctx))
|
||||||
|
return (!docView->isPreview() || m_preview);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TogglePlayOptionCommand::onChecked(Context* ctx)
|
||||||
|
{
|
||||||
|
if (auto docView = this->docView(ctx))
|
||||||
|
return (docView->isPreview() && m_preview ? (*m_preview)(): (*m_general)());
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TogglePlayOptionCommand::onExecute(Context* ctx)
|
||||||
|
{
|
||||||
|
if (auto docView = this->docView(ctx)) {
|
||||||
|
if (docView->isPreview()) {
|
||||||
|
ASSERT(m_preview);
|
||||||
|
if (m_preview)
|
||||||
|
(*m_preview)(!(*m_preview)());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
(*m_general)(!(*m_general)());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Command* CommandFactory::createTogglePlayOnceCommand()
|
||||||
|
{
|
||||||
|
auto& pref = Preferences::instance();
|
||||||
|
return new TogglePlayOptionCommand(
|
||||||
|
CommandId::TogglePlayOnce(),
|
||||||
|
&pref.editor.playOnce,
|
||||||
|
&pref.preview.playOnce);
|
||||||
|
}
|
||||||
|
|
||||||
|
Command* CommandFactory::createTogglePlayAllCommand()
|
||||||
|
{
|
||||||
|
auto& pref = Preferences::instance();
|
||||||
|
return new TogglePlayOptionCommand(
|
||||||
|
CommandId::TogglePlayAll(),
|
||||||
|
&pref.editor.playAll,
|
||||||
|
&pref.preview.playAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
Command* CommandFactory::createTogglePlaySubtagsCommand()
|
||||||
|
{
|
||||||
|
auto& pref = Preferences::instance();
|
||||||
|
return new TogglePlayOptionCommand(
|
||||||
|
CommandId::TogglePlaySubtags(),
|
||||||
|
&pref.editor.playSubtags,
|
||||||
|
&pref.preview.playSubtags);
|
||||||
|
}
|
||||||
|
|
||||||
|
Command* CommandFactory::createToggleRewindOnStopCommand()
|
||||||
|
{
|
||||||
|
auto& pref = Preferences::instance();
|
||||||
|
return new TogglePlayOptionCommand(
|
||||||
|
CommandId::ToggleRewindOnStop(),
|
||||||
|
&pref.general.rewindOnStop,
|
||||||
|
nullptr); // No option for preview
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -12,6 +12,7 @@
|
|||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
|
|
||||||
#include "app/app.h"
|
#include "app/app.h"
|
||||||
|
#include "app/app_menus.h"
|
||||||
#include "app/color.h"
|
#include "app/color.h"
|
||||||
#include "app/color_picker.h"
|
#include "app/color_picker.h"
|
||||||
#include "app/color_utils.h"
|
#include "app/color_utils.h"
|
||||||
@ -34,6 +35,7 @@
|
|||||||
#include "app/tools/tool_box.h"
|
#include "app/tools/tool_box.h"
|
||||||
#include "app/ui/color_bar.h"
|
#include "app/ui/color_bar.h"
|
||||||
#include "app/ui/context_bar.h"
|
#include "app/ui/context_bar.h"
|
||||||
|
#include "app/ui/doc_view.h"
|
||||||
#include "app/ui/editor/drawing_state.h"
|
#include "app/ui/editor/drawing_state.h"
|
||||||
#include "app/ui/editor/editor_customization_delegate.h"
|
#include "app/ui/editor/editor_customization_delegate.h"
|
||||||
#include "app/ui/editor/editor_decorator.h"
|
#include "app/ui/editor/editor_decorator.h"
|
||||||
@ -2789,76 +2791,29 @@ bool Editor::isPlaying() const
|
|||||||
return m_isPlaying;
|
return m_isPlaying;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::showAnimationSpeedMultiplierPopup(Option<bool>& playOnce,
|
void Editor::showAnimationSpeedMultiplierPopup()
|
||||||
Option<bool>& playAll,
|
|
||||||
Option<bool>& playSubtags,
|
|
||||||
const bool withStopBehaviorOptions)
|
|
||||||
{
|
{
|
||||||
const double options[] = { 0.25, 0.5, 1.0, 1.5, 2.0, 3.0 };
|
if (auto menu = AppMenus::instance()->getAnimationMenu()) {
|
||||||
Menu menu;
|
UIContext::SetTargetView setView(m_docView);
|
||||||
|
menu->showPopup(mousePosInDisplay(), display());
|
||||||
for (double option : options) {
|
|
||||||
MenuItem* item = new MenuItem(fmt::format(Strings::preview_speed_x(), option));
|
|
||||||
item->Click.connect([this, option]{ setAnimationSpeedMultiplier(option); });
|
|
||||||
item->setSelected(m_aniSpeed == option);
|
|
||||||
menu.addChild(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.addChild(new MenuSeparator);
|
|
||||||
|
|
||||||
// Play once option
|
|
||||||
{
|
|
||||||
MenuItem* item = new MenuItem(Strings::preview_play_once());
|
|
||||||
item->Click.connect(
|
|
||||||
[&playOnce]() {
|
|
||||||
playOnce(!playOnce());
|
|
||||||
});
|
|
||||||
item->setSelected(playOnce());
|
|
||||||
menu.addChild(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Play all option
|
|
||||||
{
|
|
||||||
MenuItem* item = new MenuItem(Strings::preview_play_all_no_tags());
|
|
||||||
item->Click.connect(
|
|
||||||
[&playAll]() {
|
|
||||||
playAll(!playAll());
|
|
||||||
});
|
|
||||||
item->setSelected(playAll());
|
|
||||||
menu.addChild(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Play subtags & repeats
|
|
||||||
{
|
|
||||||
MenuItem* item = new MenuItem(Strings::preview_play_subtags_and_repeats());
|
|
||||||
item->Click.connect(
|
|
||||||
[&playSubtags]() {
|
|
||||||
playSubtags(!playSubtags());
|
|
||||||
});
|
|
||||||
item->setSelected(playSubtags());
|
|
||||||
menu.addChild(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (withStopBehaviorOptions) {
|
|
||||||
MenuItem* item = new MenuItem(Strings::preview_rewind_on_stop());
|
|
||||||
item->Click.connect(
|
|
||||||
[]() {
|
|
||||||
// Switch the "rewind_on_stop" option
|
|
||||||
Preferences::instance().general.rewindOnStop(
|
|
||||||
!Preferences::instance().general.rewindOnStop());
|
|
||||||
});
|
|
||||||
item->setSelected(Preferences::instance().general.rewindOnStop());
|
|
||||||
menu.addChild(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
menu.showPopup(mousePosInDisplay(), display());
|
|
||||||
|
|
||||||
if (isPlaying()) {
|
if (isPlaying()) {
|
||||||
// Re-play
|
// Re-play
|
||||||
stop();
|
stop();
|
||||||
play(playOnce(),
|
|
||||||
playAll(),
|
// TODO improve/generalize this in some way
|
||||||
playSubtags());
|
auto& pref = Preferences::instance();
|
||||||
|
if (m_docView->isPreview()) {
|
||||||
|
play(pref.preview.playOnce(),
|
||||||
|
pref.preview.playAll(),
|
||||||
|
pref.preview.playSubtags());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
play(pref.editor.playOnce(),
|
||||||
|
pref.editor.playAll(),
|
||||||
|
pref.editor.playSubtags());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -282,10 +282,7 @@ namespace app {
|
|||||||
bool isPlaying() const;
|
bool isPlaying() const;
|
||||||
|
|
||||||
// Shows a popup menu to change the editor animation speed.
|
// Shows a popup menu to change the editor animation speed.
|
||||||
void showAnimationSpeedMultiplierPopup(Option<bool>& playOnce,
|
void showAnimationSpeedMultiplierPopup();
|
||||||
Option<bool>& playAll,
|
|
||||||
Option<bool>& playSubtags,
|
|
||||||
const bool withStopBehaviorOptions);
|
|
||||||
double getAnimationSpeedMultiplier() const;
|
double getAnimationSpeedMultiplier() const;
|
||||||
void setAnimationSpeedMultiplier(double speed);
|
void setAnimationSpeedMultiplier(double speed);
|
||||||
|
|
||||||
|
@ -332,13 +332,7 @@ void PreviewEditorWindow::onPopupSpeed()
|
|||||||
if (!miniEditor || !miniEditor->document())
|
if (!miniEditor || !miniEditor->document())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto& pref = Preferences::instance();
|
miniEditor->showAnimationSpeedMultiplierPopup();
|
||||||
|
|
||||||
miniEditor->showAnimationSpeedMultiplierPopup(
|
|
||||||
pref.preview.playOnce,
|
|
||||||
pref.preview.playAll,
|
|
||||||
pref.preview.playSubtags,
|
|
||||||
false);
|
|
||||||
m_aniSpeed = miniEditor->getAnimationSpeedMultiplier();
|
m_aniSpeed = miniEditor->getAnimationSpeedMultiplier();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -95,10 +95,7 @@ void AniControls::onRightClick(Item* item)
|
|||||||
|
|
||||||
auto editor = Editor::activeEditor();
|
auto editor = Editor::activeEditor();
|
||||||
if (item == getItem(ACTION_PLAY) && editor) {
|
if (item == getItem(ACTION_PLAY) && editor) {
|
||||||
editor->showAnimationSpeedMultiplierPopup(
|
editor->showAnimationSpeedMultiplierPopup();
|
||||||
Preferences::instance().editor.playOnce,
|
|
||||||
Preferences::instance().editor.playAll,
|
|
||||||
Preferences::instance().editor.playSubtags, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -34,8 +34,7 @@ namespace app {
|
|||||||
UIContext* UIContext::m_instance = nullptr;
|
UIContext* UIContext::m_instance = nullptr;
|
||||||
|
|
||||||
UIContext::UIContext()
|
UIContext::UIContext()
|
||||||
: m_lastSelectedView(nullptr)
|
: m_closedDocs(preferences())
|
||||||
, m_closedDocs(preferences())
|
|
||||||
{
|
{
|
||||||
ASSERT(m_instance == nullptr);
|
ASSERT(m_instance == nullptr);
|
||||||
m_instance = this;
|
m_instance = this;
|
||||||
@ -67,6 +66,10 @@ DocView* UIContext::activeView() const
|
|||||||
if (!isUIAvailable())
|
if (!isUIAvailable())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
// Bypass the active workspace view.
|
||||||
|
if (m_targetView)
|
||||||
|
return m_targetView;
|
||||||
|
|
||||||
Workspace* workspace = App::instance()->workspace();
|
Workspace* workspace = App::instance()->workspace();
|
||||||
if (!workspace)
|
if (!workspace)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -49,6 +49,23 @@ namespace app {
|
|||||||
void reopenLastClosedDoc();
|
void reopenLastClosedDoc();
|
||||||
std::vector<Doc*> getAndRemoveAllClosedDocs();
|
std::vector<Doc*> getAndRemoveAllClosedDocs();
|
||||||
|
|
||||||
|
// Sets the DocView used to run some specific commands
|
||||||
|
// (e.g. commands that depend on the current view or the preview
|
||||||
|
// view).
|
||||||
|
class SetTargetView {
|
||||||
|
DocView* m_old;
|
||||||
|
public:
|
||||||
|
SetTargetView(DocView* newView) {
|
||||||
|
auto ctx = UIContext::instance();
|
||||||
|
m_old = ctx->m_targetView;
|
||||||
|
ctx->m_targetView = newView;
|
||||||
|
}
|
||||||
|
~SetTargetView() {
|
||||||
|
auto ctx = UIContext::instance();
|
||||||
|
ctx->m_targetView = m_old;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onAddDocument(Doc* doc) override;
|
void onAddDocument(Doc* doc) override;
|
||||||
void onRemoveDocument(Doc* doc) override;
|
void onRemoveDocument(Doc* doc) override;
|
||||||
@ -62,7 +79,13 @@ namespace app {
|
|||||||
void onCloseDocument(Doc* doc) override;
|
void onCloseDocument(Doc* doc) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DocView* m_lastSelectedView;
|
DocView* m_lastSelectedView = nullptr;
|
||||||
|
|
||||||
|
// Temporary DocView used to change activeView() behavior, used in
|
||||||
|
// some specific commands that depends on the current DocView (or
|
||||||
|
// the preview DocView).
|
||||||
|
DocView* m_targetView = nullptr;
|
||||||
|
|
||||||
ClosedDocs m_closedDocs;
|
ClosedDocs m_closedDocs;
|
||||||
|
|
||||||
static UIContext* m_instance;
|
static UIContext* m_instance;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "ui/menu.h"
|
#include "ui/menu.h"
|
||||||
|
|
||||||
|
#include "base/scoped_value.h"
|
||||||
#include "gfx/size.h"
|
#include "gfx/size.h"
|
||||||
#include "os/font.h"
|
#include "os/font.h"
|
||||||
#include "ui/display.h"
|
#include "ui/display.h"
|
||||||
@ -344,6 +345,11 @@ bool MenuItem::hasSubmenu() const
|
|||||||
void Menu::showPopup(const gfx::Point& pos,
|
void Menu::showPopup(const gfx::Point& pos,
|
||||||
Display* parentDisplay)
|
Display* parentDisplay)
|
||||||
{
|
{
|
||||||
|
// Set the owner menu item to nullptr temporarily in case that we
|
||||||
|
// are re-using a menu from the root menu as popup menu (e.g. like
|
||||||
|
// "animation_menu", that is used when right-cliking a Play button)
|
||||||
|
base::ScopedValue<MenuItem*> restoreOwner(m_menuitem, nullptr, m_menuitem);
|
||||||
|
|
||||||
// Generally, when we call showPopup() the menu shouldn't contain a
|
// Generally, when we call showPopup() the menu shouldn't contain a
|
||||||
// parent menu-box, because we're filtering kMouseDownMessage to
|
// parent menu-box, because we're filtering kMouseDownMessage to
|
||||||
// close the popup automatically when we click outside the menubox.
|
// close the popup automatically when we click outside the menubox.
|
||||||
@ -1169,7 +1175,11 @@ void Menu::highlightItem(MenuItem* menuitem, bool click, bool open_submenu, bool
|
|||||||
menuitem->invalidate();
|
menuitem->invalidate();
|
||||||
|
|
||||||
// Scroll
|
// Scroll
|
||||||
View* view = View::getView(menuitem->parent()->parent());
|
View* view = nullptr;
|
||||||
|
if (menuitem->parent() &&
|
||||||
|
menuitem->parent()->parent()) {
|
||||||
|
view = View::getView(menuitem->parent()->parent());
|
||||||
|
}
|
||||||
if (view) {
|
if (view) {
|
||||||
gfx::Rect itemBounds = menuitem->bounds();
|
gfx::Rect itemBounds = menuitem->bounds();
|
||||||
itemBounds.y -= menuitem->parent()->origin().y;
|
itemBounds.y -= menuitem->parent()->origin().y;
|
||||||
|
Loading…
Reference in New Issue
Block a user