mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-28 18:32:50 +00:00
Add keyboard shortcuts customization (close #253)
Changes: * Add KeyboardShortcutsCommand and window * Add SelectAccelerator window * Replace modules/gui.cpp functions with app::KeyboardShortcuts and app::Key with the logic to load/save/handle keyboard shortcuts * Change ui::Accelerator concept: now it represent just one keyboard shortcut, not a set of shortcuts * Remove ui::Accelerator from ui::MenuItem, now the key is associated in app::AppMenuItem and it's a app::Key * Add Command::onGetFriendlyName() to get a user friendly name of the command depending on its parameters
This commit is contained in:
parent
ec99866a23
commit
f939ef5f02
10
data/gui.xml
10
data/gui.xml
@ -2,7 +2,7 @@
|
|||||||
<!-- ASE menus, tools and keyboard shortcuts -->
|
<!-- ASE menus, tools and keyboard shortcuts -->
|
||||||
<gui version="1.0.6-dev">
|
<gui version="1.0.6-dev">
|
||||||
<!-- Keyboard shortcuts -->
|
<!-- Keyboard shortcuts -->
|
||||||
<keyboard>
|
<keyboard version="1">
|
||||||
|
|
||||||
<!-- Keyboard shortcuts for commands (menu options) -->
|
<!-- Keyboard shortcuts for commands (menu options) -->
|
||||||
<commands>
|
<commands>
|
||||||
@ -51,6 +51,7 @@
|
|||||||
<key command="ConfigureTools" shortcut="C" />
|
<key command="ConfigureTools" shortcut="C" />
|
||||||
<key command="Options" shortcut="Ctrl+K" mac="Cmd+," />
|
<key command="Options" shortcut="Ctrl+K" mac="Cmd+," />
|
||||||
<key command="Options" shortcut="Ctrl+Shift+O" mac="Cmd+Shift+O" /> <!-- TODO remove this shortcut in v1.1 -->
|
<key command="Options" shortcut="Ctrl+Shift+O" mac="Cmd+Shift+O" /> <!-- TODO remove this shortcut in v1.1 -->
|
||||||
|
<key command="KeyboardShortcuts" shortcut="Ctrl+Alt+Shift+K" mac="Cmd+Alt+Shift+K" />
|
||||||
<!-- Sprite -->
|
<!-- Sprite -->
|
||||||
<key command="SpriteProperties" shortcut="Ctrl+P" mac="Cmd+P" />
|
<key command="SpriteProperties" shortcut="Ctrl+P" mac="Cmd+P" />
|
||||||
<!-- Layer -->
|
<!-- Layer -->
|
||||||
@ -345,8 +346,8 @@
|
|||||||
<key tool="hand" shortcut="Space" />
|
<key tool="hand" shortcut="Space" />
|
||||||
</quicktools>
|
</quicktools>
|
||||||
|
|
||||||
<!-- Special keyboard shortcuts for the sprite editor -->
|
<!-- Special keyboard shortcuts for specific actions -->
|
||||||
<spriteeditor>
|
<actions>
|
||||||
<!-- When you drag-and-drop the selection, pressing this
|
<!-- When you drag-and-drop the selection, pressing this
|
||||||
keyboard shortcut you can copy instead of move -->
|
keyboard shortcut you can copy instead of move -->
|
||||||
<key action="CopySelection" shortcut="Ctrl" />
|
<key action="CopySelection" shortcut="Ctrl" />
|
||||||
@ -370,7 +371,7 @@
|
|||||||
<!-- Modifiers for selection tool -->
|
<!-- Modifiers for selection tool -->
|
||||||
<key action="AddSelection" shortcut="Shift" />
|
<key action="AddSelection" shortcut="Shift" />
|
||||||
<key action="SubtractSelection" shortcut="Alt" />
|
<key action="SubtractSelection" shortcut="Alt" />
|
||||||
</spriteeditor>
|
</actions>
|
||||||
|
|
||||||
</keyboard>
|
</keyboard>
|
||||||
|
|
||||||
@ -436,6 +437,7 @@
|
|||||||
</menu>
|
</menu>
|
||||||
<separator />
|
<separator />
|
||||||
<item command="ConfigureTools" text="Tool&s..." />
|
<item command="ConfigureTools" text="Tool&s..." />
|
||||||
|
<item command="KeyboardShortcuts" text="&Keyboard Shortcuts..." />
|
||||||
<item command="Options" text="Pre&ferences..." />
|
<item command="Options" text="Pre&ferences..." />
|
||||||
</menu>
|
</menu>
|
||||||
<menu text="&Sprite">
|
<menu text="&Sprite">
|
||||||
|
35
data/widgets/keyboard_shortcuts.xml
Normal file
35
data/widgets/keyboard_shortcuts.xml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<!-- Aseprite -->
|
||||||
|
<!-- Copyright (C) 2001-2014 by David Capello -->
|
||||||
|
<gui>
|
||||||
|
<window id="keyboard_shortcuts" text="Keyboard Shortcuts">
|
||||||
|
<hbox>
|
||||||
|
<vbox expansive="true">
|
||||||
|
<hbox>
|
||||||
|
<label text="Section:" />
|
||||||
|
<combobox id="section" expansive="true" />
|
||||||
|
</hbox>
|
||||||
|
<view id="menus_view" expansive="true">
|
||||||
|
<listbox id="menus" />
|
||||||
|
</view>
|
||||||
|
<view id="commands_view" expansive="true">
|
||||||
|
<listbox id="commands" />
|
||||||
|
</view>
|
||||||
|
<view id="tools_view" expansive="true">
|
||||||
|
<listbox id="tools" />
|
||||||
|
</view>
|
||||||
|
<view id="actions_view" expansive="true">
|
||||||
|
<listbox id="actions" />
|
||||||
|
</view>
|
||||||
|
</vbox>
|
||||||
|
<vbox>
|
||||||
|
<button text="&OK" closewindow="true" id="ok" magnet="true" width="60" />
|
||||||
|
<button text="&Cancel" closewindow="true" />
|
||||||
|
<separator horizontal="true" />
|
||||||
|
<button text="&Import" id="import_button" />
|
||||||
|
<button text="&Export" id="export_button" />
|
||||||
|
<separator horizontal="true" />
|
||||||
|
<button text="&Reset" id="reset_button" />
|
||||||
|
</vbox>
|
||||||
|
</hbox>
|
||||||
|
</window>
|
||||||
|
</gui>
|
36
data/widgets/select_accelerator.xml
Normal file
36
data/widgets/select_accelerator.xml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<!-- Aseprite -->
|
||||||
|
<!-- Copyright (C) 2001-2014 by David Capello -->
|
||||||
|
<gui>
|
||||||
|
<window id="select_accelerator" text="Keyboard Shortcut">
|
||||||
|
<vbox expansive="true">
|
||||||
|
<grid columns="3">
|
||||||
|
<label text="Key:" />
|
||||||
|
<hbox id="key_placeholder" expansive="true" />
|
||||||
|
<button text="Clear" id="clear_button" width="60" />
|
||||||
|
|
||||||
|
<label text="Modifiers:" />
|
||||||
|
<hbox cell_hspan="2">
|
||||||
|
<check text="Ctrl" id="ctrl" />
|
||||||
|
<check text="Cmd" id="cmd" />
|
||||||
|
<check text="Alt" id="alt" />
|
||||||
|
<check text="Shift" id="shift" />
|
||||||
|
<check text="Space" id="space" />
|
||||||
|
</hbox>
|
||||||
|
|
||||||
|
<label text="" id="assigned_to" cell_hspan="3" />
|
||||||
|
</grid>
|
||||||
|
|
||||||
|
<separator horizontal="true" />
|
||||||
|
|
||||||
|
<box horizontal="true">
|
||||||
|
<boxfiller />
|
||||||
|
<box horizontal="true" homogeneous="true">
|
||||||
|
<button text="OK" id="ok_button" magnet="true" width="60" />
|
||||||
|
<button text="Cancel" id="cancel_button" />
|
||||||
|
<button text="Delete" id="delete_button" />
|
||||||
|
</box>
|
||||||
|
</box>
|
||||||
|
|
||||||
|
</vbox>
|
||||||
|
</window>
|
||||||
|
</gui>
|
@ -44,6 +44,7 @@ add_library(app-lib
|
|||||||
commands/cmd_grid.cpp
|
commands/cmd_grid.cpp
|
||||||
commands/cmd_import_sprite_sheet.cpp
|
commands/cmd_import_sprite_sheet.cpp
|
||||||
commands/cmd_invert_mask.cpp
|
commands/cmd_invert_mask.cpp
|
||||||
|
commands/cmd_keyboard_shortcuts.cpp
|
||||||
commands/cmd_launch.cpp
|
commands/cmd_launch.cpp
|
||||||
commands/cmd_layer_from_background.cpp
|
commands/cmd_layer_from_background.cpp
|
||||||
commands/cmd_layer_properties.cpp
|
commands/cmd_layer_properties.cpp
|
||||||
@ -184,6 +185,7 @@ add_library(app-lib
|
|||||||
ui/file_list.cpp
|
ui/file_list.cpp
|
||||||
ui/file_selector.cpp
|
ui/file_selector.cpp
|
||||||
ui/hex_color_entry.cpp
|
ui/hex_color_entry.cpp
|
||||||
|
ui/keyboard_shortcuts.cpp
|
||||||
ui/main_menu_bar.cpp
|
ui/main_menu_bar.cpp
|
||||||
ui/main_window.cpp
|
ui/main_window.cpp
|
||||||
ui/mini_editor.cpp
|
ui/mini_editor.cpp
|
||||||
@ -193,6 +195,7 @@ add_library(app-lib
|
|||||||
ui/palettes_listbox.cpp
|
ui/palettes_listbox.cpp
|
||||||
ui/popup_window_pin.cpp
|
ui/popup_window_pin.cpp
|
||||||
ui/resources_listbox.cpp
|
ui/resources_listbox.cpp
|
||||||
|
ui/select_accelerator.cpp
|
||||||
ui/skin/button_icon_impl.cpp
|
ui/skin/button_icon_impl.cpp
|
||||||
ui/skin/skin_part.cpp
|
ui/skin/skin_part.cpp
|
||||||
ui/skin/skin_property.cpp
|
ui/skin/skin_property.cpp
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
#include "app/ui/document_view.h"
|
#include "app/ui/document_view.h"
|
||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
#include "app/ui/editor/editor_view.h"
|
#include "app/ui/editor/editor_view.h"
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui/main_window.h"
|
#include "app/ui/main_window.h"
|
||||||
#include "app/ui/status_bar.h"
|
#include "app/ui/status_bar.h"
|
||||||
#include "app/ui/tabs.h"
|
#include "app/ui/tabs.h"
|
||||||
@ -326,7 +327,8 @@ App::~App()
|
|||||||
delete m_legacy;
|
delete m_legacy;
|
||||||
delete m_modules;
|
delete m_modules;
|
||||||
|
|
||||||
// Destroy the loaded gui.xml file.
|
// Destroy the loaded gui.xml data.
|
||||||
|
delete KeyboardShortcuts::instance();
|
||||||
delete GuiXml::instance();
|
delete GuiXml::instance();
|
||||||
|
|
||||||
m_instance = NULL;
|
m_instance = NULL;
|
||||||
|
@ -29,12 +29,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace ui {
|
|
||||||
class MenuBar;
|
|
||||||
class Widget;
|
|
||||||
class Window;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace raster {
|
namespace raster {
|
||||||
class Layer;
|
class Layer;
|
||||||
}
|
}
|
||||||
|
@ -28,13 +28,15 @@
|
|||||||
#include "app/commands/params.h"
|
#include "app/commands/params.h"
|
||||||
#include "app/console.h"
|
#include "app/console.h"
|
||||||
#include "app/gui_xml.h"
|
#include "app/gui_xml.h"
|
||||||
#include "app/modules/gui.h"
|
|
||||||
#include "app/recent_files.h"
|
#include "app/recent_files.h"
|
||||||
|
#include "app/resource_finder.h"
|
||||||
#include "app/tools/tool_box.h"
|
#include "app/tools/tool_box.h"
|
||||||
#include "app/ui/app_menuitem.h"
|
#include "app/ui/app_menuitem.h"
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui/main_window.h"
|
#include "app/ui/main_window.h"
|
||||||
#include "app/util/filetoks.h"
|
#include "app/util/filetoks.h"
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
|
#include "base/fs.h"
|
||||||
#include "ui/ui.h"
|
#include "ui/ui.h"
|
||||||
|
|
||||||
#include "tinyxml.h"
|
#include "tinyxml.h"
|
||||||
@ -74,9 +76,8 @@ void AppMenus::reload()
|
|||||||
TiXmlHandle handle(doc);
|
TiXmlHandle handle(doc);
|
||||||
const char* path = GuiXml::instance()->filename();
|
const char* path = GuiXml::instance()->filename();
|
||||||
|
|
||||||
/**************************************************/
|
////////////////////////////////////////
|
||||||
/* load menus */
|
// Load menus
|
||||||
/**************************************************/
|
|
||||||
|
|
||||||
PRINTF(" - Loading menus from \"%s\"...\n", path);
|
PRINTF(" - Loading menus from \"%s\"...\n", path);
|
||||||
|
|
||||||
@ -94,127 +95,25 @@ void AppMenus::reload()
|
|||||||
m_celPopupMenu.reset(loadMenuById(handle, "cel_popup"));
|
m_celPopupMenu.reset(loadMenuById(handle, "cel_popup"));
|
||||||
m_celMovementPopupMenu.reset(loadMenuById(handle, "cel_movement_popup"));
|
m_celMovementPopupMenu.reset(loadMenuById(handle, "cel_movement_popup"));
|
||||||
|
|
||||||
/**************************************************/
|
////////////////////////////////////////
|
||||||
/* load keyboard shortcuts for commands */
|
// Load keyboard shortcuts for commands
|
||||||
/**************************************************/
|
|
||||||
|
|
||||||
PRINTF(" - Loading commands keyboard shortcuts from \"%s\"...\n", path);
|
PRINTF(" - Loading commands keyboard shortcuts from \"%s\"...\n", path);
|
||||||
|
|
||||||
// <gui><keyboard><commands><key>
|
|
||||||
TiXmlElement* xmlKey = handle
|
TiXmlElement* xmlKey = handle
|
||||||
.FirstChild("gui")
|
.FirstChild("gui")
|
||||||
.FirstChild("keyboard")
|
.FirstChild("keyboard").ToElement();
|
||||||
.FirstChild("commands")
|
|
||||||
.FirstChild("key").ToElement();
|
|
||||||
while (xmlKey) {
|
|
||||||
const char* command_name = xmlKey->Attribute("command");
|
|
||||||
const char* command_key = getShortcut(xmlKey);
|
|
||||||
|
|
||||||
if (command_name && command_key) {
|
KeyboardShortcuts::instance()->clear();
|
||||||
Command* command = CommandsModule::instance()->getCommandByName(command_name);
|
KeyboardShortcuts::instance()->importFile(xmlKey, KeySource::Original);
|
||||||
if (command) {
|
|
||||||
// Read context
|
|
||||||
KeyContext keycontext = KeyContext::Any;
|
|
||||||
const char* keycontextstr = xmlKey->Attribute("context");
|
|
||||||
if (keycontextstr) {
|
|
||||||
if (strcmp(keycontextstr, "Selection") == 0)
|
|
||||||
keycontext = KeyContext::Selection;
|
|
||||||
else if (strcmp(keycontextstr, "Normal") == 0)
|
|
||||||
keycontext = KeyContext::Normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read params
|
// Load user settings
|
||||||
Params params;
|
{
|
||||||
|
ResourceFinder rf;
|
||||||
TiXmlElement* xmlParam = xmlKey->FirstChildElement("param");
|
rf.includeUserDir("user.aseprite-keys");
|
||||||
while (xmlParam) {
|
std::string fn = rf.getFirstOrCreateDefault();
|
||||||
const char* param_name = xmlParam->Attribute("name");
|
if (base::is_file(fn))
|
||||||
const char* param_value = xmlParam->Attribute("value");
|
KeyboardShortcuts::instance()->importFile(fn, KeySource::UserDefined);
|
||||||
|
|
||||||
if (param_name && param_value)
|
|
||||||
params.set(param_name, param_value);
|
|
||||||
|
|
||||||
xmlParam = xmlParam->NextSiblingElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool first_shortcut =
|
|
||||||
(get_accel_to_execute_command(command_name, ¶ms) == NULL);
|
|
||||||
|
|
||||||
PRINTF(" - Shortcut for command `%s' <%s>\n", command_name, command_key);
|
|
||||||
|
|
||||||
// add the keyboard shortcut to the command
|
|
||||||
Accelerator* accel =
|
|
||||||
add_keyboard_shortcut_to_execute_command(command_key, command_name, ¶ms, keycontext);
|
|
||||||
|
|
||||||
// add the shortcut to the menuitems with this
|
|
||||||
// command (this is only visual, the "manager_msg_proc"
|
|
||||||
// is the only one that process keyboard shortcuts)
|
|
||||||
if (first_shortcut)
|
|
||||||
applyShortcutToMenuitemsWithCommand(m_rootMenu, command, ¶ms, accel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlKey = xmlKey->NextSiblingElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load keyboard shortcuts for tools
|
|
||||||
PRINTF(" - Loading tools keyboard shortcuts from \"%s\"...\n", path);
|
|
||||||
// <gui><keyboard><tools><key>
|
|
||||||
xmlKey = handle
|
|
||||||
.FirstChild("gui")
|
|
||||||
.FirstChild("keyboard")
|
|
||||||
.FirstChild("tools")
|
|
||||||
.FirstChild("key").ToElement();
|
|
||||||
while (xmlKey) {
|
|
||||||
const char* tool_id = xmlKey->Attribute("tool");
|
|
||||||
const char* tool_key = getShortcut(xmlKey);
|
|
||||||
|
|
||||||
if (tool_id && tool_key) {
|
|
||||||
tools::Tool* tool = App::instance()->getToolBox()->getToolById(tool_id);
|
|
||||||
if (tool) {
|
|
||||||
PRINTF(" - Shortcut for tool `%s': <%s>\n", tool_id, tool_key);
|
|
||||||
add_keyboard_shortcut_to_change_tool(tool_key, tool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xmlKey = xmlKey->NextSiblingElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load keyboard shortcuts for quicktools
|
|
||||||
// <gui><keyboard><quicktools><key>
|
|
||||||
xmlKey = handle
|
|
||||||
.FirstChild("gui")
|
|
||||||
.FirstChild("keyboard")
|
|
||||||
.FirstChild("quicktools")
|
|
||||||
.FirstChild("key").ToElement();
|
|
||||||
while (xmlKey) {
|
|
||||||
const char* tool_id = xmlKey->Attribute("tool");
|
|
||||||
const char* tool_key = getShortcut(xmlKey);
|
|
||||||
if (tool_id && tool_key) {
|
|
||||||
tools::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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 = getShortcut(xmlKey);
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +276,12 @@ Widget* AppMenus::createInvalidVersionMenuitem()
|
|||||||
return menuitem;
|
return menuitem;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppMenus::applyShortcutToMenuitemsWithCommand(Menu* menu, Command *command, Params* params, Accelerator* accel)
|
void AppMenus::applyShortcutToMenuitemsWithCommand(Command* command, Params* params, Key* key)
|
||||||
|
{
|
||||||
|
applyShortcutToMenuitemsWithCommand(m_rootMenu, command, params, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppMenus::applyShortcutToMenuitemsWithCommand(Menu* menu, Command* command, Params* params, Key* key)
|
||||||
{
|
{
|
||||||
UI_FOREACH_WIDGET(menu->getChildren(), it) {
|
UI_FOREACH_WIDGET(menu->getChildren(), it) {
|
||||||
Widget* child = *it;
|
Widget* child = *it;
|
||||||
@ -393,32 +297,14 @@ void AppMenus::applyShortcutToMenuitemsWithCommand(Menu* menu, Command *command,
|
|||||||
ustricmp(mi_command->short_name(), command->short_name()) == 0 &&
|
ustricmp(mi_command->short_name(), command->short_name()) == 0 &&
|
||||||
((mi_params && *mi_params == *params) ||
|
((mi_params && *mi_params == *params) ||
|
||||||
(Params() == *params))) {
|
(Params() == *params))) {
|
||||||
// Set the accelerator to be shown in this menu-item
|
// Set the keyboard shortcut to be shown in this menu-item
|
||||||
menuitem->setAccel(new Accelerator(*accel));
|
menuitem->setKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Menu* submenu = menuitem->getSubmenu())
|
if (Menu* submenu = menuitem->getSubmenu())
|
||||||
applyShortcutToMenuitemsWithCommand(submenu, command, params, accel);
|
applyShortcutToMenuitemsWithCommand(submenu, command, params, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* AppMenus::getShortcut(TiXmlElement* elem)
|
|
||||||
{
|
|
||||||
const char* shortcut = NULL;
|
|
||||||
|
|
||||||
#if defined ALLEGRO_WINDOWS
|
|
||||||
if (!shortcut) shortcut = elem->Attribute("win");
|
|
||||||
#elif defined ALLEGRO_MACOSX
|
|
||||||
if (!shortcut) shortcut = elem->Attribute("mac");
|
|
||||||
#elif defined ALLEGRO_UNIX
|
|
||||||
if (!shortcut) shortcut = elem->Attribute("linux");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!shortcut)
|
|
||||||
shortcut = elem->Attribute("shortcut");
|
|
||||||
|
|
||||||
return shortcut;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -28,11 +28,8 @@
|
|||||||
class TiXmlElement;
|
class TiXmlElement;
|
||||||
class TiXmlHandle;
|
class TiXmlHandle;
|
||||||
|
|
||||||
namespace ui {
|
|
||||||
class Accelerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
class Key;
|
||||||
class Command;
|
class Command;
|
||||||
class Params;
|
class Params;
|
||||||
|
|
||||||
@ -59,13 +56,14 @@ namespace app {
|
|||||||
Menu* getCelPopupMenu() { return m_celPopupMenu; }
|
Menu* getCelPopupMenu() { return m_celPopupMenu; }
|
||||||
Menu* getCelMovementPopupMenu() { return m_celMovementPopupMenu; }
|
Menu* getCelMovementPopupMenu() { return m_celMovementPopupMenu; }
|
||||||
|
|
||||||
|
void applyShortcutToMenuitemsWithCommand(Command* command, Params* params, Key* key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Menu* loadMenuById(TiXmlHandle& handle, const char *id);
|
Menu* loadMenuById(TiXmlHandle& handle, const char *id);
|
||||||
Menu* convertXmlelemToMenu(TiXmlElement* elem);
|
Menu* convertXmlelemToMenu(TiXmlElement* elem);
|
||||||
Widget* convertXmlelemToMenuitem(TiXmlElement* elem);
|
Widget* convertXmlelemToMenuitem(TiXmlElement* elem);
|
||||||
Widget* createInvalidVersionMenuitem();
|
Widget* createInvalidVersionMenuitem();
|
||||||
void applyShortcutToMenuitemsWithCommand(Menu* menu, Command* command, Params* params, Accelerator* accel);
|
void applyShortcutToMenuitemsWithCommand(Menu* menu, Command* command, Params* params, Key* key);
|
||||||
const char* getShortcut(TiXmlElement* elem);
|
|
||||||
|
|
||||||
base::UniquePtr<Menu> m_rootMenu;
|
base::UniquePtr<Menu> m_rootMenu;
|
||||||
MenuItem* m_recentListMenuitem;
|
MenuItem* m_recentListMenuitem;
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#include "app/find_widget.h"
|
#include "app/find_widget.h"
|
||||||
#include "app/ini_file.h"
|
#include "app/ini_file.h"
|
||||||
#include "app/load_widget.h"
|
#include "app/load_widget.h"
|
||||||
#include "app/modules/gui.h"
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui/main_window.h"
|
#include "app/ui/main_window.h"
|
||||||
#include "ui/ui.h"
|
#include "ui/ui.h"
|
||||||
|
|
||||||
@ -74,19 +74,14 @@ void AdvancedModeCommand::onExecute(Context* context)
|
|||||||
|
|
||||||
if (oldMode == MainWindow::NormalMode &&
|
if (oldMode == MainWindow::NormalMode &&
|
||||||
get_config_bool("AdvancedMode", "Warning", true)) {
|
get_config_bool("AdvancedMode", "Warning", true)) {
|
||||||
Accelerator* accel = get_accel_to_execute_command(short_name());
|
Key* key = KeyboardShortcuts::instance()->command(short_name());
|
||||||
if (accel != NULL) {
|
if (!key->accels().empty()) {
|
||||||
char warning[1024];
|
|
||||||
char buf[1024];
|
|
||||||
|
|
||||||
base::UniquePtr<Window> window(app::load_widget<Window>("advanced_mode.xml", "advanced_mode_warning"));
|
base::UniquePtr<Window> window(app::load_widget<Window>("advanced_mode.xml", "advanced_mode_warning"));
|
||||||
Widget* warning_label = app::find_widget<Widget>(window, "warning_label");
|
Widget* warning_label = app::find_widget<Widget>(window, "warning_label");
|
||||||
Widget* donot_show = app::find_widget<Widget>(window, "donot_show");
|
Widget* donot_show = app::find_widget<Widget>(window, "donot_show");
|
||||||
|
|
||||||
strcpy(warning, "You can back pressing the \"%s\" key.");
|
warning_label->setTextf("You can go back pressing \"%s\" key.",
|
||||||
std::sprintf(buf, warning, accel->toString().c_str());
|
key->accels().front().toString().c_str());
|
||||||
|
|
||||||
warning_label->setText(buf);
|
|
||||||
|
|
||||||
window->openWindowInForeground();
|
window->openWindowInForeground();
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ private:
|
|||||||
|
|
||||||
CancelCommand::CancelCommand()
|
CancelCommand::CancelCommand()
|
||||||
: Command("Cancel",
|
: Command("Cancel",
|
||||||
"Cancel",
|
"Cancel Current Operation",
|
||||||
CmdUIOnlyFlag)
|
CmdUIOnlyFlag)
|
||||||
, m_type(NoOp)
|
, m_type(NoOp)
|
||||||
{
|
{
|
||||||
|
@ -48,6 +48,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
void onLoadParams(Params* params);
|
void onLoadParams(Params* params);
|
||||||
void onExecute(Context* context);
|
void onExecute(Context* context);
|
||||||
|
std::string onGetFriendlyName() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
ChangeBrushCommand::ChangeBrushCommand()
|
ChangeBrushCommand::ChangeBrushCommand()
|
||||||
@ -96,6 +97,30 @@ void ChangeBrushCommand::onExecute(Context* context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ChangeBrushCommand::onGetFriendlyName() const
|
||||||
|
{
|
||||||
|
std::string text = "Brush";
|
||||||
|
|
||||||
|
switch (m_change) {
|
||||||
|
case None:
|
||||||
|
break;
|
||||||
|
case IncrementSize:
|
||||||
|
text += ": Increment Size";
|
||||||
|
break;
|
||||||
|
case DecrementSize:
|
||||||
|
text += ": Decrement Size";
|
||||||
|
break;
|
||||||
|
case IncrementAngle:
|
||||||
|
text += ": Increment Angle";
|
||||||
|
break;
|
||||||
|
case DecrementAngle:
|
||||||
|
text += ": Decrement Angle";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
Command* CommandFactory::createChangeBrushCommand()
|
Command* CommandFactory::createChangeBrushCommand()
|
||||||
{
|
{
|
||||||
return new ChangeBrushCommand;
|
return new ChangeBrushCommand;
|
||||||
|
@ -50,6 +50,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
void onLoadParams(Params* params);
|
void onLoadParams(Params* params);
|
||||||
void onExecute(Context* context);
|
void onExecute(Context* context);
|
||||||
|
std::string onGetFriendlyName() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
ChangeColorCommand::ChangeColorCommand()
|
ChangeColorCommand::ChangeColorCommand()
|
||||||
@ -108,6 +109,29 @@ void ChangeColorCommand::onExecute(Context* context)
|
|||||||
colorbar->setFgColor(color);
|
colorbar->setFgColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ChangeColorCommand::onGetFriendlyName() const
|
||||||
|
{
|
||||||
|
std::string text = "Color";
|
||||||
|
|
||||||
|
switch (m_change) {
|
||||||
|
case None:
|
||||||
|
return text;
|
||||||
|
case IncrementIndex:
|
||||||
|
text += ": Increment";
|
||||||
|
break;
|
||||||
|
case DecrementIndex:
|
||||||
|
text += ": Decrement";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_background)
|
||||||
|
text += " Background Index";
|
||||||
|
else
|
||||||
|
text += " Foreground Index";
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
Command* CommandFactory::createChangeColorCommand()
|
Command* CommandFactory::createChangeColorCommand()
|
||||||
{
|
{
|
||||||
return new ChangeColorCommand;
|
return new ChangeColorCommand;
|
||||||
|
@ -49,7 +49,7 @@ protected:
|
|||||||
|
|
||||||
DeveloperConsoleCommand::DeveloperConsoleCommand()
|
DeveloperConsoleCommand::DeveloperConsoleCommand()
|
||||||
: Command("DeveloperConsole",
|
: Command("DeveloperConsole",
|
||||||
"DeveloperConsole",
|
"Developer Console",
|
||||||
CmdUIOnlyFlag)
|
CmdUIOnlyFlag)
|
||||||
{
|
{
|
||||||
m_devConsole = NULL;
|
m_devConsole = NULL;
|
||||||
|
@ -188,6 +188,23 @@ void FlipCommand::onExecute(Context* context)
|
|||||||
update_screen_for_document(document);
|
update_screen_for_document(document);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string FlipCommand::onGetFriendlyName() const
|
||||||
|
{
|
||||||
|
std::string text = "Flip";
|
||||||
|
|
||||||
|
if (m_flipMask)
|
||||||
|
text += " Selection";
|
||||||
|
else
|
||||||
|
text += " Canvas";
|
||||||
|
|
||||||
|
if (m_flipType == raster::algorithm::FlipHorizontal)
|
||||||
|
text += " Horizontal";
|
||||||
|
else
|
||||||
|
text += " Vertical";
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
Command* CommandFactory::createFlipCommand()
|
Command* CommandFactory::createFlipCommand()
|
||||||
{
|
{
|
||||||
return new FlipCommand;
|
return new FlipCommand;
|
||||||
|
@ -36,6 +36,7 @@ namespace app {
|
|||||||
void onLoadParams(Params* params);
|
void onLoadParams(Params* params);
|
||||||
bool onEnabled(Context* context);
|
bool onEnabled(Context* context);
|
||||||
void onExecute(Context* context);
|
void onExecute(Context* context);
|
||||||
|
std::string onGetFriendlyName() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_flipMask;
|
bool m_flipMask;
|
||||||
|
@ -58,7 +58,7 @@ class GotoFirstFrameCommand : public GotoCommand {
|
|||||||
public:
|
public:
|
||||||
GotoFirstFrameCommand()
|
GotoFirstFrameCommand()
|
||||||
: GotoCommand("GotoFirstFrame",
|
: GotoCommand("GotoFirstFrame",
|
||||||
"Goto First Frame") { }
|
"Go to First Frame") { }
|
||||||
Command* clone() const override { return new GotoFirstFrameCommand(*this); }
|
Command* clone() const override { return new GotoFirstFrameCommand(*this); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -71,7 +71,7 @@ class GotoPreviousFrameCommand : public GotoCommand {
|
|||||||
public:
|
public:
|
||||||
GotoPreviousFrameCommand()
|
GotoPreviousFrameCommand()
|
||||||
: GotoCommand("GotoPreviousFrame",
|
: GotoCommand("GotoPreviousFrame",
|
||||||
"Goto Previous Frame") { }
|
"Go to Previous Frame") { }
|
||||||
Command* clone() const override { return new GotoPreviousFrameCommand(*this); }
|
Command* clone() const override { return new GotoPreviousFrameCommand(*this); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -88,7 +88,7 @@ protected:
|
|||||||
class GotoNextFrameCommand : public GotoCommand {
|
class GotoNextFrameCommand : public GotoCommand {
|
||||||
public:
|
public:
|
||||||
GotoNextFrameCommand() : GotoCommand("GotoNextFrame",
|
GotoNextFrameCommand() : GotoCommand("GotoNextFrame",
|
||||||
"Goto Next Frame") { }
|
"Go to Next Frame") { }
|
||||||
Command* clone() const override { return new GotoNextFrameCommand(*this); }
|
Command* clone() const override { return new GotoNextFrameCommand(*this); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -104,7 +104,7 @@ protected:
|
|||||||
class GotoLastFrameCommand : public GotoCommand {
|
class GotoLastFrameCommand : public GotoCommand {
|
||||||
public:
|
public:
|
||||||
GotoLastFrameCommand() : GotoCommand("GotoLastFrame",
|
GotoLastFrameCommand() : GotoCommand("GotoLastFrame",
|
||||||
"Goto Last Frame") { }
|
"Go to Last Frame") { }
|
||||||
Command* clone() const override { return new GotoLastFrameCommand(*this); }
|
Command* clone() const override { return new GotoLastFrameCommand(*this); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -116,7 +116,7 @@ protected:
|
|||||||
class GotoFrameCommand : public GotoCommand {
|
class GotoFrameCommand : public GotoCommand {
|
||||||
public:
|
public:
|
||||||
GotoFrameCommand() : GotoCommand("GotoFrame",
|
GotoFrameCommand() : GotoCommand("GotoFrame",
|
||||||
"Goto Frame")
|
"Go to Frame")
|
||||||
, m_frame(0) { }
|
, m_frame(0) { }
|
||||||
Command* clone() const override { return new GotoFrameCommand(*this); }
|
Command* clone() const override { return new GotoFrameCommand(*this); }
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ protected:
|
|||||||
|
|
||||||
GotoPreviousLayerCommand::GotoPreviousLayerCommand()
|
GotoPreviousLayerCommand::GotoPreviousLayerCommand()
|
||||||
: GotoCommand("GotoPreviousLayer",
|
: GotoCommand("GotoPreviousLayer",
|
||||||
"Goto Previous Layer",
|
"Go to Previous Layer",
|
||||||
CmdUIOnlyFlag)
|
CmdUIOnlyFlag)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ protected:
|
|||||||
|
|
||||||
GotoNextLayerCommand::GotoNextLayerCommand()
|
GotoNextLayerCommand::GotoNextLayerCommand()
|
||||||
: GotoCommand("GotoNextLayer",
|
: GotoCommand("GotoNextLayer",
|
||||||
"Goto Next Layer",
|
"Go to Next Layer",
|
||||||
CmdUIOnlyFlag)
|
CmdUIOnlyFlag)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ protected:
|
|||||||
|
|
||||||
GotoNextTabCommand::GotoNextTabCommand()
|
GotoNextTabCommand::GotoNextTabCommand()
|
||||||
: Command("GotoNextTab",
|
: Command("GotoNextTab",
|
||||||
"Goto Next Tab",
|
"Go to Next Tab",
|
||||||
CmdUIOnlyFlag)
|
CmdUIOnlyFlag)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ protected:
|
|||||||
|
|
||||||
GotoPreviousTabCommand::GotoPreviousTabCommand()
|
GotoPreviousTabCommand::GotoPreviousTabCommand()
|
||||||
: Command("GotoPreviousTab",
|
: Command("GotoPreviousTab",
|
||||||
"Goto Previous tab",
|
"Go to Previous tab",
|
||||||
CmdRecordableFlag)
|
CmdRecordableFlag)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
481
src/app/commands/cmd_keyboard_shortcuts.cpp
Normal file
481
src/app/commands/cmd_keyboard_shortcuts.cpp
Normal file
@ -0,0 +1,481 @@
|
|||||||
|
/* Aseprite
|
||||||
|
* Copyright (C) 2001-2014 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "app/app_menus.h"
|
||||||
|
#include "app/commands/command.h"
|
||||||
|
#include "app/context.h"
|
||||||
|
#include "app/file_selector.h"
|
||||||
|
#include "app/modules/gui.h"
|
||||||
|
#include "app/resource_finder.h"
|
||||||
|
#include "app/tools/tool.h"
|
||||||
|
#include "app/ui/app_menuitem.h"
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
|
#include "app/ui/select_accelerator.h"
|
||||||
|
#include "app/ui/skin/skin_theme.h"
|
||||||
|
#include "base/bind.h"
|
||||||
|
#include "base/fs.h"
|
||||||
|
#include "base/path.h"
|
||||||
|
#include "ui/graphics.h"
|
||||||
|
#include "ui/listitem.h"
|
||||||
|
#include "ui/paint_event.h"
|
||||||
|
#include "ui/preferred_size_event.h"
|
||||||
|
#include "ui/resize_event.h"
|
||||||
|
|
||||||
|
#include "generated_keyboard_shortcuts.h"
|
||||||
|
|
||||||
|
#define KEYBOARD_FILENAME_EXTENSION "aseprite-keys"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
using namespace ui;
|
||||||
|
using namespace skin;
|
||||||
|
|
||||||
|
static int g_sep = 0;
|
||||||
|
|
||||||
|
class KeyItem : public ListItem {
|
||||||
|
public:
|
||||||
|
KeyItem(const std::string& text, Key* key, AppMenuItem* menuitem, int level)
|
||||||
|
: ListItem(text)
|
||||||
|
, m_key(key)
|
||||||
|
, m_keyOrig(key ? new Key(*key): NULL)
|
||||||
|
, m_menuitem(menuitem)
|
||||||
|
, m_level(level)
|
||||||
|
, m_changeButton(NULL)
|
||||||
|
, m_addButton(NULL)
|
||||||
|
, m_hotAccel(-1) {
|
||||||
|
this->border_width.t = this->border_width.b = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~KeyItem() {
|
||||||
|
destroyButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreKeys() {
|
||||||
|
if (m_key) {
|
||||||
|
if (m_keyOrig)
|
||||||
|
*m_key = *m_keyOrig;
|
||||||
|
else if (m_menuitem)
|
||||||
|
m_menuitem->setKey(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void onChangeAccel() {
|
||||||
|
Accelerator origAccel = m_key->accels()[m_hotAccel];
|
||||||
|
SelectAccelerator window(origAccel, true);
|
||||||
|
window.openWindowInForeground();
|
||||||
|
|
||||||
|
if (window.isModified()) {
|
||||||
|
m_key->disableAccel(origAccel);
|
||||||
|
m_key->add(window.accel(), KeySource::UserDefined);
|
||||||
|
}
|
||||||
|
else if (window.isDeleted()) {
|
||||||
|
m_key->disableAccel(origAccel);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRoot()->layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onAddAccel() {
|
||||||
|
ui::Accelerator accel;
|
||||||
|
SelectAccelerator window(accel, false);
|
||||||
|
window.openWindowInForeground();
|
||||||
|
|
||||||
|
if (window.isModified()) {
|
||||||
|
if (!m_key) {
|
||||||
|
ASSERT(m_menuitem);
|
||||||
|
if (!m_menuitem)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_key = app::KeyboardShortcuts::instance()->command(
|
||||||
|
m_menuitem->getCommand()->short_name(),
|
||||||
|
m_menuitem->getParams());
|
||||||
|
|
||||||
|
m_menuitem->setKey(m_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_key->add(window.accel(), KeySource::UserDefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRoot()->layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onPreferredSize(PreferredSizeEvent& ev) override {
|
||||||
|
gfx::Size size = getTextSize();
|
||||||
|
size.w = this->border_width.l + size.w + this->border_width.r;
|
||||||
|
size.h = this->border_width.t + size.h + this->border_width.b
|
||||||
|
+ 4*jguiscale();
|
||||||
|
|
||||||
|
if (m_key && !m_key->accels().empty()) {
|
||||||
|
size_t combos = m_key->accels().size();
|
||||||
|
if (combos > 1)
|
||||||
|
size.h *= combos;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev.setPreferredSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onPaint(PaintEvent& ev) override {
|
||||||
|
Graphics* g = ev.getGraphics();
|
||||||
|
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
|
||||||
|
gfx::Rect bounds = getClientBounds();
|
||||||
|
gfx::Color fg, bg;
|
||||||
|
|
||||||
|
if (isSelected()) {
|
||||||
|
fg = theme->getColor(ThemeColor::ListItemSelectedText);
|
||||||
|
bg = theme->getColor(ThemeColor::ListItemSelectedFace);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fg = theme->getColor(ThemeColor::ListItemNormalText);
|
||||||
|
bg = theme->getColor(ThemeColor::ListItemNormalFace);
|
||||||
|
}
|
||||||
|
|
||||||
|
g->fillRect(bg, bounds);
|
||||||
|
|
||||||
|
bounds.shrink(getBorder());
|
||||||
|
g->drawUIString(getText(), fg, bg,
|
||||||
|
gfx::Point(
|
||||||
|
bounds.x + m_level*16 * jguiscale(),
|
||||||
|
bounds.y + 2*jguiscale()));
|
||||||
|
|
||||||
|
if (m_key && !m_key->accels().empty()) {
|
||||||
|
std::string buf;
|
||||||
|
int y = bounds.y;
|
||||||
|
int dh = getTextSize().h + 4*jguiscale();
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (const Accelerator& accel : m_key->accels()) {
|
||||||
|
if (i != m_hotAccel || !m_changeButton) {
|
||||||
|
g->drawString(accel.toString(), fg, bg,
|
||||||
|
gfx::Point(bounds.x + g_sep, y + 2*jguiscale()));
|
||||||
|
}
|
||||||
|
|
||||||
|
y += dh;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onResize(ResizeEvent& ev) override {
|
||||||
|
ListItem::onResize(ev);
|
||||||
|
|
||||||
|
destroyButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool onProcessMessage(Message* msg) override {
|
||||||
|
switch (msg->type()) {
|
||||||
|
|
||||||
|
case kMouseLeaveMessage: {
|
||||||
|
m_hotAccel = -1;
|
||||||
|
destroyButtons();
|
||||||
|
invalidate();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case kMouseMoveMessage: {
|
||||||
|
gfx::Rect bounds = getBounds();
|
||||||
|
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||||
|
int hotAccel = -1;
|
||||||
|
|
||||||
|
const Accelerators* accels = (m_key ? &m_key->accels() : NULL);
|
||||||
|
int y = bounds.y;
|
||||||
|
int dh = getTextSize().h + 4*jguiscale();
|
||||||
|
int maxi = (accels && accels->size() > 1 ? accels->size(): 1);
|
||||||
|
|
||||||
|
for (int i=0; i<maxi; ++i, y += dh) {
|
||||||
|
int w = Graphics::measureUIStringLength(
|
||||||
|
(accels && i < (int)accels->size() ? (*accels)[i].toString().c_str(): ""),
|
||||||
|
getFont());
|
||||||
|
gfx::Rect itemBounds(bounds.x + g_sep, y, w, dh);
|
||||||
|
|
||||||
|
if (mouseMsg->position().y >= bounds.y &&
|
||||||
|
mouseMsg->position().y < bounds.y+bounds.h) {
|
||||||
|
itemBounds = itemBounds.enlarge(
|
||||||
|
gfx::Border(
|
||||||
|
4*jguiscale(), 0,
|
||||||
|
6*jguiscale(), 1*jguiscale()));
|
||||||
|
|
||||||
|
if (accels && i < (int)accels->size() &&
|
||||||
|
itemBounds.contains(mouseMsg->position())) {
|
||||||
|
hotAccel = i;
|
||||||
|
|
||||||
|
if (!m_changeButton) {
|
||||||
|
m_changeButton = new Button("");
|
||||||
|
m_changeButton->Click.connect(Bind<void>(&KeyItem::onChangeAccel, this));
|
||||||
|
setup_mini_look(m_changeButton);
|
||||||
|
addChild(m_changeButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_changeButton->setBgColor(gfx::ColorNone);
|
||||||
|
m_changeButton->setBounds(itemBounds);
|
||||||
|
m_changeButton->setText((*accels)[i].toString());
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 0 && (!m_menuitem || m_menuitem->getCommand())) {
|
||||||
|
if (!m_addButton) {
|
||||||
|
m_addButton = new Button("");
|
||||||
|
m_addButton->Click.connect(Bind<void>(&KeyItem::onAddAccel, this));
|
||||||
|
setup_mini_look(m_addButton);
|
||||||
|
addChild(m_addButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
itemBounds.w = 8*jguiscale() + Graphics::measureUIStringLength("Add", getFont());
|
||||||
|
itemBounds.x -= itemBounds.w + 2*jguiscale();
|
||||||
|
|
||||||
|
m_addButton->setBgColor(gfx::ColorNone);
|
||||||
|
m_addButton->setBounds(itemBounds);
|
||||||
|
m_addButton->setText("Add");
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_hotAccel != hotAccel) {
|
||||||
|
if (hotAccel == -1)
|
||||||
|
destroyButtons();
|
||||||
|
m_hotAccel = hotAccel;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ListItem::onProcessMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroyButtons() {
|
||||||
|
delete m_changeButton;
|
||||||
|
delete m_addButton;
|
||||||
|
m_changeButton = NULL;
|
||||||
|
m_addButton = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key* m_key;
|
||||||
|
Key* m_keyOrig;
|
||||||
|
AppMenuItem* m_menuitem;
|
||||||
|
int m_level;
|
||||||
|
ui::Accelerators m_newAccels;
|
||||||
|
ui::Button* m_changeButton;
|
||||||
|
ui::Button* m_addButton;
|
||||||
|
int m_hotAccel;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KeyboardShortcutsWindow : public app::gen::KeyboardShortcuts {
|
||||||
|
public:
|
||||||
|
KeyboardShortcutsWindow() {
|
||||||
|
setAutoRemap(false);
|
||||||
|
|
||||||
|
section()->addItem("Menus");
|
||||||
|
section()->addItem("Commands");
|
||||||
|
section()->addItem("Tools");
|
||||||
|
section()->addItem("Action Modifiers");
|
||||||
|
|
||||||
|
section()->Change.connect(Bind<void>(&KeyboardShortcutsWindow::onSectionChange, this));
|
||||||
|
importButton()->Click.connect(Bind<void>(&KeyboardShortcutsWindow::onImport, this));
|
||||||
|
exportButton()->Click.connect(Bind<void>(&KeyboardShortcutsWindow::onExport, this));
|
||||||
|
resetButton()->Click.connect(Bind<void>(&KeyboardShortcutsWindow::onReset, this));
|
||||||
|
|
||||||
|
fillAllLists();
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreKeys() {
|
||||||
|
for (KeyItem* keyItem : m_allKeyItems) {
|
||||||
|
keyItem->restoreKeys();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void deleteAllKeyItems() {
|
||||||
|
while (menus()->getLastChild())
|
||||||
|
menus()->removeChild(menus()->getLastChild());
|
||||||
|
while (commands()->getLastChild())
|
||||||
|
commands()->removeChild(commands()->getLastChild());
|
||||||
|
while (tools()->getLastChild())
|
||||||
|
tools()->removeChild(tools()->getLastChild());
|
||||||
|
while (actions()->getLastChild())
|
||||||
|
actions()->removeChild(actions()->getLastChild());
|
||||||
|
|
||||||
|
for (KeyItem* keyItem : m_allKeyItems) {
|
||||||
|
delete keyItem;
|
||||||
|
}
|
||||||
|
m_allKeyItems.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillAllLists() {
|
||||||
|
deleteAllKeyItems();
|
||||||
|
|
||||||
|
// Load keyboard shortcuts
|
||||||
|
fillList(this->menus(), AppMenus::instance()->getRootMenu(), 0);
|
||||||
|
for (Key* key : *app::KeyboardShortcuts::instance()) {
|
||||||
|
std::string text = key->triggerString();
|
||||||
|
if (key->keycontext() == KeyContext::Selection)
|
||||||
|
text += " (w/selection)";
|
||||||
|
KeyItem* keyItem = new KeyItem(text, key, NULL, 0);
|
||||||
|
|
||||||
|
ListBox* listBox = NULL;
|
||||||
|
switch (key->type()) {
|
||||||
|
case KeyType::Command:
|
||||||
|
listBox = this->commands();
|
||||||
|
break;
|
||||||
|
case KeyType::Tool:
|
||||||
|
case KeyType::Quicktool: {
|
||||||
|
listBox = this->tools();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KeyType::Action:
|
||||||
|
listBox = this->actions();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(listBox);
|
||||||
|
if (listBox) {
|
||||||
|
m_allKeyItems.push_back(keyItem);
|
||||||
|
listBox->addChild(keyItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->commands()->sortItems();
|
||||||
|
this->tools()->sortItems();
|
||||||
|
this->actions()->sortItems();
|
||||||
|
|
||||||
|
onSectionChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSectionChange() {
|
||||||
|
int section = this->section()->getSelectedItemIndex();
|
||||||
|
|
||||||
|
menusView()->setVisible(section == 0);
|
||||||
|
commandsView()->setVisible(section == 1);
|
||||||
|
toolsView()->setVisible(section == 2);
|
||||||
|
actionsView()->setVisible(section == 3);
|
||||||
|
layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onImport() {
|
||||||
|
std::string filename = app::show_file_selector("Import Keyboard Shortcuts", "",
|
||||||
|
KEYBOARD_FILENAME_EXTENSION);
|
||||||
|
if (filename.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
app::KeyboardShortcuts::instance()->importFile(filename.c_str(), KeySource::UserDefined);
|
||||||
|
fillAllLists();
|
||||||
|
layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onExport() {
|
||||||
|
again:
|
||||||
|
std::string filename = app::show_file_selector("Export Keyboard Shortcuts", "",
|
||||||
|
KEYBOARD_FILENAME_EXTENSION);
|
||||||
|
if (!filename.empty()) {
|
||||||
|
if (base::is_file(filename)) {
|
||||||
|
int ret = Alert::show("Warning<<File exists, overwrite it?<<%s||&Yes||&No||&Cancel",
|
||||||
|
base::get_file_name(filename).c_str());
|
||||||
|
if (ret == 2)
|
||||||
|
goto again;
|
||||||
|
else if (ret != 1)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
app::KeyboardShortcuts::instance()->exportFile(filename.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onReset() {
|
||||||
|
if (Alert::show("Warning"
|
||||||
|
"<<Do you want to restore all keyboard shortcuts"
|
||||||
|
"<<to their original default settings?"
|
||||||
|
"||&Yes||&No") == 1) {
|
||||||
|
app::KeyboardShortcuts::instance()->reset();
|
||||||
|
layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillList(ListBox* listbox, Menu* menu, int level) {
|
||||||
|
for (Widget* child : menu->getChildren()) {
|
||||||
|
if (AppMenuItem* menuItem = dynamic_cast<AppMenuItem*>(child)) {
|
||||||
|
if (menuItem == AppMenus::instance()->getRecentListMenuitem())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
KeyItem* keyItem = new KeyItem(
|
||||||
|
menuItem->getText().c_str(),
|
||||||
|
menuItem->getKey(), menuItem, level);
|
||||||
|
|
||||||
|
listbox->addChild(keyItem);
|
||||||
|
|
||||||
|
if (menuItem->hasSubmenu())
|
||||||
|
fillList(listbox, menuItem->getSubmenu(), level+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<KeyItem*> m_allKeyItems;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KeyboardShortcutsCommand : public Command {
|
||||||
|
public:
|
||||||
|
KeyboardShortcutsCommand();
|
||||||
|
Command* clone() const override { return new KeyboardShortcutsCommand(*this); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onExecute(Context* context);
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyboardShortcutsCommand::KeyboardShortcutsCommand()
|
||||||
|
: Command("KeyboardShortcuts",
|
||||||
|
"Keyboard Shortcuts",
|
||||||
|
CmdUIOnlyFlag)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardShortcutsCommand::onExecute(Context* context)
|
||||||
|
{
|
||||||
|
KeyboardShortcutsWindow window;
|
||||||
|
|
||||||
|
window.setBounds(gfx::Rect(0, 0, ui::display_w()*3/4, ui::display_h()*3/4));
|
||||||
|
g_sep = window.getBounds().w / 2;
|
||||||
|
|
||||||
|
window.centerWindow();
|
||||||
|
window.setVisible(true);
|
||||||
|
window.openWindowInForeground();
|
||||||
|
|
||||||
|
if (window.getKiller() == window.ok()) {
|
||||||
|
// Save keyboard shortcuts in configuration file
|
||||||
|
{
|
||||||
|
ResourceFinder rf;
|
||||||
|
rf.includeUserDir("user." KEYBOARD_FILENAME_EXTENSION);
|
||||||
|
std::string fn = rf.getFirstOrCreateDefault();
|
||||||
|
KeyboardShortcuts::instance()->exportFile(fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window.restoreKeys();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Command* CommandFactory::createKeyboardShortcutsCommand()
|
||||||
|
{
|
||||||
|
return new KeyboardShortcutsCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
@ -32,6 +32,7 @@
|
|||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
#include "app/undo_transaction.h"
|
#include "app/undo_transaction.h"
|
||||||
#include "app/undoers/set_mask_position.h"
|
#include "app/undoers/set_mask_position.h"
|
||||||
|
#include "base/convert_to.h"
|
||||||
#include "raster/mask.h"
|
#include "raster/mask.h"
|
||||||
#include "raster/sprite.h"
|
#include "raster/sprite.h"
|
||||||
#include "ui/view.h"
|
#include "ui/view.h"
|
||||||
@ -146,6 +147,65 @@ void MoveMaskCommand::onExecute(Context* context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string MoveMaskCommand::onGetFriendlyName() const
|
||||||
|
{
|
||||||
|
std::string text = "Move";
|
||||||
|
|
||||||
|
switch (m_target) {
|
||||||
|
|
||||||
|
case Boundaries: {
|
||||||
|
text += " Selection Boundaries";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Content: {
|
||||||
|
text += " Selection Content";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
text += " " + base::convert_to<std::string>(m_quantity);
|
||||||
|
|
||||||
|
switch (m_units) {
|
||||||
|
case Pixel:
|
||||||
|
text += " pixel";
|
||||||
|
break;
|
||||||
|
case TileWidth:
|
||||||
|
text += " horizontal tile";
|
||||||
|
break;
|
||||||
|
case TileHeight:
|
||||||
|
text += " vertical tile";
|
||||||
|
break;
|
||||||
|
case ZoomedPixel:
|
||||||
|
text += " zoomed pixel";
|
||||||
|
break;
|
||||||
|
case ZoomedTileWidth:
|
||||||
|
text += " zoomed horizontal tile";
|
||||||
|
break;
|
||||||
|
case ZoomedTileHeight:
|
||||||
|
text += " zoomed vertical tile";
|
||||||
|
break;
|
||||||
|
case ViewportWidth:
|
||||||
|
text += " viewport width";
|
||||||
|
break;
|
||||||
|
case ViewportHeight:
|
||||||
|
text += " viewport height";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (m_quantity != 1)
|
||||||
|
text += "s";
|
||||||
|
|
||||||
|
switch (m_direction) {
|
||||||
|
case Left: text += " left"; break;
|
||||||
|
case Right: text += " right"; break;
|
||||||
|
case Up: text += " up"; break;
|
||||||
|
case Down: text += " down"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
Command* CommandFactory::createMoveMaskCommand()
|
Command* CommandFactory::createMoveMaskCommand()
|
||||||
{
|
{
|
||||||
return new MoveMaskCommand;
|
return new MoveMaskCommand;
|
||||||
|
@ -48,6 +48,7 @@ namespace app {
|
|||||||
void onLoadParams(Params* params);
|
void onLoadParams(Params* params);
|
||||||
bool onEnabled(Context* context);
|
bool onEnabled(Context* context);
|
||||||
void onExecute(Context* context);
|
void onExecute(Context* context);
|
||||||
|
std::string onGetFriendlyName() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Target m_target;
|
Target m_target;
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
using namespace ui;
|
|
||||||
using namespace gfx;
|
using namespace gfx;
|
||||||
|
|
||||||
class ShowOnionSkinCommand : public Command {
|
class ShowOnionSkinCommand : public Command {
|
||||||
|
@ -159,7 +159,7 @@ private:
|
|||||||
|
|
||||||
PaletteEditorCommand::PaletteEditorCommand()
|
PaletteEditorCommand::PaletteEditorCommand()
|
||||||
: Command("PaletteEditor",
|
: Command("PaletteEditor",
|
||||||
"PaletteEditor",
|
"Palette Editor",
|
||||||
CmdRecordableFlag)
|
CmdRecordableFlag)
|
||||||
{
|
{
|
||||||
m_open = true;
|
m_open = true;
|
||||||
|
@ -28,10 +28,10 @@
|
|||||||
#include "app/context.h"
|
#include "app/context.h"
|
||||||
#include "app/modules/editors.h"
|
#include "app/modules/editors.h"
|
||||||
#include "app/modules/gfx.h"
|
#include "app/modules/gfx.h"
|
||||||
#include "app/modules/gui.h"
|
|
||||||
#include "app/settings/document_settings.h"
|
#include "app/settings/document_settings.h"
|
||||||
#include "app/settings/settings.h"
|
#include "app/settings/settings.h"
|
||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui/status_bar.h"
|
#include "app/ui/status_bar.h"
|
||||||
#include "app/util/render.h"
|
#include "app/util/render.h"
|
||||||
#include "raster/conversion_she.h"
|
#include "raster/conversion_she.h"
|
||||||
@ -127,7 +127,8 @@ protected:
|
|||||||
case kKeyDownMessage: {
|
case kKeyDownMessage: {
|
||||||
KeyMessage* keyMsg = static_cast<KeyMessage*>(msg);
|
KeyMessage* keyMsg = static_cast<KeyMessage*>(msg);
|
||||||
Command* command = NULL;
|
Command* command = NULL;
|
||||||
get_command_from_key_message(msg, &command, NULL);
|
KeyboardShortcuts::instance()
|
||||||
|
->getCommandFromKeyMessage(msg, &command, NULL);
|
||||||
|
|
||||||
// Change frame
|
// Change frame
|
||||||
if (command != NULL &&
|
if (command != NULL &&
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "app/ui/timeline.h"
|
#include "app/ui/timeline.h"
|
||||||
#include "app/undo_transaction.h"
|
#include "app/undo_transaction.h"
|
||||||
#include "app/util/range_utils.h"
|
#include "app/util/range_utils.h"
|
||||||
|
#include "base/convert_to.h"
|
||||||
#include "raster/cel.h"
|
#include "raster/cel.h"
|
||||||
#include "raster/image.h"
|
#include "raster/image.h"
|
||||||
#include "raster/mask.h"
|
#include "raster/mask.h"
|
||||||
@ -53,6 +54,7 @@ protected:
|
|||||||
void onLoadParams(Params* params);
|
void onLoadParams(Params* params);
|
||||||
bool onEnabled(Context* context);
|
bool onEnabled(Context* context);
|
||||||
void onExecute(Context* context);
|
void onExecute(Context* context);
|
||||||
|
std::string onGetFriendlyName() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_flipMask;
|
bool m_flipMask;
|
||||||
@ -235,6 +237,20 @@ void RotateCommand::onExecute(Context* context)
|
|||||||
update_screen_for_document(reader.document());
|
update_screen_for_document(reader.document());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string RotateCommand::onGetFriendlyName() const
|
||||||
|
{
|
||||||
|
std::string text = "Rotate";
|
||||||
|
|
||||||
|
if (m_flipMask)
|
||||||
|
text += " Selection";
|
||||||
|
else
|
||||||
|
text += " Sprite";
|
||||||
|
|
||||||
|
text += " " + base::convert_to<std::string>(m_angle) + "\xc2\xb0";
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
Command* CommandFactory::createRotateCommand()
|
Command* CommandFactory::createRotateCommand()
|
||||||
{
|
{
|
||||||
return new RotateCommand;
|
return new RotateCommand;
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "app/settings/document_settings.h"
|
#include "app/settings/document_settings.h"
|
||||||
#include "app/settings/settings.h"
|
#include "app/settings/settings.h"
|
||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
|
#include "base/convert_to.h"
|
||||||
#include "ui/view.h"
|
#include "ui/view.h"
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
@ -52,6 +53,7 @@ protected:
|
|||||||
void onLoadParams(Params* params);
|
void onLoadParams(Params* params);
|
||||||
bool onEnabled(Context* context);
|
bool onEnabled(Context* context);
|
||||||
void onExecute(Context* context);
|
void onExecute(Context* context);
|
||||||
|
std::string onGetFriendlyName() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Direction m_direction;
|
Direction m_direction;
|
||||||
@ -142,6 +144,49 @@ void ScrollCommand::onExecute(Context* context)
|
|||||||
current_editor->setEditorScroll(scroll.x+dx, scroll.y+dy, true);
|
current_editor->setEditorScroll(scroll.x+dx, scroll.y+dy, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ScrollCommand::onGetFriendlyName() const
|
||||||
|
{
|
||||||
|
std::string text = "Scroll " + base::convert_to<std::string>(m_quantity);
|
||||||
|
|
||||||
|
switch (m_units) {
|
||||||
|
case Pixel:
|
||||||
|
text += " pixel";
|
||||||
|
break;
|
||||||
|
case TileWidth:
|
||||||
|
text += " horizontal tile";
|
||||||
|
break;
|
||||||
|
case TileHeight:
|
||||||
|
text += " vertical tile";
|
||||||
|
break;
|
||||||
|
case ZoomedPixel:
|
||||||
|
text += " zoomed pixel";
|
||||||
|
break;
|
||||||
|
case ZoomedTileWidth:
|
||||||
|
text += " zoomed horizontal tile";
|
||||||
|
break;
|
||||||
|
case ZoomedTileHeight:
|
||||||
|
text += " zoomed vertical tile";
|
||||||
|
break;
|
||||||
|
case ViewportWidth:
|
||||||
|
text += " viewport width";
|
||||||
|
break;
|
||||||
|
case ViewportHeight:
|
||||||
|
text += " viewport height";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (m_quantity != 1)
|
||||||
|
text += "s";
|
||||||
|
|
||||||
|
switch (m_direction) {
|
||||||
|
case Left: text += " left"; break;
|
||||||
|
case Right: text += " right"; break;
|
||||||
|
case Up: text += " up"; break;
|
||||||
|
case Down: text += " down"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
Command* CommandFactory::createScrollCommand()
|
Command* CommandFactory::createScrollCommand()
|
||||||
{
|
{
|
||||||
return new ScrollCommand;
|
return new ScrollCommand;
|
||||||
|
@ -39,7 +39,7 @@ protected:
|
|||||||
|
|
||||||
SwitchColorsCommand::SwitchColorsCommand()
|
SwitchColorsCommand::SwitchColorsCommand()
|
||||||
: Command("SwitchColors",
|
: Command("SwitchColors",
|
||||||
"SwitchColors",
|
"Switch Colors",
|
||||||
CmdUIOnlyFlag)
|
CmdUIOnlyFlag)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "app/commands/params.h"
|
#include "app/commands/params.h"
|
||||||
#include "app/modules/editors.h"
|
#include "app/modules/editors.h"
|
||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
|
#include "base/convert_to.h"
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ protected:
|
|||||||
void onLoadParams(Params* params);
|
void onLoadParams(Params* params);
|
||||||
bool onEnabled(Context* context);
|
bool onEnabled(Context* context);
|
||||||
void onExecute(Context* context);
|
void onExecute(Context* context);
|
||||||
|
std::string onGetFriendlyName() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Action m_action;
|
Action m_action;
|
||||||
@ -98,6 +100,25 @@ void ZoomCommand::onExecute(Context* context)
|
|||||||
current_editor->setEditorZoom(zoom);
|
current_editor->setEditorZoom(zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ZoomCommand::onGetFriendlyName() const
|
||||||
|
{
|
||||||
|
std::string text = "Zoom";
|
||||||
|
|
||||||
|
switch (m_action) {
|
||||||
|
case In:
|
||||||
|
text += " in";
|
||||||
|
break;
|
||||||
|
case Out:
|
||||||
|
text += " out";
|
||||||
|
break;
|
||||||
|
case Set:
|
||||||
|
text += " " + base::convert_to<std::string>(m_percentage) + "%";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
Command* CommandFactory::createZoomCommand()
|
Command* CommandFactory::createZoomCommand()
|
||||||
{
|
{
|
||||||
return new ZoomCommand;
|
return new ZoomCommand;
|
||||||
|
@ -37,6 +37,11 @@ Command::~Command()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Command::friendlyName() const
|
||||||
|
{
|
||||||
|
return onGetFriendlyName();
|
||||||
|
}
|
||||||
|
|
||||||
void Command::loadParams(Params* params)
|
void Command::loadParams(Params* params)
|
||||||
{
|
{
|
||||||
onLoadParams(params);
|
onLoadParams(params);
|
||||||
@ -101,4 +106,9 @@ void Command::onExecute(Context* context)
|
|||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Command::onGetFriendlyName() const
|
||||||
|
{
|
||||||
|
return m_friendly_name;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "app/commands/command_factory.h"
|
#include "app/commands/command_factory.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
class Context;
|
class Context;
|
||||||
@ -44,7 +45,7 @@ namespace app {
|
|||||||
virtual Command* clone() const { return new Command(*this); }
|
virtual Command* clone() const { return new Command(*this); }
|
||||||
|
|
||||||
const char* short_name() const { return m_short_name; }
|
const char* short_name() const { return m_short_name; }
|
||||||
const char* friendly_name() const { return m_friendly_name; }
|
std::string friendlyName() const;
|
||||||
|
|
||||||
void loadParams(Params* params);
|
void loadParams(Params* params);
|
||||||
bool isEnabled(Context* context);
|
bool isEnabled(Context* context);
|
||||||
@ -56,6 +57,7 @@ namespace app {
|
|||||||
virtual bool onEnabled(Context* context);
|
virtual bool onEnabled(Context* context);
|
||||||
virtual bool onChecked(Context* context);
|
virtual bool onChecked(Context* context);
|
||||||
virtual void onExecute(Context* context);
|
virtual void onExecute(Context* context);
|
||||||
|
virtual std::string onGetFriendlyName() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -61,6 +61,7 @@ FOR_EACH_COMMAND(GridSettings)
|
|||||||
FOR_EACH_COMMAND(ImportSpriteSheet)
|
FOR_EACH_COMMAND(ImportSpriteSheet)
|
||||||
FOR_EACH_COMMAND(InvertColor)
|
FOR_EACH_COMMAND(InvertColor)
|
||||||
FOR_EACH_COMMAND(InvertMask)
|
FOR_EACH_COMMAND(InvertMask)
|
||||||
|
FOR_EACH_COMMAND(KeyboardShortcuts)
|
||||||
FOR_EACH_COMMAND(Launch)
|
FOR_EACH_COMMAND(Launch)
|
||||||
FOR_EACH_COMMAND(LayerFromBackground)
|
FOR_EACH_COMMAND(LayerFromBackground)
|
||||||
FOR_EACH_COMMAND(LayerProperties)
|
FOR_EACH_COMMAND(LayerProperties)
|
||||||
|
@ -26,58 +26,58 @@
|
|||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
class Params {
|
class Params {
|
||||||
std::map<std::string, std::string> m_params;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef std::map<std::string, std::string> Map;
|
||||||
|
typedef Map::iterator iterator;
|
||||||
|
typedef Map::const_iterator const_iterator;
|
||||||
|
|
||||||
|
iterator begin() { return m_params.begin(); }
|
||||||
|
iterator end() { return m_params.end(); }
|
||||||
|
const_iterator begin() const { return m_params.begin(); }
|
||||||
|
const_iterator end() const { return m_params.end(); }
|
||||||
|
|
||||||
Params() { }
|
Params() { }
|
||||||
Params(const Params& copy) : m_params(copy.m_params) { }
|
Params(const Params& copy) : m_params(copy.m_params) { }
|
||||||
virtual ~Params() { }
|
virtual ~Params() { }
|
||||||
|
|
||||||
Params* clone()
|
Params* clone() const {
|
||||||
{
|
|
||||||
return new Params(*this);
|
return new Params(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const
|
bool empty() const {
|
||||||
{
|
|
||||||
return m_params.empty();
|
return m_params.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_param(const char* name) const
|
bool has_param(const char* name) const {
|
||||||
{
|
|
||||||
return m_params.find(name) != m_params.end();
|
return m_params.find(name) != m_params.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const Params& params) const
|
bool operator==(const Params& params) const {
|
||||||
{
|
|
||||||
return m_params == params.m_params;
|
return m_params == params.m_params;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const Params& params) const
|
bool operator!=(const Params& params) const {
|
||||||
{
|
|
||||||
return m_params != params.m_params;
|
return m_params != params.m_params;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string& set(const char* name, const char* value)
|
std::string& set(const char* name, const char* value) {
|
||||||
{
|
|
||||||
return m_params[name] = value;
|
return m_params[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string& get(const char* name)
|
std::string& get(const char* name) {
|
||||||
{
|
|
||||||
return m_params[name];
|
return m_params[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T get_as(const char* name)
|
T get_as(const char* name) {
|
||||||
{
|
|
||||||
std::istringstream stream(m_params[name]);
|
std::istringstream stream(m_params[name]);
|
||||||
T value;
|
T value;
|
||||||
stream >> value;
|
stream >> value;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Map m_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "app/tools/ink.h"
|
#include "app/tools/ink.h"
|
||||||
#include "app/tools/tool_box.h"
|
#include "app/tools/tool_box.h"
|
||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui/main_menu_bar.h"
|
#include "app/ui/main_menu_bar.h"
|
||||||
#include "app/ui/main_menu_bar.h"
|
#include "app/ui/main_menu_bar.h"
|
||||||
#include "app/ui/main_window.h"
|
#include "app/ui/main_window.h"
|
||||||
@ -63,19 +64,12 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
#ifdef ALLEGRO_WINDOWS
|
#ifdef ALLEGRO_WINDOWS
|
||||||
#include <winalleg.h>
|
#include <winalleg.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SPRITEDITOR_ACTION_COPYSELECTION "CopySelection"
|
|
||||||
#define SPRITEDITOR_ACTION_SNAPTOGRID "SnapToGrid"
|
|
||||||
#define SPRITEDITOR_ACTION_ANGLESNAP "AngleSnap"
|
|
||||||
#define SPRITEDITOR_ACTION_MAINTAINASPECTRATIO "MaintainAspectRatio"
|
|
||||||
#define SPRITEDITOR_ACTION_LOCKAXIS "LockAxis"
|
|
||||||
#define SPRITEDITOR_ACTION_ADDSEL "AddSelection"
|
|
||||||
#define SPRITEDITOR_ACTION_SUBSEL "SubtractSelection"
|
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
using namespace gfx;
|
using namespace gfx;
|
||||||
@ -95,38 +89,6 @@ static struct {
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct Shortcut {
|
|
||||||
enum class Type {
|
|
||||||
ExecuteCommand,
|
|
||||||
ChangeTool,
|
|
||||||
EditorQuicktool,
|
|
||||||
SpriteEditor
|
|
||||||
};
|
|
||||||
|
|
||||||
Accelerator* accel;
|
|
||||||
Type type;
|
|
||||||
Command* command;
|
|
||||||
KeyContext keycontext;
|
|
||||||
tools::Tool* tool;
|
|
||||||
std::string action;
|
|
||||||
Params* params;
|
|
||||||
|
|
||||||
Shortcut(Type type);
|
|
||||||
~Shortcut();
|
|
||||||
|
|
||||||
void add_shortcut(const char* shortcut_string);
|
|
||||||
bool is_pressed(Message* 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(tools::Tool* tool);
|
|
||||||
static Shortcut* get_keyboard_shortcut_for_quicktool(tools::Tool* tool);
|
|
||||||
static Shortcut* get_keyboard_shortcut_for_spriteeditor(const char* action_name);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class CustomizedGuiManager : public Manager
|
class CustomizedGuiManager : public Manager
|
||||||
, public LayoutIO
|
, public LayoutIO
|
||||||
{
|
{
|
||||||
@ -144,8 +106,6 @@ static she::Clipboard* main_clipboard = NULL;
|
|||||||
static CustomizedGuiManager* manager = NULL;
|
static CustomizedGuiManager* manager = NULL;
|
||||||
static Theme* ase_theme = NULL;
|
static Theme* ase_theme = NULL;
|
||||||
|
|
||||||
static std::vector<Shortcut*>* shortcuts = NULL;
|
|
||||||
|
|
||||||
// Default GUI screen configuration
|
// Default GUI screen configuration
|
||||||
static int screen_scaling;
|
static int screen_scaling;
|
||||||
|
|
||||||
@ -155,25 +115,9 @@ static void reload_default_font();
|
|||||||
static void load_gui_config(int& w, int& h, bool& maximized);
|
static void load_gui_config(int& w, int& h, bool& maximized);
|
||||||
static void save_gui_config();
|
static void save_gui_config();
|
||||||
|
|
||||||
static KeyContext get_current_keycontext()
|
|
||||||
{
|
|
||||||
app::Context* ctx = UIContext::instance();
|
|
||||||
DocumentLocation location = ctx->activeLocation();
|
|
||||||
Document* doc = location.document();
|
|
||||||
|
|
||||||
if (doc &&
|
|
||||||
doc->isMaskVisible() &&
|
|
||||||
ctx->settings()->getCurrentTool()->getInk(0)->isSelection())
|
|
||||||
return KeyContext::Selection;
|
|
||||||
else
|
|
||||||
return KeyContext::Normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initializes GUI.
|
// Initializes GUI.
|
||||||
int init_module_gui()
|
int init_module_gui()
|
||||||
{
|
{
|
||||||
shortcuts = new std::vector<Shortcut*>;
|
|
||||||
|
|
||||||
int w, h;
|
int w, h;
|
||||||
bool maximized;
|
bool maximized;
|
||||||
load_gui_config(w, h, maximized);
|
load_gui_config(w, h, maximized);
|
||||||
@ -233,13 +177,6 @@ void exit_module_gui()
|
|||||||
{
|
{
|
||||||
save_gui_config();
|
save_gui_config();
|
||||||
|
|
||||||
// destroy shortcuts
|
|
||||||
ASSERT(shortcuts != NULL);
|
|
||||||
for (Shortcut* shortcut : *shortcuts)
|
|
||||||
delete shortcut;
|
|
||||||
delete shortcuts;
|
|
||||||
shortcuts = NULL;
|
|
||||||
|
|
||||||
delete manager;
|
delete manager;
|
||||||
|
|
||||||
// Now we can destroy theme
|
// Now we can destroy theme
|
||||||
@ -470,295 +407,6 @@ CheckBox* check_button_new(const char *text, int b1, int b2, int b3, int b4)
|
|||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// Keyboard shortcuts
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
Accelerator* add_keyboard_shortcut_to_execute_command(const char* shortcut_string,
|
|
||||||
const char* command_name, Params* params, KeyContext keyContext)
|
|
||||||
{
|
|
||||||
Shortcut* shortcut = get_keyboard_shortcut_for_command(command_name, params);
|
|
||||||
if (!shortcut) {
|
|
||||||
shortcut = new Shortcut(Shortcut::Type::ExecuteCommand);
|
|
||||||
shortcut->command = CommandsModule::instance()->getCommandByName(command_name);
|
|
||||||
shortcut->params = params ? params->clone(): new Params;
|
|
||||||
shortcut->keycontext = keyContext;
|
|
||||||
shortcuts->push_back(shortcut);
|
|
||||||
}
|
|
||||||
shortcut->add_shortcut(shortcut_string);
|
|
||||||
return shortcut->accel;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accelerator* 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::Type::ChangeTool);
|
|
||||||
shortcut->tool = tool;
|
|
||||||
|
|
||||||
shortcuts->push_back(shortcut);
|
|
||||||
}
|
|
||||||
|
|
||||||
shortcut->add_shortcut(shortcut_string);
|
|
||||||
return shortcut->accel;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accelerator* 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::Type::EditorQuicktool);
|
|
||||||
shortcut->tool = tool;
|
|
||||||
|
|
||||||
shortcuts->push_back(shortcut);
|
|
||||||
}
|
|
||||||
|
|
||||||
shortcut->add_shortcut(shortcut_string);
|
|
||||||
return shortcut->accel;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accelerator* 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::Type::SpriteEditor);
|
|
||||||
shortcut->action = action_name;
|
|
||||||
|
|
||||||
shortcuts->push_back(shortcut);
|
|
||||||
}
|
|
||||||
|
|
||||||
shortcut->add_shortcut(shortcut_string);
|
|
||||||
return shortcut->accel;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_command_from_key_message(Message* msg, Command** command, Params** params)
|
|
||||||
{
|
|
||||||
for (Shortcut* shortcut : *shortcuts) {
|
|
||||||
if (shortcut->type == Shortcut::Type::ExecuteCommand &&
|
|
||||||
shortcut->is_pressed(msg)) {
|
|
||||||
if (command) *command = shortcut->command;
|
|
||||||
if (params) *params = shortcut->params;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accelerator* get_accel_to_execute_command(const char* command_name, Params* params)
|
|
||||||
{
|
|
||||||
Shortcut* shortcut = get_keyboard_shortcut_for_command(command_name, params);
|
|
||||||
if (shortcut)
|
|
||||||
return shortcut->accel;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accelerator* get_accel_to_change_tool(tools::Tool* tool)
|
|
||||||
{
|
|
||||||
Shortcut* shortcut = get_keyboard_shortcut_for_tool(tool);
|
|
||||||
if (shortcut)
|
|
||||||
return shortcut->accel;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accelerator* get_accel_to_copy_selection()
|
|
||||||
{
|
|
||||||
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_COPYSELECTION);
|
|
||||||
if (shortcut)
|
|
||||||
return shortcut->accel;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accelerator* get_accel_to_snap_to_grid()
|
|
||||||
{
|
|
||||||
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_SNAPTOGRID);
|
|
||||||
if (shortcut)
|
|
||||||
return shortcut->accel;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accelerator* get_accel_to_angle_snap()
|
|
||||||
{
|
|
||||||
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_ANGLESNAP);
|
|
||||||
if (shortcut)
|
|
||||||
return shortcut->accel;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accelerator* get_accel_to_maintain_aspect_ratio()
|
|
||||||
{
|
|
||||||
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_MAINTAINASPECTRATIO);
|
|
||||||
if (shortcut)
|
|
||||||
return shortcut->accel;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accelerator* get_accel_to_lock_axis()
|
|
||||||
{
|
|
||||||
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_LOCKAXIS);
|
|
||||||
if (shortcut)
|
|
||||||
return shortcut->accel;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accelerator* get_accel_to_add_selection()
|
|
||||||
{
|
|
||||||
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_ADDSEL);
|
|
||||||
if (shortcut)
|
|
||||||
return shortcut->accel;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accelerator* get_accel_to_subtract_selection()
|
|
||||||
{
|
|
||||||
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_SUBSEL);
|
|
||||||
if (shortcut)
|
|
||||||
return shortcut->accel;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
tools::Tool* get_selected_quicktool(tools::Tool* currentTool)
|
|
||||||
{
|
|
||||||
if (currentTool && currentTool->getInk(0)->isSelection()) {
|
|
||||||
Accelerator* copyselection_accel = get_accel_to_copy_selection();
|
|
||||||
if (copyselection_accel && copyselection_accel->checkFromAllegroKeyArray())
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
tools::ToolBox* toolbox = App::instance()->getToolBox();
|
|
||||||
|
|
||||||
// Iterate over all tools
|
|
||||||
for (tools::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(Shortcut::Type type)
|
|
||||||
{
|
|
||||||
this->type = type;
|
|
||||||
this->accel = new Accelerator;
|
|
||||||
this->command = NULL;
|
|
||||||
this->keycontext = KeyContext::Any;
|
|
||||||
this->tool = NULL;
|
|
||||||
this->params = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Shortcut::~Shortcut()
|
|
||||||
{
|
|
||||||
delete params;
|
|
||||||
delete accel;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shortcut::add_shortcut(const char* shortcut_string)
|
|
||||||
{
|
|
||||||
this->accel->addKeysFromString(shortcut_string);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Shortcut::is_pressed(Message* msg)
|
|
||||||
{
|
|
||||||
bool res = false;
|
|
||||||
|
|
||||||
if (accel) {
|
|
||||||
res = accel->check(msg->keyModifiers(),
|
|
||||||
static_cast<KeyMessage*>(msg)->scancode(),
|
|
||||||
static_cast<KeyMessage*>(msg)->unicodeChar());
|
|
||||||
|
|
||||||
if (res &&
|
|
||||||
keycontext != KeyContext::Any &&
|
|
||||||
keycontext != get_current_keycontext()) {
|
|
||||||
res = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Shortcut::is_pressed_from_key_array()
|
|
||||||
{
|
|
||||||
bool res = false;
|
|
||||||
|
|
||||||
if (accel) {
|
|
||||||
res = accel->checkFromAllegroKeyArray();
|
|
||||||
|
|
||||||
if (res &&
|
|
||||||
keycontext != KeyContext::Any &&
|
|
||||||
keycontext != get_current_keycontext()) {
|
|
||||||
res = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Shortcut* get_keyboard_shortcut_for_command(const char* command_name, Params* params)
|
|
||||||
{
|
|
||||||
Command* command = CommandsModule::instance()->getCommandByName(command_name);
|
|
||||||
if (!command)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
for (Shortcut* shortcut : *shortcuts) {
|
|
||||||
if (shortcut->type == Shortcut::Type::ExecuteCommand &&
|
|
||||||
shortcut->command == command &&
|
|
||||||
((!params && shortcut->params->empty()) ||
|
|
||||||
(params && *shortcut->params == *params))) {
|
|
||||||
return shortcut;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Shortcut* get_keyboard_shortcut_for_tool(tools::Tool* tool)
|
|
||||||
{
|
|
||||||
for (Shortcut* shortcut : *shortcuts) {
|
|
||||||
if (shortcut->type == Shortcut::Type::ChangeTool &&
|
|
||||||
shortcut->tool == tool) {
|
|
||||||
return shortcut;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Shortcut* get_keyboard_shortcut_for_quicktool(tools::Tool* tool)
|
|
||||||
{
|
|
||||||
for (Shortcut* shortcut : *shortcuts) {
|
|
||||||
if (shortcut->type == Shortcut::Type::EditorQuicktool &&
|
|
||||||
shortcut->tool == tool) {
|
|
||||||
return shortcut;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Shortcut* get_keyboard_shortcut_for_spriteeditor(const char* action_name)
|
|
||||||
{
|
|
||||||
for (Shortcut* shortcut : *shortcuts) {
|
|
||||||
if (shortcut->type == Shortcut::Type::SpriteEditor &&
|
|
||||||
shortcut->action == action_name) {
|
|
||||||
return shortcut;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Manager event handler.
|
// Manager event handler.
|
||||||
bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
||||||
{
|
{
|
||||||
@ -809,26 +457,24 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Shortcut* shortcut : *shortcuts) {
|
for (const Key* key : *KeyboardShortcuts::instance()) {
|
||||||
if (shortcut->is_pressed(msg)) {
|
if (key->isPressed(msg)) {
|
||||||
// Cancel menu-bar loops (to close any popup menu)
|
// Cancel menu-bar loops (to close any popup menu)
|
||||||
App::instance()->getMainWindow()->getMenuBar()->cancelMenuLoop();
|
App::instance()->getMainWindow()->getMenuBar()->cancelMenuLoop();
|
||||||
|
|
||||||
switch (shortcut->type) {
|
switch (key->type()) {
|
||||||
|
|
||||||
case Shortcut::Type::ChangeTool: {
|
case KeyType::Tool: {
|
||||||
tools::Tool* current_tool = UIContext::instance()->settings()->getCurrentTool();
|
tools::Tool* current_tool = UIContext::instance()->settings()->getCurrentTool();
|
||||||
tools::Tool* select_this_tool = shortcut->tool;
|
tools::Tool* select_this_tool = key->tool();
|
||||||
tools::ToolBox* toolbox = App::instance()->getToolBox();
|
tools::ToolBox* toolbox = App::instance()->getToolBox();
|
||||||
std::vector<tools::Tool*> possibles;
|
std::vector<tools::Tool*> possibles;
|
||||||
|
|
||||||
// Iterate over all tools
|
// Collect all tools with the pressed keyboard-shortcut
|
||||||
for (tools::ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
|
for (tools::Tool* tool : *toolbox) {
|
||||||
Shortcut* shortcut = get_keyboard_shortcut_for_tool(*it);
|
Key* key = KeyboardShortcuts::instance()->tool(tool);
|
||||||
|
if (key && key->isPressed(msg))
|
||||||
// Collect all tools with the pressed keyboard-shortcut
|
possibles.push_back(tool);
|
||||||
if (shortcut && shortcut->is_pressed(msg))
|
|
||||||
possibles.push_back(*it);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (possibles.size() >= 2) {
|
if (possibles.size() >= 2) {
|
||||||
@ -859,8 +505,8 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Shortcut::Type::ExecuteCommand: {
|
case KeyType::Command: {
|
||||||
Command* command = shortcut->command;
|
Command* command = key->command();
|
||||||
|
|
||||||
// Commands are executed only when the main window is
|
// Commands are executed only when the main window is
|
||||||
// the current window running at foreground.
|
// the current window running at foreground.
|
||||||
@ -875,16 +521,17 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
|||||||
else if (child->isDesktop() && child == App::instance()->getMainWindow()) {
|
else if (child->isDesktop() && child == App::instance()->getMainWindow()) {
|
||||||
// OK, so we can execute the command represented
|
// OK, so we can execute the command represented
|
||||||
// by the pressed-key in the message...
|
// by the pressed-key in the message...
|
||||||
UIContext::instance()->executeCommand(command, shortcut->params);
|
UIContext::instance()->executeCommand(
|
||||||
|
command, key->params());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Shortcut::Type::EditorQuicktool: {
|
case KeyType::Quicktool: {
|
||||||
// Do nothing, it is used in the editor through the
|
// Do nothing, it is used in the editor through the
|
||||||
// get_selected_quicktool() function.
|
// KeyboardShortcuts::getCurrentQuicktool() function.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,10 +22,7 @@
|
|||||||
|
|
||||||
#include "app/ui/skin/skin_property.h"
|
#include "app/ui/skin/skin_property.h"
|
||||||
#include "base/exception.h"
|
#include "base/exception.h"
|
||||||
#include "ui/accelerator.h"
|
|
||||||
#include "ui/base.h"
|
#include "ui/base.h"
|
||||||
#include <list>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
class ButtonBase;
|
class ButtonBase;
|
||||||
@ -45,12 +42,6 @@ namespace app {
|
|||||||
class Tool;
|
class Tool;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class KeyContext {
|
|
||||||
Any,
|
|
||||||
Normal,
|
|
||||||
Selection,
|
|
||||||
};
|
|
||||||
|
|
||||||
int init_module_gui();
|
int init_module_gui();
|
||||||
void exit_module_gui();
|
void exit_module_gui();
|
||||||
|
|
||||||
@ -78,29 +69,6 @@ namespace app {
|
|||||||
|
|
||||||
ui::CheckBox* check_button_new(const char* text, int b1, int b2, int b3, int b4);
|
ui::CheckBox* check_button_new(const char* text, int b1, int b2, int b3, int b4);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// Keyboard shortcuts
|
|
||||||
|
|
||||||
ui::Accelerator* add_keyboard_shortcut_to_execute_command(const char* shortcut,
|
|
||||||
const char* command_name, Params* params, KeyContext keyContext);
|
|
||||||
|
|
||||||
ui::Accelerator* add_keyboard_shortcut_to_change_tool(const char* shortcut, tools::Tool* tool);
|
|
||||||
ui::Accelerator* add_keyboard_shortcut_to_quicktool(const char* shortcut, tools::Tool* tool);
|
|
||||||
ui::Accelerator* add_keyboard_shortcut_to_spriteeditor(const char* shortcut, const char* action_name);
|
|
||||||
|
|
||||||
bool get_command_from_key_message(ui::Message* msg, Command** command, Params** params);
|
|
||||||
ui::Accelerator* get_accel_to_execute_command(const char* command, Params* params = NULL);
|
|
||||||
ui::Accelerator* get_accel_to_change_tool(tools::Tool* tool);
|
|
||||||
ui::Accelerator* get_accel_to_copy_selection();
|
|
||||||
ui::Accelerator* get_accel_to_snap_to_grid();
|
|
||||||
ui::Accelerator* get_accel_to_angle_snap();
|
|
||||||
ui::Accelerator* get_accel_to_maintain_aspect_ratio();
|
|
||||||
ui::Accelerator* get_accel_to_lock_axis();
|
|
||||||
ui::Accelerator* get_accel_to_add_selection();
|
|
||||||
ui::Accelerator* get_accel_to_subtract_selection();
|
|
||||||
|
|
||||||
tools::Tool* get_selected_quicktool(tools::Tool* currentTool);
|
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -25,9 +25,12 @@
|
|||||||
#include "app/commands/command.h"
|
#include "app/commands/command.h"
|
||||||
#include "app/commands/params.h"
|
#include "app/commands/params.h"
|
||||||
#include "app/modules/gui.h"
|
#include "app/modules/gui.h"
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui_context.h"
|
#include "app/ui_context.h"
|
||||||
|
#include "ui/accelerator.h"
|
||||||
#include "ui/menu.h"
|
#include "ui/menu.h"
|
||||||
#include "ui/message.h"
|
#include "ui/message.h"
|
||||||
|
#include "ui/preferred_size_event.h"
|
||||||
#include "ui/widget.h"
|
#include "ui/widget.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@ -38,8 +41,9 @@ namespace app {
|
|||||||
|
|
||||||
using namespace ui;
|
using namespace ui;
|
||||||
|
|
||||||
AppMenuItem::AppMenuItem(const char* text, Command* command, Params* params)
|
AppMenuItem::AppMenuItem(const char* text, Command* command, const Params* params)
|
||||||
: MenuItem(text)
|
: MenuItem(text)
|
||||||
|
, m_key(NULL)
|
||||||
, m_command(command)
|
, m_command(command)
|
||||||
, m_params(params ? params->clone(): NULL)
|
, m_params(params ? params->clone(): NULL)
|
||||||
{
|
{
|
||||||
@ -82,6 +86,31 @@ bool AppMenuItem::onProcessMessage(Message* msg)
|
|||||||
return MenuItem::onProcessMessage(msg);
|
return MenuItem::onProcessMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppMenuItem::onPreferredSize(PreferredSizeEvent& ev)
|
||||||
|
{
|
||||||
|
gfx::Size size(0, 0);
|
||||||
|
|
||||||
|
if (hasText()) {
|
||||||
|
size.w =
|
||||||
|
+ this->border_width.l
|
||||||
|
+ getTextWidth()
|
||||||
|
+ (inBar() ? this->child_spacing/4: this->child_spacing)
|
||||||
|
+ this->border_width.r;
|
||||||
|
|
||||||
|
size.h =
|
||||||
|
+ this->border_width.t
|
||||||
|
+ getTextHeight()
|
||||||
|
+ this->border_width.b;
|
||||||
|
|
||||||
|
if (m_key && !m_key->accels().empty()) {
|
||||||
|
size.w += Graphics::measureUIStringLength(
|
||||||
|
m_key->accels().front().toString().c_str(), getFont());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ev.setPreferredSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
void AppMenuItem::onClick()
|
void AppMenuItem::onClick()
|
||||||
{
|
{
|
||||||
MenuItem::onClick();
|
MenuItem::onClick();
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "ui/menu.h"
|
#include "ui/menu.h"
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
class Key;
|
||||||
class Command;
|
class Command;
|
||||||
class Params;
|
class Params;
|
||||||
|
|
||||||
@ -33,17 +34,22 @@ namespace app {
|
|||||||
// used to check the availability of the command).
|
// used to check the availability of the command).
|
||||||
class AppMenuItem : public ui::MenuItem {
|
class AppMenuItem : public ui::MenuItem {
|
||||||
public:
|
public:
|
||||||
AppMenuItem(const char* text, Command* command, Params* params);
|
AppMenuItem(const char* text, Command* command, const Params* params);
|
||||||
~AppMenuItem();
|
~AppMenuItem();
|
||||||
|
|
||||||
|
Key* getKey() { return m_key; }
|
||||||
|
void setKey(Key* key) { m_key = key; }
|
||||||
|
|
||||||
Command* getCommand() { return m_command; }
|
Command* getCommand() { return m_command; }
|
||||||
Params* getParams() { return m_params; }
|
Params* getParams() { return m_params; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool onProcessMessage(ui::Message* msg) override;
|
bool onProcessMessage(ui::Message* msg) override;
|
||||||
|
void onPreferredSize(ui::PreferredSizeEvent& ev) override;
|
||||||
void onClick() override;
|
void onClick() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Key* m_key;
|
||||||
Command* m_command;
|
Command* m_command;
|
||||||
Params* m_params;
|
Params* m_params;
|
||||||
};
|
};
|
||||||
|
@ -24,11 +24,11 @@
|
|||||||
|
|
||||||
#include "app/app.h"
|
#include "app/app.h"
|
||||||
#include "app/modules/editors.h"
|
#include "app/modules/editors.h"
|
||||||
#include "app/modules/gui.h"
|
|
||||||
#include "app/modules/palettes.h"
|
#include "app/modules/palettes.h"
|
||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
#include "app/ui/editor/editor_customization_delegate.h"
|
#include "app/ui/editor/editor_customization_delegate.h"
|
||||||
#include "app/ui/editor/editor_view.h"
|
#include "app/ui/editor/editor_view.h"
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui/main_window.h"
|
#include "app/ui/main_window.h"
|
||||||
#include "app/ui/mini_editor.h"
|
#include "app/ui/mini_editor.h"
|
||||||
#include "app/ui/workspace.h"
|
#include "app/ui/workspace.h"
|
||||||
@ -77,61 +77,42 @@ public:
|
|||||||
|
|
||||||
// EditorCustomizationDelegate implementation
|
// EditorCustomizationDelegate implementation
|
||||||
tools::Tool* getQuickTool(tools::Tool* currentTool) override {
|
tools::Tool* getQuickTool(tools::Tool* currentTool) override {
|
||||||
return get_selected_quicktool(currentTool);
|
return KeyboardShortcuts::instance()
|
||||||
|
->getCurrentQuicktool(currentTool);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isCopySelectionKeyPressed() override {
|
bool isCopySelectionKeyPressed() override {
|
||||||
Accelerator* accel = get_accel_to_copy_selection();
|
return isKeyActionPressed(KeyAction::CopySelection);
|
||||||
if (accel)
|
|
||||||
return accel->checkFromAllegroKeyArray();
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSnapToGridKeyPressed() override {
|
bool isSnapToGridKeyPressed() override {
|
||||||
Accelerator* accel = get_accel_to_snap_to_grid();
|
return isKeyActionPressed(KeyAction::SnapToGrid);
|
||||||
if (accel)
|
|
||||||
return accel->checkFromAllegroKeyArray();
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAngleSnapKeyPressed() override {
|
bool isAngleSnapKeyPressed() override {
|
||||||
Accelerator* accel = get_accel_to_angle_snap();
|
return isKeyActionPressed(KeyAction::AngleSnap);
|
||||||
if (accel)
|
|
||||||
return accel->checkFromAllegroKeyArray();
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isMaintainAspectRatioKeyPressed() override {
|
bool isMaintainAspectRatioKeyPressed() override {
|
||||||
Accelerator* accel = get_accel_to_maintain_aspect_ratio();
|
return isKeyActionPressed(KeyAction::MaintainAspectRatio);
|
||||||
if (accel)
|
|
||||||
return accel->checkFromAllegroKeyArray();
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isLockAxisKeyPressed() override {
|
bool isLockAxisKeyPressed() override {
|
||||||
Accelerator* accel = get_accel_to_lock_axis();
|
return isKeyActionPressed(KeyAction::LockAxis);
|
||||||
if (accel)
|
|
||||||
return accel->checkFromAllegroKeyArray();
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAddSelectionPressed() override {
|
bool isAddSelectionPressed() override {
|
||||||
Accelerator* accel = get_accel_to_add_selection();
|
return isKeyActionPressed(KeyAction::AddSelection);
|
||||||
if (accel)
|
|
||||||
return accel->checkFromAllegroKeyArray();
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSubtractSelectionPressed() override {
|
bool isSubtractSelectionPressed() override {
|
||||||
Accelerator* accel = get_accel_to_subtract_selection();
|
return isKeyActionPressed(KeyAction::SubtractSelection);
|
||||||
if (accel)
|
}
|
||||||
return accel->checkFromAllegroKeyArray();
|
|
||||||
|
private:
|
||||||
|
bool isKeyActionPressed(KeyAction action) {
|
||||||
|
if (Key* key = KeyboardShortcuts::instance()->action(action))
|
||||||
|
return key->checkFromAllegroKeyArray();
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -25,13 +25,13 @@
|
|||||||
#include "app/commands/command.h"
|
#include "app/commands/command.h"
|
||||||
#include "app/commands/commands.h"
|
#include "app/commands/commands.h"
|
||||||
#include "app/commands/params.h"
|
#include "app/commands/params.h"
|
||||||
#include "app/modules/gui.h"
|
|
||||||
#include "app/tools/controller.h"
|
#include "app/tools/controller.h"
|
||||||
#include "app/tools/ink.h"
|
#include "app/tools/ink.h"
|
||||||
#include "app/tools/tool.h"
|
#include "app/tools/tool.h"
|
||||||
#include "app/tools/tool_loop.h"
|
#include "app/tools/tool_loop.h"
|
||||||
#include "app/tools/tool_loop_manager.h"
|
#include "app/tools/tool_loop_manager.h"
|
||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui_context.h"
|
#include "app/ui_context.h"
|
||||||
#include "raster/blend.h"
|
#include "raster/blend.h"
|
||||||
#include "ui/message.h"
|
#include "ui/message.h"
|
||||||
@ -178,7 +178,8 @@ bool DrawingState::onKeyDown(Editor* editor, KeyMessage* msg)
|
|||||||
|
|
||||||
Command* command = NULL;
|
Command* command = NULL;
|
||||||
Params* params = NULL;
|
Params* params = NULL;
|
||||||
if (get_command_from_key_message(msg, &command, ¶ms)) {
|
if (KeyboardShortcuts::instance()
|
||||||
|
->getCommandFromKeyMessage(msg, &command, ¶ms)) {
|
||||||
// We accept zoom commands.
|
// We accept zoom commands.
|
||||||
if (strcmp(command->short_name(), CommandId::Zoom) == 0) {
|
if (strcmp(command->short_name(), CommandId::Zoom) == 0) {
|
||||||
UIContext::instance()->executeCommand(command, params);
|
UIContext::instance()->executeCommand(command, params);
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include "app/commands/cmd_move_mask.h"
|
#include "app/commands/cmd_move_mask.h"
|
||||||
#include "app/commands/command.h"
|
#include "app/commands/command.h"
|
||||||
#include "app/commands/commands.h"
|
#include "app/commands/commands.h"
|
||||||
#include "app/modules/gui.h"
|
|
||||||
#include "app/settings/settings.h"
|
#include "app/settings/settings.h"
|
||||||
#include "app/tools/ink.h"
|
#include "app/tools/ink.h"
|
||||||
#include "app/tools/tool.h"
|
#include "app/tools/tool.h"
|
||||||
@ -38,6 +37,7 @@
|
|||||||
#include "app/ui/editor/pixels_movement.h"
|
#include "app/ui/editor/pixels_movement.h"
|
||||||
#include "app/ui/editor/standby_state.h"
|
#include "app/ui/editor/standby_state.h"
|
||||||
#include "app/ui/editor/transform_handles.h"
|
#include "app/ui/editor/transform_handles.h"
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui/main_window.h"
|
#include "app/ui/main_window.h"
|
||||||
#include "app/ui/status_bar.h"
|
#include "app/ui/status_bar.h"
|
||||||
#include "app/ui_context.h"
|
#include "app/ui_context.h"
|
||||||
@ -326,7 +326,8 @@ bool MovingPixelsState::onKeyDown(Editor* editor, KeyMessage* msg)
|
|||||||
else {
|
else {
|
||||||
Command* command = NULL;
|
Command* command = NULL;
|
||||||
Params* params = NULL;
|
Params* params = NULL;
|
||||||
if (get_command_from_key_message(msg, &command, ¶ms)) {
|
if (KeyboardShortcuts::instance()
|
||||||
|
->getCommandFromKeyMessage(msg, &command, ¶ms)) {
|
||||||
// We accept zoom commands.
|
// We accept zoom commands.
|
||||||
if (strcmp(command->short_name(), CommandId::Zoom) == 0) {
|
if (strcmp(command->short_name(), CommandId::Zoom) == 0) {
|
||||||
UIContext::instance()->executeCommand(command, params);
|
UIContext::instance()->executeCommand(command, params);
|
||||||
|
589
src/app/ui/keyboard_shortcuts.cpp
Normal file
589
src/app/ui/keyboard_shortcuts.cpp
Normal file
@ -0,0 +1,589 @@
|
|||||||
|
/* Aseprite
|
||||||
|
* Copyright (C) 2001-2014 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
|
|
||||||
|
#include "app/app.h"
|
||||||
|
#include "app/app_menus.h"
|
||||||
|
#include "app/commands/command.h"
|
||||||
|
#include "app/commands/commands.h"
|
||||||
|
#include "app/commands/params.h"
|
||||||
|
#include "app/document.h"
|
||||||
|
#include "app/document_location.h"
|
||||||
|
#include "app/settings/settings.h"
|
||||||
|
#include "app/tools/ink.h"
|
||||||
|
#include "app/tools/tool.h"
|
||||||
|
#include "app/tools/tool_box.h"
|
||||||
|
#include "app/ui_context.h"
|
||||||
|
#include "app/xml_document.h"
|
||||||
|
#include "app/xml_exception.h"
|
||||||
|
#include "ui/accelerator.h"
|
||||||
|
#include "ui/message.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#define XML_KEYBOARD_FILE_VERSION "1"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
const char* name;
|
||||||
|
const char* userfriendly;
|
||||||
|
app::KeyAction action;
|
||||||
|
} actions[] = {
|
||||||
|
{ "CopySelection" , "Copy Selection" , app::KeyAction::CopySelection },
|
||||||
|
{ "SnapToGrid" , "Snap To Grid" , app::KeyAction::SnapToGrid },
|
||||||
|
{ "AngleSnap" , "Angle Snap" , app::KeyAction::AngleSnap },
|
||||||
|
{ "MaintainAspectRatio" , "Maintain Aspect Ratio", app::KeyAction::MaintainAspectRatio },
|
||||||
|
{ "LockAxis" , "Lock Axis" , app::KeyAction::LockAxis },
|
||||||
|
{ "AddSelection" , "Add Selection" , app::KeyAction::AddSelection },
|
||||||
|
{ "SubtractSelection" , "Subtract Selection" , app::KeyAction::SubtractSelection },
|
||||||
|
{ NULL , NULL , app::KeyAction::None }
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* get_shortcut(TiXmlElement* elem)
|
||||||
|
{
|
||||||
|
const char* shortcut = NULL;
|
||||||
|
|
||||||
|
#if defined ALLEGRO_WINDOWS
|
||||||
|
if (!shortcut) shortcut = elem->Attribute("win");
|
||||||
|
#elif defined ALLEGRO_MACOSX
|
||||||
|
if (!shortcut) shortcut = elem->Attribute("mac");
|
||||||
|
#elif defined ALLEGRO_UNIX
|
||||||
|
if (!shortcut) shortcut = elem->Attribute("linux");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!shortcut)
|
||||||
|
shortcut = elem->Attribute("shortcut");
|
||||||
|
|
||||||
|
return shortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_user_friendly_string_for_keyaction(app::KeyAction action)
|
||||||
|
{
|
||||||
|
for (int c=0; actions[c].name; ++c) {
|
||||||
|
if (action == actions[c].action)
|
||||||
|
return actions[c].userfriendly;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
|
||||||
|
template<> app::KeyAction convert_to(const std::string& from) {
|
||||||
|
app::KeyAction action = app::KeyAction::None;
|
||||||
|
|
||||||
|
for (int c=0; actions[c].name; ++c) {
|
||||||
|
if (from == actions[c].name)
|
||||||
|
return actions[c].action;
|
||||||
|
}
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> std::string convert_to(const app::KeyAction& from) {
|
||||||
|
for (int c=0; actions[c].name; ++c) {
|
||||||
|
if (from == actions[c].action)
|
||||||
|
return actions[c].name;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace base
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
using namespace ui;
|
||||||
|
|
||||||
|
Key::Key(Command* command, const Params* params, KeyContext keyContext)
|
||||||
|
: m_type(KeyType::Command)
|
||||||
|
, m_useUsers(false)
|
||||||
|
, m_keycontext(keyContext)
|
||||||
|
, m_command(command)
|
||||||
|
, m_params(params ? params->clone(): NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Key::Key(KeyType type, tools::Tool* tool)
|
||||||
|
: m_type(type)
|
||||||
|
, m_useUsers(false)
|
||||||
|
, m_keycontext(KeyContext::Any)
|
||||||
|
, m_tool(tool)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Key::Key(KeyAction action)
|
||||||
|
: m_type(KeyType::Action)
|
||||||
|
, m_useUsers(false)
|
||||||
|
, m_keycontext(KeyContext::Any)
|
||||||
|
, m_action(action)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Key::setUserAccels(const Accelerators& accels)
|
||||||
|
{
|
||||||
|
m_useUsers = true;
|
||||||
|
m_users = accels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Key::add(const ui::Accelerator& accel, KeySource source)
|
||||||
|
{
|
||||||
|
Accelerators* accels = &m_accels;
|
||||||
|
|
||||||
|
if (source == KeySource::UserDefined) {
|
||||||
|
if (!m_useUsers) {
|
||||||
|
m_useUsers = true;
|
||||||
|
m_users = m_accels;
|
||||||
|
}
|
||||||
|
accels = &m_users;
|
||||||
|
|
||||||
|
KeyboardShortcuts::instance()->disableAccel(accel);
|
||||||
|
}
|
||||||
|
|
||||||
|
accels->push_back(accel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Key::isPressed(Message* msg) const
|
||||||
|
{
|
||||||
|
ASSERT(dynamic_cast<KeyMessage*>(msg) != NULL);
|
||||||
|
|
||||||
|
for (const Accelerator& accel : accels()) {
|
||||||
|
if (accel.check(msg->keyModifiers(),
|
||||||
|
static_cast<KeyMessage*>(msg)->scancode(),
|
||||||
|
static_cast<KeyMessage*>(msg)->unicodeChar()) &&
|
||||||
|
(m_keycontext == KeyContext::Any ||
|
||||||
|
m_keycontext == KeyboardShortcuts::instance()->getCurrentKeyContext())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Key::checkFromAllegroKeyArray()
|
||||||
|
{
|
||||||
|
for (const Accelerator& accel : this->accels()) {
|
||||||
|
if (accel.checkFromAllegroKeyArray())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Key::hasAccel(const ui::Accelerator& accel) const
|
||||||
|
{
|
||||||
|
return (std::find(accels().begin(), accels().end(), accel) != accels().end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Key::disableAccel(const ui::Accelerator& accel)
|
||||||
|
{
|
||||||
|
if (!m_useUsers) {
|
||||||
|
m_useUsers = true;
|
||||||
|
m_users = m_accels;
|
||||||
|
}
|
||||||
|
|
||||||
|
Accelerators::iterator it = std::find(m_users.begin(), m_users.end(), accel);
|
||||||
|
if (it != m_users.end())
|
||||||
|
m_users.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Key::reset()
|
||||||
|
{
|
||||||
|
m_users.clear();
|
||||||
|
m_useUsers = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Key::triggerString() const
|
||||||
|
{
|
||||||
|
switch (m_type) {
|
||||||
|
case KeyType::Command:
|
||||||
|
if (m_params)
|
||||||
|
m_command->loadParams(m_params);
|
||||||
|
return m_command->friendlyName();
|
||||||
|
case KeyType::Tool:
|
||||||
|
case KeyType::Quicktool: {
|
||||||
|
std::string text = m_tool->getText();
|
||||||
|
if (m_type == KeyType::Quicktool)
|
||||||
|
text += " (quick)";
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
case KeyType::Action:
|
||||||
|
return get_user_friendly_string_for_keyaction(m_action);
|
||||||
|
}
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardShortcuts* KeyboardShortcuts::instance()
|
||||||
|
{
|
||||||
|
static KeyboardShortcuts* singleton = NULL;
|
||||||
|
if (!singleton)
|
||||||
|
singleton = new KeyboardShortcuts();
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardShortcuts::KeyboardShortcuts()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardShortcuts::~KeyboardShortcuts()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardShortcuts::clear()
|
||||||
|
{
|
||||||
|
for (Key* key : m_keys) {
|
||||||
|
delete key;
|
||||||
|
}
|
||||||
|
m_keys.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||||
|
{
|
||||||
|
// <keyboard><commands><key>
|
||||||
|
TiXmlHandle handle(rootElement);
|
||||||
|
TiXmlElement* xmlKey = handle
|
||||||
|
.FirstChild("commands")
|
||||||
|
.FirstChild("key").ToElement();
|
||||||
|
while (xmlKey) {
|
||||||
|
const char* command_name = xmlKey->Attribute("command");
|
||||||
|
const char* command_key = get_shortcut(xmlKey);
|
||||||
|
|
||||||
|
if (command_name && command_key) {
|
||||||
|
Command* command = CommandsModule::instance()->getCommandByName(command_name);
|
||||||
|
if (command) {
|
||||||
|
// Read context
|
||||||
|
KeyContext keycontext = KeyContext::Any;
|
||||||
|
const char* keycontextstr = xmlKey->Attribute("context");
|
||||||
|
if (keycontextstr) {
|
||||||
|
if (strcmp(keycontextstr, "Selection") == 0)
|
||||||
|
keycontext = KeyContext::Selection;
|
||||||
|
else if (strcmp(keycontextstr, "Normal") == 0)
|
||||||
|
keycontext = KeyContext::Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read params
|
||||||
|
Params params;
|
||||||
|
|
||||||
|
TiXmlElement* xmlParam = xmlKey->FirstChildElement("param");
|
||||||
|
while (xmlParam) {
|
||||||
|
const char* param_name = xmlParam->Attribute("name");
|
||||||
|
const char* param_value = xmlParam->Attribute("value");
|
||||||
|
|
||||||
|
if (param_name && param_value)
|
||||||
|
params.set(param_name, param_value);
|
||||||
|
|
||||||
|
xmlParam = xmlParam->NextSiblingElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINTF(" - Shortcut for command `%s' <%s>\n", command_name, command_key);
|
||||||
|
|
||||||
|
// add the keyboard shortcut to the command
|
||||||
|
Key* key = this->command(command_name, ¶ms, keycontext);
|
||||||
|
if (key) {
|
||||||
|
key->add(Accelerator(command_key), source);
|
||||||
|
|
||||||
|
// Add the shortcut to the menuitems with this
|
||||||
|
// command (this is only visual, the "manager_msg_proc"
|
||||||
|
// is the only one that process keyboard shortcuts)
|
||||||
|
if (key->accels().size() == 1) {
|
||||||
|
AppMenus::instance()->applyShortcutToMenuitemsWithCommand(
|
||||||
|
command, ¶ms, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlKey = xmlKey->NextSiblingElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load keyboard shortcuts for tools
|
||||||
|
// <gui><keyboard><tools><key>
|
||||||
|
xmlKey = handle
|
||||||
|
.FirstChild("tools")
|
||||||
|
.FirstChild("key").ToElement();
|
||||||
|
while (xmlKey) {
|
||||||
|
const char* tool_id = xmlKey->Attribute("tool");
|
||||||
|
const char* tool_key = get_shortcut(xmlKey);
|
||||||
|
|
||||||
|
if (tool_id && tool_key) {
|
||||||
|
tools::Tool* tool = App::instance()->getToolBox()->getToolById(tool_id);
|
||||||
|
if (tool) {
|
||||||
|
PRINTF(" - Shortcut for tool `%s': <%s>\n", tool_id, tool_key);
|
||||||
|
|
||||||
|
Key* key = this->tool(tool);
|
||||||
|
if (key)
|
||||||
|
key->add(Accelerator(tool_key), source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xmlKey = xmlKey->NextSiblingElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load keyboard shortcuts for quicktools
|
||||||
|
// <gui><keyboard><quicktools><key>
|
||||||
|
xmlKey = handle
|
||||||
|
.FirstChild("quicktools")
|
||||||
|
.FirstChild("key").ToElement();
|
||||||
|
while (xmlKey) {
|
||||||
|
const char* tool_id = xmlKey->Attribute("tool");
|
||||||
|
const char* tool_key = get_shortcut(xmlKey);
|
||||||
|
if (tool_id && tool_key) {
|
||||||
|
tools::Tool* tool = App::instance()->getToolBox()->getToolById(tool_id);
|
||||||
|
if (tool) {
|
||||||
|
PRINTF(" - Shortcut for quicktool `%s': <%s>\n", tool_id, tool_key);
|
||||||
|
|
||||||
|
Key* key = this->quicktool(tool);
|
||||||
|
if (key)
|
||||||
|
key->add(Accelerator(tool_key), source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xmlKey = xmlKey->NextSiblingElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load special keyboard shortcuts for sprite editor customization
|
||||||
|
// <gui><keyboard><spriteeditor>
|
||||||
|
xmlKey = handle
|
||||||
|
.FirstChild("actions")
|
||||||
|
.FirstChild("key").ToElement();
|
||||||
|
while (xmlKey) {
|
||||||
|
const char* tool_action = xmlKey->Attribute("action");
|
||||||
|
const char* tool_key = get_shortcut(xmlKey);
|
||||||
|
|
||||||
|
if (tool_action && tool_key) {
|
||||||
|
PRINTF(" - Shortcut for sprite editor `%s': <%s>\n", tool_action, tool_key);
|
||||||
|
|
||||||
|
KeyAction action = base::convert_to<KeyAction, std::string>(tool_action);
|
||||||
|
|
||||||
|
if (action != KeyAction::None) {
|
||||||
|
Key* key = this->action(action);
|
||||||
|
if (key)
|
||||||
|
key->add(Accelerator(tool_key), source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xmlKey = xmlKey->NextSiblingElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardShortcuts::importFile(const std::string& filename, KeySource source)
|
||||||
|
{
|
||||||
|
XmlDocumentRef doc = app::open_xml(filename);
|
||||||
|
TiXmlHandle handle(doc);
|
||||||
|
TiXmlElement* xmlKey = handle.FirstChild("keyboard").ToElement();
|
||||||
|
|
||||||
|
importFile(xmlKey, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardShortcuts::exportFile(const std::string& filename)
|
||||||
|
{
|
||||||
|
XmlDocumentRef doc(new TiXmlDocument());
|
||||||
|
|
||||||
|
TiXmlElement keyboard("keyboard");
|
||||||
|
TiXmlElement commands("commands");
|
||||||
|
TiXmlElement tools("tools");
|
||||||
|
TiXmlElement quicktools("quicktools");
|
||||||
|
TiXmlElement actions("actions");
|
||||||
|
|
||||||
|
keyboard.SetAttribute("version", XML_KEYBOARD_FILE_VERSION);
|
||||||
|
|
||||||
|
exportKeys(commands, KeyType::Command);
|
||||||
|
exportKeys(tools, KeyType::Tool);
|
||||||
|
exportKeys(quicktools, KeyType::Quicktool);
|
||||||
|
exportKeys(actions, KeyType::Action);
|
||||||
|
|
||||||
|
keyboard.InsertEndChild(commands);
|
||||||
|
keyboard.InsertEndChild(tools);
|
||||||
|
keyboard.InsertEndChild(quicktools);
|
||||||
|
keyboard.InsertEndChild(actions);
|
||||||
|
doc->InsertEndChild(keyboard);
|
||||||
|
save_xml(doc, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardShortcuts::exportKeys(TiXmlElement& parent, KeyType type)
|
||||||
|
{
|
||||||
|
for (Key* key : m_keys) {
|
||||||
|
// Save only user defined accelerators.
|
||||||
|
if (key->type() != type || key->userAccels().empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (const ui::Accelerator& accel : key->userAccels()) {
|
||||||
|
TiXmlElement elem("key");
|
||||||
|
|
||||||
|
switch (key->type()) {
|
||||||
|
case KeyType::Command:
|
||||||
|
elem.SetAttribute("command", key->command()->short_name());
|
||||||
|
if (key->params()) {
|
||||||
|
for (const auto& param : *key->params()) {
|
||||||
|
if (param.second.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TiXmlElement paramElem("param");
|
||||||
|
paramElem.SetAttribute("name", param.first.c_str());
|
||||||
|
paramElem.SetAttribute("value", param.second.c_str());
|
||||||
|
elem.InsertEndChild(paramElem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KeyType::Tool:
|
||||||
|
case KeyType::Quicktool:
|
||||||
|
elem.SetAttribute("tool", key->tool()->getId().c_str());
|
||||||
|
break;
|
||||||
|
case KeyType::Action:
|
||||||
|
elem.SetAttribute("action",
|
||||||
|
base::convert_to<std::string>(key->action()).c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
elem.SetAttribute("shortcut", accel.toString().c_str());
|
||||||
|
parent.InsertEndChild(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardShortcuts::reset()
|
||||||
|
{
|
||||||
|
for (Key* key : m_keys)
|
||||||
|
key->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Key* KeyboardShortcuts::command(const char* commandName,
|
||||||
|
Params* params, KeyContext keyContext)
|
||||||
|
{
|
||||||
|
Command* command = CommandsModule::instance()->getCommandByName(commandName);
|
||||||
|
if (!command)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (Key* key : m_keys) {
|
||||||
|
if (key->type() == KeyType::Command &&
|
||||||
|
key->keycontext() == keyContext &&
|
||||||
|
key->command() == command &&
|
||||||
|
((!params && key->params()->empty()) ||
|
||||||
|
(params && *key->params() == *params))) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Key* key = new Key(command, params, keyContext);
|
||||||
|
m_keys.push_back(key);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key* KeyboardShortcuts::tool(tools::Tool* tool)
|
||||||
|
{
|
||||||
|
for (Key* key : m_keys) {
|
||||||
|
if (key->type() == KeyType::Tool &&
|
||||||
|
key->tool() == tool) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Key* key = new Key(KeyType::Tool, tool);
|
||||||
|
m_keys.push_back(key);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key* KeyboardShortcuts::quicktool(tools::Tool* tool)
|
||||||
|
{
|
||||||
|
for (Key* key : m_keys) {
|
||||||
|
if (key->type() == KeyType::Quicktool &&
|
||||||
|
key->tool() == tool) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Key* key = new Key(KeyType::Quicktool, tool);
|
||||||
|
m_keys.push_back(key);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key* KeyboardShortcuts::action(KeyAction action)
|
||||||
|
{
|
||||||
|
for (Key* key : m_keys) {
|
||||||
|
if (key->type() == KeyType::Action &&
|
||||||
|
key->action() == action) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Key* key = new Key(action);
|
||||||
|
m_keys.push_back(key);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel)
|
||||||
|
{
|
||||||
|
for (Key* key : m_keys) {
|
||||||
|
if (key->hasAccel(accel))
|
||||||
|
key->disableAccel(accel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyContext KeyboardShortcuts::getCurrentKeyContext()
|
||||||
|
{
|
||||||
|
app::Context* ctx = UIContext::instance();
|
||||||
|
DocumentLocation location = ctx->activeLocation();
|
||||||
|
Document* doc = location.document();
|
||||||
|
|
||||||
|
if (doc &&
|
||||||
|
doc->isMaskVisible() &&
|
||||||
|
ctx->settings()->getCurrentTool()->getInk(0)->isSelection())
|
||||||
|
return KeyContext::Selection;
|
||||||
|
else
|
||||||
|
return KeyContext::Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KeyboardShortcuts::getCommandFromKeyMessage(Message* msg, Command** command, Params** params)
|
||||||
|
{
|
||||||
|
for (Key* key : m_keys) {
|
||||||
|
if (key->type() == KeyType::Command && key->isPressed(msg)) {
|
||||||
|
if (command) *command = key->command();
|
||||||
|
if (params) *params = key->params();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tools::Tool* KeyboardShortcuts::getCurrentQuicktool(tools::Tool* currentTool)
|
||||||
|
{
|
||||||
|
if (currentTool && currentTool->getInk(0)->isSelection()) {
|
||||||
|
Key* key = action(KeyAction::CopySelection);
|
||||||
|
if (key && key->checkFromAllegroKeyArray())
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tools::ToolBox* toolbox = App::instance()->getToolBox();
|
||||||
|
|
||||||
|
// Iterate over all tools
|
||||||
|
for (tools::Tool* tool : *toolbox) {
|
||||||
|
Key* key = quicktool(tool);
|
||||||
|
|
||||||
|
// Collect all tools with the pressed keyboard-shortcut
|
||||||
|
if (key && key->checkFromAllegroKeyArray()) {
|
||||||
|
return tool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
175
src/app/ui/keyboard_shortcuts.h
Normal file
175
src/app/ui/keyboard_shortcuts.h
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
/* Aseprite
|
||||||
|
* Copyright (C) 2001-2014 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 APP_UI_KEYBOARD_SHORTCUTS_H_INCLUDED
|
||||||
|
#define APP_UI_KEYBOARD_SHORTCUTS_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/convert_to.h"
|
||||||
|
#include "base/disable_copying.h"
|
||||||
|
#include "ui/accelerator.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class TiXmlElement;
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
class Message;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
class Command;
|
||||||
|
class Params;
|
||||||
|
|
||||||
|
namespace tools {
|
||||||
|
class Tool;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class KeyContext {
|
||||||
|
Any,
|
||||||
|
Normal,
|
||||||
|
Selection,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class KeySource {
|
||||||
|
Original,
|
||||||
|
UserDefined
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class KeyType {
|
||||||
|
Command,
|
||||||
|
Tool,
|
||||||
|
Quicktool,
|
||||||
|
Action,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class KeyAction {
|
||||||
|
None,
|
||||||
|
CopySelection,
|
||||||
|
SnapToGrid,
|
||||||
|
AngleSnap,
|
||||||
|
MaintainAspectRatio,
|
||||||
|
LockAxis,
|
||||||
|
AddSelection,
|
||||||
|
SubtractSelection,
|
||||||
|
};
|
||||||
|
|
||||||
|
class Key {
|
||||||
|
public:
|
||||||
|
Key(Command* command, const Params* params, KeyContext keyContext);
|
||||||
|
Key(KeyType type, tools::Tool* tool);
|
||||||
|
explicit Key(KeyAction action);
|
||||||
|
|
||||||
|
KeyType type() const { return m_type; }
|
||||||
|
const ui::Accelerators& accels() const {
|
||||||
|
return (m_useUsers ? m_users: m_accels);
|
||||||
|
}
|
||||||
|
const ui::Accelerators& origAccels() const { return m_accels; }
|
||||||
|
const ui::Accelerators& userAccels() const { return m_users; }
|
||||||
|
|
||||||
|
void setUserAccels(const ui::Accelerators& accels);
|
||||||
|
|
||||||
|
void add(const ui::Accelerator& accel, KeySource source);
|
||||||
|
bool isPressed(ui::Message* msg) const;
|
||||||
|
bool checkFromAllegroKeyArray();
|
||||||
|
|
||||||
|
bool hasAccel(const ui::Accelerator& accel) const;
|
||||||
|
void disableAccel(const ui::Accelerator& accel);
|
||||||
|
|
||||||
|
// Resets user accelerators to the original ones.
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
// for KeyType::Command
|
||||||
|
Command* command() const { return m_command; }
|
||||||
|
Params* params() const { return m_params; }
|
||||||
|
KeyContext keycontext() const { return m_keycontext; }
|
||||||
|
// for KeyType::Tool or Quicktool
|
||||||
|
tools::Tool* tool() const { return m_tool; }
|
||||||
|
// for KeyType::Action
|
||||||
|
KeyAction action() const { return m_action; }
|
||||||
|
|
||||||
|
std::string triggerString() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
KeyType m_type;
|
||||||
|
ui::Accelerators m_accels;
|
||||||
|
ui::Accelerators m_users;
|
||||||
|
bool m_useUsers;
|
||||||
|
KeyContext m_keycontext;
|
||||||
|
|
||||||
|
// for KeyType::Command
|
||||||
|
Command* m_command;
|
||||||
|
Params* m_params;
|
||||||
|
// for KeyType::Tool or Quicktool
|
||||||
|
tools::Tool* m_tool;
|
||||||
|
// for KeyType::Action
|
||||||
|
KeyAction m_action;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KeyboardShortcuts {
|
||||||
|
public:
|
||||||
|
typedef std::vector<Key*> Keys;
|
||||||
|
typedef Keys::iterator iterator;
|
||||||
|
typedef Keys::const_iterator const_iterator;
|
||||||
|
|
||||||
|
static KeyboardShortcuts* instance();
|
||||||
|
~KeyboardShortcuts();
|
||||||
|
|
||||||
|
iterator begin() { return m_keys.begin(); }
|
||||||
|
iterator end() { return m_keys.end(); }
|
||||||
|
const_iterator begin() const { return m_keys.begin(); }
|
||||||
|
const_iterator end() const { return m_keys.end(); }
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
void importFile(TiXmlElement* rootElement, KeySource source);
|
||||||
|
void importFile(const std::string& filename, KeySource source);
|
||||||
|
void exportFile(const std::string& filename);
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
Key* command(const char* commandName,
|
||||||
|
Params* params = NULL, KeyContext keyContext = KeyContext::Any);
|
||||||
|
Key* tool(tools::Tool* tool);
|
||||||
|
Key* quicktool(tools::Tool* tool);
|
||||||
|
Key* action(KeyAction action);
|
||||||
|
|
||||||
|
void disableAccel(const ui::Accelerator& accel);
|
||||||
|
|
||||||
|
KeyContext getCurrentKeyContext();
|
||||||
|
bool getCommandFromKeyMessage(ui::Message* msg, Command** command, Params** params);
|
||||||
|
tools::Tool* getCurrentQuicktool(tools::Tool* currentTool);
|
||||||
|
|
||||||
|
private:
|
||||||
|
KeyboardShortcuts();
|
||||||
|
|
||||||
|
void exportKeys(TiXmlElement& parent, KeyType type);
|
||||||
|
|
||||||
|
Keys m_keys;
|
||||||
|
|
||||||
|
DISABLE_COPYING(KeyboardShortcuts);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
|
||||||
|
template<> app::KeyAction convert_to(const std::string& from);
|
||||||
|
template<> std::string convert_to(const app::KeyAction& from);
|
||||||
|
|
||||||
|
} // namespace base
|
||||||
|
|
||||||
|
#endif
|
187
src/app/ui/select_accelerator.cpp
Normal file
187
src/app/ui/select_accelerator.cpp
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
/* Aseprite
|
||||||
|
* Copyright (C) 2001-2014 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "app/ui/select_accelerator.h"
|
||||||
|
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
|
#include "base/bind.h"
|
||||||
|
#include "base/signal.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
using namespace ui;
|
||||||
|
|
||||||
|
class SelectAccelerator::KeyField : public ui::Entry {
|
||||||
|
public:
|
||||||
|
KeyField(const Accelerator& accel) : ui::Entry(256, "") {
|
||||||
|
setFocusMagnet(true);
|
||||||
|
setAccel(accel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAccel(const Accelerator& accel) {
|
||||||
|
m_accel = accel;
|
||||||
|
updateText();
|
||||||
|
}
|
||||||
|
|
||||||
|
Signal1<void, const ui::Accelerator*> AccelChange;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onProcessMessage(Message* msg) override {
|
||||||
|
switch (msg->type()) {
|
||||||
|
case kKeyDownMessage:
|
||||||
|
if (hasFocus() && !isReadOnly()) {
|
||||||
|
KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
|
||||||
|
|
||||||
|
m_accel = Accelerator(
|
||||||
|
keymsg->keyModifiers(),
|
||||||
|
keymsg->scancode(),
|
||||||
|
keymsg->unicodeChar() >= 32 ? keymsg->unicodeChar(): 0);
|
||||||
|
updateText();
|
||||||
|
|
||||||
|
AccelChange(&m_accel);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Entry::onProcessMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateText() {
|
||||||
|
setText(
|
||||||
|
Accelerator(
|
||||||
|
kKeyNoneModifier,
|
||||||
|
m_accel.scancode(),
|
||||||
|
m_accel.unicodeChar()).toString().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
Accelerator m_accel;
|
||||||
|
};
|
||||||
|
|
||||||
|
SelectAccelerator::SelectAccelerator(const ui::Accelerator& accel, bool canDelete)
|
||||||
|
: m_keyField(new KeyField(accel))
|
||||||
|
, m_accel(accel)
|
||||||
|
, m_deleted(false)
|
||||||
|
, m_modified(false)
|
||||||
|
{
|
||||||
|
updateModifiers();
|
||||||
|
updateAssignedTo();
|
||||||
|
|
||||||
|
keyPlaceholder()->addChild(m_keyField);
|
||||||
|
|
||||||
|
alt()->Click.connect(Bind<void>(&SelectAccelerator::onModifierChange, this, kKeyAltModifier, alt()));
|
||||||
|
cmd()->Click.connect(Bind<void>(&SelectAccelerator::onModifierChange, this, kKeyCmdModifier, cmd()));
|
||||||
|
ctrl()->Click.connect(Bind<void>(&SelectAccelerator::onModifierChange, this, kKeyCtrlModifier, ctrl()));
|
||||||
|
shift()->Click.connect(Bind<void>(&SelectAccelerator::onModifierChange, this, kKeyShiftModifier, shift()));
|
||||||
|
space()->Click.connect(Bind<void>(&SelectAccelerator::onModifierChange, this, kKeySpaceModifier, space()));
|
||||||
|
|
||||||
|
m_keyField->AccelChange.connect(&SelectAccelerator::onAccelChange, this);
|
||||||
|
clearButton()->Click.connect(Bind<void>(&SelectAccelerator::onClear, this));
|
||||||
|
okButton()->Click.connect(Bind<void>(&SelectAccelerator::onOK, this));
|
||||||
|
cancelButton()->Click.connect(Bind<void>(&SelectAccelerator::onCancel, this));
|
||||||
|
|
||||||
|
if (canDelete)
|
||||||
|
deleteButton()->Click.connect(Bind<void>(&SelectAccelerator::onDelete, this));
|
||||||
|
else
|
||||||
|
deleteButton()->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectAccelerator::onModifierChange(KeyModifiers modifier, CheckBox* checkbox)
|
||||||
|
{
|
||||||
|
bool state = (checkbox->isSelected());
|
||||||
|
|
||||||
|
m_accel = Accelerator(
|
||||||
|
(KeyModifiers)((m_accel.modifiers() & ~modifier) | (state ? modifier : 0)),
|
||||||
|
m_accel.scancode(),
|
||||||
|
m_accel.unicodeChar());
|
||||||
|
|
||||||
|
m_keyField->setAccel(m_accel);
|
||||||
|
updateAssignedTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectAccelerator::onAccelChange(const ui::Accelerator* accel)
|
||||||
|
{
|
||||||
|
m_accel = *accel;
|
||||||
|
updateModifiers();
|
||||||
|
updateAssignedTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectAccelerator::onClear()
|
||||||
|
{
|
||||||
|
m_accel = Accelerator(kKeyNoneModifier, kKeyNil, 0);
|
||||||
|
|
||||||
|
m_keyField->setAccel(m_accel);
|
||||||
|
updateModifiers();
|
||||||
|
updateAssignedTo();
|
||||||
|
|
||||||
|
m_keyField->requestFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectAccelerator::onOK()
|
||||||
|
{
|
||||||
|
m_modified = (m_origAccel != m_accel);
|
||||||
|
closeWindow(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectAccelerator::onCancel()
|
||||||
|
{
|
||||||
|
closeWindow(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectAccelerator::onDelete()
|
||||||
|
{
|
||||||
|
if (Alert::show("Warning"
|
||||||
|
"<<Do you really want to delete this keyboard shortcut?"
|
||||||
|
"||&Yes||&No") != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_deleted = true;
|
||||||
|
closeWindow(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectAccelerator::updateModifiers()
|
||||||
|
{
|
||||||
|
alt()->setSelected(m_accel.modifiers() & kKeyAltModifier ? true: false);
|
||||||
|
ctrl()->setSelected(m_accel.modifiers() & kKeyCtrlModifier ? true: false);
|
||||||
|
shift()->setSelected(m_accel.modifiers() & kKeyShiftModifier ? true: false);
|
||||||
|
space()->setSelected(m_accel.modifiers() & kKeySpaceModifier ? true: false);
|
||||||
|
#if __APPLE__
|
||||||
|
cmd()->setSelected(m_accel.modifiers() & kKeyCmdModifier ? true: false);
|
||||||
|
#else
|
||||||
|
cmd()->setVisible(false);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectAccelerator::updateAssignedTo()
|
||||||
|
{
|
||||||
|
std::string res = "None";
|
||||||
|
|
||||||
|
for (Key* key : *KeyboardShortcuts::instance()) {
|
||||||
|
if (key->hasAccel(m_accel)) {
|
||||||
|
res = key->triggerString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assignedTo()->setText("Assigned to: " + res);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
58
src/app/ui/select_accelerator.h
Normal file
58
src/app/ui/select_accelerator.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* Aseprite
|
||||||
|
* Copyright (C) 2001-2014 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 APP_UI_SELECT_ACCELERATOR_H_INCLUDED
|
||||||
|
#define APP_UI_SELECT_ACCELERATOR_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/accelerator.h"
|
||||||
|
|
||||||
|
#include "generated_select_accelerator.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
class SelectAccelerator : public app::gen::SelectAccelerator {
|
||||||
|
public:
|
||||||
|
explicit SelectAccelerator(const ui::Accelerator& accelerator, bool canDelete);
|
||||||
|
|
||||||
|
bool isDeleted() const { return m_deleted; }
|
||||||
|
bool isModified() const { return m_modified; }
|
||||||
|
const ui::Accelerator& accel() const { return m_accel; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onModifierChange(ui::KeyModifiers modifier, ui::CheckBox* checkbox);
|
||||||
|
void onAccelChange(const ui::Accelerator* accel);
|
||||||
|
void onClear();
|
||||||
|
void onOK();
|
||||||
|
void onCancel();
|
||||||
|
void onDelete();
|
||||||
|
void updateModifiers();
|
||||||
|
void updateAssignedTo();
|
||||||
|
|
||||||
|
class KeyField;
|
||||||
|
|
||||||
|
KeyField* m_keyField;
|
||||||
|
ui::Accelerator m_origAccel;
|
||||||
|
ui::Accelerator m_accel;
|
||||||
|
bool m_deleted;
|
||||||
|
bool m_modified;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif
|
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include "app/modules/gui.h"
|
#include "app/modules/gui.h"
|
||||||
#include "app/resource_finder.h"
|
#include "app/resource_finder.h"
|
||||||
|
#include "app/ui/app_menuitem.h"
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui/skin/button_icon_impl.h"
|
#include "app/ui/skin/button_icon_impl.h"
|
||||||
#include "app/ui/skin/skin_property.h"
|
#include "app/ui/skin/skin_property.h"
|
||||||
#include "app/ui/skin/skin_slider_property.h"
|
#include "app/ui/skin/skin_slider_property.h"
|
||||||
@ -1242,7 +1244,7 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
|
|||||||
{
|
{
|
||||||
int scale = jguiscale();
|
int scale = jguiscale();
|
||||||
Graphics* g = ev.getGraphics();
|
Graphics* g = ev.getGraphics();
|
||||||
MenuItem* widget = static_cast<MenuItem*>(ev.getSource());
|
AppMenuItem* widget = static_cast<AppMenuItem*>(ev.getSource());
|
||||||
gfx::Rect bounds = widget->getClientBounds();
|
gfx::Rect bounds = widget->getClientBounds();
|
||||||
gfx::Color fg, bg;
|
gfx::Color fg, bg;
|
||||||
int c, bar;
|
int c, bar;
|
||||||
@ -1324,13 +1326,13 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Draw the keyboard shortcut
|
// Draw the keyboard shortcut
|
||||||
else if (widget->getAccel()) {
|
else if (widget->getKey() && !widget->getKey()->accels().empty()) {
|
||||||
int old_align = widget->getAlign();
|
int old_align = widget->getAlign();
|
||||||
|
|
||||||
pos = bounds;
|
pos = bounds;
|
||||||
pos.w -= widget->child_spacing/4;
|
pos.w -= widget->child_spacing/4;
|
||||||
|
|
||||||
std::string buf = widget->getAccel()->toString();
|
std::string buf = widget->getKey()->accels().front().toString();
|
||||||
|
|
||||||
widget->setAlign(JI_RIGHT | JI_MIDDLE);
|
widget->setAlign(JI_RIGHT | JI_MIDDLE);
|
||||||
drawTextString(g, buf.c_str(), fg, ColorNone, widget, pos, 0);
|
drawTextString(g, buf.c_str(), fg, ColorNone, widget, pos, 0);
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "app/tools/tool.h"
|
#include "app/tools/tool.h"
|
||||||
#include "app/ui/color_button.h"
|
#include "app/ui/color_button.h"
|
||||||
#include "app/ui/editor/editor.h"
|
#include "app/ui/editor/editor.h"
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui/main_window.h"
|
#include "app/ui/main_window.h"
|
||||||
#include "app/ui/skin/skin_theme.h"
|
#include "app/ui/skin/skin_theme.h"
|
||||||
#include "app/ui/status_bar.h"
|
#include "app/ui/status_bar.h"
|
||||||
@ -362,10 +363,10 @@ void StatusBar::showTool(int msecs, tools::Tool* tool)
|
|||||||
std::string text = tool->getText();
|
std::string text = tool->getText();
|
||||||
|
|
||||||
// Tool shortcut
|
// Tool shortcut
|
||||||
Accelerator* accel = get_accel_to_change_tool(tool);
|
Key* key = KeyboardShortcuts::instance()->tool(tool);
|
||||||
if (accel) {
|
if (key && !key->accels().empty()) {
|
||||||
text += ", Shortcut: ";
|
text += ", Shortcut: ";
|
||||||
text += accel->toString();
|
text += key->accels().front().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set text
|
// Set text
|
||||||
|
@ -27,9 +27,9 @@
|
|||||||
#include "app/commands/commands.h"
|
#include "app/commands/commands.h"
|
||||||
#include "app/modules/editors.h"
|
#include "app/modules/editors.h"
|
||||||
#include "app/modules/gfx.h"
|
#include "app/modules/gfx.h"
|
||||||
#include "app/modules/gui.h"
|
|
||||||
#include "app/settings/settings.h"
|
#include "app/settings/settings.h"
|
||||||
#include "app/tools/tool_box.h"
|
#include "app/tools/tool_box.h"
|
||||||
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui/main_window.h"
|
#include "app/ui/main_window.h"
|
||||||
#include "app/ui/mini_editor.h"
|
#include "app/ui/mini_editor.h"
|
||||||
#include "app/ui/skin/skin_theme.h"
|
#include "app/ui/skin/skin_theme.h"
|
||||||
@ -542,10 +542,10 @@ void ToolBar::openTipWindow(int group_index, Tool* tool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tool shortcut
|
// Tool shortcut
|
||||||
Accelerator* accel = get_accel_to_change_tool(tool);
|
Key* key = KeyboardShortcuts::instance()->tool(tool);
|
||||||
if (accel) {
|
if (key && !key->accels().empty()) {
|
||||||
tooltip += "\n\nShortcut: ";
|
tooltip += "\n\nShortcut: ";
|
||||||
tooltip += accel->toString();
|
tooltip += key->accels().front().toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (group_index == ConfigureToolIndex) {
|
else if (group_index == ConfigureToolIndex) {
|
||||||
|
@ -46,4 +46,14 @@ XmlDocumentRef open_xml(const std::string& filename)
|
|||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void save_xml(XmlDocumentRef doc, const std::string& filename)
|
||||||
|
{
|
||||||
|
FileHandle file(open_file(filename, "wb"));
|
||||||
|
if (!file)
|
||||||
|
throw Exception("Error loading file: " + filename);
|
||||||
|
|
||||||
|
if (!doc->SaveFile(file))
|
||||||
|
throw XmlException(doc);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -32,6 +32,7 @@ namespace app {
|
|||||||
typedef SharedPtr<TiXmlDocument> XmlDocumentRef;
|
typedef SharedPtr<TiXmlDocument> XmlDocumentRef;
|
||||||
|
|
||||||
XmlDocumentRef open_xml(const std::string& filename);
|
XmlDocumentRef open_xml(const std::string& filename);
|
||||||
|
void save_xml(XmlDocumentRef doc, const std::string& filename);
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
||||||
|
@ -24,26 +24,28 @@
|
|||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
void Accelerator::addKey(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar)
|
Accelerator::Accelerator()
|
||||||
|
: m_modifiers(kKeyNoneModifier)
|
||||||
|
, m_scancode(kKeyNil)
|
||||||
|
, m_unicodeChar(0)
|
||||||
{
|
{
|
||||||
KeyCombo key;
|
|
||||||
|
|
||||||
key.modifiers = modifiers;
|
|
||||||
key.scancode = scancode;
|
|
||||||
key.unicodeChar = unicodeChar;
|
|
||||||
|
|
||||||
m_combos.push_back(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Accelerator::addKeysFromString(const std::string& str)
|
Accelerator::Accelerator(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar)
|
||||||
|
: m_modifiers(modifiers)
|
||||||
|
, m_scancode(scancode)
|
||||||
|
, m_unicodeChar(unicodeChar)
|
||||||
{
|
{
|
||||||
KeyModifiers modifiers = kKeyNoneModifier;
|
}
|
||||||
KeyScancode scancode = kKeyNil;
|
|
||||||
int unicodeChar = 0;
|
|
||||||
|
|
||||||
|
Accelerator::Accelerator(const std::string& str)
|
||||||
|
: m_modifiers(kKeyNoneModifier)
|
||||||
|
, m_scancode(kKeyNil)
|
||||||
|
, m_unicodeChar(0)
|
||||||
|
{
|
||||||
// Special case: plus sign
|
// Special case: plus sign
|
||||||
if (str == "+") {
|
if (str == "+") {
|
||||||
addKey(kKeyNoneModifier, kKeyNil, '+');
|
m_unicodeChar = '+';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,137 +54,143 @@ void Accelerator::addKeysFromString(const std::string& str)
|
|||||||
for (std::string tok : tokens) {
|
for (std::string tok : tokens) {
|
||||||
tok = base::string_to_lower(tok);
|
tok = base::string_to_lower(tok);
|
||||||
|
|
||||||
if (scancode == kKeySpace) {
|
if (m_scancode == kKeySpace) {
|
||||||
modifiers = (KeyModifiers)((int)modifiers | (int)kKeySpaceModifier);
|
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeySpaceModifier);
|
||||||
scancode = kKeyNil;
|
m_scancode = kKeyNil;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modifiers
|
// Modifiers
|
||||||
if (tok == "shift") {
|
if (tok == "shift") {
|
||||||
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyShiftModifier);
|
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeyShiftModifier);
|
||||||
}
|
}
|
||||||
else if (tok == "alt") {
|
else if (tok == "alt") {
|
||||||
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyAltModifier);
|
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeyAltModifier);
|
||||||
}
|
}
|
||||||
else if (tok == "ctrl") {
|
else if (tok == "ctrl") {
|
||||||
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCtrlModifier);
|
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeyCtrlModifier);
|
||||||
}
|
}
|
||||||
else if (tok == "cmd") {
|
else if (tok == "cmd") {
|
||||||
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCmdModifier);
|
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeyCmdModifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scancode
|
// Scancode
|
||||||
|
|
||||||
// word with one character
|
// Word with one character
|
||||||
else if (tok.size() == 1) {
|
else if (tok.size() == 1) {
|
||||||
if ((tok[0] >= 'a') && (tok[0] <= 'z')) {
|
if ((tok[0] >= 'a') && (tok[0] <= 'z')) {
|
||||||
unicodeChar = tok[0];
|
m_unicodeChar = tok[0];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
unicodeChar = tok[0];
|
m_unicodeChar = tok[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((tok[0] >= 'a') && (tok[0] <= 'z'))
|
if ((tok[0] >= 'a') && (tok[0] <= 'z'))
|
||||||
scancode = (KeyScancode)((int)kKeyA + tolower(tok[0]) - 'a');
|
m_scancode = (KeyScancode)((int)kKeyA + tolower(tok[0]) - 'a');
|
||||||
else if ((tok[0] >= '0') && (tok[0] <= '9'))
|
else if ((tok[0] >= '0') && (tok[0] <= '9'))
|
||||||
scancode = (KeyScancode)((int)kKey0 + tok[0] - '0');
|
m_scancode = (KeyScancode)((int)kKey0 + tok[0] - '0');
|
||||||
else {
|
else {
|
||||||
switch (tok[0]) {
|
switch (tok[0]) {
|
||||||
case '~': scancode = kKeyTilde; break;
|
case '~': m_scancode = kKeyTilde; break;
|
||||||
case '-': scancode = kKeyMinus; break;
|
case '-': m_scancode = kKeyMinus; break;
|
||||||
case '=': scancode = kKeyEquals; break;
|
case '=': m_scancode = kKeyEquals; break;
|
||||||
case '[': scancode = kKeyOpenbrace; break;
|
case '[': m_scancode = kKeyOpenbrace; break;
|
||||||
case ']': scancode = kKeyClosebrace; break;
|
case ']': m_scancode = kKeyClosebrace; break;
|
||||||
case ';': scancode = kKeyColon; break;
|
case ';': m_scancode = kKeyColon; break;
|
||||||
case '\'': scancode = kKeyQuote; break;
|
case '\'': m_scancode = kKeyQuote; break;
|
||||||
case '\\': scancode = kKeyBackslash; break;
|
case '\\': m_scancode = kKeyBackslash; break;
|
||||||
case ',': scancode = kKeyComma; break;
|
case ',': m_scancode = kKeyComma; break;
|
||||||
case '.': scancode = kKeyStop; break;
|
case '.': m_scancode = kKeyStop; break;
|
||||||
case '/': scancode = kKeySlash; break;
|
case '/': m_scancode = kKeySlash; break;
|
||||||
case '*': scancode = kKeyAsterisk; break;
|
case '*': m_scancode = kKeyAsterisk; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* other ones */
|
// Other ones
|
||||||
else {
|
else {
|
||||||
/* F1, F2, ..., F11, F12 */
|
// F1, F2, ..., F11, F12
|
||||||
if (tok[0] == 'f' && (tok.size() <= 3)) {
|
if (tok[0] == 'f' && (tok.size() <= 3)) {
|
||||||
int num = strtol(tok.c_str()+1, NULL, 10);
|
int num = strtol(tok.c_str()+1, NULL, 10);
|
||||||
if ((num >= 1) && (num <= 12))
|
if ((num >= 1) && (num <= 12))
|
||||||
scancode = (KeyScancode)((int)kKeyF1 + num - 1);
|
m_scancode = (KeyScancode)((int)kKeyF1 + num - 1);
|
||||||
}
|
}
|
||||||
else if ((tok == "escape") || (tok == "esc"))
|
else if ((tok == "escape") || (tok == "esc"))
|
||||||
scancode = kKeyEsc;
|
m_scancode = kKeyEsc;
|
||||||
else if (tok == "backspace")
|
else if (tok == "backspace")
|
||||||
scancode = kKeyBackspace;
|
m_scancode = kKeyBackspace;
|
||||||
else if (tok == "tab")
|
else if (tok == "tab")
|
||||||
scancode = kKeyTab;
|
m_scancode = kKeyTab;
|
||||||
else if (tok == "enter")
|
else if (tok == "enter")
|
||||||
scancode = kKeyEnter;
|
m_scancode = kKeyEnter;
|
||||||
else if (tok == "space")
|
else if (tok == "space")
|
||||||
scancode = kKeySpace;
|
m_scancode = kKeySpace;
|
||||||
else if ((tok == "insert") || (tok == "ins"))
|
else if ((tok == "insert") || (tok == "ins"))
|
||||||
scancode = kKeyInsert;
|
m_scancode = kKeyInsert;
|
||||||
else if ((tok == "delete") || (tok == "del"))
|
else if ((tok == "delete") || (tok == "del"))
|
||||||
scancode = kKeyDel;
|
m_scancode = kKeyDel;
|
||||||
else if (tok == "home")
|
else if (tok == "home")
|
||||||
scancode = kKeyHome;
|
m_scancode = kKeyHome;
|
||||||
else if (tok == "end")
|
else if (tok == "end")
|
||||||
scancode = kKeyEnd;
|
m_scancode = kKeyEnd;
|
||||||
else if ((tok == "page up") || (tok == "pgup"))
|
else if ((tok == "page up") || (tok == "pgup"))
|
||||||
scancode = kKeyPageUp;
|
m_scancode = kKeyPageUp;
|
||||||
else if ((tok == "page down") || (tok == "pgdn"))
|
else if ((tok == "page down") || (tok == "pgdn"))
|
||||||
scancode = kKeyPageDown;
|
m_scancode = kKeyPageDown;
|
||||||
else if (tok == "left")
|
else if (tok == "left")
|
||||||
scancode = kKeyLeft;
|
m_scancode = kKeyLeft;
|
||||||
else if (tok == "right")
|
else if (tok == "right")
|
||||||
scancode = kKeyRight;
|
m_scancode = kKeyRight;
|
||||||
else if (tok == "up")
|
else if (tok == "up")
|
||||||
scancode = kKeyUp;
|
m_scancode = kKeyUp;
|
||||||
else if (tok == "down")
|
else if (tok == "down")
|
||||||
scancode = kKeyDown;
|
m_scancode = kKeyDown;
|
||||||
else if (tok == "0 pad")
|
else if (tok == "0 pad")
|
||||||
scancode = kKey0Pad;
|
m_scancode = kKey0Pad;
|
||||||
else if (tok == "1 pad")
|
else if (tok == "1 pad")
|
||||||
scancode = kKey1Pad;
|
m_scancode = kKey1Pad;
|
||||||
else if (tok == "2 pad")
|
else if (tok == "2 pad")
|
||||||
scancode = kKey2Pad;
|
m_scancode = kKey2Pad;
|
||||||
else if (tok == "3 pad")
|
else if (tok == "3 pad")
|
||||||
scancode = kKey3Pad;
|
m_scancode = kKey3Pad;
|
||||||
else if (tok == "4 pad")
|
else if (tok == "4 pad")
|
||||||
scancode = kKey4Pad;
|
m_scancode = kKey4Pad;
|
||||||
else if (tok == "5 pad")
|
else if (tok == "5 pad")
|
||||||
scancode = kKey5Pad;
|
m_scancode = kKey5Pad;
|
||||||
else if (tok == "6 pad")
|
else if (tok == "6 pad")
|
||||||
scancode = kKey6Pad;
|
m_scancode = kKey6Pad;
|
||||||
else if (tok == "7 pad")
|
else if (tok == "7 pad")
|
||||||
scancode = kKey7Pad;
|
m_scancode = kKey7Pad;
|
||||||
else if (tok == "8 pad")
|
else if (tok == "8 pad")
|
||||||
scancode = kKey8Pad;
|
m_scancode = kKey8Pad;
|
||||||
else if (tok == "9 pad")
|
else if (tok == "9 pad")
|
||||||
scancode = kKey9Pad;
|
m_scancode = kKey9Pad;
|
||||||
else if (tok == "slash pad")
|
else if (tok == "slash pad")
|
||||||
scancode = kKeySlashPad;
|
m_scancode = kKeySlashPad;
|
||||||
else if (tok == "asterisk")
|
else if (tok == "asterisk")
|
||||||
scancode = kKeyAsterisk;
|
m_scancode = kKeyAsterisk;
|
||||||
else if (tok == "minus pad")
|
else if (tok == "minus pad")
|
||||||
scancode = kKeyMinusPad;
|
m_scancode = kKeyMinusPad;
|
||||||
else if (tok == "plus pad")
|
else if (tok == "plus pad")
|
||||||
scancode = kKeyPlusPad;
|
m_scancode = kKeyPlusPad;
|
||||||
else if (tok == "del pad")
|
else if (tok == "del pad")
|
||||||
scancode = kKeyDelPad;
|
m_scancode = kKeyDelPad;
|
||||||
else if (tok == "enter pad")
|
else if (tok == "enter pad")
|
||||||
scancode = kKeyEnterPad;
|
m_scancode = kKeyEnterPad;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addKey(modifiers, scancode, unicodeChar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Accelerator::KeyCombo::toString()
|
bool Accelerator::isEmpty() const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(m_modifiers == kKeyNoneModifier &&
|
||||||
|
m_scancode == kKeyNil &&
|
||||||
|
m_unicodeChar == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Accelerator::toString() const
|
||||||
{
|
{
|
||||||
// Same order that Allegro scancodes
|
// Same order that Allegro scancodes
|
||||||
static const char *table[] = {
|
static const char* table[] = {
|
||||||
NULL,
|
NULL,
|
||||||
"A",
|
"A",
|
||||||
"B",
|
"B",
|
||||||
@ -287,34 +295,29 @@ std::string Accelerator::KeyCombo::toString()
|
|||||||
"KEY_COLON2",
|
"KEY_COLON2",
|
||||||
"Kanji",
|
"Kanji",
|
||||||
};
|
};
|
||||||
|
static size_t table_size = sizeof(table) / sizeof(table[0]);
|
||||||
|
|
||||||
std::string buf;
|
std::string buf;
|
||||||
|
|
||||||
// Shifts
|
// Shifts
|
||||||
if (this->modifiers & kKeyCtrlModifier) buf += "Ctrl+";
|
if (m_modifiers & kKeyCtrlModifier) buf += "Ctrl+";
|
||||||
if (this->modifiers & kKeyCmdModifier) buf += "Cmd+";
|
if (m_modifiers & kKeyCmdModifier) buf += "Cmd+";
|
||||||
if (this->modifiers & kKeyAltModifier) buf += "Alt+";
|
if (m_modifiers & kKeyAltModifier) buf += "Alt+";
|
||||||
if (this->modifiers & kKeyShiftModifier) buf += "Shift+";
|
if (m_modifiers & kKeyShiftModifier) buf += "Shift+";
|
||||||
if (this->modifiers & kKeySpaceModifier) buf += "Space+";
|
if (m_modifiers & kKeySpaceModifier) buf += "Space+";
|
||||||
|
|
||||||
// Key
|
// Key
|
||||||
if (this->unicodeChar)
|
if (m_unicodeChar)
|
||||||
buf += (wchar_t)toupper(this->unicodeChar);
|
buf += (wchar_t)toupper(m_unicodeChar);
|
||||||
else if (this->scancode)
|
else if (m_scancode && m_scancode > 0 && m_scancode < (int)table_size)
|
||||||
buf += table[this->scancode];
|
buf += table[m_scancode];
|
||||||
else if (!buf.empty() && buf[buf.size()-1] == '+')
|
else if (!buf.empty() && buf[buf.size()-1] == '+')
|
||||||
buf.erase(buf.size()-1);
|
buf.erase(buf.size()-1);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Accelerator::toString()
|
bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar) const
|
||||||
{
|
|
||||||
ASSERT(!m_combos.empty());
|
|
||||||
return m_combos.front().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar)
|
|
||||||
{
|
{
|
||||||
#ifdef REPORT_KEYS
|
#ifdef REPORT_KEYS
|
||||||
char buf[256];
|
char buf[256];
|
||||||
@ -373,40 +376,29 @@ bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicod
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef REPORT_KEYS
|
#ifdef REPORT_KEYS
|
||||||
{
|
printf("%3d==%3d %3d==%3d %s==%s ",
|
||||||
base::UniquePtr<Accelerator> a2(new Accelerator);
|
m_scancode, scancode,
|
||||||
a2->addKey(modifiers, scancode, unicodeChar);
|
m_unicodeChar, unicodeChar,
|
||||||
buf2 = a2->getString();
|
toString().c_str(),
|
||||||
}
|
Accelerator(modifiers, scancode, unicodeChar).toString().c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (KeyCombos::iterator it = m_combos.begin(), end = m_combos.end();
|
if ((m_modifiers == modifiers) &&
|
||||||
it != end; ++it) {
|
((m_scancode != kKeyNil && m_scancode == scancode) ||
|
||||||
|
(m_unicodeChar && m_unicodeChar == unicodeChar))) {
|
||||||
#ifdef REPORT_KEYS
|
#ifdef REPORT_KEYS
|
||||||
printf("%3d==%3d %3d==%3d %s==%s ",
|
printf("true\n");
|
||||||
it->scancode, scancode, it->unicodeChar, unicodeChar,
|
|
||||||
it->getString().c_str(), buf2.c_str();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((it->modifiers == modifiers) &&
|
|
||||||
((it->scancode != kKeyNil && it->scancode == scancode) ||
|
|
||||||
(it->unicodeChar && it->unicodeChar == unicodeChar))) {
|
|
||||||
|
|
||||||
#ifdef REPORT_KEYS
|
|
||||||
printf("true\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#ifdef REPORT_KEYS
|
|
||||||
printf("false\n");
|
|
||||||
#endif
|
#endif
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef REPORT_KEYS
|
||||||
|
printf("false\n");
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Accelerator::checkFromAllegroKeyArray()
|
bool Accelerator::checkFromAllegroKeyArray() const
|
||||||
{
|
{
|
||||||
KeyModifiers modifiers = kKeyNoneModifier;
|
KeyModifiers modifiers = kKeyNoneModifier;
|
||||||
|
|
||||||
@ -417,14 +409,8 @@ bool Accelerator::checkFromAllegroKeyArray()
|
|||||||
if (key[KEY_ALT] ) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyAltModifier);
|
if (key[KEY_ALT] ) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyAltModifier);
|
||||||
if (key[KEY_COMMAND ]) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCmdModifier);
|
if (key[KEY_COMMAND ]) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCmdModifier);
|
||||||
|
|
||||||
for (KeyCombos::iterator it = m_combos.begin(), end = m_combos.end();
|
return ((m_scancode == 0 || key[m_scancode]) &&
|
||||||
it != end; ++it) {
|
(m_modifiers == modifiers));
|
||||||
if ((it->scancode == 0 || key[it->scancode]) &&
|
|
||||||
(it->modifiers == modifiers)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
|
@ -15,33 +15,42 @@
|
|||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
class Accelerator
|
class Accelerator {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
void addKey(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar);
|
Accelerator();
|
||||||
|
Accelerator(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar);
|
||||||
|
// Convert string like "Ctrl+Q" or "Alt+X" into an accelerator.
|
||||||
|
explicit Accelerator(const std::string& str);
|
||||||
|
|
||||||
// Adds keys from strings like "Ctrl+Q" or "Alt+X"
|
bool isEmpty() const;
|
||||||
void addKeysFromString(const std::string& str);
|
std::string toString() const;
|
||||||
|
|
||||||
bool isEmpty() const { return m_combos.empty(); }
|
bool check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar) const;
|
||||||
std::string toString();
|
bool checkFromAllegroKeyArray() const;
|
||||||
|
|
||||||
bool check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar);
|
bool operator==(const Accelerator& other) const {
|
||||||
bool checkFromAllegroKeyArray();
|
return
|
||||||
|
(m_modifiers == other.m_modifiers &&
|
||||||
|
m_scancode == other.m_scancode &&
|
||||||
|
m_unicodeChar == other.m_unicodeChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Accelerator& other) const {
|
||||||
|
return !operator==(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyModifiers modifiers() const { return m_modifiers; }
|
||||||
|
KeyScancode scancode() const { return m_scancode; }
|
||||||
|
int unicodeChar() const { return m_unicodeChar; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct KeyCombo {
|
KeyModifiers m_modifiers;
|
||||||
KeyModifiers modifiers;
|
KeyScancode m_scancode;
|
||||||
KeyScancode scancode;
|
int m_unicodeChar;
|
||||||
int unicodeChar;
|
|
||||||
|
|
||||||
std::string toString();
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::vector<KeyCombo> KeyCombos;
|
|
||||||
KeyCombos m_combos;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef std::vector<Accelerator> Accelerators;
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -106,7 +106,7 @@ size_t ListBox::getItemsCount() const
|
|||||||
return getChildren().size();
|
return getChildren().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup the scroll to center the selected item in the viewport */
|
// Setup the scroll to center the selected item in the viewport
|
||||||
void ListBox::centerScroll()
|
void ListBox::centerScroll()
|
||||||
{
|
{
|
||||||
View* view = View::getView(this);
|
View* view = View::getView(this);
|
||||||
@ -123,6 +123,23 @@ void ListBox::centerScroll()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool sort_by_text(Widget* a, Widget* b) {
|
||||||
|
return a->getText() < b->getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListBox::sortItems()
|
||||||
|
{
|
||||||
|
WidgetsList widgets = getChildren();
|
||||||
|
std::sort(widgets.begin(), widgets.end(), &sort_by_text);
|
||||||
|
|
||||||
|
// Remove all children and add then again.
|
||||||
|
while (!getChildren().empty())
|
||||||
|
removeChild(getChildren().back());
|
||||||
|
|
||||||
|
for (Widget* child : widgets)
|
||||||
|
addChild(child);
|
||||||
|
}
|
||||||
|
|
||||||
bool ListBox::onProcessMessage(Message* msg)
|
bool ListBox::onProcessMessage(Message* msg)
|
||||||
{
|
{
|
||||||
switch (msg->type()) {
|
switch (msg->type()) {
|
||||||
|
@ -15,8 +15,7 @@ namespace ui {
|
|||||||
|
|
||||||
class ListItem;
|
class ListItem;
|
||||||
|
|
||||||
class ListBox : public Widget
|
class ListBox : public Widget {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
ListBox();
|
ListBox();
|
||||||
|
|
||||||
@ -29,6 +28,7 @@ namespace ui {
|
|||||||
size_t getItemsCount() const;
|
size_t getItemsCount() const;
|
||||||
|
|
||||||
void centerScroll();
|
void centerScroll();
|
||||||
|
void sortItems();
|
||||||
|
|
||||||
Signal0<void> ChangeSelectedItem;
|
Signal0<void> ChangeSelectedItem;
|
||||||
Signal0<void> DoubleClickItem;
|
Signal0<void> DoubleClickItem;
|
||||||
|
@ -195,7 +195,6 @@ void MenuBar::setExpandOnMouseover(bool state)
|
|||||||
MenuItem::MenuItem(const std::string& text)
|
MenuItem::MenuItem(const std::string& text)
|
||||||
: Widget(kMenuItemWidget)
|
: Widget(kMenuItemWidget)
|
||||||
{
|
{
|
||||||
m_accel = NULL;
|
|
||||||
m_highlighted = false;
|
m_highlighted = false;
|
||||||
m_submenu = NULL;
|
m_submenu = NULL;
|
||||||
m_submenu_menubox = NULL;
|
m_submenu_menubox = NULL;
|
||||||
@ -206,11 +205,7 @@ MenuItem::MenuItem(const std::string& text)
|
|||||||
|
|
||||||
MenuItem::~MenuItem()
|
MenuItem::~MenuItem()
|
||||||
{
|
{
|
||||||
if (m_accel)
|
delete m_submenu;
|
||||||
delete m_accel;
|
|
||||||
|
|
||||||
if (m_submenu)
|
|
||||||
delete m_submenu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu* MenuBox::getMenu()
|
Menu* MenuBox::getMenu()
|
||||||
@ -233,11 +228,6 @@ Menu* MenuItem::getSubmenu()
|
|||||||
return m_submenu;
|
return m_submenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
Accelerator* MenuItem::getAccel()
|
|
||||||
{
|
|
||||||
return m_accel;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MenuBox::setMenu(Menu* menu)
|
void MenuBox::setMenu(Menu* menu)
|
||||||
{
|
{
|
||||||
if (Menu* oldMenu = getMenu())
|
if (Menu* oldMenu = getMenu())
|
||||||
@ -262,21 +252,6 @@ void MenuItem::setSubmenu(Menu* menu)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the keyboard shortcuts (accelerators) for the specified
|
|
||||||
* widget (a menu-item).
|
|
||||||
*
|
|
||||||
* @warning The specified @a accel will be freed automatically when
|
|
||||||
* the menu-item is deleted.
|
|
||||||
*/
|
|
||||||
void MenuItem::setAccel(Accelerator* accel)
|
|
||||||
{
|
|
||||||
if (m_accel)
|
|
||||||
delete m_accel;
|
|
||||||
|
|
||||||
m_accel = accel;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MenuItem::isHighlighted() const
|
bool MenuItem::isHighlighted() const
|
||||||
{
|
{
|
||||||
return m_highlighted;
|
return m_highlighted;
|
||||||
@ -909,10 +884,6 @@ void MenuItem::onPreferredSize(PreferredSizeEvent& ev)
|
|||||||
+ this->border_width.t
|
+ this->border_width.t
|
||||||
+ getTextHeight()
|
+ getTextHeight()
|
||||||
+ this->border_width.b;
|
+ this->border_width.b;
|
||||||
|
|
||||||
if (m_accel && !m_accel->isEmpty()) {
|
|
||||||
size.w += Graphics::measureUIStringLength(m_accel->toString().c_str(), getFont());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.setPreferredSize(size);
|
ev.setPreferredSize(size);
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
|
|
||||||
class Accelerator;
|
|
||||||
class MenuItem;
|
class MenuItem;
|
||||||
class Timer;
|
class Timer;
|
||||||
struct MenuBaseData;
|
struct MenuBaseData;
|
||||||
@ -104,9 +103,6 @@ namespace ui {
|
|||||||
Menu* getSubmenu();
|
Menu* getSubmenu();
|
||||||
void setSubmenu(Menu* submenu);
|
void setSubmenu(Menu* submenu);
|
||||||
|
|
||||||
Accelerator* getAccel();
|
|
||||||
void setAccel(Accelerator* accel);
|
|
||||||
|
|
||||||
bool isHighlighted() const;
|
bool isHighlighted() const;
|
||||||
void setHighlighted(bool state);
|
void setHighlighted(bool state);
|
||||||
|
|
||||||
@ -133,15 +129,15 @@ namespace ui {
|
|||||||
virtual void onPreferredSize(PreferredSizeEvent& ev) override;
|
virtual void onPreferredSize(PreferredSizeEvent& ev) override;
|
||||||
virtual void onClick();
|
virtual void onClick();
|
||||||
|
|
||||||
private:
|
|
||||||
bool inBar();
|
bool inBar();
|
||||||
|
|
||||||
|
private:
|
||||||
void openSubmenu(bool select_first);
|
void openSubmenu(bool select_first);
|
||||||
void closeSubmenu(bool last_of_close_chain);
|
void closeSubmenu(bool last_of_close_chain);
|
||||||
void startTimer();
|
void startTimer();
|
||||||
void stopTimer();
|
void stopTimer();
|
||||||
void executeClick();
|
void executeClick();
|
||||||
|
|
||||||
Accelerator* m_accel; // Hot-key
|
|
||||||
bool m_highlighted; // Is it highlighted?
|
bool m_highlighted; // Is it highlighted?
|
||||||
Menu* m_submenu; // The sub-menu
|
Menu* m_submenu; // The sub-menu
|
||||||
MenuBox* m_submenu_menubox; // The opened menubox for this menu-item
|
MenuBox* m_submenu_menubox; // The opened menubox for this menu-item
|
||||||
|
Loading…
x
Reference in New Issue
Block a user