mirror of
https://github.com/aseprite/aseprite.git
synced 2024-09-02 04:59:24 +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 -->
|
||||
<gui version="1.0.6-dev">
|
||||
<!-- Keyboard shortcuts -->
|
||||
<keyboard>
|
||||
<keyboard version="1">
|
||||
|
||||
<!-- Keyboard shortcuts for commands (menu options) -->
|
||||
<commands>
|
||||
@ -51,6 +51,7 @@
|
||||
<key command="ConfigureTools" shortcut="C" />
|
||||
<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="KeyboardShortcuts" shortcut="Ctrl+Alt+Shift+K" mac="Cmd+Alt+Shift+K" />
|
||||
<!-- Sprite -->
|
||||
<key command="SpriteProperties" shortcut="Ctrl+P" mac="Cmd+P" />
|
||||
<!-- Layer -->
|
||||
@ -345,8 +346,8 @@
|
||||
<key tool="hand" shortcut="Space" />
|
||||
</quicktools>
|
||||
|
||||
<!-- Special keyboard shortcuts for the sprite editor -->
|
||||
<spriteeditor>
|
||||
<!-- Special keyboard shortcuts for specific actions -->
|
||||
<actions>
|
||||
<!-- When you drag-and-drop the selection, pressing this
|
||||
keyboard shortcut you can copy instead of move -->
|
||||
<key action="CopySelection" shortcut="Ctrl" />
|
||||
@ -370,7 +371,7 @@
|
||||
<!-- Modifiers for selection tool -->
|
||||
<key action="AddSelection" shortcut="Shift" />
|
||||
<key action="SubtractSelection" shortcut="Alt" />
|
||||
</spriteeditor>
|
||||
</actions>
|
||||
|
||||
</keyboard>
|
||||
|
||||
@ -436,6 +437,7 @@
|
||||
</menu>
|
||||
<separator />
|
||||
<item command="ConfigureTools" text="Tool&s..." />
|
||||
<item command="KeyboardShortcuts" text="&Keyboard Shortcuts..." />
|
||||
<item command="Options" text="Pre&ferences..." />
|
||||
</menu>
|
||||
<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_import_sprite_sheet.cpp
|
||||
commands/cmd_invert_mask.cpp
|
||||
commands/cmd_keyboard_shortcuts.cpp
|
||||
commands/cmd_launch.cpp
|
||||
commands/cmd_layer_from_background.cpp
|
||||
commands/cmd_layer_properties.cpp
|
||||
@ -184,6 +185,7 @@ add_library(app-lib
|
||||
ui/file_list.cpp
|
||||
ui/file_selector.cpp
|
||||
ui/hex_color_entry.cpp
|
||||
ui/keyboard_shortcuts.cpp
|
||||
ui/main_menu_bar.cpp
|
||||
ui/main_window.cpp
|
||||
ui/mini_editor.cpp
|
||||
@ -193,6 +195,7 @@ add_library(app-lib
|
||||
ui/palettes_listbox.cpp
|
||||
ui/popup_window_pin.cpp
|
||||
ui/resources_listbox.cpp
|
||||
ui/select_accelerator.cpp
|
||||
ui/skin/button_icon_impl.cpp
|
||||
ui/skin/skin_part.cpp
|
||||
ui/skin/skin_property.cpp
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include "app/ui/document_view.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/editor/editor_view.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui/tabs.h"
|
||||
@ -326,7 +327,8 @@ App::~App()
|
||||
delete m_legacy;
|
||||
delete m_modules;
|
||||
|
||||
// Destroy the loaded gui.xml file.
|
||||
// Destroy the loaded gui.xml data.
|
||||
delete KeyboardShortcuts::instance();
|
||||
delete GuiXml::instance();
|
||||
|
||||
m_instance = NULL;
|
||||
|
@ -29,12 +29,6 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ui {
|
||||
class MenuBar;
|
||||
class Widget;
|
||||
class Window;
|
||||
}
|
||||
|
||||
namespace raster {
|
||||
class Layer;
|
||||
}
|
||||
|
@ -28,13 +28,15 @@
|
||||
#include "app/commands/params.h"
|
||||
#include "app/console.h"
|
||||
#include "app/gui_xml.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/recent_files.h"
|
||||
#include "app/resource_finder.h"
|
||||
#include "app/tools/tool_box.h"
|
||||
#include "app/ui/app_menuitem.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/util/filetoks.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/fs.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
#include "tinyxml.h"
|
||||
@ -74,9 +76,8 @@ void AppMenus::reload()
|
||||
TiXmlHandle handle(doc);
|
||||
const char* path = GuiXml::instance()->filename();
|
||||
|
||||
/**************************************************/
|
||||
/* load menus */
|
||||
/**************************************************/
|
||||
////////////////////////////////////////
|
||||
// Load menus
|
||||
|
||||
PRINTF(" - Loading menus from \"%s\"...\n", path);
|
||||
|
||||
@ -94,127 +95,25 @@ void AppMenus::reload()
|
||||
m_celPopupMenu.reset(loadMenuById(handle, "cel_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);
|
||||
|
||||
// <gui><keyboard><commands><key>
|
||||
TiXmlElement* xmlKey = handle
|
||||
.FirstChild("gui")
|
||||
.FirstChild("keyboard")
|
||||
.FirstChild("commands")
|
||||
.FirstChild("key").ToElement();
|
||||
while (xmlKey) {
|
||||
const char* command_name = xmlKey->Attribute("command");
|
||||
const char* command_key = getShortcut(xmlKey);
|
||||
.FirstChild("keyboard").ToElement();
|
||||
|
||||
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;
|
||||
}
|
||||
KeyboardShortcuts::instance()->clear();
|
||||
KeyboardShortcuts::instance()->importFile(xmlKey, KeySource::Original);
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
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();
|
||||
// Load user settings
|
||||
{
|
||||
ResourceFinder rf;
|
||||
rf.includeUserDir("user.aseprite-keys");
|
||||
std::string fn = rf.getFirstOrCreateDefault();
|
||||
if (base::is_file(fn))
|
||||
KeyboardShortcuts::instance()->importFile(fn, KeySource::UserDefined);
|
||||
}
|
||||
}
|
||||
|
||||
@ -377,7 +276,12 @@ Widget* AppMenus::createInvalidVersionMenuitem()
|
||||
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) {
|
||||
Widget* child = *it;
|
||||
@ -393,32 +297,14 @@ void AppMenus::applyShortcutToMenuitemsWithCommand(Menu* menu, Command *command,
|
||||
ustricmp(mi_command->short_name(), command->short_name()) == 0 &&
|
||||
((mi_params && *mi_params == *params) ||
|
||||
(Params() == *params))) {
|
||||
// Set the accelerator to be shown in this menu-item
|
||||
menuitem->setAccel(new Accelerator(*accel));
|
||||
// Set the keyboard shortcut to be shown in this menu-item
|
||||
menuitem->setKey(key);
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -28,11 +28,8 @@
|
||||
class TiXmlElement;
|
||||
class TiXmlHandle;
|
||||
|
||||
namespace ui {
|
||||
class Accelerator;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
class Key;
|
||||
class Command;
|
||||
class Params;
|
||||
|
||||
@ -59,13 +56,14 @@ namespace app {
|
||||
Menu* getCelPopupMenu() { return m_celPopupMenu; }
|
||||
Menu* getCelMovementPopupMenu() { return m_celMovementPopupMenu; }
|
||||
|
||||
void applyShortcutToMenuitemsWithCommand(Command* command, Params* params, Key* key);
|
||||
|
||||
private:
|
||||
Menu* loadMenuById(TiXmlHandle& handle, const char *id);
|
||||
Menu* convertXmlelemToMenu(TiXmlElement* elem);
|
||||
Widget* convertXmlelemToMenuitem(TiXmlElement* elem);
|
||||
Widget* createInvalidVersionMenuitem();
|
||||
void applyShortcutToMenuitemsWithCommand(Menu* menu, Command* command, Params* params, Accelerator* accel);
|
||||
const char* getShortcut(TiXmlElement* elem);
|
||||
void applyShortcutToMenuitemsWithCommand(Menu* menu, Command* command, Params* params, Key* key);
|
||||
|
||||
base::UniquePtr<Menu> m_rootMenu;
|
||||
MenuItem* m_recentListMenuitem;
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "app/find_widget.h"
|
||||
#include "app/ini_file.h"
|
||||
#include "app/load_widget.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
@ -74,19 +74,14 @@ void AdvancedModeCommand::onExecute(Context* context)
|
||||
|
||||
if (oldMode == MainWindow::NormalMode &&
|
||||
get_config_bool("AdvancedMode", "Warning", true)) {
|
||||
Accelerator* accel = get_accel_to_execute_command(short_name());
|
||||
if (accel != NULL) {
|
||||
char warning[1024];
|
||||
char buf[1024];
|
||||
|
||||
Key* key = KeyboardShortcuts::instance()->command(short_name());
|
||||
if (!key->accels().empty()) {
|
||||
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* donot_show = app::find_widget<Widget>(window, "donot_show");
|
||||
|
||||
strcpy(warning, "You can back pressing the \"%s\" key.");
|
||||
std::sprintf(buf, warning, accel->toString().c_str());
|
||||
|
||||
warning_label->setText(buf);
|
||||
warning_label->setTextf("You can go back pressing \"%s\" key.",
|
||||
key->accels().front().toString().c_str());
|
||||
|
||||
window->openWindowInForeground();
|
||||
|
||||
|
@ -48,7 +48,7 @@ private:
|
||||
|
||||
CancelCommand::CancelCommand()
|
||||
: Command("Cancel",
|
||||
"Cancel",
|
||||
"Cancel Current Operation",
|
||||
CmdUIOnlyFlag)
|
||||
, m_type(NoOp)
|
||||
{
|
||||
|
@ -48,6 +48,7 @@ public:
|
||||
protected:
|
||||
void onLoadParams(Params* params);
|
||||
void onExecute(Context* context);
|
||||
std::string onGetFriendlyName() const;
|
||||
};
|
||||
|
||||
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()
|
||||
{
|
||||
return new ChangeBrushCommand;
|
||||
|
@ -50,6 +50,7 @@ public:
|
||||
protected:
|
||||
void onLoadParams(Params* params);
|
||||
void onExecute(Context* context);
|
||||
std::string onGetFriendlyName() const;
|
||||
};
|
||||
|
||||
ChangeColorCommand::ChangeColorCommand()
|
||||
@ -108,6 +109,29 @@ void ChangeColorCommand::onExecute(Context* context)
|
||||
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()
|
||||
{
|
||||
return new ChangeColorCommand;
|
||||
|
@ -49,7 +49,7 @@ protected:
|
||||
|
||||
DeveloperConsoleCommand::DeveloperConsoleCommand()
|
||||
: Command("DeveloperConsole",
|
||||
"DeveloperConsole",
|
||||
"Developer Console",
|
||||
CmdUIOnlyFlag)
|
||||
{
|
||||
m_devConsole = NULL;
|
||||
|
@ -188,6 +188,23 @@ void FlipCommand::onExecute(Context* context)
|
||||
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()
|
||||
{
|
||||
return new FlipCommand;
|
||||
|
@ -36,6 +36,7 @@ namespace app {
|
||||
void onLoadParams(Params* params);
|
||||
bool onEnabled(Context* context);
|
||||
void onExecute(Context* context);
|
||||
std::string onGetFriendlyName() const;
|
||||
|
||||
private:
|
||||
bool m_flipMask;
|
||||
|
@ -58,7 +58,7 @@ class GotoFirstFrameCommand : public GotoCommand {
|
||||
public:
|
||||
GotoFirstFrameCommand()
|
||||
: GotoCommand("GotoFirstFrame",
|
||||
"Goto First Frame") { }
|
||||
"Go to First Frame") { }
|
||||
Command* clone() const override { return new GotoFirstFrameCommand(*this); }
|
||||
|
||||
protected:
|
||||
@ -71,7 +71,7 @@ class GotoPreviousFrameCommand : public GotoCommand {
|
||||
public:
|
||||
GotoPreviousFrameCommand()
|
||||
: GotoCommand("GotoPreviousFrame",
|
||||
"Goto Previous Frame") { }
|
||||
"Go to Previous Frame") { }
|
||||
Command* clone() const override { return new GotoPreviousFrameCommand(*this); }
|
||||
|
||||
protected:
|
||||
@ -88,7 +88,7 @@ protected:
|
||||
class GotoNextFrameCommand : public GotoCommand {
|
||||
public:
|
||||
GotoNextFrameCommand() : GotoCommand("GotoNextFrame",
|
||||
"Goto Next Frame") { }
|
||||
"Go to Next Frame") { }
|
||||
Command* clone() const override { return new GotoNextFrameCommand(*this); }
|
||||
|
||||
protected:
|
||||
@ -104,7 +104,7 @@ protected:
|
||||
class GotoLastFrameCommand : public GotoCommand {
|
||||
public:
|
||||
GotoLastFrameCommand() : GotoCommand("GotoLastFrame",
|
||||
"Goto Last Frame") { }
|
||||
"Go to Last Frame") { }
|
||||
Command* clone() const override { return new GotoLastFrameCommand(*this); }
|
||||
|
||||
protected:
|
||||
@ -116,7 +116,7 @@ protected:
|
||||
class GotoFrameCommand : public GotoCommand {
|
||||
public:
|
||||
GotoFrameCommand() : GotoCommand("GotoFrame",
|
||||
"Goto Frame")
|
||||
"Go to Frame")
|
||||
, m_frame(0) { }
|
||||
Command* clone() const override { return new GotoFrameCommand(*this); }
|
||||
|
||||
|
@ -59,7 +59,7 @@ protected:
|
||||
|
||||
GotoPreviousLayerCommand::GotoPreviousLayerCommand()
|
||||
: GotoCommand("GotoPreviousLayer",
|
||||
"Goto Previous Layer",
|
||||
"Go to Previous Layer",
|
||||
CmdUIOnlyFlag)
|
||||
{
|
||||
}
|
||||
@ -101,7 +101,7 @@ protected:
|
||||
|
||||
GotoNextLayerCommand::GotoNextLayerCommand()
|
||||
: GotoCommand("GotoNextLayer",
|
||||
"Goto Next Layer",
|
||||
"Go to Next Layer",
|
||||
CmdUIOnlyFlag)
|
||||
{
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ protected:
|
||||
|
||||
GotoNextTabCommand::GotoNextTabCommand()
|
||||
: Command("GotoNextTab",
|
||||
"Goto Next Tab",
|
||||
"Go to Next Tab",
|
||||
CmdUIOnlyFlag)
|
||||
{
|
||||
}
|
||||
@ -60,7 +60,7 @@ protected:
|
||||
|
||||
GotoPreviousTabCommand::GotoPreviousTabCommand()
|
||||
: Command("GotoPreviousTab",
|
||||
"Goto Previous tab",
|
||||
"Go to Previous tab",
|
||||
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/undo_transaction.h"
|
||||
#include "app/undoers/set_mask_position.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "raster/mask.h"
|
||||
#include "raster/sprite.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()
|
||||
{
|
||||
return new MoveMaskCommand;
|
||||
|
@ -48,6 +48,7 @@ namespace app {
|
||||
void onLoadParams(Params* params);
|
||||
bool onEnabled(Context* context);
|
||||
void onExecute(Context* context);
|
||||
std::string onGetFriendlyName() const;
|
||||
|
||||
private:
|
||||
Target m_target;
|
||||
|
@ -29,7 +29,6 @@
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace ui;
|
||||
using namespace gfx;
|
||||
|
||||
class ShowOnionSkinCommand : public Command {
|
||||
|
@ -159,7 +159,7 @@ private:
|
||||
|
||||
PaletteEditorCommand::PaletteEditorCommand()
|
||||
: Command("PaletteEditor",
|
||||
"PaletteEditor",
|
||||
"Palette Editor",
|
||||
CmdRecordableFlag)
|
||||
{
|
||||
m_open = true;
|
||||
|
@ -28,10 +28,10 @@
|
||||
#include "app/context.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/modules/gfx.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/settings/document_settings.h"
|
||||
#include "app/settings/settings.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/util/render.h"
|
||||
#include "raster/conversion_she.h"
|
||||
@ -127,7 +127,8 @@ protected:
|
||||
case kKeyDownMessage: {
|
||||
KeyMessage* keyMsg = static_cast<KeyMessage*>(msg);
|
||||
Command* command = NULL;
|
||||
get_command_from_key_message(msg, &command, NULL);
|
||||
KeyboardShortcuts::instance()
|
||||
->getCommandFromKeyMessage(msg, &command, NULL);
|
||||
|
||||
// Change frame
|
||||
if (command != NULL &&
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "app/ui/timeline.h"
|
||||
#include "app/undo_transaction.h"
|
||||
#include "app/util/range_utils.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "raster/cel.h"
|
||||
#include "raster/image.h"
|
||||
#include "raster/mask.h"
|
||||
@ -53,6 +54,7 @@ protected:
|
||||
void onLoadParams(Params* params);
|
||||
bool onEnabled(Context* context);
|
||||
void onExecute(Context* context);
|
||||
std::string onGetFriendlyName() const;
|
||||
|
||||
private:
|
||||
bool m_flipMask;
|
||||
@ -235,6 +237,20 @@ void RotateCommand::onExecute(Context* context)
|
||||
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()
|
||||
{
|
||||
return new RotateCommand;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "app/settings/document_settings.h"
|
||||
#include "app/settings/settings.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "ui/view.h"
|
||||
|
||||
namespace app {
|
||||
@ -52,6 +53,7 @@ protected:
|
||||
void onLoadParams(Params* params);
|
||||
bool onEnabled(Context* context);
|
||||
void onExecute(Context* context);
|
||||
std::string onGetFriendlyName() const;
|
||||
|
||||
private:
|
||||
Direction m_direction;
|
||||
@ -142,6 +144,49 @@ void ScrollCommand::onExecute(Context* context)
|
||||
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()
|
||||
{
|
||||
return new ScrollCommand;
|
||||
|
@ -39,7 +39,7 @@ protected:
|
||||
|
||||
SwitchColorsCommand::SwitchColorsCommand()
|
||||
: Command("SwitchColors",
|
||||
"SwitchColors",
|
||||
"Switch Colors",
|
||||
CmdUIOnlyFlag)
|
||||
{
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "app/commands/params.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "base/convert_to.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
@ -38,6 +39,7 @@ protected:
|
||||
void onLoadParams(Params* params);
|
||||
bool onEnabled(Context* context);
|
||||
void onExecute(Context* context);
|
||||
std::string onGetFriendlyName() const;
|
||||
|
||||
private:
|
||||
Action m_action;
|
||||
@ -98,6 +100,25 @@ void ZoomCommand::onExecute(Context* context)
|
||||
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()
|
||||
{
|
||||
return new ZoomCommand;
|
||||
|
@ -37,6 +37,11 @@ Command::~Command()
|
||||
{
|
||||
}
|
||||
|
||||
std::string Command::friendlyName() const
|
||||
{
|
||||
return onGetFriendlyName();
|
||||
}
|
||||
|
||||
void Command::loadParams(Params* params)
|
||||
{
|
||||
onLoadParams(params);
|
||||
@ -101,4 +106,9 @@ void Command::onExecute(Context* context)
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
std::string Command::onGetFriendlyName() const
|
||||
{
|
||||
return m_friendly_name;
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -21,6 +21,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "app/commands/command_factory.h"
|
||||
#include <string>
|
||||
|
||||
namespace app {
|
||||
class Context;
|
||||
@ -44,7 +45,7 @@ namespace app {
|
||||
virtual Command* clone() const { return new Command(*this); }
|
||||
|
||||
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);
|
||||
bool isEnabled(Context* context);
|
||||
@ -56,6 +57,7 @@ namespace app {
|
||||
virtual bool onEnabled(Context* context);
|
||||
virtual bool onChecked(Context* context);
|
||||
virtual void onExecute(Context* context);
|
||||
virtual std::string onGetFriendlyName() const;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -61,6 +61,7 @@ FOR_EACH_COMMAND(GridSettings)
|
||||
FOR_EACH_COMMAND(ImportSpriteSheet)
|
||||
FOR_EACH_COMMAND(InvertColor)
|
||||
FOR_EACH_COMMAND(InvertMask)
|
||||
FOR_EACH_COMMAND(KeyboardShortcuts)
|
||||
FOR_EACH_COMMAND(Launch)
|
||||
FOR_EACH_COMMAND(LayerFromBackground)
|
||||
FOR_EACH_COMMAND(LayerProperties)
|
||||
|
@ -26,58 +26,58 @@
|
||||
namespace app {
|
||||
|
||||
class Params {
|
||||
std::map<std::string, std::string> m_params;
|
||||
|
||||
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(const Params& copy) : m_params(copy.m_params) { }
|
||||
virtual ~Params() { }
|
||||
|
||||
Params* clone()
|
||||
{
|
||||
Params* clone() const {
|
||||
return new Params(*this);
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
bool empty() const {
|
||||
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();
|
||||
}
|
||||
|
||||
bool operator==(const Params& params) const
|
||||
{
|
||||
bool operator==(const Params& params) const {
|
||||
return m_params == params.m_params;
|
||||
}
|
||||
|
||||
bool operator!=(const Params& params) const
|
||||
{
|
||||
bool operator!=(const Params& params) const {
|
||||
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;
|
||||
}
|
||||
|
||||
std::string& get(const char* name)
|
||||
{
|
||||
std::string& get(const char* name) {
|
||||
return m_params[name];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T get_as(const char* name)
|
||||
{
|
||||
T get_as(const char* name) {
|
||||
std::istringstream stream(m_params[name]);
|
||||
T value;
|
||||
stream >> value;
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
Map m_params;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "app/tools/ink.h"
|
||||
#include "app/tools/tool_box.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_window.h"
|
||||
@ -63,19 +64,12 @@
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#ifdef ALLEGRO_WINDOWS
|
||||
#include <winalleg.h>
|
||||
|
||||
#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 {
|
||||
|
||||
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
|
||||
, public LayoutIO
|
||||
{
|
||||
@ -144,8 +106,6 @@ static she::Clipboard* main_clipboard = NULL;
|
||||
static CustomizedGuiManager* manager = NULL;
|
||||
static Theme* ase_theme = NULL;
|
||||
|
||||
static std::vector<Shortcut*>* shortcuts = NULL;
|
||||
|
||||
// Default GUI screen configuration
|
||||
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 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.
|
||||
int init_module_gui()
|
||||
{
|
||||
shortcuts = new std::vector<Shortcut*>;
|
||||
|
||||
int w, h;
|
||||
bool maximized;
|
||||
load_gui_config(w, h, maximized);
|
||||
@ -233,13 +177,6 @@ void exit_module_gui()
|
||||
{
|
||||
save_gui_config();
|
||||
|
||||
// destroy shortcuts
|
||||
ASSERT(shortcuts != NULL);
|
||||
for (Shortcut* shortcut : *shortcuts)
|
||||
delete shortcut;
|
||||
delete shortcuts;
|
||||
shortcuts = NULL;
|
||||
|
||||
delete manager;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// 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.
|
||||
bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
||||
{
|
||||
@ -809,26 +457,24 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
||||
break;
|
||||
}
|
||||
|
||||
for (Shortcut* shortcut : *shortcuts) {
|
||||
if (shortcut->is_pressed(msg)) {
|
||||
for (const Key* key : *KeyboardShortcuts::instance()) {
|
||||
if (key->isPressed(msg)) {
|
||||
// Cancel menu-bar loops (to close any popup menu)
|
||||
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* select_this_tool = shortcut->tool;
|
||||
tools::Tool* select_this_tool = key->tool();
|
||||
tools::ToolBox* toolbox = App::instance()->getToolBox();
|
||||
std::vector<tools::Tool*> possibles;
|
||||
|
||||
// Iterate over all tools
|
||||
for (tools::ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
|
||||
Shortcut* shortcut = get_keyboard_shortcut_for_tool(*it);
|
||||
|
||||
// Collect all tools with the pressed keyboard-shortcut
|
||||
if (shortcut && shortcut->is_pressed(msg))
|
||||
possibles.push_back(*it);
|
||||
// Collect all tools with the pressed keyboard-shortcut
|
||||
for (tools::Tool* tool : *toolbox) {
|
||||
Key* key = KeyboardShortcuts::instance()->tool(tool);
|
||||
if (key && key->isPressed(msg))
|
||||
possibles.push_back(tool);
|
||||
}
|
||||
|
||||
if (possibles.size() >= 2) {
|
||||
@ -859,8 +505,8 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
||||
return true;
|
||||
}
|
||||
|
||||
case Shortcut::Type::ExecuteCommand: {
|
||||
Command* command = shortcut->command;
|
||||
case KeyType::Command: {
|
||||
Command* command = key->command();
|
||||
|
||||
// Commands are executed only when the main window is
|
||||
// the current window running at foreground.
|
||||
@ -875,16 +521,17 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
||||
else if (child->isDesktop() && child == App::instance()->getMainWindow()) {
|
||||
// OK, so we can execute the command represented
|
||||
// by the pressed-key in the message...
|
||||
UIContext::instance()->executeCommand(command, shortcut->params);
|
||||
UIContext::instance()->executeCommand(
|
||||
command, key->params());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Shortcut::Type::EditorQuicktool: {
|
||||
case KeyType::Quicktool: {
|
||||
// Do nothing, it is used in the editor through the
|
||||
// get_selected_quicktool() function.
|
||||
// KeyboardShortcuts::getCurrentQuicktool() function.
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -22,10 +22,7 @@
|
||||
|
||||
#include "app/ui/skin/skin_property.h"
|
||||
#include "base/exception.h"
|
||||
#include "ui/accelerator.h"
|
||||
#include "ui/base.h"
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
namespace ui {
|
||||
class ButtonBase;
|
||||
@ -45,12 +42,6 @@ namespace app {
|
||||
class Tool;
|
||||
}
|
||||
|
||||
enum class KeyContext {
|
||||
Any,
|
||||
Normal,
|
||||
Selection,
|
||||
};
|
||||
|
||||
int init_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);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
|
||||
#endif
|
||||
|
@ -25,9 +25,12 @@
|
||||
#include "app/commands/command.h"
|
||||
#include "app/commands/params.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "ui/accelerator.h"
|
||||
#include "ui/menu.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/preferred_size_event.h"
|
||||
#include "ui/widget.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
@ -38,8 +41,9 @@ namespace app {
|
||||
|
||||
using namespace ui;
|
||||
|
||||
AppMenuItem::AppMenuItem(const char* text, Command* command, Params* params)
|
||||
AppMenuItem::AppMenuItem(const char* text, Command* command, const Params* params)
|
||||
: MenuItem(text)
|
||||
, m_key(NULL)
|
||||
, m_command(command)
|
||||
, m_params(params ? params->clone(): NULL)
|
||||
{
|
||||
@ -82,6 +86,31 @@ bool AppMenuItem::onProcessMessage(Message* 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()
|
||||
{
|
||||
MenuItem::onClick();
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "ui/menu.h"
|
||||
|
||||
namespace app {
|
||||
class Key;
|
||||
class Command;
|
||||
class Params;
|
||||
|
||||
@ -33,17 +34,22 @@ namespace app {
|
||||
// used to check the availability of the command).
|
||||
class AppMenuItem : public ui::MenuItem {
|
||||
public:
|
||||
AppMenuItem(const char* text, Command* command, Params* params);
|
||||
AppMenuItem(const char* text, Command* command, const Params* params);
|
||||
~AppMenuItem();
|
||||
|
||||
Key* getKey() { return m_key; }
|
||||
void setKey(Key* key) { m_key = key; }
|
||||
|
||||
Command* getCommand() { return m_command; }
|
||||
Params* getParams() { return m_params; }
|
||||
|
||||
protected:
|
||||
bool onProcessMessage(ui::Message* msg) override;
|
||||
void onPreferredSize(ui::PreferredSizeEvent& ev) override;
|
||||
void onClick() override;
|
||||
|
||||
private:
|
||||
Key* m_key;
|
||||
Command* m_command;
|
||||
Params* m_params;
|
||||
};
|
||||
|
@ -24,11 +24,11 @@
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/modules/palettes.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/editor/editor_customization_delegate.h"
|
||||
#include "app/ui/editor/editor_view.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/mini_editor.h"
|
||||
#include "app/ui/workspace.h"
|
||||
@ -77,61 +77,42 @@ public:
|
||||
|
||||
// EditorCustomizationDelegate implementation
|
||||
tools::Tool* getQuickTool(tools::Tool* currentTool) override {
|
||||
return get_selected_quicktool(currentTool);
|
||||
return KeyboardShortcuts::instance()
|
||||
->getCurrentQuicktool(currentTool);
|
||||
}
|
||||
|
||||
bool isCopySelectionKeyPressed() override {
|
||||
Accelerator* accel = get_accel_to_copy_selection();
|
||||
if (accel)
|
||||
return accel->checkFromAllegroKeyArray();
|
||||
else
|
||||
return false;
|
||||
return isKeyActionPressed(KeyAction::CopySelection);
|
||||
}
|
||||
|
||||
bool isSnapToGridKeyPressed() override {
|
||||
Accelerator* accel = get_accel_to_snap_to_grid();
|
||||
if (accel)
|
||||
return accel->checkFromAllegroKeyArray();
|
||||
else
|
||||
return false;
|
||||
return isKeyActionPressed(KeyAction::SnapToGrid);
|
||||
}
|
||||
|
||||
bool isAngleSnapKeyPressed() override {
|
||||
Accelerator* accel = get_accel_to_angle_snap();
|
||||
if (accel)
|
||||
return accel->checkFromAllegroKeyArray();
|
||||
else
|
||||
return false;
|
||||
return isKeyActionPressed(KeyAction::AngleSnap);
|
||||
}
|
||||
|
||||
bool isMaintainAspectRatioKeyPressed() override {
|
||||
Accelerator* accel = get_accel_to_maintain_aspect_ratio();
|
||||
if (accel)
|
||||
return accel->checkFromAllegroKeyArray();
|
||||
else
|
||||
return false;
|
||||
return isKeyActionPressed(KeyAction::MaintainAspectRatio);
|
||||
}
|
||||
|
||||
bool isLockAxisKeyPressed() override {
|
||||
Accelerator* accel = get_accel_to_lock_axis();
|
||||
if (accel)
|
||||
return accel->checkFromAllegroKeyArray();
|
||||
else
|
||||
return false;
|
||||
return isKeyActionPressed(KeyAction::LockAxis);
|
||||
}
|
||||
|
||||
bool isAddSelectionPressed() override {
|
||||
Accelerator* accel = get_accel_to_add_selection();
|
||||
if (accel)
|
||||
return accel->checkFromAllegroKeyArray();
|
||||
else
|
||||
return false;
|
||||
return isKeyActionPressed(KeyAction::AddSelection);
|
||||
}
|
||||
|
||||
bool isSubtractSelectionPressed() override {
|
||||
Accelerator* accel = get_accel_to_subtract_selection();
|
||||
if (accel)
|
||||
return accel->checkFromAllegroKeyArray();
|
||||
return isKeyActionPressed(KeyAction::SubtractSelection);
|
||||
}
|
||||
|
||||
private:
|
||||
bool isKeyActionPressed(KeyAction action) {
|
||||
if (Key* key = KeyboardShortcuts::instance()->action(action))
|
||||
return key->checkFromAllegroKeyArray();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -25,13 +25,13 @@
|
||||
#include "app/commands/command.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/commands/params.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/tools/controller.h"
|
||||
#include "app/tools/ink.h"
|
||||
#include "app/tools/tool.h"
|
||||
#include "app/tools/tool_loop.h"
|
||||
#include "app/tools/tool_loop_manager.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "raster/blend.h"
|
||||
#include "ui/message.h"
|
||||
@ -178,7 +178,8 @@ bool DrawingState::onKeyDown(Editor* editor, KeyMessage* msg)
|
||||
|
||||
Command* command = NULL;
|
||||
Params* params = NULL;
|
||||
if (get_command_from_key_message(msg, &command, ¶ms)) {
|
||||
if (KeyboardShortcuts::instance()
|
||||
->getCommandFromKeyMessage(msg, &command, ¶ms)) {
|
||||
// We accept zoom commands.
|
||||
if (strcmp(command->short_name(), CommandId::Zoom) == 0) {
|
||||
UIContext::instance()->executeCommand(command, params);
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include "app/commands/cmd_move_mask.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/settings/settings.h"
|
||||
#include "app/tools/ink.h"
|
||||
#include "app/tools/tool.h"
|
||||
@ -38,6 +37,7 @@
|
||||
#include "app/ui/editor/pixels_movement.h"
|
||||
#include "app/ui/editor/standby_state.h"
|
||||
#include "app/ui/editor/transform_handles.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
#include "app/ui_context.h"
|
||||
@ -326,7 +326,8 @@ bool MovingPixelsState::onKeyDown(Editor* editor, KeyMessage* msg)
|
||||
else {
|
||||
Command* command = NULL;
|
||||
Params* params = NULL;
|
||||
if (get_command_from_key_message(msg, &command, ¶ms)) {
|
||||
if (KeyboardShortcuts::instance()
|
||||
->getCommandFromKeyMessage(msg, &command, ¶ms)) {
|
||||
// We accept zoom commands.
|
||||
if (strcmp(command->short_name(), CommandId::Zoom) == 0) {
|
||||
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/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/skin_property.h"
|
||||
#include "app/ui/skin/skin_slider_property.h"
|
||||
@ -1242,7 +1244,7 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
|
||||
{
|
||||
int scale = jguiscale();
|
||||
Graphics* g = ev.getGraphics();
|
||||
MenuItem* widget = static_cast<MenuItem*>(ev.getSource());
|
||||
AppMenuItem* widget = static_cast<AppMenuItem*>(ev.getSource());
|
||||
gfx::Rect bounds = widget->getClientBounds();
|
||||
gfx::Color fg, bg;
|
||||
int c, bar;
|
||||
@ -1324,13 +1326,13 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
|
||||
}
|
||||
}
|
||||
// Draw the keyboard shortcut
|
||||
else if (widget->getAccel()) {
|
||||
else if (widget->getKey() && !widget->getKey()->accels().empty()) {
|
||||
int old_align = widget->getAlign();
|
||||
|
||||
pos = bounds;
|
||||
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);
|
||||
drawTextString(g, buf.c_str(), fg, ColorNone, widget, pos, 0);
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "app/tools/tool.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui/status_bar.h"
|
||||
@ -362,10 +363,10 @@ void StatusBar::showTool(int msecs, tools::Tool* tool)
|
||||
std::string text = tool->getText();
|
||||
|
||||
// Tool shortcut
|
||||
Accelerator* accel = get_accel_to_change_tool(tool);
|
||||
if (accel) {
|
||||
Key* key = KeyboardShortcuts::instance()->tool(tool);
|
||||
if (key && !key->accels().empty()) {
|
||||
text += ", Shortcut: ";
|
||||
text += accel->toString();
|
||||
text += key->accels().front().toString();
|
||||
}
|
||||
|
||||
// Set text
|
||||
|
@ -27,9 +27,9 @@
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/modules/gfx.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/settings/settings.h"
|
||||
#include "app/tools/tool_box.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/mini_editor.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
@ -542,10 +542,10 @@ void ToolBar::openTipWindow(int group_index, Tool* tool)
|
||||
}
|
||||
|
||||
// Tool shortcut
|
||||
Accelerator* accel = get_accel_to_change_tool(tool);
|
||||
if (accel) {
|
||||
Key* key = KeyboardShortcuts::instance()->tool(tool);
|
||||
if (key && !key->accels().empty()) {
|
||||
tooltip += "\n\nShortcut: ";
|
||||
tooltip += accel->toString();
|
||||
tooltip += key->accels().front().toString();
|
||||
}
|
||||
}
|
||||
else if (group_index == ConfigureToolIndex) {
|
||||
|
@ -46,4 +46,14 @@ XmlDocumentRef open_xml(const std::string& filename)
|
||||
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
|
||||
|
@ -32,6 +32,7 @@ namespace app {
|
||||
typedef SharedPtr<TiXmlDocument> XmlDocumentRef;
|
||||
|
||||
XmlDocumentRef open_xml(const std::string& filename);
|
||||
void save_xml(XmlDocumentRef doc, const std::string& filename);
|
||||
|
||||
} // namespace app
|
||||
|
||||
|
@ -24,26 +24,28 @@
|
||||
|
||||
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
|
||||
if (str == "+") {
|
||||
addKey(kKeyNoneModifier, kKeyNil, '+');
|
||||
m_unicodeChar = '+';
|
||||
return;
|
||||
}
|
||||
|
||||
@ -52,137 +54,143 @@ void Accelerator::addKeysFromString(const std::string& str)
|
||||
for (std::string tok : tokens) {
|
||||
tok = base::string_to_lower(tok);
|
||||
|
||||
if (scancode == kKeySpace) {
|
||||
modifiers = (KeyModifiers)((int)modifiers | (int)kKeySpaceModifier);
|
||||
scancode = kKeyNil;
|
||||
if (m_scancode == kKeySpace) {
|
||||
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeySpaceModifier);
|
||||
m_scancode = kKeyNil;
|
||||
}
|
||||
|
||||
// Modifiers
|
||||
if (tok == "shift") {
|
||||
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyShiftModifier);
|
||||
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeyShiftModifier);
|
||||
}
|
||||
else if (tok == "alt") {
|
||||
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyAltModifier);
|
||||
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeyAltModifier);
|
||||
}
|
||||
else if (tok == "ctrl") {
|
||||
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCtrlModifier);
|
||||
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeyCtrlModifier);
|
||||
}
|
||||
else if (tok == "cmd") {
|
||||
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCmdModifier);
|
||||
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeyCmdModifier);
|
||||
}
|
||||
|
||||
// Scancode
|
||||
|
||||
// word with one character
|
||||
// Word with one character
|
||||
else if (tok.size() == 1) {
|
||||
if ((tok[0] >= 'a') && (tok[0] <= 'z')) {
|
||||
unicodeChar = tok[0];
|
||||
m_unicodeChar = tok[0];
|
||||
}
|
||||
else {
|
||||
unicodeChar = tok[0];
|
||||
m_unicodeChar = tok[0];
|
||||
}
|
||||
|
||||
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'))
|
||||
scancode = (KeyScancode)((int)kKey0 + tok[0] - '0');
|
||||
m_scancode = (KeyScancode)((int)kKey0 + tok[0] - '0');
|
||||
else {
|
||||
switch (tok[0]) {
|
||||
case '~': scancode = kKeyTilde; break;
|
||||
case '-': scancode = kKeyMinus; break;
|
||||
case '=': scancode = kKeyEquals; break;
|
||||
case '[': scancode = kKeyOpenbrace; break;
|
||||
case ']': scancode = kKeyClosebrace; break;
|
||||
case ';': scancode = kKeyColon; break;
|
||||
case '\'': scancode = kKeyQuote; break;
|
||||
case '\\': scancode = kKeyBackslash; break;
|
||||
case ',': scancode = kKeyComma; break;
|
||||
case '.': scancode = kKeyStop; break;
|
||||
case '/': scancode = kKeySlash; break;
|
||||
case '*': scancode = kKeyAsterisk; break;
|
||||
case '~': m_scancode = kKeyTilde; break;
|
||||
case '-': m_scancode = kKeyMinus; break;
|
||||
case '=': m_scancode = kKeyEquals; break;
|
||||
case '[': m_scancode = kKeyOpenbrace; break;
|
||||
case ']': m_scancode = kKeyClosebrace; break;
|
||||
case ';': m_scancode = kKeyColon; break;
|
||||
case '\'': m_scancode = kKeyQuote; break;
|
||||
case '\\': m_scancode = kKeyBackslash; break;
|
||||
case ',': m_scancode = kKeyComma; break;
|
||||
case '.': m_scancode = kKeyStop; break;
|
||||
case '/': m_scancode = kKeySlash; break;
|
||||
case '*': m_scancode = kKeyAsterisk; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* other ones */
|
||||
// Other ones
|
||||
else {
|
||||
/* F1, F2, ..., F11, F12 */
|
||||
// F1, F2, ..., F11, F12
|
||||
if (tok[0] == 'f' && (tok.size() <= 3)) {
|
||||
int num = strtol(tok.c_str()+1, NULL, 10);
|
||||
if ((num >= 1) && (num <= 12))
|
||||
scancode = (KeyScancode)((int)kKeyF1 + num - 1);
|
||||
m_scancode = (KeyScancode)((int)kKeyF1 + num - 1);
|
||||
}
|
||||
else if ((tok == "escape") || (tok == "esc"))
|
||||
scancode = kKeyEsc;
|
||||
m_scancode = kKeyEsc;
|
||||
else if (tok == "backspace")
|
||||
scancode = kKeyBackspace;
|
||||
m_scancode = kKeyBackspace;
|
||||
else if (tok == "tab")
|
||||
scancode = kKeyTab;
|
||||
m_scancode = kKeyTab;
|
||||
else if (tok == "enter")
|
||||
scancode = kKeyEnter;
|
||||
m_scancode = kKeyEnter;
|
||||
else if (tok == "space")
|
||||
scancode = kKeySpace;
|
||||
m_scancode = kKeySpace;
|
||||
else if ((tok == "insert") || (tok == "ins"))
|
||||
scancode = kKeyInsert;
|
||||
m_scancode = kKeyInsert;
|
||||
else if ((tok == "delete") || (tok == "del"))
|
||||
scancode = kKeyDel;
|
||||
m_scancode = kKeyDel;
|
||||
else if (tok == "home")
|
||||
scancode = kKeyHome;
|
||||
m_scancode = kKeyHome;
|
||||
else if (tok == "end")
|
||||
scancode = kKeyEnd;
|
||||
m_scancode = kKeyEnd;
|
||||
else if ((tok == "page up") || (tok == "pgup"))
|
||||
scancode = kKeyPageUp;
|
||||
m_scancode = kKeyPageUp;
|
||||
else if ((tok == "page down") || (tok == "pgdn"))
|
||||
scancode = kKeyPageDown;
|
||||
m_scancode = kKeyPageDown;
|
||||
else if (tok == "left")
|
||||
scancode = kKeyLeft;
|
||||
m_scancode = kKeyLeft;
|
||||
else if (tok == "right")
|
||||
scancode = kKeyRight;
|
||||
m_scancode = kKeyRight;
|
||||
else if (tok == "up")
|
||||
scancode = kKeyUp;
|
||||
m_scancode = kKeyUp;
|
||||
else if (tok == "down")
|
||||
scancode = kKeyDown;
|
||||
m_scancode = kKeyDown;
|
||||
else if (tok == "0 pad")
|
||||
scancode = kKey0Pad;
|
||||
m_scancode = kKey0Pad;
|
||||
else if (tok == "1 pad")
|
||||
scancode = kKey1Pad;
|
||||
m_scancode = kKey1Pad;
|
||||
else if (tok == "2 pad")
|
||||
scancode = kKey2Pad;
|
||||
m_scancode = kKey2Pad;
|
||||
else if (tok == "3 pad")
|
||||
scancode = kKey3Pad;
|
||||
m_scancode = kKey3Pad;
|
||||
else if (tok == "4 pad")
|
||||
scancode = kKey4Pad;
|
||||
m_scancode = kKey4Pad;
|
||||
else if (tok == "5 pad")
|
||||
scancode = kKey5Pad;
|
||||
m_scancode = kKey5Pad;
|
||||
else if (tok == "6 pad")
|
||||
scancode = kKey6Pad;
|
||||
m_scancode = kKey6Pad;
|
||||
else if (tok == "7 pad")
|
||||
scancode = kKey7Pad;
|
||||
m_scancode = kKey7Pad;
|
||||
else if (tok == "8 pad")
|
||||
scancode = kKey8Pad;
|
||||
m_scancode = kKey8Pad;
|
||||
else if (tok == "9 pad")
|
||||
scancode = kKey9Pad;
|
||||
m_scancode = kKey9Pad;
|
||||
else if (tok == "slash pad")
|
||||
scancode = kKeySlashPad;
|
||||
m_scancode = kKeySlashPad;
|
||||
else if (tok == "asterisk")
|
||||
scancode = kKeyAsterisk;
|
||||
m_scancode = kKeyAsterisk;
|
||||
else if (tok == "minus pad")
|
||||
scancode = kKeyMinusPad;
|
||||
m_scancode = kKeyMinusPad;
|
||||
else if (tok == "plus pad")
|
||||
scancode = kKeyPlusPad;
|
||||
m_scancode = kKeyPlusPad;
|
||||
else if (tok == "del pad")
|
||||
scancode = kKeyDelPad;
|
||||
m_scancode = kKeyDelPad;
|
||||
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
|
||||
static const char *table[] = {
|
||||
static const char* table[] = {
|
||||
NULL,
|
||||
"A",
|
||||
"B",
|
||||
@ -287,34 +295,29 @@ std::string Accelerator::KeyCombo::toString()
|
||||
"KEY_COLON2",
|
||||
"Kanji",
|
||||
};
|
||||
static size_t table_size = sizeof(table) / sizeof(table[0]);
|
||||
|
||||
std::string buf;
|
||||
|
||||
// Shifts
|
||||
if (this->modifiers & kKeyCtrlModifier) buf += "Ctrl+";
|
||||
if (this->modifiers & kKeyCmdModifier) buf += "Cmd+";
|
||||
if (this->modifiers & kKeyAltModifier) buf += "Alt+";
|
||||
if (this->modifiers & kKeyShiftModifier) buf += "Shift+";
|
||||
if (this->modifiers & kKeySpaceModifier) buf += "Space+";
|
||||
if (m_modifiers & kKeyCtrlModifier) buf += "Ctrl+";
|
||||
if (m_modifiers & kKeyCmdModifier) buf += "Cmd+";
|
||||
if (m_modifiers & kKeyAltModifier) buf += "Alt+";
|
||||
if (m_modifiers & kKeyShiftModifier) buf += "Shift+";
|
||||
if (m_modifiers & kKeySpaceModifier) buf += "Space+";
|
||||
|
||||
// Key
|
||||
if (this->unicodeChar)
|
||||
buf += (wchar_t)toupper(this->unicodeChar);
|
||||
else if (this->scancode)
|
||||
buf += table[this->scancode];
|
||||
if (m_unicodeChar)
|
||||
buf += (wchar_t)toupper(m_unicodeChar);
|
||||
else if (m_scancode && m_scancode > 0 && m_scancode < (int)table_size)
|
||||
buf += table[m_scancode];
|
||||
else if (!buf.empty() && buf[buf.size()-1] == '+')
|
||||
buf.erase(buf.size()-1);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string Accelerator::toString()
|
||||
{
|
||||
ASSERT(!m_combos.empty());
|
||||
return m_combos.front().toString();
|
||||
}
|
||||
|
||||
bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar)
|
||||
bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar) const
|
||||
{
|
||||
#ifdef REPORT_KEYS
|
||||
char buf[256];
|
||||
@ -373,40 +376,29 @@ bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicod
|
||||
#endif
|
||||
|
||||
#ifdef REPORT_KEYS
|
||||
{
|
||||
base::UniquePtr<Accelerator> a2(new Accelerator);
|
||||
a2->addKey(modifiers, scancode, unicodeChar);
|
||||
buf2 = a2->getString();
|
||||
}
|
||||
printf("%3d==%3d %3d==%3d %s==%s ",
|
||||
m_scancode, scancode,
|
||||
m_unicodeChar, unicodeChar,
|
||||
toString().c_str(),
|
||||
Accelerator(modifiers, scancode, unicodeChar).toString().c_str());
|
||||
#endif
|
||||
|
||||
for (KeyCombos::iterator it = m_combos.begin(), end = m_combos.end();
|
||||
it != end; ++it) {
|
||||
if ((m_modifiers == modifiers) &&
|
||||
((m_scancode != kKeyNil && m_scancode == scancode) ||
|
||||
(m_unicodeChar && m_unicodeChar == unicodeChar))) {
|
||||
#ifdef REPORT_KEYS
|
||||
printf("%3d==%3d %3d==%3d %s==%s ",
|
||||
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");
|
||||
printf("true\n");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef REPORT_KEYS
|
||||
printf("false\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Accelerator::checkFromAllegroKeyArray()
|
||||
bool Accelerator::checkFromAllegroKeyArray() const
|
||||
{
|
||||
KeyModifiers modifiers = kKeyNoneModifier;
|
||||
|
||||
@ -417,14 +409,8 @@ bool Accelerator::checkFromAllegroKeyArray()
|
||||
if (key[KEY_ALT] ) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyAltModifier);
|
||||
if (key[KEY_COMMAND ]) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCmdModifier);
|
||||
|
||||
for (KeyCombos::iterator it = m_combos.begin(), end = m_combos.end();
|
||||
it != end; ++it) {
|
||||
if ((it->scancode == 0 || key[it->scancode]) &&
|
||||
(it->modifiers == modifiers)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return ((m_scancode == 0 || key[m_scancode]) &&
|
||||
(m_modifiers == modifiers));
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
@ -15,33 +15,42 @@
|
||||
|
||||
namespace ui {
|
||||
|
||||
class Accelerator
|
||||
{
|
||||
class Accelerator {
|
||||
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"
|
||||
void addKeysFromString(const std::string& str);
|
||||
bool isEmpty() const;
|
||||
std::string toString() const;
|
||||
|
||||
bool isEmpty() const { return m_combos.empty(); }
|
||||
std::string toString();
|
||||
bool check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar) const;
|
||||
bool checkFromAllegroKeyArray() const;
|
||||
|
||||
bool check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar);
|
||||
bool checkFromAllegroKeyArray();
|
||||
bool operator==(const Accelerator& other) const {
|
||||
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:
|
||||
struct KeyCombo {
|
||||
KeyModifiers modifiers;
|
||||
KeyScancode scancode;
|
||||
int unicodeChar;
|
||||
|
||||
std::string toString();
|
||||
};
|
||||
|
||||
typedef std::vector<KeyCombo> KeyCombos;
|
||||
KeyCombos m_combos;
|
||||
KeyModifiers m_modifiers;
|
||||
KeyScancode m_scancode;
|
||||
int m_unicodeChar;
|
||||
};
|
||||
|
||||
typedef std::vector<Accelerator> Accelerators;
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif
|
||||
|
@ -106,7 +106,7 @@ size_t ListBox::getItemsCount() const
|
||||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
switch (msg->type()) {
|
||||
|
@ -15,8 +15,7 @@ namespace ui {
|
||||
|
||||
class ListItem;
|
||||
|
||||
class ListBox : public Widget
|
||||
{
|
||||
class ListBox : public Widget {
|
||||
public:
|
||||
ListBox();
|
||||
|
||||
@ -29,6 +28,7 @@ namespace ui {
|
||||
size_t getItemsCount() const;
|
||||
|
||||
void centerScroll();
|
||||
void sortItems();
|
||||
|
||||
Signal0<void> ChangeSelectedItem;
|
||||
Signal0<void> DoubleClickItem;
|
||||
|
@ -195,7 +195,6 @@ void MenuBar::setExpandOnMouseover(bool state)
|
||||
MenuItem::MenuItem(const std::string& text)
|
||||
: Widget(kMenuItemWidget)
|
||||
{
|
||||
m_accel = NULL;
|
||||
m_highlighted = false;
|
||||
m_submenu = NULL;
|
||||
m_submenu_menubox = NULL;
|
||||
@ -206,11 +205,7 @@ MenuItem::MenuItem(const std::string& text)
|
||||
|
||||
MenuItem::~MenuItem()
|
||||
{
|
||||
if (m_accel)
|
||||
delete m_accel;
|
||||
|
||||
if (m_submenu)
|
||||
delete m_submenu;
|
||||
delete m_submenu;
|
||||
}
|
||||
|
||||
Menu* MenuBox::getMenu()
|
||||
@ -233,11 +228,6 @@ Menu* MenuItem::getSubmenu()
|
||||
return m_submenu;
|
||||
}
|
||||
|
||||
Accelerator* MenuItem::getAccel()
|
||||
{
|
||||
return m_accel;
|
||||
}
|
||||
|
||||
void MenuBox::setMenu(Menu* menu)
|
||||
{
|
||||
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
|
||||
{
|
||||
return m_highlighted;
|
||||
@ -909,10 +884,6 @@ void MenuItem::onPreferredSize(PreferredSizeEvent& ev)
|
||||
+ this->border_width.t
|
||||
+ getTextHeight()
|
||||
+ this->border_width.b;
|
||||
|
||||
if (m_accel && !m_accel->isEmpty()) {
|
||||
size.w += Graphics::measureUIStringLength(m_accel->toString().c_str(), getFont());
|
||||
}
|
||||
}
|
||||
|
||||
ev.setPreferredSize(size);
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
namespace ui {
|
||||
|
||||
class Accelerator;
|
||||
class MenuItem;
|
||||
class Timer;
|
||||
struct MenuBaseData;
|
||||
@ -104,9 +103,6 @@ namespace ui {
|
||||
Menu* getSubmenu();
|
||||
void setSubmenu(Menu* submenu);
|
||||
|
||||
Accelerator* getAccel();
|
||||
void setAccel(Accelerator* accel);
|
||||
|
||||
bool isHighlighted() const;
|
||||
void setHighlighted(bool state);
|
||||
|
||||
@ -133,15 +129,15 @@ namespace ui {
|
||||
virtual void onPreferredSize(PreferredSizeEvent& ev) override;
|
||||
virtual void onClick();
|
||||
|
||||
private:
|
||||
bool inBar();
|
||||
|
||||
private:
|
||||
void openSubmenu(bool select_first);
|
||||
void closeSubmenu(bool last_of_close_chain);
|
||||
void startTimer();
|
||||
void stopTimer();
|
||||
void executeClick();
|
||||
|
||||
Accelerator* m_accel; // Hot-key
|
||||
bool m_highlighted; // Is it highlighted?
|
||||
Menu* m_submenu; // The sub-menu
|
||||
MenuBox* m_submenu_menubox; // The opened menubox for this menu-item
|
||||
|
Loading…
Reference in New Issue
Block a user