[aseprite] 65/134: Fix several issues with keyboard shortcuts customization
Tobias Hansen
thansen at moszumanska.debian.org
Sat Mar 14 17:10:07 UTC 2015
This is an automated email from the git hooks/post-receive script.
thansen pushed a commit to branch master
in repository aseprite.
commit 0b13e53c67dbb9a5ead0f58251ad455e8e988db7
Author: David Capello <davidcapello at gmail.com>
Date: Sat Nov 15 18:31:12 2014 -0300
Fix several issues with keyboard shortcuts customization
Changes:
* Now default action modifiers can be removed (fix #521)
* Now action modifiers have a KeyContext (the key context depend on the
action itself, cannot be configured by the user)
* Fix Accelerator::check() and Accelerator::operator=() when the unicode
char and scancode are nil (i.e. we are comparing only modifiers)
* Convert Accelerators to a class to simplify code
* Remove unused variables in Accelerator::check() when REPORT_KEYS is
defined
---
src/app/commands/cmd_keyboard_shortcuts.cpp | 17 ++-
src/app/ui/keyboard_shortcuts.cpp | 221 +++++++++++++++++++++-------
src/app/ui/keyboard_shortcuts.h | 12 +-
src/app/ui/select_accelerator.cpp | 12 +-
src/app/ui/select_accelerator.h | 4 +-
src/ui/accelerator.cpp | 38 ++++-
src/ui/accelerator.h | 33 ++++-
7 files changed, 261 insertions(+), 76 deletions(-)
diff --git a/src/app/commands/cmd_keyboard_shortcuts.cpp b/src/app/commands/cmd_keyboard_shortcuts.cpp
index 25c519b..6651cf4 100644
--- a/src/app/commands/cmd_keyboard_shortcuts.cpp
+++ b/src/app/commands/cmd_keyboard_shortcuts.cpp
@@ -82,12 +82,13 @@ private:
void onChangeAccel(int index) {
Accelerator origAccel = m_key->accels()[index];
- SelectAccelerator window(origAccel);
+ SelectAccelerator window(origAccel, m_key->keycontext());
window.openWindowInForeground();
if (window.isModified()) {
m_key->disableAccel(origAccel);
- m_key->add(window.accel(), KeySource::UserDefined);
+ if (!window.accel().isEmpty())
+ m_key->add(window.accel(), KeySource::UserDefined);
}
getRoot()->layout();
@@ -106,7 +107,7 @@ private:
void onAddAccel() {
ui::Accelerator accel;
- SelectAccelerator window(accel);
+ SelectAccelerator window(accel, m_key->keycontext());
window.openWindowInForeground();
if (window.isModified()) {
@@ -359,8 +360,14 @@ private:
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)";
+ switch (key->keycontext()) {
+ case KeyContext::Selection:
+ text = "Selection context: " + text;
+ break;
+ case KeyContext::MovingPixels:
+ text = "Moving pixels context: " + text;
+ break;
+ }
KeyItem* keyItem = new KeyItem(text, key, NULL, 0);
ListBox* listBox = NULL;
diff --git a/src/app/ui/keyboard_shortcuts.cpp b/src/app/ui/keyboard_shortcuts.cpp
index cb597a5..5d54719 100644
--- a/src/app/ui/keyboard_shortcuts.cpp
+++ b/src/app/ui/keyboard_shortcuts.cpp
@@ -39,8 +39,6 @@
#include "ui/accelerator.h"
#include "ui/message.h"
-#include <algorithm>
-
#define XML_KEYBOARD_FILE_VERSION "1"
namespace {
@@ -80,6 +78,13 @@ namespace {
return shortcut;
}
+ bool bool_attr_is_true(const TiXmlElement* elem, const char* attribute_name)
+ {
+ const char* value = elem->Attribute(attribute_name);
+
+ return (value != NULL) && (strcmp(value, "true") == 0);
+ }
+
std::string get_user_friendly_string_for_keyaction(app::KeyAction action)
{
for (int c=0; actions[c].name; ++c) {
@@ -118,6 +123,9 @@ namespace app {
using namespace ui;
+//////////////////////////////////////////////////////////////////////
+// Key
+
Key::Key(Command* command, const Params* params, KeyContext keyContext)
: m_type(KeyType::Command)
, m_useUsers(false)
@@ -141,12 +149,38 @@ Key::Key(KeyAction action)
, m_keycontext(KeyContext::Any)
, m_action(action)
{
-}
-
-void Key::setUserAccels(const Accelerators& accels)
-{
- m_useUsers = true;
- m_users = accels;
+ switch (action) {
+ case KeyAction::None:
+ m_keycontext = KeyContext::Any;
+ break;
+ case KeyAction::CopySelection:
+ m_keycontext = KeyContext::MovingPixels;
+ break;
+ case KeyAction::SnapToGrid:
+ m_keycontext = KeyContext::MovingPixels;
+ break;
+ case KeyAction::AngleSnap:
+ m_keycontext = KeyContext::MovingPixels;
+ break;
+ case KeyAction::MaintainAspectRatio:
+ m_keycontext = KeyContext::MovingPixels;
+ break;
+ case KeyAction::LockAxis:
+ m_keycontext = KeyContext::MovingPixels;
+ break;
+ case KeyAction::AddSelection:
+ m_keycontext = KeyContext::Selection;
+ break;
+ case KeyAction::SubtractSelection:
+ m_keycontext = KeyContext::Selection;
+ break;
+ case KeyAction::LeftMouseButton:
+ m_keycontext = KeyContext::Any;
+ break;
+ case KeyAction::RightMouseButton:
+ m_keycontext = KeyContext::Any;
+ break;
+ }
}
void Key::add(const ui::Accelerator& accel, KeySource source)
@@ -159,11 +193,16 @@ void Key::add(const ui::Accelerator& accel, KeySource source)
m_users = m_accels;
}
accels = &m_users;
+ }
- KeyboardShortcuts::instance()->disableAccel(accel);
+ // Remove the accelerator from other commands
+ if (source == KeySource::UserDefined) {
+ KeyboardShortcuts::instance()->disableAccel(accel, m_keycontext);
+ m_userRemoved.remove(accel);
}
- accels->push_back(accel);
+ // Add the accelerator
+ accels->add(accel);
}
bool Key::isPressed(Message* msg) const
@@ -194,7 +233,7 @@ bool Key::checkFromAllegroKeyArray()
bool Key::hasAccel(const ui::Accelerator& accel) const
{
- return (std::find(accels().begin(), accels().end(), accel) != accels().end());
+ return accels().has(accel);
}
void Key::disableAccel(const ui::Accelerator& accel)
@@ -204,14 +243,16 @@ void Key::disableAccel(const ui::Accelerator& accel)
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);
+ m_users.remove(accel);
+
+ if (m_accels.has(accel))
+ m_userRemoved.add(accel);
}
void Key::reset()
{
m_users.clear();
+ m_userRemoved.clear();
m_useUsers = false;
}
@@ -235,6 +276,9 @@ std::string Key::triggerString() const
return "Unknown";
}
+//////////////////////////////////////////////////////////////////////
+// KeyboardShortcuts
+
KeyboardShortcuts* KeyboardShortcuts::instance()
{
static KeyboardShortcuts* singleton = NULL;
@@ -270,6 +314,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
while (xmlKey) {
const char* command_name = xmlKey->Attribute("command");
const char* command_key = get_shortcut(xmlKey);
+ bool removed = bool_attr_is_true(xmlKey, "removed");
if (command_name && command_key) {
Command* command = CommandsModule::instance()->getCommandByName(command_name);
@@ -303,15 +348,21 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
// 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);
+ Accelerator accel(command_key);
+
+ if (!removed) {
+ key->add(accel, 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);
+ }
}
+ else
+ key->disableAccel(accel);
}
}
}
@@ -327,6 +378,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
while (xmlKey) {
const char* tool_id = xmlKey->Attribute("tool");
const char* tool_key = get_shortcut(xmlKey);
+ bool removed = bool_attr_is_true(xmlKey, "removed");
if (tool_id && tool_key) {
tools::Tool* tool = App::instance()->getToolBox()->getToolById(tool_id);
@@ -334,8 +386,14 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
PRINTF(" - Shortcut for tool `%s': <%s>\n", tool_id, tool_key);
Key* key = this->tool(tool);
- if (key)
- key->add(Accelerator(tool_key), source);
+ if (key) {
+ Accelerator accel(tool_key);
+
+ if (!removed)
+ key->add(accel, source);
+ else
+ key->disableAccel(accel);
+ }
}
}
xmlKey = xmlKey->NextSiblingElement();
@@ -349,14 +407,22 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
while (xmlKey) {
const char* tool_id = xmlKey->Attribute("tool");
const char* tool_key = get_shortcut(xmlKey);
+ bool removed = bool_attr_is_true(xmlKey, "removed");
+
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);
+ if (key) {
+ Accelerator accel(tool_key);
+
+ if (!removed)
+ key->add(accel, source);
+ else
+ key->disableAccel(accel);
+ }
}
}
xmlKey = xmlKey->NextSiblingElement();
@@ -370,6 +436,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
while (xmlKey) {
const char* tool_action = xmlKey->Attribute("action");
const char* tool_key = get_shortcut(xmlKey);
+ bool removed = bool_attr_is_true(xmlKey, "removed");
if (tool_action && tool_key) {
PRINTF(" - Shortcut for sprite editor `%s': <%s>\n", tool_action, tool_key);
@@ -378,8 +445,14 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
if (action != KeyAction::None) {
Key* key = this->action(action);
- if (key)
- key->add(Accelerator(tool_key), source);
+ if (key) {
+ Accelerator accel(tool_key);
+
+ if (!removed)
+ key->add(accel, source);
+ else
+ key->disableAccel(accel);
+ }
}
}
xmlKey = xmlKey->NextSiblingElement();
@@ -424,41 +497,77 @@ void KeyboardShortcuts::exportKeys(TiXmlElement& parent, KeyType type)
{
for (Key* key : m_keys) {
// Save only user defined accelerators.
- if (key->type() != type || key->userAccels().empty())
+ if (key->type() != type)
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);
- }
- }
+ for (const ui::Accelerator& accel : key->userRemovedAccels())
+ exportAccel(parent, key, accel, true);
+
+ for (const ui::Accelerator& accel : key->userAccels())
+ exportAccel(parent, key, accel, false);
+ }
+}
+
+void KeyboardShortcuts::exportAccel(TiXmlElement& parent, Key* key, const ui::Accelerator& accel, bool removed)
+{
+ TiXmlElement elem("key");
+
+ switch (key->type()) {
+
+ case KeyType::Command: {
+ const char* keycontextStr = NULL;
+
+ elem.SetAttribute("command", key->command()->short_name());
+
+ switch (key->keycontext()) {
+ case KeyContext::Any:
+ // Without "context" attribute
break;
- case KeyType::Tool:
- case KeyType::Quicktool:
- elem.SetAttribute("tool", key->tool()->getId().c_str());
+ case KeyContext::Normal:
+ keycontextStr = "Normal";
break;
- case KeyType::Action:
- elem.SetAttribute("action",
- base::convert_to<std::string>(key->action()).c_str());
+ case KeyContext::Selection:
+ keycontextStr = "Selection";
+ break;
+ case KeyContext::MovingPixels:
+ keycontextStr = "MovingPixels";
break;
}
- elem.SetAttribute("shortcut", accel.toString().c_str());
- parent.InsertEndChild(elem);
+ if (keycontextStr)
+ elem.SetAttribute("context", keycontextStr);
+
+ 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());
+
+ if (removed)
+ elem.SetAttribute("removed", "true");
+
+ parent.InsertEndChild(elem);
}
void KeyboardShortcuts::reset()
@@ -531,10 +640,10 @@ Key* KeyboardShortcuts::action(KeyAction action)
return key;
}
-void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel)
+void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel, KeyContext keyContext)
{
for (Key* key : m_keys) {
- if (key->hasAccel(accel))
+ if (key->keycontext() == keyContext && key->hasAccel(accel))
key->disableAccel(accel);
}
}
diff --git a/src/app/ui/keyboard_shortcuts.h b/src/app/ui/keyboard_shortcuts.h
index 4c70986..65a61aa 100644
--- a/src/app/ui/keyboard_shortcuts.h
+++ b/src/app/ui/keyboard_shortcuts.h
@@ -44,6 +44,7 @@ namespace app {
Any,
Normal,
Selection,
+ MovingPixels,
};
enum class KeySource {
@@ -83,8 +84,7 @@ namespace app {
}
const ui::Accelerators& origAccels() const { return m_accels; }
const ui::Accelerators& userAccels() const { return m_users; }
-
- void setUserAccels(const ui::Accelerators& accels);
+ const ui::Accelerators& userRemovedAccels() const { return m_userRemoved; }
void add(const ui::Accelerator& accel, KeySource source);
bool isPressed(ui::Message* msg) const;
@@ -109,8 +109,9 @@ namespace app {
private:
KeyType m_type;
- ui::Accelerators m_accels;
- ui::Accelerators m_users;
+ ui::Accelerators m_accels; // Default accelerators (from gui.xml)
+ ui::Accelerators m_users; // User-defined accelerators
+ ui::Accelerators m_userRemoved; // Default accelerators removed by user
bool m_useUsers;
KeyContext m_keycontext;
@@ -149,7 +150,7 @@ namespace app {
Key* quicktool(tools::Tool* tool);
Key* action(KeyAction action);
- void disableAccel(const ui::Accelerator& accel);
+ void disableAccel(const ui::Accelerator& accel, KeyContext keyContext);
KeyContext getCurrentKeyContext();
bool getCommandFromKeyMessage(ui::Message* msg, Command** command, Params** params);
@@ -159,6 +160,7 @@ namespace app {
KeyboardShortcuts();
void exportKeys(TiXmlElement& parent, KeyType type);
+ void exportAccel(TiXmlElement& parent, Key* key, const ui::Accelerator& accel, bool removed);
Keys m_keys;
diff --git a/src/app/ui/select_accelerator.cpp b/src/app/ui/select_accelerator.cpp
index e5ee3e9..046136d 100644
--- a/src/app/ui/select_accelerator.cpp
+++ b/src/app/ui/select_accelerator.cpp
@@ -63,6 +63,12 @@ protected:
keymsg->scancode(),
keymsg->unicodeChar() > 32 ?
std::tolower(keymsg->unicodeChar()): 0);
+
+ // Convert the accelerator to a string, and parse it
+ // again. Just to obtain the exact accelerator we'll read
+ // when we import the gui.xml file or an .aseprite-keys file.
+ m_accel = Accelerator(m_accel.toString());
+
updateText();
AccelChange(&m_accel);
@@ -84,8 +90,9 @@ protected:
Accelerator m_accel;
};
-SelectAccelerator::SelectAccelerator(const ui::Accelerator& accel)
+SelectAccelerator::SelectAccelerator(const ui::Accelerator& accel, KeyContext keyContext)
: m_keyField(new KeyField(accel))
+ , m_keyContext(keyContext)
, m_accel(accel)
, m_modified(false)
{
@@ -170,7 +177,8 @@ void SelectAccelerator::updateAssignedTo()
std::string res = "None";
for (Key* key : *KeyboardShortcuts::instance()) {
- if (key->hasAccel(m_accel)) {
+ if (key->keycontext() == m_keyContext &&
+ key->hasAccel(m_accel)) {
res = key->triggerString();
break;
}
diff --git a/src/app/ui/select_accelerator.h b/src/app/ui/select_accelerator.h
index 475d8c2..843fb28 100644
--- a/src/app/ui/select_accelerator.h
+++ b/src/app/ui/select_accelerator.h
@@ -20,6 +20,7 @@
#define APP_UI_SELECT_ACCELERATOR_H_INCLUDED
#pragma once
+#include "app/ui/keyboard_shortcuts.h"
#include "ui/accelerator.h"
#include "generated_select_accelerator.h"
@@ -28,7 +29,7 @@ namespace app {
class SelectAccelerator : public app::gen::SelectAccelerator {
public:
- explicit SelectAccelerator(const ui::Accelerator& accelerator);
+ SelectAccelerator(const ui::Accelerator& accelerator, KeyContext keyContext);
bool isModified() const { return m_modified; }
const ui::Accelerator& accel() const { return m_accel; }
@@ -45,6 +46,7 @@ namespace app {
class KeyField;
KeyField* m_keyField;
+ KeyContext m_keyContext;
ui::Accelerator m_origAccel;
ui::Accelerator m_accel;
bool m_modified;
diff --git a/src/ui/accelerator.cpp b/src/ui/accelerator.cpp
index d5a9885..4afcbc4 100644
--- a/src/ui/accelerator.cpp
+++ b/src/ui/accelerator.cpp
@@ -19,11 +19,16 @@
#include <string>
#include <vector>
+#include <algorithm>
+
// #define REPORT_KEYS
#define PREPROCESS_KEYS
namespace ui {
+//////////////////////////////////////////////////////////////////////
+// Accelerator
+
Accelerator::Accelerator()
: m_modifiers(kKeyNoneModifier)
, m_scancode(kKeyNil)
@@ -197,6 +202,8 @@ bool Accelerator::operator==(const Accelerator& other) const
return true;
else if (m_unicodeChar != 0)
return (std::tolower(m_unicodeChar) == std::tolower(other.m_unicodeChar));
+ else // Only comparing modifiers, and they are equal
+ return true;
}
return false;
@@ -345,11 +352,6 @@ std::string Accelerator::toString() const
bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar) const
{
-#ifdef REPORT_KEYS
- char buf[256];
- std::string buf2;
-#endif
-
// Preprocess the character to be compared with the accelerator
#ifdef PREPROCESS_KEYS
// Directly scancode
@@ -411,15 +413,18 @@ bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicod
if ((m_modifiers == modifiers) &&
((m_scancode != kKeyNil && m_scancode == scancode) ||
- (m_unicodeChar && m_unicodeChar == unicodeChar))) {
+ (m_unicodeChar && m_unicodeChar == unicodeChar) ||
+ (m_scancode == kKeyNil && scancode == kKeyNil && !m_unicodeChar && !unicodeChar))) {
#ifdef REPORT_KEYS
printf("true\n");
+ fflush(stdout);
#endif
return true;
}
#ifdef REPORT_KEYS
printf("false\n");
+ fflush(stdout);
#endif
return false;
}
@@ -439,4 +444,25 @@ bool Accelerator::checkFromAllegroKeyArray() const
(m_modifiers == modifiers));
}
+//////////////////////////////////////////////////////////////////////
+// Accelerators
+
+bool Accelerators::has(const Accelerator& accel) const
+{
+ return (std::find(begin(), end(), accel) != end());
+}
+
+void Accelerators::add(const Accelerator& accel)
+{
+ if (!has(accel))
+ m_list.push_back(accel);
+}
+
+void Accelerators::remove(const Accelerator& accel)
+{
+ auto it = std::find(begin(), end(), accel);
+ if (it != end())
+ m_list.erase(it);
+}
+
} // namespace ui
diff --git a/src/ui/accelerator.h b/src/ui/accelerator.h
index 7014374..cecc663 100644
--- a/src/ui/accelerator.h
+++ b/src/ui/accelerator.h
@@ -43,7 +43,38 @@ namespace ui {
int m_unicodeChar;
};
- typedef std::vector<Accelerator> Accelerators;
+ class Accelerators {
+ public:
+ typedef std::vector<Accelerator> List;
+ typedef List::iterator iterator;
+ typedef List::const_iterator const_iterator;
+
+ iterator begin() { return m_list.begin(); }
+ iterator end() { return m_list.end(); }
+ const_iterator begin() const { return m_list.begin(); }
+ const_iterator end() const { return m_list.end(); }
+
+ bool empty() const { return m_list.empty(); }
+ size_t size() const { return m_list.size(); }
+
+ const ui::Accelerator& front() const { return m_list.front(); }
+
+ const ui::Accelerator& operator[](int index) const {
+ return m_list[index];
+ }
+
+ ui::Accelerator& operator[](int index) {
+ return m_list[index];
+ }
+
+ void clear() { m_list.clear(); }
+ bool has(const Accelerator& accel) const;
+ void add(const Accelerator& accel);
+ void remove(const Accelerator& accel);
+
+ private:
+ List m_list;
+ };
} // namespace ui
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/aseprite.git
More information about the Pkg-games-commits
mailing list