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 <spriteeditor> section in gui.xml to specify which key is
  used to copy the selection (instead of moving). "Ctrl" is the default.
+ Added EditorCustomizationDelegate interface.
This commit is contained in:
David Capello 2011-10-29 19:21:19 -03:00
parent 2623b1af99
commit d55e4c58e4
10 changed files with 191 additions and 33 deletions

View File

@ -160,6 +160,13 @@
<key tool="hand" shortcut="Space" />
</quicktools>
<!-- Special keyboard shortcuts for the sprite editor -->
<spriteeditor>
<!-- When you drag-and-drop the selection, pressing this
keyboard shortcut you can copy instead of move -->
<key action="CopySelection" shortcut="Ctrl" />
</spriteeditor>
</keyboard>
<menus>

View File

@ -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

View File

@ -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<Shortcut*>::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<Shortcut*>::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)

View File

@ -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

View File

@ -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);
// <gui><keyboard><tools><key>
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
// <gui><keyboard><quicktools><key>
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
// <gui><keyboard><spriteeditor>
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();
}

View File

@ -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,15 +830,19 @@ void Editor::updateStatusBar()
void Editor::editor_update_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();
}
}
//////////////////////////////////////////////////////////////////////
// Message handler for the editor

View File

@ -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();

View File

@ -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

View File

@ -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) {

View File

@ -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);