From d55e4c58e4c36271ad9471983073dcb067bb75e5 Mon Sep 17 00:00:00 2001 From: David Capello Date: Sat, 29 Oct 2011 19:21:19 -0300 Subject: [PATCH] Fix regression bug: user isn't able to copy pixels using Ctrl + selection tool. + The problem is that "Ctrl" key is a quicktool (move cel), and it was stealing the "Ctrl" key to the selection tool. + Added section in gui.xml to specify which key is used to copy the selection (instead of moving). "Ctrl" is the default. + Added EditorCustomizationDelegate interface. --- data/gui.xml | 7 +++ src/modules/editors.cpp | 21 ++++++- src/modules/gui.cpp | 62 +++++++++++++++++-- src/modules/gui.h | 5 +- src/modules/rootmenu.cpp | 31 ++++++---- src/widgets/editor/editor.cpp | 28 +++++++-- src/widgets/editor/editor.h | 9 +++ .../editor/editor_customization_delegate.h | 44 +++++++++++++ src/widgets/editor/moving_pixels_state.cpp | 11 ++-- src/widgets/editor/standby_state.cpp | 6 +- 10 files changed, 191 insertions(+), 33 deletions(-) create mode 100644 src/widgets/editor/editor_customization_delegate.h diff --git a/data/gui.xml b/data/gui.xml index 4f568eeb9..58f55808c 100644 --- a/data/gui.xml +++ b/data/gui.xml @@ -160,6 +160,13 @@ + + + + + + diff --git a/src/modules/editors.cpp b/src/modules/editors.cpp index 6e175f59a..c8872069a 100644 --- a/src/modules/editors.cpp +++ b/src/modules/editors.cpp @@ -31,6 +31,7 @@ #include "ui_context.h" #include "util/misc.h" #include "widgets/editor/editor.h" +#include "widgets/editor/editor_customization_delegate.h" #include "widgets/editor/editor_view.h" #include "widgets/popup_frame_pin.h" #include "widgets/statebar.h" @@ -82,19 +83,22 @@ static void update_mini_editor_frame(Editor* editor); static void on_mini_editor_frame_close(CloseEvent& ev); class WrappedEditor : public Editor, - public EditorListener + public EditorListener, + public EditorCustomizationDelegate { public: WrappedEditor() { addListener(this); + setCustomizationDelegate(this); } ~WrappedEditor() { removeListener(this); + setCustomizationDelegate(NULL); } // EditorListener implementation - void dispose() { + void dispose() OVERRIDE { // Do nothing } @@ -111,6 +115,19 @@ public: // Do nothing } + // EditorCustomizationDelegate implementation + tools::Tool* getQuickTool(tools::Tool* currentTool) OVERRIDE { + return get_selected_quicktool(currentTool); + } + + bool isCopySelectionKeyPressed() OVERRIDE { + JAccel accel = get_accel_to_copy_selection(); + if (accel) + return jaccel_check_from_key(accel); + else + return false; + } + }; class MiniEditor : public Editor diff --git a/src/modules/gui.cpp b/src/modules/gui.cpp index 3d8d52d83..9f68098cf 100644 --- a/src/modules/gui.cpp +++ b/src/modules/gui.cpp @@ -29,13 +29,14 @@ #endif #include "app.h" +#include "base/memory.h" #include "base/shared_ptr.h" #include "commands/command.h" #include "commands/commands.h" #include "commands/params.h" #include "console.h" -#include "drop_files.h" #include "document_wrappers.h" +#include "drop_files.h" #include "gfxmode.h" #include "gui/gui.h" #include "gui/intern.h" @@ -50,6 +51,7 @@ #include "skin/button_icon_impl.h" #include "skin/skin_property.h" #include "skin/skin_theme.h" +#include "tools/ink.h" #include "tools/tool_box.h" #include "ui_context.h" #include "widgets/editor/editor.h" @@ -62,6 +64,8 @@ #define MONITOR_TIMER_MSECS 100 +#define SPRITEDITOR_ACTION_COPYSELECTION "CopySelection" + ////////////////////////////////////////////////////////////////////// using namespace gfx; @@ -86,7 +90,8 @@ static GfxMode lastWorkingGfxMode; enum ShortcutType { Shortcut_ExecuteCommand, Shortcut_ChangeTool, - Shortcut_EditorQuicktool }; + Shortcut_EditorQuicktool, + Shortcut_SpriteEditor }; struct Shortcut { @@ -95,6 +100,7 @@ struct Shortcut union { Command* command; tools::Tool* tool; + char* action; }; Params* params; @@ -110,6 +116,7 @@ struct Shortcut static Shortcut* get_keyboard_shortcut_for_command(const char* command_name, Params* params); static Shortcut* get_keyboard_shortcut_for_tool(tools::Tool* tool); static Shortcut* get_keyboard_shortcut_for_quicktool(tools::Tool* tool); +static Shortcut* get_keyboard_shortcut_for_spriteeditor(const char* action_name); ////////////////////////////////////////////////////////////////////// @@ -835,7 +842,6 @@ CheckBox* check_button_new(const char *text, int b1, int b2, int b3, int b4) JAccel add_keyboard_shortcut_to_execute_command(const char* shortcut_string, const char* command_name, Params* params) { Shortcut* shortcut = get_keyboard_shortcut_for_command(command_name, params); - if (!shortcut) { shortcut = new Shortcut(Shortcut_ExecuteCommand); shortcut->command = CommandsModule::instance()->getCommandByName(command_name); @@ -851,7 +857,6 @@ JAccel add_keyboard_shortcut_to_execute_command(const char* shortcut_string, con JAccel add_keyboard_shortcut_to_change_tool(const char* shortcut_string, tools::Tool* tool) { Shortcut* shortcut = get_keyboard_shortcut_for_tool(tool); - if (!shortcut) { shortcut = new Shortcut(Shortcut_ChangeTool); shortcut->tool = tool; @@ -866,7 +871,6 @@ JAccel add_keyboard_shortcut_to_change_tool(const char* shortcut_string, tools:: JAccel add_keyboard_shortcut_to_quicktool(const char* shortcut_string, tools::Tool* tool) { Shortcut* shortcut = get_keyboard_shortcut_for_quicktool(tool); - if (!shortcut) { shortcut = new Shortcut(Shortcut_EditorQuicktool); shortcut->tool = tool; @@ -878,6 +882,20 @@ JAccel add_keyboard_shortcut_to_quicktool(const char* shortcut_string, tools::To return shortcut->accel; } +JAccel add_keyboard_shortcut_to_spriteeditor(const char* shortcut_string, const char* action_name) +{ + Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(action_name); + if (!shortcut) { + shortcut = new Shortcut(Shortcut_SpriteEditor); + shortcut->action = base_strdup(action_name); + + shortcuts->push_back(shortcut); + } + + shortcut->add_shortcut(shortcut_string); + return shortcut->accel; +} + Command* get_command_from_key_message(Message* msg) { for (std::vector::iterator @@ -912,8 +930,23 @@ JAccel get_accel_to_change_tool(tools::Tool* tool) return NULL; } -tools::Tool* get_selected_quicktool() +JAccel get_accel_to_copy_selection() { + Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_COPYSELECTION); + if (shortcut) + return shortcut->accel; + else + return NULL; +} + +tools::Tool* get_selected_quicktool(tools::Tool* currentTool) +{ + if (currentTool && currentTool->getInk(0)->isSelection()) { + JAccel copyselection_accel = get_accel_to_copy_selection(); + if (copyselection_accel && jaccel_check_from_key(copyselection_accel)) + return NULL; + } + tools::ToolBox* toolbox = App::instance()->getToolBox(); // Iterate over all tools @@ -941,6 +974,8 @@ Shortcut::Shortcut(ShortcutType type) Shortcut::~Shortcut() { delete params; + if (type == Shortcut_SpriteEditor) + base_free(action); jaccel_free(accel); } @@ -1021,6 +1056,21 @@ static Shortcut* get_keyboard_shortcut_for_quicktool(tools::Tool* tool) return NULL; } +static Shortcut* get_keyboard_shortcut_for_spriteeditor(const char* action_name) +{ + for (std::vector::iterator + it = shortcuts->begin(); it != shortcuts->end(); ++it) { + Shortcut* shortcut = *it; + + if (shortcut->type == Shortcut_SpriteEditor && + strcmp(shortcut->action, action_name) == 0) { + return shortcut; + } + } + + return NULL; +} + // Adds a routine to be called each 100 milliseconds to monitor // whatever you want. It's mainly used to monitor the progress of a // file-operation (see @ref fop_operate) diff --git a/src/modules/gui.h b/src/modules/gui.h index ac8a4bcc4..376313a36 100644 --- a/src/modules/gui.h +++ b/src/modules/gui.h @@ -110,11 +110,14 @@ CheckBox* check_button_new(const char* text, int b1, int b2, int b3, int b4); JAccel add_keyboard_shortcut_to_execute_command(const char* shortcut, const char* command_name, Params* params); JAccel add_keyboard_shortcut_to_change_tool(const char* shortcut, tools::Tool* tool); JAccel add_keyboard_shortcut_to_quicktool(const char* shortcut, tools::Tool* tool); +JAccel add_keyboard_shortcut_to_spriteeditor(const char* shortcut, const char* action_name); Command* get_command_from_key_message(Message* msg); JAccel get_accel_to_execute_command(const char* command, Params* params = NULL); JAccel get_accel_to_change_tool(tools::Tool* tool); -tools::Tool* get_selected_quicktool(); +JAccel get_accel_to_copy_selection(); + +tools::Tool* get_selected_quicktool(tools::Tool* currentTool); ////////////////////////////////////////////////////////////////////// // Monitors diff --git a/src/modules/rootmenu.cpp b/src/modules/rootmenu.cpp index 563e78958..ee387fd85 100644 --- a/src/modules/rootmenu.cpp +++ b/src/modules/rootmenu.cpp @@ -184,12 +184,8 @@ static int load_root_menu() xmlKey = xmlKey->NextSiblingElement(); } - /**************************************************/ - /* load keyboard shortcuts for tools */ - /**************************************************/ - + // Load keyboard shortcuts for tools PRINTF(" - Loading tools keyboard shortcuts from \"%s\"...\n", path); - // xmlKey = handle .FirstChild("gui") @@ -207,16 +203,10 @@ static int load_root_menu() add_keyboard_shortcut_to_change_tool(tool_key, tool); } } - xmlKey = xmlKey->NextSiblingElement(); } - /**************************************************/ - /* load keyboard shortcuts for quicktools */ - /**************************************************/ - - PRINTF(" - Loading tools keyboard shortcuts from \"%s\"...\n", path); - + // Load keyboard shortcuts for quicktools // xmlKey = handle .FirstChild("gui") @@ -234,7 +224,24 @@ static int load_root_menu() add_keyboard_shortcut_to_quicktool(tool_key, tool); } } + xmlKey = xmlKey->NextSiblingElement(); + } + // Load special keyboard shortcuts for sprite editor customization + // + xmlKey = handle + .FirstChild("gui") + .FirstChild("keyboard") + .FirstChild("spriteeditor") + .FirstChild("key").ToElement(); + while (xmlKey) { + const char* tool_action = xmlKey->Attribute("action"); + const char* tool_key = xmlKey->Attribute("shortcut"); + + if (tool_action && tool_key) { + PRINTF(" - Shortcut for sprite editor `%s': <%s>\n", tool_action, tool_key); + add_keyboard_shortcut_to_spriteeditor(tool_key, tool_action); + } xmlKey = xmlKey->NextSiblingElement(); } diff --git a/src/widgets/editor/editor.cpp b/src/widgets/editor/editor.cpp index 4909e192c..c2e7faa7f 100644 --- a/src/widgets/editor/editor.cpp +++ b/src/widgets/editor/editor.cpp @@ -43,6 +43,7 @@ #include "util/misc.h" #include "util/render.h" #include "widgets/color_bar.h" +#include "widgets/editor/editor_customization_delegate.h" #include "widgets/editor/editor_decorator.h" #include "widgets/editor/standby_state.h" #include "widgets/statebar.h" @@ -118,6 +119,7 @@ Editor::Editor() : Widget(editor_type()) , m_defaultState(EditorStatePtr(new StandbyState())) , m_state(m_defaultState) + , m_customizationDelegate(NULL) { m_document = NULL; m_sprite = NULL; @@ -147,6 +149,8 @@ Editor::Editor() Editor::~Editor() { + setCustomizationDelegate(NULL); + jmanager_remove_timer(m_mask_timer_id); remove_editor(this); @@ -773,6 +777,14 @@ void Editor::removeListener(EditorListener* listener) m_listeners.removeListener(listener); } +void Editor::setCustomizationDelegate(EditorCustomizationDelegate* delegate) +{ + if (m_customizationDelegate) + m_customizationDelegate->dispose(); + + m_customizationDelegate = delegate; +} + // Returns the visible area of the active sprite. Rect Editor::getVisibleSpriteBounds() { @@ -818,14 +830,18 @@ void Editor::updateStatusBar() void Editor::editor_update_quicktool() { - tools::Tool* old_quicktool = m_quicktool; + if (m_customizationDelegate) { + UIContext* context = UIContext::instance(); + tools::Tool* current_tool = context->getSettings()->getCurrentTool(); + tools::Tool* old_quicktool = m_quicktool; - m_quicktool = get_selected_quicktool(); + m_quicktool = m_customizationDelegate->getQuickTool(current_tool); - // If the tool has changed, we must to update the status bar because - // the new tool can display something different in the status bar (e.g. Eyedropper) - if (old_quicktool != m_quicktool) - updateStatusBar(); + // If the tool has changed, we must to update the status bar because + // the new tool can display something different in the status bar (e.g. Eyedropper) + if (old_quicktool != m_quicktool) + updateStatusBar(); + } } ////////////////////////////////////////////////////////////////////// diff --git a/src/widgets/editor/editor.h b/src/widgets/editor/editor.h index 81bc2b01e..1c71ababb 100644 --- a/src/widgets/editor/editor.h +++ b/src/widgets/editor/editor.h @@ -33,6 +33,7 @@ #define MAX_ZOOM 5 class Context; +class EditorCustomizationDelegate; class PixelsMovement; class Sprite; class View; @@ -105,6 +106,12 @@ public: void addListener(EditorListener* listener); void removeListener(EditorListener* listener); + void setCustomizationDelegate(EditorCustomizationDelegate* delegate); + + EditorCustomizationDelegate* getCustomizationDelegate() { + return m_customizationDelegate; + } + // Returns the visible area of the active sprite. gfx::Rect getVisibleSpriteBounds(); @@ -225,6 +232,8 @@ private: EditorListeners m_listeners; + EditorCustomizationDelegate* m_customizationDelegate; + }; int editor_type(); diff --git a/src/widgets/editor/editor_customization_delegate.h b/src/widgets/editor/editor_customization_delegate.h new file mode 100644 index 000000000..3e182f8a0 --- /dev/null +++ b/src/widgets/editor/editor_customization_delegate.h @@ -0,0 +1,44 @@ +/* ASE - Allegro Sprite Editor + * Copyright (C) 2001-2011 David Capello + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef WIDGETS_EDITOR_CUSTOMIZATION_DELEGATE_H_INCLUDED +#define WIDGETS_EDITOR_CUSTOMIZATION_DELEGATE_H_INCLUDED + +class Editor; + +namespace tools { + class Tool; +} + +class EditorCustomizationDelegate +{ +public: + virtual ~EditorCustomizationDelegate() { } + virtual void dispose() = 0; + + // Called to know if the user is pressing a keyboard shortcut to + // select another tool temporarily (a "quick tool"). The given + // "currentTool" is the current tool selected in the toolbox. + virtual tools::Tool* getQuickTool(tools::Tool* currentTool) = 0; + + // Returns true if the user wants to copy the selection instead of + // to move it. + virtual bool isCopySelectionKeyPressed() = 0; +}; + +#endif // WIDGETS_EDITOR_CUSTOMIZATION_DELEGATE_H_INCLUDED diff --git a/src/widgets/editor/moving_pixels_state.cpp b/src/widgets/editor/moving_pixels_state.cpp index abb29c3a0..34eabf8f6 100644 --- a/src/widgets/editor/moving_pixels_state.cpp +++ b/src/widgets/editor/moving_pixels_state.cpp @@ -33,6 +33,7 @@ #include "tools/tool.h" #include "util/misc.h" #include "widgets/editor/editor.h" +#include "widgets/editor/editor_customization_delegate.h" #include "widgets/editor/pixels_movement.h" #include "widgets/editor/standby_state.h" #include "widgets/statebar.h" @@ -41,6 +42,8 @@ MovingPixelsState::MovingPixelsState(Editor* editor, Message* msg, Image* imge, int x, int y, int opacity) { + EditorCustomizationDelegate* customization = editor->getCustomizationDelegate(); + // Copy the mask to the extra cel image Document* document = editor->getDocument(); Sprite* sprite = editor->getSprite(); @@ -50,8 +53,8 @@ MovingPixelsState::MovingPixelsState(Editor* editor, Message* msg, Image* imge, m_pixelsMovement = new PixelsMovement(document, sprite, tmpImage, x, y, opacity); delete tmpImage; - // If the CTRL key is pressed start dragging a copy of the selection - if (key[KEY_LCONTROL] || key[KEY_RCONTROL]) // TODO configurable + // If the Ctrl key is pressed start dragging a copy of the selection + if (customization && customization->isCopySelectionKeyPressed()) m_pixelsMovement->copyMask(); else m_pixelsMovement->cutMask(); @@ -205,9 +208,9 @@ bool MovingPixelsState::onSetCursor(Editor* editor) bool MovingPixelsState::onKeyDown(Editor* editor, Message* msg) { ASSERT(m_pixelsMovement != NULL); + EditorCustomizationDelegate* customization = editor->getCustomizationDelegate(); - if (msg->key.scancode == KEY_LCONTROL || // TODO configurable - msg->key.scancode == KEY_RCONTROL) { + if (customization && customization->isCopySelectionKeyPressed()) { // If the user press the CTRL key when he is dragging pixels (but // not pressing the mouse buttons). if (!jmouse_b(0) && m_pixelsMovement) { diff --git a/src/widgets/editor/standby_state.cpp b/src/widgets/editor/standby_state.cpp index 83c2d9acf..387ccc4d9 100644 --- a/src/widgets/editor/standby_state.cpp +++ b/src/widgets/editor/standby_state.cpp @@ -39,6 +39,7 @@ #include "widgets/color_bar.h" #include "widgets/editor/drawing_state.h" #include "widgets/editor/editor.h" +#include "widgets/editor/editor_customization_delegate.h" #include "widgets/editor/moving_cel_state.h" #include "widgets/editor/moving_pixels_state.h" #include "widgets/editor/scrolling_state.h" @@ -286,10 +287,11 @@ bool StandbyState::onSetCursor(Editor* editor) if (current_ink->isSelection()) { // Move pixels if (editor->isInsideSelection()) { + EditorCustomizationDelegate* customization = editor->getCustomizationDelegate(); + editor->hideDrawingCursor(); - if (key[KEY_LCONTROL] || - key[KEY_RCONTROL]) // TODO configurable keys + if (customization && customization->isCopySelectionKeyPressed()) jmouse_set_cursor(JI_CURSOR_NORMAL_ADD); else jmouse_set_cursor(JI_CURSOR_MOVE);