diff --git a/data/gui.xml b/data/gui.xml
index f91529ab3..e3b3b4b80 100644
--- a/data/gui.xml
+++ b/data/gui.xml
@@ -148,6 +148,15 @@
+
+
+
+
+
+
+
+
diff --git a/src/gui/jaccel.cpp b/src/gui/jaccel.cpp
index dc7770226..d687d8cb5 100644
--- a/src/gui/jaccel.cpp
+++ b/src/gui/jaccel.cpp
@@ -225,8 +225,7 @@ static void proc_one_word(JAccel accel, char* word)
}
}
- if (ascii || scancode)
- jaccel_add_key(accel, shifts, ascii, scancode);
+ jaccel_add_key(accel, shifts, ascii, scancode);
}
/* process strings like " " */
@@ -467,17 +466,21 @@ bool jaccel_check(JAccel accel, int shifts, int ascii, int scancode)
JI_LIST_FOR_EACH(accel->key_list, link) {
key = (KeyCombo *)link->data;
+
#ifdef REPORT_KEYS
keycombo_get_string(key, buf);
printf("%3d==%3d %3d==%3d %s==%s ",
key->scancode, scancode, key->ascii, ascii, buf, buf2);
#endif
+
if (((key->scancode && key->scancode == scancode)
|| (key->ascii && key->ascii == ascii))
- && (key->shifts == (shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG)))) {
+ && (key->shifts == (shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG | KB_ALT_FLAG)))) {
+
#ifdef REPORT_KEYS
printf("true\n");
#endif
+
return true;
}
#ifdef REPORT_KEYS
@@ -487,3 +490,25 @@ bool jaccel_check(JAccel accel, int shifts, int ascii, int scancode)
return false;
}
+
+bool jaccel_check_from_key(JAccel accel)
+{
+ int shifts = 0;
+
+ if (key[KEY_LSHIFT]) shifts |= KB_SHIFT_FLAG;
+ if (key[KEY_RSHIFT]) shifts |= KB_SHIFT_FLAG;
+ if (key[KEY_LCONTROL]) shifts |= KB_CTRL_FLAG;
+ if (key[KEY_RCONTROL]) shifts |= KB_CTRL_FLAG;
+ if (key[KEY_ALT]) shifts |= KB_ALT_FLAG;
+
+ JLink link;
+ JI_LIST_FOR_EACH(accel->key_list, link) {
+ KeyCombo* keyCombo = (KeyCombo*)link->data;
+
+ if ((keyCombo->scancode == 0 || key[keyCombo->scancode]) &&
+ (keyCombo->shifts == (shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG | KB_ALT_FLAG)))) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/gui/jaccel.h b/src/gui/jaccel.h
index afb2521e7..3209fb59e 100644
--- a/src/gui/jaccel.h
+++ b/src/gui/jaccel.h
@@ -20,5 +20,6 @@ bool jaccel_is_empty(JAccel accel);
void jaccel_to_string(JAccel accel, char *buf);
bool jaccel_check(JAccel accel, int shifts, int ascii, int scancode);
+bool jaccel_check_from_key(JAccel accel);
#endif
diff --git a/src/modules/gui.cpp b/src/modules/gui.cpp
index 381cc934b..0ef7de117 100644
--- a/src/modules/gui.cpp
+++ b/src/modules/gui.cpp
@@ -90,7 +90,8 @@ static GfxMode lastWorkingGfxMode;
//////////////////////////////////////////////////////////////////////
enum ShortcutType { Shortcut_ExecuteCommand,
- Shortcut_ChangeTool };
+ Shortcut_ChangeTool,
+ Shortcut_EditorQuicktool };
struct Shortcut
{
@@ -106,12 +107,14 @@ struct Shortcut
~Shortcut();
void add_shortcut(const char* shortcut_string);
- bool is_key_pressed(JMessage msg);
+ bool is_pressed(JMessage msg);
+ bool is_pressed_from_key_array();
};
static Shortcut* get_keyboard_shortcut_for_command(const char* command_name, Params* params);
static Shortcut* get_keyboard_shortcut_for_tool(Tool* tool);
+static Shortcut* get_keyboard_shortcut_for_quicktool(Tool* tool);
//////////////////////////////////////////////////////////////////////
@@ -929,6 +932,21 @@ JAccel add_keyboard_shortcut_to_change_tool(const char* shortcut_string, Tool* t
return shortcut->accel;
}
+JAccel add_keyboard_shortcut_to_quicktool(const char* shortcut_string, Tool* tool)
+{
+ Shortcut* shortcut = get_keyboard_shortcut_for_quicktool(tool);
+
+ if (!shortcut) {
+ shortcut = new Shortcut(Shortcut_EditorQuicktool);
+ shortcut->tool = tool;
+
+ shortcuts->push_back(shortcut);
+ }
+
+ shortcut->add_shortcut(shortcut_string);
+ return shortcut->accel;
+}
+
Command* get_command_from_key_message(JMessage msg)
{
for (std::vector::iterator
@@ -938,7 +956,7 @@ Command* get_command_from_key_message(JMessage msg)
if (shortcut->type == Shortcut_ExecuteCommand &&
// TODO why?
// shortcut->argument.empty() &&
- shortcut->is_key_pressed(msg)) {
+ shortcut->is_pressed(msg)) {
return shortcut->command;
}
}
@@ -963,6 +981,23 @@ JAccel get_accel_to_change_tool(Tool* tool)
return NULL;
}
+Tool* get_selected_quicktool()
+{
+ ToolBox* toolbox = App::instance()->getToolBox();
+
+ // Iterate over all tools
+ for (ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
+ Shortcut* shortcut = get_keyboard_shortcut_for_quicktool(*it);
+
+ // Collect all tools with the pressed keyboard-shortcut
+ if (shortcut && shortcut->is_pressed_from_key_array()) {
+ return *it;
+ }
+ }
+
+ return NULL;
+}
+
Shortcut::Shortcut(ShortcutType type)
{
this->type = type;
@@ -985,7 +1020,7 @@ void Shortcut::add_shortcut(const char* shortcut_string)
jaccel_add_keys_from_string(this->accel, buf);
}
-bool Shortcut::is_key_pressed(JMessage msg)
+bool Shortcut::is_pressed(JMessage msg)
{
if (accel) {
return jaccel_check(accel,
@@ -996,6 +1031,14 @@ bool Shortcut::is_key_pressed(JMessage msg)
return false;
}
+bool Shortcut::is_pressed_from_key_array()
+{
+ if (accel) {
+ return jaccel_check_from_key(accel);
+ }
+ return false;
+}
+
static Shortcut* get_keyboard_shortcut_for_command(const char* command_name, Params* params)
{
Command* command = CommandsModule::instance()->get_command_by_name(command_name);
@@ -1032,6 +1075,21 @@ static Shortcut* get_keyboard_shortcut_for_tool(Tool* tool)
return NULL;
}
+static Shortcut* get_keyboard_shortcut_for_quicktool(Tool* tool)
+{
+ for (std::vector::iterator
+ it = shortcuts->begin(); it != shortcuts->end(); ++it) {
+ Shortcut* shortcut = *it;
+
+ if (shortcut->type == Shortcut_EditorQuicktool &&
+ shortcut->tool == tool) {
+ 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
@@ -1120,7 +1178,7 @@ static bool manager_msg_proc(JWidget widget, JMessage msg)
it = shortcuts->begin(); it != shortcuts->end(); ++it) {
Shortcut* shortcut = *it;
- if (shortcut->is_key_pressed(msg)) {
+ if (shortcut->is_pressed(msg)) {
switch (shortcut->type) {
case Shortcut_ChangeTool: {
@@ -1134,7 +1192,7 @@ static bool manager_msg_proc(JWidget widget, JMessage msg)
Shortcut* shortcut = get_keyboard_shortcut_for_tool(*it);
// Collect all tools with the pressed keyboard-shortcut
- if (shortcut && shortcut->is_key_pressed(msg))
+ if (shortcut && shortcut->is_pressed(msg))
possibles.push_back(*it);
}
@@ -1197,6 +1255,12 @@ static bool manager_msg_proc(JWidget widget, JMessage msg)
break;
}
+ case Shortcut_EditorQuicktool: {
+ // Do nothing, it is used in the editor through the
+ // get_selected_quicktool() function.
+ break;
+ }
+
}
break;
}
diff --git a/src/modules/gui.h b/src/modules/gui.h
index 15009cc31..25b4d3334 100644
--- a/src/modules/gui.h
+++ b/src/modules/gui.h
@@ -105,10 +105,12 @@ 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, Tool* tool);
+JAccel add_keyboard_shortcut_to_quicktool(const char* shortcut, Tool* tool);
Command* get_command_from_key_message(JMessage msg);
JAccel get_accel_to_execute_command(const char* command, Params* params = NULL);
JAccel get_accel_to_change_tool(Tool* tool);
+Tool* get_selected_quicktool();
//////////////////////////////////////////////////////////////////////
// Monitors
diff --git a/src/modules/rootmenu.cpp b/src/modules/rootmenu.cpp
index a137017ea..32a2cf265 100644
--- a/src/modules/rootmenu.cpp
+++ b/src/modules/rootmenu.cpp
@@ -113,6 +113,8 @@ static int load_root_menu()
throw ase_exception("Error loading main menu from file:\n%s\nReinstall the application.",
static_cast(path));
+ PRINTF("Main menu loaded.\n");
+
layer_popup_menu = load_menu_by_id(handle, "layer_popup");
frame_popup_menu = load_menu_by_id(handle, "frame_popup");
cel_popup_menu = load_menu_by_id(handle, "cel_popup");
@@ -190,7 +192,6 @@ static int load_root_menu()
if (tool_id && tool_key) {
Tool* tool = App::instance()->getToolBox()->getToolById(tool_id);
if (tool) {
- /* add the keyboard shortcut to the tool */
PRINTF(" - Shortcut for tool `%s': <%s>\n", tool_id, tool_key);
add_keyboard_shortcut_to_change_tool(tool_key, tool);
}
@@ -199,6 +200,33 @@ static int load_root_menu()
xmlKey = xmlKey->NextSiblingElement();
}
+ /**************************************************/
+ /* load keyboard shortcuts for quicktools */
+ /**************************************************/
+
+ PRINTF(" - Loading tools keyboard shortcuts from \"%s\"...\n", path);
+
+ //
+ xmlKey = handle
+ .FirstChild("gui")
+ .FirstChild("keyboard")
+ .FirstChild("quicktools")
+ .FirstChild("key").ToElement();
+ while (xmlKey) {
+ const char* tool_id = xmlKey->Attribute("tool");
+ const char* tool_key = xmlKey->Attribute("shortcut");
+
+ if (tool_id && tool_key) {
+ Tool* tool = App::instance()->getToolBox()->getToolById(tool_id);
+ if (tool) {
+ PRINTF(" - Shortcut for quicktool `%s': <%s>\n", tool_id, tool_key);
+ add_keyboard_shortcut_to_quicktool(tool_key, tool);
+ }
+ }
+
+ xmlKey = xmlKey->NextSiblingElement();
+ }
+
// Sets the "menu" of the "menu-bar" to the new "root-menu"
if (app_get_menubar()) {
jmenubar_set_menu(app_get_menubar(), root_menu);
diff --git a/src/widgets/editor.h b/src/widgets/editor.h
index d7951a046..45a33c80c 100644
--- a/src/widgets/editor.h
+++ b/src/widgets/editor.h
@@ -89,9 +89,9 @@ class Editor : public Widget
// True if the cursor is inside the mask/selection
bool m_insideSelection : 1;
- bool m_alt_pressed : 1;
- bool m_ctrl_pressed : 1;
- bool m_space_pressed : 1;
+ // Current selected quicktool (this genererally should be NULL if
+ // the user is not pressing any keyboard key).
+ Tool* m_quicktool;
/* offset for the sprite */
int m_offset_x;
@@ -166,6 +166,7 @@ public:
private:
void editor_update_statusbar_for_pixel_movement();
+ void editor_update_quicktool();
void editor_draw_cursor(int x, int y, bool refresh = true);
void editor_move_cursor(int x, int y, bool refresh = true);
diff --git a/src/widgets/editor/editor.cpp b/src/widgets/editor/editor.cpp
index 693782512..5c214efac 100644
--- a/src/widgets/editor/editor.cpp
+++ b/src/widgets/editor/editor.cpp
@@ -92,9 +92,8 @@ Editor::Editor()
m_cursor_candraw = false;
m_insideSelection = false;
- m_alt_pressed = false;
- m_ctrl_pressed = false;
- m_space_pressed = false;
+
+ m_quicktool = NULL;
m_offset_x = 0;
m_offset_y = 0;
@@ -687,10 +686,12 @@ void Editor::dropPixels()
Tool* Editor::getCurrentEditorTool()
{
- UIContext* context = UIContext::instance();
- Tool* current_tool = context->getSettings()->getCurrentTool();
-
- return current_tool;
+ if (m_quicktool)
+ return m_quicktool;
+ else {
+ UIContext* context = UIContext::instance();
+ return context->getSettings()->getCurrentTool();
+ }
}
void Editor::screen_to_editor(int xin, int yin, int *xout, int *yout)
@@ -747,9 +748,11 @@ void Editor::editor_update_statusbar_for_standby()
int x, y;
screen_to_editor(jmouse_x(0), jmouse_y(0), &x, &y);
+ if (!m_sprite) {
+ app_get_statusbar()->clearText();
+ }
// For eye-dropper
- if (m_alt_pressed ||
- current_tool->getInk(0)->isEyedropper()) {
+ else if (current_tool->getInk(0)->isEyedropper()) {
int imgtype = m_sprite->getImgType();
ase_uint32 pixel = m_sprite->getPixel(x, y);
Color color = Color::fromImage(imgtype, pixel);
@@ -767,11 +770,13 @@ void Editor::editor_update_statusbar_for_standby()
}
// For other tools
else {
+ Mask* mask = m_sprite->getMask();
+
app_get_statusbar()->setStatusText
(0, "Pos %d %d, Size %d %d, Frame %d",
x, y,
- ((m_sprite->getMask()->bitmap)? m_sprite->getMask()->w: m_sprite->getWidth()),
- ((m_sprite->getMask()->bitmap)? m_sprite->getMask()->h: m_sprite->getHeight()),
+ ((mask && mask->bitmap)? mask->w: m_sprite->getWidth()),
+ ((mask && mask->bitmap)? mask->h: m_sprite->getHeight()),
m_sprite->getCurrentFrame()+1);
}
}
@@ -787,6 +792,18 @@ void Editor::editor_update_statusbar_for_pixel_movement()
bounds.x, bounds.y, bounds.w, bounds.h);
}
+void Editor::editor_update_quicktool()
+{
+ Tool* old_quicktool = m_quicktool;
+
+ m_quicktool = get_selected_quicktool();
+
+ // 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)
+ editor_update_statusbar_for_standby();
+}
+
void Editor::editor_refresh_region()
{
if (this->update_region) {
@@ -981,19 +998,11 @@ bool Editor::onProcessMessage(JMessage msg)
// 'cursor_candraw' field to avoid a heavy if-condition in the
// 'editor_setcursor' routine
editor_update_candraw();
-
- if (msg->any.shifts & KB_ALT_FLAG) m_alt_pressed = true;
- if (msg->any.shifts & KB_CTRL_FLAG) m_ctrl_pressed = true;
- if (key[KEY_SPACE]) m_space_pressed = true;
+ editor_update_quicktool();
break;
case JM_MOUSELEAVE:
hide_drawing_cursor();
-
- if (m_alt_pressed) m_alt_pressed = false;
- if (m_ctrl_pressed) m_ctrl_pressed = false;
- if (m_space_pressed) m_space_pressed = false;
-
app_get_statusbar()->clearText();
break;
@@ -1036,7 +1045,6 @@ bool Editor::onProcessMessage(JMessage msg)
// Start scroll loop
if (msg->mouse.middle ||
- m_space_pressed ||
current_tool->getInk(msg->mouse.right ? 1: 0)->isScrollMovement()) {
m_state = EDITOR_STATE_SCROLLING;
@@ -1064,9 +1072,7 @@ bool Editor::onProcessMessage(JMessage msg)
}
// Move frames position
- if ((m_ctrl_pressed &&
- !current_tool->getInk(msg->mouse.right ? 1: 0)->isSelection()) ||
- current_tool->getInk(msg->mouse.right ? 1: 0)->isCelMovement()) {
+ if (current_tool->getInk(msg->mouse.right ? 1: 0)->isCelMovement()) {
if ((m_sprite->getCurrentLayer()) &&
(m_sprite->getCurrentLayer()->getType() == GFXOBJ_LAYER_IMAGE)) {
// TODO you can move the `Background' with tiled mode
@@ -1106,7 +1112,7 @@ bool Editor::onProcessMessage(JMessage msg)
delete tmpImage;
// If the CTRL key is pressed start dragging a copy of the selection
- if (m_ctrl_pressed)
+ if (key[KEY_LCONTROL] || key[KEY_RCONTROL]) // TODO configurable
m_pixelsMovement->copyMask();
else
m_pixelsMovement->cutMask();
@@ -1124,8 +1130,7 @@ bool Editor::onProcessMessage(JMessage msg)
captureMouse();
}
// Call the eyedropper command
- else if (m_alt_pressed ||
- current_tool->getInk(msg->mouse.right ? 1: 0)->isEyedropper()) {
+ else if (current_tool->getInk(msg->mouse.right ? 1: 0)->isEyedropper()) {
Command* eyedropper_cmd =
CommandsModule::instance()->get_command_by_name(CommandId::eyedropper);
@@ -1332,30 +1337,18 @@ bool Editor::onProcessMessage(JMessage msg)
}
if (this->hasMouse()) {
- switch (msg->key.scancode) {
-
- // Eye-dropper is activated with ALT key
- case KEY_ALT:
- m_alt_pressed = true;
- editor_setcursor(jmouse_x(0), jmouse_y(0));
- return true;
+ editor_update_quicktool();
- case KEY_LCONTROL:
- case KEY_RCONTROL:
- // If the user press the CTRL key when he is dragging pixels (but not pressing the mouse buttons)...
- if (!m_ctrl_pressed && !jmouse_b(0) && m_pixelsMovement) {
- // Drop pixels (sure the user will press the mouse button to start dragging a copy)
- dropPixels();
- }
- m_ctrl_pressed = true;
- editor_setcursor(jmouse_x(0), jmouse_y(0));
- return true;
-
- case KEY_SPACE:
- m_space_pressed = true;
- editor_setcursor(jmouse_x(0), jmouse_y(0));
- return true;
+ if (msg->key.scancode == KEY_LCONTROL || // TODO configurable
+ msg->key.scancode == KEY_RCONTROL) {
+ // If the user press the CTRL key when he is dragging pixels (but not pressing the mouse buttons)...
+ if (!jmouse_b(0) && m_pixelsMovement) {
+ // Drop pixels (sure the user will press the mouse button to start dragging a copy)
+ dropPixels();
+ }
}
+
+ editor_setcursor(jmouse_x(0), jmouse_y(0));
}
// When we are drawing, we "eat" all pressed keys
@@ -1365,37 +1358,14 @@ bool Editor::onProcessMessage(JMessage msg)
break;
case JM_KEYRELEASED:
- switch (msg->key.scancode) {
+ editor_update_quicktool();
+ editor_setcursor(jmouse_x(0), jmouse_y(0));
+ break;
- // Eye-dropper is deactivated with ALT key
- case KEY_ALT:
- if (m_alt_pressed) {
- m_alt_pressed = false;
- editor_setcursor(jmouse_x(0), jmouse_y(0));
- return true;
- }
- break;
-
- case KEY_LCONTROL:
- case KEY_RCONTROL:
- if (m_ctrl_pressed) {
- m_ctrl_pressed = false;
- editor_setcursor(jmouse_x(0), jmouse_y(0));
- return true;
- }
- break;
-
- case KEY_SPACE:
- if (m_space_pressed) {
- // We have to clear all the KEY_SPACE in buffer
- clear_keybuf();
-
- m_space_pressed = false;
- editor_setcursor(jmouse_x(0), jmouse_y(0));
- return true;
- }
- break;
- }
+ case JM_FOCUSLEAVE:
+ // As we use keys like Space-bar as modifier, we can clear the
+ // keyboard buffer when we lost the focus.
+ clear_keybuf();
break;
case JM_WHEEL:
@@ -1627,23 +1597,6 @@ void Editor::editor_setcursor(int x, int y)
jmouse_set_cursor(JI_CURSOR_FORBIDDEN);
}
}
- // Eyedropper
- else if (m_alt_pressed) {
- hide_drawing_cursor();
- jmouse_set_cursor(JI_CURSOR_EYEDROPPER);
- }
- // Move layer
- else if (m_ctrl_pressed &&
- (!current_tool ||
- !current_tool->getInk(0)->isSelection())) {
- hide_drawing_cursor();
- jmouse_set_cursor(JI_CURSOR_MOVE);
- }
- // Scroll
- else if (m_space_pressed) {
- hide_drawing_cursor();
- jmouse_set_cursor(JI_CURSOR_SCROLL);
- }
else {
if (current_tool) {
// If the current tool change selection (e.g. rectangular marquee, etc.)
@@ -1654,7 +1607,8 @@ void Editor::editor_setcursor(int x, int y)
// Move pixels
if (m_sprite->getMask()->contains_point(x, y)) {
hide_drawing_cursor();
- if (m_ctrl_pressed)
+ if (key[KEY_LCONTROL] ||
+ key[KEY_RCONTROL]) // TODO configurable keys
jmouse_set_cursor(JI_CURSOR_NORMAL_ADD);
else
jmouse_set_cursor(JI_CURSOR_MOVE);
@@ -1676,6 +1630,11 @@ void Editor::editor_setcursor(int x, int y)
jmouse_set_cursor(JI_CURSOR_SCROLL);
return;
}
+ else if (current_tool->getInk(0)->isCelMovement()) {
+ hide_drawing_cursor();
+ jmouse_set_cursor(JI_CURSOR_MOVE);
+ return;
+ }
}
if (m_insideSelection) {