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