mirror of https://github.com/aseprite/aseprite.git
Revert Esc key behavior to drop+deselect (fix #5102)
This adds a new button in the context bar so we have the three available options to handle a transformation/drop pixels: * Drop pixels and deselect (Esc key) * Drop pixels but keep the selection (Enter key), new "Apply" command * Discard changes/undo (Ctrl+Z) This adds a new key context (Transformation) and also fixes tooltip shortcuts on context bar buttons to show the current configured shortcut for each action. Revertsdebab653fa
and194f8424a8
This commit is contained in:
parent
0c49f2d7ad
commit
f61c2c3950
Binary file not shown.
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
@ -331,6 +331,8 @@
|
|||
<part id="flag_highlight" x="16" y="240" w="16" h="10"/>
|
||||
<part id="drop_pixels_ok" x="176" y="176" w="7" h="8"/>
|
||||
<part id="drop_pixels_ok_selected" x="176" y="184" w="7" h="8"/>
|
||||
<part id="drop_pixels_drop" x="184" y="176" w="7" h="8"/>
|
||||
<part id="drop_pixels_drop_selected" x="184" y="184" w="7" h="8"/>
|
||||
<part id="drop_pixels_cancel" x="192" y="176" w="7" h="8"/>
|
||||
<part id="drop_pixels_cancel_selected" x="192" y="184" w="7" h="8"/>
|
||||
<part id="warning_box" x="112" y="80" w="9" h="10"/>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
@ -327,6 +327,8 @@
|
|||
<part id="flag_highlight" x="16" y="240" w="16" h="10"/>
|
||||
<part id="drop_pixels_ok" x="176" y="176" w="7" h="8"/>
|
||||
<part id="drop_pixels_ok_selected" x="176" y="184" w="7" h="8"/>
|
||||
<part id="drop_pixels_drop" x="184" y="176" w="7" h="8"/>
|
||||
<part id="drop_pixels_drop_selected" x="184" y="184" w="7" h="8"/>
|
||||
<part id="drop_pixels_cancel" x="192" y="176" w="7" h="8"/>
|
||||
<part id="drop_pixels_cancel_selected" x="192" y="184" w="7" h="8"/>
|
||||
<part id="warning_box" x="112" y="80" w="9" h="10"/>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2018-2024 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2018-2025 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2018 David Capello -->
|
||||
<gui>
|
||||
<!-- Keyboard shortcuts -->
|
||||
|
@ -371,6 +371,12 @@
|
|||
<param name="quantity" value="1" />
|
||||
</key>
|
||||
|
||||
<!-- Main selection actions (apply transformation / undo) -->
|
||||
<key command="DeselectMask" shortcut="Esc" context="Transformation" />
|
||||
<key command="Apply" shortcut="Enter" context="Transformation" />
|
||||
<key command="Apply" shortcut="Enter Pad" context="Transformation" />
|
||||
<key command="Undo" shortcut="Ctrl+Z" mac="Cmd+Z" context="Transformation" />
|
||||
|
||||
<!-- Move selection with arrows -->
|
||||
<key command="MoveMask" shortcut="Left" context="Selection">
|
||||
<param name="target" value="content" />
|
||||
|
|
|
@ -146,10 +146,6 @@
|
|||
<value id="KEEP_AS_IS" value="1" />
|
||||
<value id="RAW_IMAGE" value="2" />
|
||||
</enum>
|
||||
<enum id="CancelSelection">
|
||||
<value id="DISCARD" value="0" />
|
||||
<value id="DESELECT" value="1" />
|
||||
</enum>
|
||||
</types>
|
||||
|
||||
<global>
|
||||
|
@ -329,7 +325,6 @@
|
|||
<option id="force_rotsprite" type="bool" default="false" />
|
||||
<option id="multicel_when_layers_or_frames" type="bool" default="true" />
|
||||
<option id="snap_to_grid" type="bool" default="true" />
|
||||
<option id="cancel_selection" type="CancelSelection" default="CancelSelection::DISCARD" />
|
||||
</section>
|
||||
<section id="quantization">
|
||||
<option id="with_alpha" type="bool" default="true" />
|
||||
|
|
|
@ -206,6 +206,7 @@ AddColor_Background = Background
|
|||
AddColor_Foreground = Foreground
|
||||
AddColor_Specific = Specific
|
||||
AdvancedMode = Advanced Mode
|
||||
Apply = Apply
|
||||
AutocropSprite = Trim Sprite
|
||||
AutocropSprite_ByGrid = Trim Sprite by Grid
|
||||
BackgroundFromLayer = Background from Layer
|
||||
|
@ -554,8 +555,6 @@ amount = Amount:
|
|||
flatten = Merge layers
|
||||
|
||||
[context_bar]
|
||||
discard_changes = Discard Changes
|
||||
deselect = Deselect
|
||||
center = Center
|
||||
fit_screen = Fit Screen
|
||||
back = Back
|
||||
|
@ -583,8 +582,9 @@ rotsprite = RotSprite
|
|||
pixel_perfect = Pixel-perfect
|
||||
linear_gradient = Linear Gradient
|
||||
radial_gradient = Radial Gradient
|
||||
drop_pixel = Drop pixels here (Enter)
|
||||
cancel_drag = Cancel drag and drop (Esc)\nRight-click: Configure action
|
||||
drop_pixel_and_deselect = Apply transformation and deselect
|
||||
drop_pixel = Apply transformation and keep selection
|
||||
cancel_drag = Cancel transformation and undo/discard changes
|
||||
auto_select_layer = Auto Select Layer
|
||||
all = All
|
||||
none = None
|
||||
|
@ -967,6 +967,7 @@ key_context_move_tool = Move Tool
|
|||
key_context_freehand_tool = Freehand Tool
|
||||
key_context_shape_tool = Shape Tool
|
||||
key_context_frames_selection = Frames Selection
|
||||
key_context_transformation = Transformation
|
||||
copy_selection = Copy Selection
|
||||
snap_to_grid = Snap To Grid
|
||||
lock_axis = Lock Axis
|
||||
|
|
|
@ -74,7 +74,7 @@ add_custom_command(
|
|||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${output_fn}.tmp ${output_fn}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
MAIN_DEPENDENCY ${strings_en_ini}
|
||||
DEPENDS ${GEN_DEP})
|
||||
DEPENDS ${GEN_DEP} commands/commands_list.h)
|
||||
list(APPEND generated_files ${output_fn})
|
||||
|
||||
# Check translations
|
||||
|
@ -368,6 +368,7 @@ target_sources(app-lib PRIVATE
|
|||
color_picker.cpp
|
||||
color_spaces.cpp
|
||||
color_utils.cpp
|
||||
commands/apply.cpp
|
||||
commands/cmd_about.cpp
|
||||
commands/cmd_add_color.cpp
|
||||
commands/cmd_advanced_mode.cpp
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2025 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/context.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
// Depends on the current context/state, used to apply the current
|
||||
// transformation (drop pixels).
|
||||
class ApplyCommand : public Command {
|
||||
public:
|
||||
ApplyCommand();
|
||||
|
||||
protected:
|
||||
void onExecute(Context* ctx) override;
|
||||
};
|
||||
|
||||
ApplyCommand::ApplyCommand() : Command(CommandId::Apply(), CmdUIOnlyFlag)
|
||||
{
|
||||
}
|
||||
|
||||
void ApplyCommand::onExecute(Context* ctx)
|
||||
{
|
||||
if (!ctx->isUIAvailable())
|
||||
return;
|
||||
|
||||
auto* editor = Editor::activeEditor();
|
||||
if (editor && editor->isMovingPixels())
|
||||
editor->dropMovingPixels();
|
||||
}
|
||||
|
||||
Command* CommandFactory::createApplyCommand()
|
||||
{
|
||||
return new ApplyCommand;
|
||||
}
|
||||
|
||||
} // namespace app
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -8,6 +8,7 @@
|
|||
FOR_EACH_COMMAND(About)
|
||||
FOR_EACH_COMMAND(AddColor)
|
||||
FOR_EACH_COMMAND(AdvancedMode)
|
||||
FOR_EACH_COMMAND(Apply)
|
||||
FOR_EACH_COMMAND(AutocropSprite)
|
||||
FOR_EACH_COMMAND(BackgroundFromLayer)
|
||||
FOR_EACH_COMMAND(BrightnessContrast)
|
||||
|
|
|
@ -681,81 +681,89 @@ void CustomizedGuiManager::onNewDisplayConfiguration(Display* display)
|
|||
bool CustomizedGuiManager::processKey(Message* msg)
|
||||
{
|
||||
App* app = App::instance();
|
||||
const KeyContext currentCtx = KeyboardShortcuts::getCurrentKeyContext();
|
||||
const KeyboardShortcuts* keys = KeyboardShortcuts::instance();
|
||||
const KeyContext contexts[] = { KeyboardShortcuts::getCurrentKeyContext(), KeyContext::Normal };
|
||||
const KeyContext contexts[] = { currentCtx, KeyContext::Normal };
|
||||
int n = (contexts[0] != contexts[1] ? 2 : 1);
|
||||
|
||||
// Find best match (prefer the shortcut that matches the context first)
|
||||
KeyPtr key = nullptr;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
for (const KeyPtr& key : *keys) {
|
||||
if (key->isPressed(msg, contexts[i])) {
|
||||
// Cancel menu-bar loops (to close any popup menu)
|
||||
app->mainWindow()->getMenuBar()->cancelMenuLoop();
|
||||
|
||||
switch (key->type()) {
|
||||
case KeyType::Tool: {
|
||||
tools::Tool* current_tool = app->activeTool();
|
||||
tools::Tool* select_this_tool = key->tool();
|
||||
tools::ToolBox* toolbox = app->toolBox();
|
||||
std::vector<tools::Tool*> possibles;
|
||||
|
||||
// Collect all tools with the pressed keyboard-shortcut
|
||||
for (tools::Tool* tool : *toolbox) {
|
||||
const KeyPtr key = keys->tool(tool);
|
||||
if (key && key->isPressed(msg))
|
||||
possibles.push_back(tool);
|
||||
}
|
||||
|
||||
if (possibles.size() >= 2) {
|
||||
bool done = false;
|
||||
|
||||
for (size_t i = 0; i < possibles.size(); ++i) {
|
||||
if (possibles[i] != current_tool &&
|
||||
ToolBar::instance()->isToolVisible(possibles[i])) {
|
||||
select_this_tool = possibles[i];
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
for (size_t i = 0; i < possibles.size(); ++i) {
|
||||
// If one of the possibilities is the current tool
|
||||
if (possibles[i] == current_tool) {
|
||||
// We select the next tool in the possibilities
|
||||
select_this_tool = possibles[(i + 1) % possibles.size()];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ToolBar::instance()->selectTool(select_this_tool);
|
||||
return true;
|
||||
}
|
||||
|
||||
case KeyType::Command: {
|
||||
Command* command = key->command();
|
||||
|
||||
// Commands are executed only when the main window is
|
||||
// the current window running.
|
||||
if (getForegroundWindow() == app->mainWindow()) {
|
||||
// OK, so we can execute the command represented
|
||||
// by the pressed-key in the message...
|
||||
UIContext::instance()->executeCommandFromMenuOrShortcut(command, key->params());
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyType::Quicktool: {
|
||||
// Do nothing, it is used in the editor through the
|
||||
// KeyboardShortcuts::getCurrentQuicktool() function.
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
for (const KeyPtr& k : *keys) {
|
||||
if (k->isPressed(msg, contexts[i]) &&
|
||||
(!key || (key->keycontext() != currentCtx && k->keycontext() == currentCtx))) {
|
||||
key = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
// Cancel menu-bar loops (to close any popup menu)
|
||||
app->mainWindow()->getMenuBar()->cancelMenuLoop();
|
||||
|
||||
switch (key->type()) {
|
||||
case KeyType::Tool: {
|
||||
tools::Tool* current_tool = app->activeTool();
|
||||
tools::Tool* select_this_tool = key->tool();
|
||||
tools::ToolBox* toolbox = app->toolBox();
|
||||
std::vector<tools::Tool*> possibles;
|
||||
|
||||
// Collect all tools with the pressed keyboard-shortcut
|
||||
for (tools::Tool* tool : *toolbox) {
|
||||
const KeyPtr key = keys->tool(tool);
|
||||
if (key && key->isPressed(msg))
|
||||
possibles.push_back(tool);
|
||||
}
|
||||
|
||||
if (possibles.size() >= 2) {
|
||||
bool done = false;
|
||||
|
||||
for (size_t i = 0; i < possibles.size(); ++i) {
|
||||
if (possibles[i] != current_tool && ToolBar::instance()->isToolVisible(possibles[i])) {
|
||||
select_this_tool = possibles[i];
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
for (size_t i = 0; i < possibles.size(); ++i) {
|
||||
// If one of the possibilities is the current tool
|
||||
if (possibles[i] == current_tool) {
|
||||
// We select the next tool in the possibilities
|
||||
select_this_tool = possibles[(i + 1) % possibles.size()];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ToolBar::instance()->selectTool(select_this_tool);
|
||||
return true;
|
||||
}
|
||||
|
||||
case KeyType::Command: {
|
||||
Command* command = key->command();
|
||||
|
||||
// Commands are executed only when the main window is
|
||||
// the current window running.
|
||||
if (getForegroundWindow() == app->mainWindow()) {
|
||||
// OK, so we can execute the command represented
|
||||
// by the pressed-key in the message...
|
||||
UIContext::instance()->executeCommandFromMenuOrShortcut(command, key->params());
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyType::Quicktool: {
|
||||
// Do nothing, it is used in the editor through the
|
||||
// KeyboardShortcuts::getCurrentQuicktool() function.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -388,7 +388,6 @@ FOR_ENUM(app::gen::TimelinePosition)
|
|||
FOR_ENUM(app::gen::ToGrayAlgorithm)
|
||||
FOR_ENUM(app::gen::WindowColorProfile)
|
||||
FOR_ENUM(app::gen::AlphaRange)
|
||||
FOR_ENUM(app::gen::CancelSelection)
|
||||
FOR_ENUM(app::tools::ColorFromTo)
|
||||
FOR_ENUM(app::tools::DynamicSensor)
|
||||
FOR_ENUM(app::tools::FreehandAlgorithm)
|
||||
|
|
|
@ -1390,11 +1390,12 @@ public:
|
|||
|
||||
class ContextBar::DropPixelsField : public ButtonSet {
|
||||
public:
|
||||
DropPixelsField() : ButtonSet(2)
|
||||
DropPixelsField() : ButtonSet(3)
|
||||
{
|
||||
auto* theme = SkinTheme::get(this);
|
||||
|
||||
addItem(theme->parts.dropPixelsOk(), theme->styles.contextBarButton());
|
||||
addItem(theme->parts.dropPixelsDrop(), theme->styles.contextBarButton());
|
||||
addItem(theme->parts.dropPixelsCancel(), theme->styles.contextBarButton());
|
||||
setOfferCapture(false);
|
||||
}
|
||||
|
@ -1402,12 +1403,29 @@ public:
|
|||
void setupTooltips(TooltipManager* tooltipManager)
|
||||
{
|
||||
// TODO Enter and Esc should be configurable keys
|
||||
tooltipManager->addTooltipFor(at(0), Strings::context_bar_drop_pixel(), BOTTOM);
|
||||
tooltipManager->addTooltipFor(at(1), Strings::context_bar_cancel_drag(), BOTTOM);
|
||||
|
||||
tooltipManager->addTooltipFor(
|
||||
at(0),
|
||||
key_tooltip(Strings::context_bar_drop_pixel_and_deselect().c_str(),
|
||||
CommandId::DeselectMask(),
|
||||
{},
|
||||
KeyContext::Transformation),
|
||||
BOTTOM);
|
||||
tooltipManager->addTooltipFor(at(1),
|
||||
key_tooltip(Strings::context_bar_drop_pixel().c_str(),
|
||||
CommandId::Apply(),
|
||||
{},
|
||||
KeyContext::Transformation),
|
||||
BOTTOM);
|
||||
tooltipManager->addTooltipFor(at(2),
|
||||
key_tooltip(Strings::context_bar_cancel_drag().c_str(),
|
||||
CommandId::Undo(),
|
||||
{},
|
||||
KeyContext::Transformation),
|
||||
BOTTOM);
|
||||
}
|
||||
|
||||
obs::signal<void(ContextBarObserver::DropAction)> DropPixels;
|
||||
obs::signal<void(ContextBarObserver::DropAction, const gfx::Point&)> ConfigureDropPixels;
|
||||
|
||||
protected:
|
||||
void onItemChange(Item* item) override
|
||||
|
@ -1415,25 +1433,11 @@ protected:
|
|||
ButtonSet::onItemChange(item);
|
||||
|
||||
switch (selectedItem()) {
|
||||
case 0: DropPixels(ContextBarObserver::DropPixels); break;
|
||||
case 1: DropPixels(ContextBarObserver::CancelDrag); break;
|
||||
case 0: DropPixels(ContextBarObserver::Deselect); break;
|
||||
case 1: DropPixels(ContextBarObserver::DropPixels); break;
|
||||
case 2: DropPixels(ContextBarObserver::CancelDrag); break;
|
||||
}
|
||||
}
|
||||
|
||||
void onRightClick(Item* item) override
|
||||
{
|
||||
ButtonSet::onRightClick(item);
|
||||
|
||||
const gfx::Rect rc = item->bounds();
|
||||
const gfx::Point pt(rc.x, rc.y2());
|
||||
|
||||
auto action = ContextBarObserver::DropPixels;
|
||||
switch (selectedItem()) {
|
||||
case 0: action = ContextBarObserver::DropPixels; break;
|
||||
case 1: action = ContextBarObserver::CancelDrag; break;
|
||||
}
|
||||
ConfigureDropPixels(action, pt);
|
||||
}
|
||||
};
|
||||
|
||||
class ContextBar::EyedropperField : public HBox {
|
||||
|
@ -1968,8 +1972,6 @@ ContextBar::ContextBar(TooltipManager* tooltipManager, ColorBar* colorBar)
|
|||
m_keysConn = KeyboardShortcuts::instance()->UserChange.connect(
|
||||
[this, tooltipManager] { setupTooltips(tooltipManager); });
|
||||
m_dropPixelsConn = m_dropPixels->DropPixels.connect(&ContextBar::onDropPixels, this);
|
||||
m_configureDropPixelsConn =
|
||||
m_dropPixels->ConfigureDropPixels.connect(&ContextBar::onConfigureDropPixels, this);
|
||||
|
||||
setActiveBrush(createBrushFromPreferences());
|
||||
|
||||
|
@ -2114,14 +2116,6 @@ void ContextBar::onDropPixels(ContextBarObserver::DropAction action)
|
|||
notify_observers(&ContextBarObserver::onDropPixels, action);
|
||||
}
|
||||
|
||||
void ContextBar::onConfigureDropPixels(ContextBarObserver::DropAction action, const gfx::Point& pt)
|
||||
{
|
||||
notify_observers<ContextBarObserver::DropAction, const gfx::Point&>(
|
||||
&ContextBarObserver::onConfigureDropPixels,
|
||||
action,
|
||||
pt);
|
||||
}
|
||||
|
||||
void ContextBar::updateSliceFields(const Site& site)
|
||||
{
|
||||
if (site.sprite())
|
||||
|
|
|
@ -129,7 +129,6 @@ private:
|
|||
void onFgOrBgColorChange(doc::Brush::ImageColor imageColor);
|
||||
void onOpacityRangeChange();
|
||||
void onDropPixels(ContextBarObserver::DropAction action);
|
||||
void onConfigureDropPixels(ContextBarObserver::DropAction action, const gfx::Point& pt);
|
||||
void updateSliceFields(const Site& site);
|
||||
|
||||
// ActiveToolObserver impl
|
||||
|
@ -214,7 +213,6 @@ private:
|
|||
obs::scoped_connection m_alphaRangeConn;
|
||||
obs::scoped_connection m_keysConn;
|
||||
obs::scoped_connection m_dropPixelsConn;
|
||||
obs::scoped_connection m_configureDropPixelsConn;
|
||||
obs::scoped_connection m_sizeConn;
|
||||
obs::scoped_connection m_angleConn;
|
||||
obs::scoped_connection m_opacityConn;
|
||||
|
|
|
@ -9,17 +9,14 @@
|
|||
#define APP_CONTEXT_BAR_OBSERVER_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "gfx/fwd.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
class ContextBarObserver {
|
||||
public:
|
||||
enum DropAction { DropPixels, CancelDrag };
|
||||
enum DropAction { Deselect, DropPixels, CancelDrag };
|
||||
|
||||
virtual ~ContextBarObserver() {}
|
||||
virtual void onDropPixels(DropAction action) {}
|
||||
virtual void onConfigureDropPixels(DropAction action, const gfx::Point& pt) {}
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
|
|
@ -470,16 +470,6 @@ bool MovingPixelsState::onKeyDown(Editor* editor, KeyMessage* msg)
|
|||
// FineControl now (e.g. if we pressed another modifier key).
|
||||
m_lockedKeyAction = KeyAction::None;
|
||||
|
||||
// TODO make these keys customizable
|
||||
if (msg->scancode() == kKeyEsc) {
|
||||
cancelDrag();
|
||||
return true;
|
||||
}
|
||||
if (msg->scancode() == kKeyEnter || msg->scancode() == kKeyEnterPad) {
|
||||
dropPixels();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use StandbyState implementation
|
||||
return StandbyState::onKeyDown(editor, msg);
|
||||
}
|
||||
|
@ -630,6 +620,12 @@ void MovingPixelsState::onBeforeCommandExecution(CommandExecutionEvent& ev)
|
|||
return;
|
||||
}
|
||||
}
|
||||
// Handle undo directly as cancelDrag() to avoid adding an action in the history.
|
||||
else if (command->id() == CommandId::Undo()) {
|
||||
cancelDrag();
|
||||
ev.cancel();
|
||||
return;
|
||||
}
|
||||
// Don't drop pixels if the user zooms/scrolls/picks a color
|
||||
// using commands.
|
||||
else if ((command->id() == CommandId::Zoom()) || (command->id() == CommandId::Scroll()) ||
|
||||
|
@ -791,66 +787,33 @@ void MovingPixelsState::onDropPixels(ContextBarObserver::DropAction action)
|
|||
return;
|
||||
|
||||
switch (action) {
|
||||
case ContextBarObserver::Deselect: deselect(); break;
|
||||
case ContextBarObserver::DropPixels: dropPixels(); break;
|
||||
case ContextBarObserver::CancelDrag: cancelDrag(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void MovingPixelsState::deselect()
|
||||
{
|
||||
if (!m_pixelsMovement || m_discarded)
|
||||
return;
|
||||
|
||||
dropPixels();
|
||||
|
||||
Command* cmd = Commands::instance()->byId(CommandId::DeselectMask());
|
||||
UIContext::instance()->executeCommandFromMenuOrShortcut(cmd);
|
||||
}
|
||||
|
||||
void MovingPixelsState::cancelDrag()
|
||||
{
|
||||
if (!m_pixelsMovement || m_discarded)
|
||||
return;
|
||||
|
||||
switch (Preferences::instance().selection.cancelSelection()) {
|
||||
case gen::CancelSelection::DISCARD:
|
||||
m_pixelsMovement->discardImage(PixelsMovement::DontCommitChanges);
|
||||
m_discarded = true;
|
||||
m_pixelsMovement->discardImage(PixelsMovement::DontCommitChanges);
|
||||
m_discarded = true;
|
||||
|
||||
// Quit from MovingPixelsState, back to standby.
|
||||
dropPixels();
|
||||
break;
|
||||
|
||||
case gen::CancelSelection::DESELECT: {
|
||||
dropPixels();
|
||||
|
||||
Command* cmd = Commands::instance()->byId(CommandId::DeselectMask());
|
||||
UIContext::instance()->executeCommandFromMenuOrShortcut(cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MovingPixelsState::onConfigureDropPixels(ContextBarObserver::DropAction action,
|
||||
const gfx::Point& pt)
|
||||
{
|
||||
if (!isActiveEditor())
|
||||
return;
|
||||
|
||||
switch (action) {
|
||||
case ContextBarObserver::DropPixels:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case ContextBarObserver::CancelDrag: {
|
||||
Menu menu;
|
||||
|
||||
MenuItem discardChanges(Strings::context_bar_discard_changes());
|
||||
MenuItem deselect(Strings::context_bar_deselect());
|
||||
menu.addChild(&discardChanges);
|
||||
menu.addChild(&deselect);
|
||||
|
||||
auto& opt = Preferences::instance().selection.cancelSelection;
|
||||
discardChanges.setSelected(opt() == gen::CancelSelection::DISCARD);
|
||||
deselect.setSelected(opt() == gen::CancelSelection::DESELECT);
|
||||
|
||||
discardChanges.Click.connect([&opt] { opt(gen::CancelSelection::DISCARD); });
|
||||
deselect.Click.connect([&opt] { opt(gen::CancelSelection::DESELECT); });
|
||||
|
||||
ContextBar* contextBar = App::instance()->contextBar();
|
||||
menu.showPopup(pt, contextBar->display());
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Quit from MovingPixelsState, back to standby.
|
||||
dropPixels();
|
||||
}
|
||||
|
||||
void MovingPixelsState::onPivotChange()
|
||||
|
|
|
@ -77,7 +77,6 @@ public:
|
|||
|
||||
// ContextBarObserver
|
||||
void onDropPixels(ContextBarObserver::DropAction action) override;
|
||||
void onConfigureDropPixels(ContextBarObserver::DropAction action, const gfx::Point& pt) override;
|
||||
|
||||
// PixelsMovementDelegate
|
||||
void onPivotChange() override;
|
||||
|
@ -95,6 +94,8 @@ private:
|
|||
void onBeforeCommandExecution(CommandExecutionEvent& ev);
|
||||
|
||||
void setTransparentColor(bool opaque, const app::Color& color);
|
||||
|
||||
void deselect();
|
||||
void dropPixels();
|
||||
void cancelDrag();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2023 Igara Studio S.A.
|
||||
// Copyright (C) 2023-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -23,6 +23,7 @@ enum class KeyContext {
|
|||
ShapeTool,
|
||||
MouseWheel,
|
||||
FramesSelection,
|
||||
Transformation,
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "app/tools/ink.h"
|
||||
#include "app/tools/tool.h"
|
||||
#include "app/tools/tool_box.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/key.h"
|
||||
#include "app/ui/timeline/timeline.h"
|
||||
#include "app/ui_context.h"
|
||||
|
@ -157,6 +158,7 @@ static struct {
|
|||
{ "FreehandTool", app::KeyContext::FreehandTool },
|
||||
{ "ShapeTool", app::KeyContext::ShapeTool },
|
||||
{ "FramesSelection", app::KeyContext::FramesSelection },
|
||||
{ "Transformation", app::KeyContext::Transformation },
|
||||
{ NULL, app::KeyContext::Any }
|
||||
};
|
||||
|
||||
|
@ -1078,6 +1080,12 @@ void KeyboardShortcuts::disableShortcut(const ui::Shortcut& shortcut,
|
|||
// static
|
||||
KeyContext KeyboardShortcuts::getCurrentKeyContext()
|
||||
{
|
||||
// For shortcuts to Apply/Cancel transformation/moving pixels state.
|
||||
auto* editor = Editor::activeEditor();
|
||||
if (editor && editor->isMovingPixels()) {
|
||||
return KeyContext::Transformation;
|
||||
}
|
||||
|
||||
auto* ctx = UIContext::instance();
|
||||
Doc* doc = ctx->activeDocument();
|
||||
if (doc && doc->isMaskVisible() &&
|
||||
|
@ -1335,6 +1343,7 @@ std::string convertKeyContextToUserFriendlyString(KeyContext keyContext)
|
|||
case KeyContext::FreehandTool: return I18N_KEY(key_context_freehand_tool);
|
||||
case KeyContext::ShapeTool: return I18N_KEY(key_context_shape_tool);
|
||||
case KeyContext::FramesSelection: return I18N_KEY(key_context_frames_selection);
|
||||
case KeyContext::Transformation: return I18N_KEY(key_context_transformation);
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue