mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-17 13:20:45 +00:00
Don't use KeyboardShortcuts singleton for temporal changes in Keyboard Shortcuts dialog
Main changes: - Improve the "Keyboard Shortcuts" dialog because instead of changing global shortcuts/menu keys and rollback everything if we select "Cancel", here we make a copy of all shortcuts, modify them in the dialog UI, and finally "commit" to the global shortcuts if the user confirms the dialog. - Fix "Reset" button in "Keyboard Shortcuts" dialog for mouse wheel customization
This commit is contained in:
parent
c5fda62173
commit
413603a71a
@ -11,7 +11,6 @@
|
||||
#include "app/app.h"
|
||||
#include "app/app_menus.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/context.h"
|
||||
#include "app/file_selector.h"
|
||||
#include "app/i18n/strings.h"
|
||||
@ -44,8 +43,7 @@
|
||||
|
||||
#include "keyboard_shortcuts.xml.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#define KEYBOARD_FILENAME_EXTENSION "aseprite-keys"
|
||||
|
||||
@ -57,6 +55,8 @@ using namespace ui;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef std::map<AppMenuItem*, KeyPtr> MenuKeys;
|
||||
|
||||
class HeaderSplitter : public Splitter {
|
||||
public:
|
||||
HeaderSplitter() : Splitter(Splitter::ByPixel, HORIZONTAL) {
|
||||
@ -126,12 +126,16 @@ class KeyItem : public ListItem {
|
||||
};
|
||||
|
||||
public:
|
||||
KeyItem(const std::string& text,
|
||||
KeyItem(KeyboardShortcuts& keys,
|
||||
MenuKeys& menuKeys,
|
||||
const std::string& text,
|
||||
const KeyPtr& key,
|
||||
AppMenuItem* menuitem,
|
||||
const int level,
|
||||
HeaderItem* headerItem)
|
||||
: ListItem(text)
|
||||
, m_keys(keys)
|
||||
, m_menuKeys(menuKeys)
|
||||
, m_key(key)
|
||||
, m_keyOrig(key ? new Key(*key): nullptr)
|
||||
, m_menuitem(menuitem)
|
||||
@ -148,14 +152,6 @@ public:
|
||||
KeyPtr key() { return m_key; }
|
||||
AppMenuItem* menuitem() const { return m_menuitem; }
|
||||
|
||||
void restoreKeys() {
|
||||
if (m_key && m_keyOrig)
|
||||
*m_key = *m_keyOrig;
|
||||
|
||||
if (m_menuitem && !m_keyOrig)
|
||||
m_menuitem->setKey(nullptr);
|
||||
}
|
||||
|
||||
std::string searchableText() const {
|
||||
if (m_menuitem) {
|
||||
Widget* w = m_menuitem;
|
||||
@ -187,22 +183,18 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void onAccelChange(const Accelerator& accel);
|
||||
|
||||
void onChangeAccel(int index) {
|
||||
LockButtons lock(this);
|
||||
Accelerator origAccel = m_key->accels()[index];
|
||||
SelectAccelerator window(origAccel,
|
||||
m_key->keycontext(),
|
||||
KeyboardShortcuts::instance()->keys());
|
||||
m_keys);
|
||||
window.openWindowInForeground();
|
||||
|
||||
if (window.isModified()) {
|
||||
onAccelChange(window.accel());
|
||||
|
||||
m_key->disableAccel(origAccel);
|
||||
if (!window.accel().isEmpty())
|
||||
m_key->add(window.accel(), KeySource::UserDefined);
|
||||
m_key->add(window.accel(), KeySource::UserDefined, m_keys);
|
||||
}
|
||||
|
||||
this->window()->layout();
|
||||
@ -229,7 +221,7 @@ private:
|
||||
ui::Accelerator accel;
|
||||
SelectAccelerator window(accel,
|
||||
m_key ? m_key->keycontext(): KeyContext::Any,
|
||||
KeyboardShortcuts::instance()->keys());
|
||||
m_keys);
|
||||
window.openWindowInForeground();
|
||||
|
||||
if ((window.isModified()) ||
|
||||
@ -240,15 +232,16 @@ private:
|
||||
if (!m_menuitem)
|
||||
return;
|
||||
|
||||
m_key = app::KeyboardShortcuts::instance()->command(
|
||||
ASSERT(m_menuitem->getCommand());
|
||||
|
||||
m_key = m_keys.command(
|
||||
m_menuitem->getCommand()->id().c_str(),
|
||||
m_menuitem->getParams());
|
||||
|
||||
m_menuitem->setKey(m_key);
|
||||
m_menuKeys[m_menuitem] = m_key;
|
||||
}
|
||||
|
||||
onAccelChange(window.accel());
|
||||
m_key->add(window.accel(), KeySource::UserDefined);
|
||||
m_key->add(window.accel(), KeySource::UserDefined, m_keys);
|
||||
}
|
||||
|
||||
this->window()->layout();
|
||||
@ -462,6 +455,8 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
KeyboardShortcuts& m_keys;
|
||||
MenuKeys& m_menuKeys;
|
||||
KeyPtr m_key;
|
||||
KeyPtr m_keyOrig;
|
||||
AppMenuItem* m_menuitem;
|
||||
@ -480,8 +475,12 @@ private:
|
||||
|
||||
class KeyboardShortcutsWindow : public app::gen::KeyboardShortcuts {
|
||||
public:
|
||||
KeyboardShortcutsWindow(const std::string& searchText)
|
||||
: m_searchChange(false)
|
||||
KeyboardShortcutsWindow(app::KeyboardShortcuts& keys,
|
||||
MenuKeys& menuKeys,
|
||||
const std::string& searchText)
|
||||
: m_keys(keys)
|
||||
, m_menuKeys(menuKeys)
|
||||
, m_searchChange(false)
|
||||
, m_wasDefault(false) {
|
||||
setAutoRemap(false);
|
||||
|
||||
@ -498,20 +497,13 @@ public:
|
||||
#endif
|
||||
|
||||
wheelBehavior()->setSelectedItem(
|
||||
app::KeyboardShortcuts::instance()->hasMouseWheelCustomization() ? 1: 0);
|
||||
m_keys.hasMouseWheelCustomization() ? 1: 0);
|
||||
if (isDefaultWheelBehavior()) {
|
||||
m_wheelKeys = app::KeyboardShortcuts::instance()
|
||||
->getDefaultMouseWheelTable(wheelZoom()->isSelected());
|
||||
m_keys.setDefaultMouseWheelKeys(wheelZoom()->isSelected());
|
||||
m_wasDefault = true;
|
||||
}
|
||||
else {
|
||||
for (const KeyPtr& key : *app::KeyboardShortcuts::instance()) {
|
||||
if (key->type() == KeyType::WheelAction)
|
||||
m_wheelKeys.push_back(std::make_shared<Key>(*key));
|
||||
}
|
||||
}
|
||||
m_keys.addMissingMouseWheelKeys();
|
||||
updateSlideZoomText();
|
||||
addMissingWheelKeys();
|
||||
|
||||
onWheelBehaviorChange();
|
||||
|
||||
@ -536,31 +528,10 @@ public:
|
||||
deleteAllKeyItems();
|
||||
}
|
||||
|
||||
void restoreKeys() {
|
||||
for (KeyItem* keyItem : m_allKeyItems) {
|
||||
keyItem->restoreKeys();
|
||||
}
|
||||
}
|
||||
|
||||
const Keys& wheelKeys() {
|
||||
return m_wheelKeys;
|
||||
}
|
||||
|
||||
bool isDefaultWheelBehavior() {
|
||||
return (wheelBehavior()->selectedItem() == 0);
|
||||
}
|
||||
|
||||
void disableWheelKey(const Accelerator& accel) {
|
||||
for (KeyPtr& key : m_wheelKeys) {
|
||||
for (int i=0; i<key->accels().size(); ++i) {
|
||||
if (key->accels()[i] == accel) {
|
||||
key->disableAccel(accel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void deleteAllKeyItems() {
|
||||
deleteList(searchList());
|
||||
@ -569,7 +540,6 @@ private:
|
||||
deleteList(tools());
|
||||
deleteList(actions());
|
||||
deleteList(wheelActions());
|
||||
ASSERT(m_allKeyItems.empty());
|
||||
}
|
||||
|
||||
void fillAllLists() {
|
||||
@ -578,8 +548,9 @@ private:
|
||||
// Load keyboard shortcuts
|
||||
fillMenusList(menus(), AppMenus::instance()->getRootMenu(), 0);
|
||||
fillToolsList(tools(), App::instance()->toolBox());
|
||||
fillWheelActionsList();
|
||||
|
||||
for (const KeyPtr& key : *app::KeyboardShortcuts::instance()) {
|
||||
for (const KeyPtr& key : m_keys) {
|
||||
if (key->type() == KeyType::Tool ||
|
||||
key->type() == KeyType::Quicktool ||
|
||||
key->type() == KeyType::WheelAction) {
|
||||
@ -600,7 +571,8 @@ private:
|
||||
+ ": " + text;
|
||||
break;
|
||||
}
|
||||
KeyItem* keyItem = new KeyItem(text, key, nullptr, 0, &m_headerItem);
|
||||
KeyItem* keyItem = new KeyItem(m_keys, m_menuKeys, text, key,
|
||||
nullptr, 0, &m_headerItem);
|
||||
|
||||
ListBox* listBox = nullptr;
|
||||
switch (key->type()) {
|
||||
@ -613,18 +585,14 @@ private:
|
||||
}
|
||||
|
||||
ASSERT(listBox);
|
||||
if (listBox) {
|
||||
m_allKeyItems.push_back(keyItem);
|
||||
if (listBox)
|
||||
listBox->addChild(keyItem);
|
||||
}
|
||||
}
|
||||
|
||||
commands()->sortItems();
|
||||
tools()->sortItems();
|
||||
actions()->sortItems();
|
||||
|
||||
fillWheelActionsList();
|
||||
|
||||
section()->selectIndex(0);
|
||||
updateViews();
|
||||
}
|
||||
@ -636,11 +604,6 @@ private:
|
||||
while (listbox->lastChild()) {
|
||||
Widget* item = listbox->lastChild();
|
||||
listbox->removeChild(item);
|
||||
|
||||
auto it = std::find(m_allKeyItems.begin(), m_allKeyItems.end(), item);
|
||||
if (it != m_allKeyItems.end())
|
||||
m_allKeyItems.erase(it);
|
||||
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
@ -667,15 +630,12 @@ private:
|
||||
}
|
||||
|
||||
KeyItem* copyItem =
|
||||
new KeyItem(itemText,
|
||||
keyItem->key(),
|
||||
keyItem->menuitem(), 0,
|
||||
&m_headerItem);
|
||||
new KeyItem(m_keys, m_menuKeys, itemText, keyItem->key(),
|
||||
keyItem->menuitem(), 0, &m_headerItem);
|
||||
|
||||
if (!item->isEnabled())
|
||||
copyItem->setEnabled(false);
|
||||
|
||||
m_allKeyItems.push_back(copyItem);
|
||||
searchList()->addChild(copyItem);
|
||||
}
|
||||
}
|
||||
@ -690,17 +650,18 @@ private:
|
||||
wheelZoom()->setVisible(isDefault);
|
||||
|
||||
if (isDefault) {
|
||||
m_wheelKeys = app::KeyboardShortcuts::instance()
|
||||
->getDefaultMouseWheelTable(wheelZoom()->isSelected());
|
||||
m_keys.setDefaultMouseWheelKeys(wheelZoom()->isSelected());
|
||||
m_wasDefault = true;
|
||||
}
|
||||
else if (m_wasDefault) {
|
||||
m_wasDefault = false;
|
||||
for (KeyPtr& key : m_wheelKeys)
|
||||
key->copyOriginalToUser();
|
||||
for (KeyPtr& key : m_keys) {
|
||||
if (key->type() == KeyType::WheelAction)
|
||||
key->copyOriginalToUser();
|
||||
}
|
||||
}
|
||||
m_keys.addMissingMouseWheelKeys();
|
||||
updateSlideZoomText();
|
||||
addMissingWheelKeys();
|
||||
|
||||
fillWheelActionsList();
|
||||
updateViews();
|
||||
@ -715,10 +676,13 @@ private:
|
||||
|
||||
void fillWheelActionsList() {
|
||||
deleteList(wheelActions());
|
||||
for (const KeyPtr& key : m_wheelKeys) {
|
||||
KeyItem* keyItem = new KeyItem(
|
||||
key->triggerString(), key, nullptr, 0, &m_headerItem);
|
||||
wheelActions()->addChild(keyItem);
|
||||
for (const KeyPtr& key : m_keys) {
|
||||
if (key->type() == KeyType::WheelAction) {
|
||||
KeyItem* keyItem = new KeyItem(
|
||||
m_keys, m_menuKeys, key->triggerString(), key,
|
||||
nullptr, 0, &m_headerItem);
|
||||
wheelActions()->addChild(keyItem);
|
||||
}
|
||||
}
|
||||
wheelActions()->sortItems();
|
||||
}
|
||||
@ -780,8 +744,7 @@ private:
|
||||
|
||||
ASSERT(!filename.empty());
|
||||
|
||||
app::KeyboardShortcuts::instance()->importFile(
|
||||
filename.front(), KeySource::UserDefined);
|
||||
m_keys.importFile(filename.front(), KeySource::UserDefined);
|
||||
|
||||
fillAllLists();
|
||||
}
|
||||
@ -797,12 +760,12 @@ private:
|
||||
|
||||
ASSERT(!filename.empty());
|
||||
|
||||
app::KeyboardShortcuts::instance()->exportFile(filename.front());
|
||||
m_keys.exportFile(filename.front());
|
||||
}
|
||||
|
||||
void onReset() {
|
||||
if (ui::Alert::show(Strings::alerts_restore_all_shortcuts()) == 1) {
|
||||
app::KeyboardShortcuts::instance()->reset();
|
||||
m_keys.reset();
|
||||
listsPlaceholder()->layout();
|
||||
}
|
||||
}
|
||||
@ -814,11 +777,12 @@ private:
|
||||
continue;
|
||||
|
||||
KeyItem* keyItem = new KeyItem(
|
||||
m_keys, m_menuKeys,
|
||||
menuItem->text().c_str(),
|
||||
menuItem->key(), menuItem, level,
|
||||
m_menuKeys[menuItem],
|
||||
menuItem, level,
|
||||
&m_headerItem);
|
||||
|
||||
m_allKeyItems.push_back(keyItem);
|
||||
listbox->addChild(keyItem);
|
||||
|
||||
if (menuItem->hasSubmenu())
|
||||
@ -831,54 +795,27 @@ private:
|
||||
for (Tool* tool : *toolbox) {
|
||||
std::string text = tool->getText();
|
||||
|
||||
KeyPtr key = app::KeyboardShortcuts::instance()->tool(tool);
|
||||
KeyItem* keyItem = new KeyItem(text, key, nullptr, 0,
|
||||
&m_headerItem);
|
||||
m_allKeyItems.push_back(keyItem);
|
||||
KeyPtr key = m_keys.tool(tool);
|
||||
KeyItem* keyItem = new KeyItem(m_keys, m_menuKeys, text, key,
|
||||
nullptr, 0, &m_headerItem);
|
||||
listbox->addChild(keyItem);
|
||||
|
||||
text += " (quick)";
|
||||
key = app::KeyboardShortcuts::instance()->quicktool(tool);
|
||||
keyItem = new KeyItem(text, key, nullptr, 0,
|
||||
&m_headerItem);
|
||||
m_allKeyItems.push_back(keyItem);
|
||||
key = m_keys.quicktool(tool);
|
||||
keyItem = new KeyItem(m_keys, m_menuKeys, text, key,
|
||||
nullptr, 0, &m_headerItem);
|
||||
listbox->addChild(keyItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds missing WhellAction in m_wheelKeys
|
||||
void addMissingWheelKeys() {
|
||||
for (int wheelAction=int(WheelAction::First);
|
||||
wheelAction<=int(WheelAction::Last); ++wheelAction) {
|
||||
auto it = std::find_if(
|
||||
m_wheelKeys.begin(), m_wheelKeys.end(),
|
||||
[wheelAction](const KeyPtr& key) -> bool {
|
||||
return key->wheelAction() == (WheelAction)wheelAction;
|
||||
});
|
||||
if (it == m_wheelKeys.end()) {
|
||||
KeyPtr key = std::make_shared<Key>((WheelAction)wheelAction);
|
||||
m_wheelKeys.push_back(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app::KeyboardShortcuts& m_keys;
|
||||
MenuKeys& m_menuKeys;
|
||||
std::vector<ListBox*> m_listBoxes;
|
||||
std::vector<KeyItem*> m_allKeyItems;
|
||||
bool m_searchChange;
|
||||
bool m_wasDefault;
|
||||
HeaderItem m_headerItem;
|
||||
Keys m_wheelKeys;
|
||||
};
|
||||
|
||||
void KeyItem::onAccelChange(const Accelerator& accel)
|
||||
{
|
||||
if (m_key && m_key->type() == KeyType::WheelAction) {
|
||||
auto window = dynamic_cast<KeyboardShortcutsWindow*>(this->window());
|
||||
if (window)
|
||||
window->disableWheelKey(accel);
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class KeyboardShortcutsCommand : public Command {
|
||||
@ -891,7 +828,8 @@ protected:
|
||||
void onExecute(Context* context) override;
|
||||
|
||||
private:
|
||||
void addMissingKeyboardShortcutsForCommands();
|
||||
void fillMenusKeys(app::KeyboardShortcuts& keys,
|
||||
MenuKeys& menuKeys, Menu* menu);
|
||||
|
||||
std::string m_search;
|
||||
};
|
||||
@ -908,14 +846,20 @@ void KeyboardShortcutsCommand::onLoadParams(const Params& params)
|
||||
|
||||
void KeyboardShortcutsCommand::onExecute(Context* context)
|
||||
{
|
||||
addMissingKeyboardShortcutsForCommands();
|
||||
app::KeyboardShortcuts* globalKeys = app::KeyboardShortcuts::instance();
|
||||
app::KeyboardShortcuts keys;
|
||||
keys.setKeys(*globalKeys, true);
|
||||
keys.addMissingKeysForCommands();
|
||||
|
||||
MenuKeys menuKeys;
|
||||
fillMenusKeys(keys, menuKeys, AppMenus::instance()->getRootMenu());
|
||||
|
||||
// Here we copy the m_search field because
|
||||
// KeyboardShortcutsWindow::fillAllLists() modifies this same
|
||||
// KeyboardShortcutsCommand instance (so m_search will be "")
|
||||
// TODO Seeing this, we need a complete new way to handle UI commands execution
|
||||
std::string neededSearchCopy = m_search;
|
||||
KeyboardShortcutsWindow window(neededSearchCopy);
|
||||
KeyboardShortcutsWindow window(keys, menuKeys, neededSearchCopy);
|
||||
|
||||
window.setBounds(gfx::Rect(0, 0, ui::display_w()*3/4, ui::display_h()*3/4));
|
||||
|
||||
@ -924,7 +868,9 @@ void KeyboardShortcutsCommand::onExecute(Context* context)
|
||||
window.openWindowInForeground();
|
||||
|
||||
if (window.closer() == window.ok()) {
|
||||
KeyboardShortcuts::instance()->UserChange();
|
||||
globalKeys->setKeys(keys, false);
|
||||
for (const auto& p : menuKeys)
|
||||
p.first->setKey(p.second);
|
||||
|
||||
// Save preferences in widgets that are bound to options automatically
|
||||
{
|
||||
@ -933,65 +879,36 @@ void KeyboardShortcutsCommand::onExecute(Context* context)
|
||||
window.sendMessage(msg);
|
||||
}
|
||||
|
||||
if (window.isDefaultWheelBehavior()) {
|
||||
for (KeyPtr& key : *KeyboardShortcuts::instance()) {
|
||||
if (key->type() == KeyType::WheelAction)
|
||||
key->reset();
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const KeyPtr& srcKey : window.wheelKeys()) {
|
||||
KeyPtr dstKey = KeyboardShortcuts::instance()->wheelAction(srcKey->wheelAction());
|
||||
*dstKey = *srcKey;
|
||||
}
|
||||
}
|
||||
|
||||
// Save keyboard shortcuts in configuration file
|
||||
{
|
||||
ResourceFinder rf;
|
||||
rf.includeUserDir("user." KEYBOARD_FILENAME_EXTENSION);
|
||||
std::string fn = rf.getFirstOrCreateDefault();
|
||||
KeyboardShortcuts::instance()->exportFile(fn);
|
||||
globalKeys->exportFile(fn);
|
||||
}
|
||||
}
|
||||
else {
|
||||
window.restoreKeys();
|
||||
}
|
||||
|
||||
AppMenus::instance()->syncNativeMenuItemKeyShortcuts();
|
||||
}
|
||||
|
||||
void KeyboardShortcutsCommand::addMissingKeyboardShortcutsForCommands()
|
||||
void KeyboardShortcutsCommand::fillMenusKeys(app::KeyboardShortcuts& keys,
|
||||
MenuKeys& menuKeys,
|
||||
Menu* menu)
|
||||
{
|
||||
std::set<std::string> commandsAlreadyAdded;
|
||||
auto keys = app::KeyboardShortcuts::instance();
|
||||
for (const KeyPtr& key : *keys) {
|
||||
if (key->type() != KeyType::Command)
|
||||
continue;
|
||||
for (auto child : menu->children()) {
|
||||
if (AppMenuItem* menuItem = dynamic_cast<AppMenuItem*>(child)) {
|
||||
if (menuItem == AppMenus::instance()->getRecentListMenuitem())
|
||||
continue;
|
||||
|
||||
if (key->params().empty())
|
||||
commandsAlreadyAdded.insert(key->command()->id());
|
||||
}
|
||||
if (menuItem->getCommand()) {
|
||||
menuKeys[menuItem] =
|
||||
keys.command(menuItem->getCommand()->id().c_str(),
|
||||
menuItem->getParams());
|
||||
}
|
||||
|
||||
std::vector<std::string> ids;
|
||||
Commands* commands = Commands::instance();
|
||||
commands->getAllIds(ids);
|
||||
|
||||
for (const std::string& id : ids) {
|
||||
Command* command = commands->byId(id.c_str());
|
||||
|
||||
// Don't add commands that need params (they will be added to
|
||||
// the list using the list of keyboard shortcuts from gui.xml).
|
||||
if (command->needsParams())
|
||||
continue;
|
||||
|
||||
auto it = commandsAlreadyAdded.find(command->id());
|
||||
if (it != commandsAlreadyAdded.end())
|
||||
continue;
|
||||
|
||||
// Create the new Key element in KeyboardShortcuts for this
|
||||
// command without params.
|
||||
keys->command(command->id().c_str());
|
||||
if (menuItem->hasSubmenu())
|
||||
fillMenusKeys(keys, menuKeys, menuItem->getSubmenu());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,9 +105,9 @@ private:
|
||||
bool onProcessMessage(ui::Message* msg) override {
|
||||
switch (msg->type()) {
|
||||
case ui::kKeyDownMessage: {
|
||||
const KeyPtr key =
|
||||
KeyboardShortcuts::instance()->command(CommandId::SwitchColors());
|
||||
if (key && key->isPressed(msg)) {
|
||||
KeyboardShortcuts* keys = KeyboardShortcuts::instance();
|
||||
const KeyPtr key = keys->command(CommandId::SwitchColors());
|
||||
if (key && key->isPressed(msg, *keys)) {
|
||||
// Switch colors
|
||||
app::Color from = m_fromButton->getColor();
|
||||
app::Color to = m_toButton->getColor();
|
||||
|
@ -365,7 +365,7 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
||||
}
|
||||
break;
|
||||
|
||||
case kKeyDownMessage:
|
||||
case kKeyDownMessage: {
|
||||
#if ENABLE_DEVMODE
|
||||
if (onProcessDevModeKeyDown(static_cast<KeyMessage*>(msg)))
|
||||
return true;
|
||||
@ -377,8 +377,9 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
||||
if (Manager::onProcessMessage(msg))
|
||||
return true;
|
||||
|
||||
for (const KeyPtr& key : *KeyboardShortcuts::instance()) {
|
||||
if (key->isPressed(msg)) {
|
||||
KeyboardShortcuts* keys = KeyboardShortcuts::instance();
|
||||
for (const KeyPtr& key : *keys) {
|
||||
if (key->isPressed(msg, *keys)) {
|
||||
// Cancel menu-bar loops (to close any popup menu)
|
||||
App::instance()->mainWindow()->getMenuBar()->cancelMenuLoop();
|
||||
|
||||
@ -393,7 +394,7 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
||||
// Collect all tools with the pressed keyboard-shortcut
|
||||
for (tools::Tool* tool : *toolbox) {
|
||||
const KeyPtr key = KeyboardShortcuts::instance()->tool(tool);
|
||||
if (key && key->isPressed(msg))
|
||||
if (key && key->isPressed(msg, *keys))
|
||||
possibles.push_back(tool);
|
||||
}
|
||||
|
||||
@ -451,6 +452,7 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kTimerMessage:
|
||||
if (static_cast<TimerMessage*>(msg)->timer() == defered_invalid_timer) {
|
||||
|
@ -113,15 +113,17 @@ protected:
|
||||
case kKeyDownMessage:
|
||||
case kKeyUpMessage:
|
||||
if (static_cast<KeyMessage*>(msg)->repeat() == 0) {
|
||||
KeyPtr lmb = KeyboardShortcuts::instance()->action(KeyAction::LeftMouseButton);
|
||||
KeyPtr rmb = KeyboardShortcuts::instance()->action(KeyAction::RightMouseButton);
|
||||
KeyboardShortcuts* keys = KeyboardShortcuts::instance();
|
||||
KeyPtr lmb = keys->action(KeyAction::LeftMouseButton);
|
||||
KeyPtr rmb = keys->action(KeyAction::RightMouseButton);
|
||||
|
||||
// Convert action keys into mouse messages.
|
||||
if (lmb->isPressed(msg) || rmb->isPressed(msg)) {
|
||||
if (lmb->isPressed(msg, *keys) ||
|
||||
rmb->isPressed(msg, *keys)) {
|
||||
MouseMessage mouseMsg(
|
||||
(msg->type() == kKeyDownMessage ? kMouseDownMessage: kMouseUpMessage),
|
||||
PointerType::Unknown,
|
||||
(lmb->isPressed(msg) ? kButtonLeft: kButtonRight),
|
||||
(lmb->isPressed(msg, *keys) ? kButtonLeft: kButtonRight),
|
||||
msg->modifiers(),
|
||||
ui::get_mouse_position());
|
||||
|
||||
|
@ -22,6 +22,7 @@ namespace ui {
|
||||
|
||||
namespace app {
|
||||
class Command;
|
||||
class KeyboardShortcuts;
|
||||
|
||||
namespace tools {
|
||||
class Tool;
|
||||
@ -110,8 +111,11 @@ namespace app {
|
||||
const ui::Accelerators& userAccels() const { return m_users; }
|
||||
const ui::Accelerators& userRemovedAccels() const { return m_userRemoved; }
|
||||
|
||||
void add(const ui::Accelerator& accel, KeySource source);
|
||||
bool isPressed(const ui::Message* msg) const;
|
||||
void add(const ui::Accelerator& accel,
|
||||
const KeySource source,
|
||||
KeyboardShortcuts& globalKeys);
|
||||
bool isPressed(const ui::Message* msg,
|
||||
KeyboardShortcuts& globalKeys) const;
|
||||
bool isPressed() const;
|
||||
bool isLooselyPressed() const;
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "app/app_menus.h"
|
||||
#include "app/commands/command.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/commands/params.h"
|
||||
#include "app/doc.h"
|
||||
#include "app/tools/ink.h"
|
||||
@ -25,6 +26,10 @@
|
||||
#include "ui/accelerator.h"
|
||||
#include "ui/message.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#define XML_KEYBOARD_FILE_VERSION "1"
|
||||
|
||||
namespace {
|
||||
@ -237,7 +242,9 @@ Key::Key(WheelAction wheelAction)
|
||||
{
|
||||
}
|
||||
|
||||
void Key::add(const ui::Accelerator& accel, KeySource source)
|
||||
void Key::add(const ui::Accelerator& accel,
|
||||
const KeySource source,
|
||||
KeyboardShortcuts& globalKeys)
|
||||
{
|
||||
Accelerators* accels = &m_accels;
|
||||
|
||||
@ -251,7 +258,7 @@ void Key::add(const ui::Accelerator& accel, KeySource source)
|
||||
|
||||
// Remove the accelerator from other commands
|
||||
if (source == KeySource::UserDefined) {
|
||||
KeyboardShortcuts::instance()->disableAccel(accel, m_keycontext, this);
|
||||
globalKeys.disableAccel(accel, m_keycontext, this);
|
||||
m_userRemoved.remove(accel);
|
||||
}
|
||||
|
||||
@ -259,7 +266,8 @@ void Key::add(const ui::Accelerator& accel, KeySource source)
|
||||
accels->add(accel);
|
||||
}
|
||||
|
||||
bool Key::isPressed(const Message* msg) const
|
||||
bool Key::isPressed(const Message* msg,
|
||||
KeyboardShortcuts& globalKeys) const
|
||||
{
|
||||
if (auto keyMsg = dynamic_cast<const KeyMessage*>(msg)) {
|
||||
for (const Accelerator& accel : accels()) {
|
||||
@ -267,7 +275,7 @@ bool Key::isPressed(const Message* msg) const
|
||||
keyMsg->scancode(),
|
||||
keyMsg->unicodeChar()) &&
|
||||
(m_keycontext == KeyContext::Any ||
|
||||
m_keycontext == KeyboardShortcuts::instance()->getCurrentKeyContext())) {
|
||||
m_keycontext == globalKeys.getCurrentKeyContext())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -378,6 +386,19 @@ KeyboardShortcuts::~KeyboardShortcuts()
|
||||
clear();
|
||||
}
|
||||
|
||||
void KeyboardShortcuts::setKeys(const KeyboardShortcuts& keys,
|
||||
const bool cloneKeys)
|
||||
{
|
||||
if (cloneKeys) {
|
||||
for (const KeyPtr& key : keys)
|
||||
m_keys.push_back(std::make_shared<Key>(*key));
|
||||
}
|
||||
else {
|
||||
m_keys = keys.m_keys;
|
||||
}
|
||||
UserChange();
|
||||
}
|
||||
|
||||
void KeyboardShortcuts::clear()
|
||||
{
|
||||
m_keys.clear();
|
||||
@ -428,7 +449,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
Accelerator accel(command_key);
|
||||
|
||||
if (!removed) {
|
||||
key->add(accel, source);
|
||||
key->add(accel, source, *this);
|
||||
|
||||
// Add the shortcut to the menuitems with this command
|
||||
// (this is only visual, the
|
||||
@ -467,7 +488,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
Accelerator accel(tool_key);
|
||||
|
||||
if (!removed)
|
||||
key->add(accel, source);
|
||||
key->add(accel, source, *this);
|
||||
else
|
||||
key->disableAccel(accel);
|
||||
}
|
||||
@ -495,7 +516,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
Accelerator accel(tool_key);
|
||||
|
||||
if (!removed)
|
||||
key->add(accel, source);
|
||||
key->add(accel, source, *this);
|
||||
else
|
||||
key->disableAccel(accel);
|
||||
}
|
||||
@ -524,7 +545,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
Accelerator accel(action_key);
|
||||
|
||||
if (!removed)
|
||||
key->add(accel, source);
|
||||
key->add(accel, source, *this);
|
||||
else
|
||||
key->disableAccel(accel);
|
||||
}
|
||||
@ -553,7 +574,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
Accelerator accel(action_key);
|
||||
|
||||
if (!removed)
|
||||
key->add(accel, source);
|
||||
key->add(accel, source, *this);
|
||||
else
|
||||
key->disableAccel(accel);
|
||||
}
|
||||
@ -780,7 +801,8 @@ KeyContext KeyboardShortcuts::getCurrentKeyContext()
|
||||
bool KeyboardShortcuts::getCommandFromKeyMessage(const Message* msg, Command** command, Params* params)
|
||||
{
|
||||
for (KeyPtr& key : m_keys) {
|
||||
if (key->type() == KeyType::Command && key->isPressed(msg)) {
|
||||
if (key->type() == KeyType::Command &&
|
||||
key->isPressed(msg, *this)) {
|
||||
if (command) *command = key->command();
|
||||
if (params) *params = key->params();
|
||||
return true;
|
||||
@ -833,7 +855,7 @@ WheelAction KeyboardShortcuts::getWheelActionFromMouseMessage(const KeyContext c
|
||||
for (const KeyPtr& key : m_keys) {
|
||||
if (key->type() == KeyType::WheelAction &&
|
||||
key->keycontext() == context &&
|
||||
key->isPressed(msg))
|
||||
key->isPressed(msg, *this))
|
||||
return key->wheelAction();
|
||||
}
|
||||
return WheelAction::None;
|
||||
@ -849,40 +871,104 @@ bool KeyboardShortcuts::hasMouseWheelCustomization() const
|
||||
return false;
|
||||
}
|
||||
|
||||
Keys KeyboardShortcuts::getDefaultMouseWheelTable(const bool zoomWithWheel) const
|
||||
void KeyboardShortcuts::clearMouseWheelKeys()
|
||||
{
|
||||
Keys keys;
|
||||
KeyPtr key;
|
||||
for (auto it=m_keys.begin(); it!=m_keys.end(); ) {
|
||||
if ((*it)->type() == KeyType::WheelAction)
|
||||
it = m_keys.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardShortcuts::addMissingMouseWheelKeys()
|
||||
{
|
||||
for (int wheelAction=int(WheelAction::First);
|
||||
wheelAction<=int(WheelAction::Last); ++wheelAction) {
|
||||
auto it = std::find_if(
|
||||
m_keys.begin(), m_keys.end(),
|
||||
[wheelAction](const KeyPtr& key) -> bool {
|
||||
return key->wheelAction() == (WheelAction)wheelAction;
|
||||
});
|
||||
if (it == m_keys.end()) {
|
||||
KeyPtr key = std::make_shared<Key>((WheelAction)wheelAction);
|
||||
m_keys.push_back(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardShortcuts::setDefaultMouseWheelKeys(const bool zoomWithWheel)
|
||||
{
|
||||
clearMouseWheelKeys();
|
||||
|
||||
KeyPtr key;
|
||||
key = std::make_shared<Key>(WheelAction::Zoom);
|
||||
key->add(Accelerator(zoomWithWheel ? kKeyNoneModifier: kKeyCtrlModifier, kKeyNil, 0), KeySource::Original);
|
||||
keys.push_back(key);
|
||||
key->add(Accelerator(zoomWithWheel ? kKeyNoneModifier:
|
||||
kKeyCtrlModifier, kKeyNil, 0),
|
||||
KeySource::Original, *this);
|
||||
m_keys.push_back(key);
|
||||
|
||||
if (!zoomWithWheel) {
|
||||
key = std::make_shared<Key>(WheelAction::VScroll);
|
||||
key->add(Accelerator(kKeyNoneModifier, kKeyNil, 0), KeySource::Original);
|
||||
keys.push_back(key);
|
||||
key->add(Accelerator(kKeyNoneModifier, kKeyNil, 0),
|
||||
KeySource::Original, *this);
|
||||
m_keys.push_back(key);
|
||||
}
|
||||
|
||||
key = std::make_shared<Key>(WheelAction::HScroll);
|
||||
key->add(Accelerator(kKeyShiftModifier, kKeyNil, 0), KeySource::Original);
|
||||
keys.push_back(key);
|
||||
key->add(Accelerator(kKeyShiftModifier, kKeyNil, 0),
|
||||
KeySource::Original, *this);
|
||||
m_keys.push_back(key);
|
||||
|
||||
key = std::make_shared<Key>(WheelAction::FgColor);
|
||||
key->add(Accelerator(kKeyAltModifier, kKeyNil, 0), KeySource::Original);
|
||||
keys.push_back(key);
|
||||
key->add(Accelerator(kKeyAltModifier, kKeyNil, 0),
|
||||
KeySource::Original, *this);
|
||||
m_keys.push_back(key);
|
||||
|
||||
key = std::make_shared<Key>(WheelAction::BgColor);
|
||||
key->add(Accelerator((KeyModifiers)(kKeyAltModifier | kKeyShiftModifier), kKeyNil, 0), KeySource::Original);
|
||||
keys.push_back(key);
|
||||
key->add(Accelerator((KeyModifiers)(kKeyAltModifier | kKeyShiftModifier), kKeyNil, 0),
|
||||
KeySource::Original, *this);
|
||||
m_keys.push_back(key);
|
||||
|
||||
if (zoomWithWheel) {
|
||||
key = std::make_shared<Key>(WheelAction::Frame);
|
||||
key->add(Accelerator(kKeyCtrlModifier, kKeyNil, 0), KeySource::Original);
|
||||
keys.push_back(key);
|
||||
key->add(Accelerator(kKeyCtrlModifier, kKeyNil, 0),
|
||||
KeySource::Original, *this);
|
||||
m_keys.push_back(key);
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardShortcuts::addMissingKeysForCommands()
|
||||
{
|
||||
std::set<std::string> commandsAlreadyAdded;
|
||||
for (const KeyPtr& key : m_keys) {
|
||||
if (key->type() != KeyType::Command)
|
||||
continue;
|
||||
|
||||
if (key->params().empty())
|
||||
commandsAlreadyAdded.insert(key->command()->id());
|
||||
}
|
||||
|
||||
return keys;
|
||||
std::vector<std::string> ids;
|
||||
Commands* commands = Commands::instance();
|
||||
commands->getAllIds(ids);
|
||||
|
||||
for (const std::string& id : ids) {
|
||||
Command* command = commands->byId(id.c_str());
|
||||
|
||||
// Don't add commands that need params (they will be added to
|
||||
// the list using the list of keyboard shortcuts from gui.xml).
|
||||
if (command->needsParams())
|
||||
continue;
|
||||
|
||||
auto it = commandsAlreadyAdded.find(command->id());
|
||||
if (it != commandsAlreadyAdded.end())
|
||||
continue;
|
||||
|
||||
// Create the new Key element in KeyboardShortcuts for this
|
||||
// command without params.
|
||||
this->command(command->id().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
std::string key_tooltip(const char* str, const app::Key* key)
|
||||
|
@ -9,7 +9,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "app/ui/key.h"
|
||||
#include "base/disable_copying.h"
|
||||
#include "obs/signal.h"
|
||||
|
||||
class TiXmlElement;
|
||||
@ -22,15 +21,21 @@ namespace app {
|
||||
typedef Keys::const_iterator const_iterator;
|
||||
|
||||
static KeyboardShortcuts* instance();
|
||||
~KeyboardShortcuts();
|
||||
|
||||
const Keys& keys() const { return m_keys; }
|
||||
KeyboardShortcuts();
|
||||
KeyboardShortcuts(const KeyboardShortcuts&) = delete;
|
||||
KeyboardShortcuts& operator=(const KeyboardShortcuts&) = delete;
|
||||
~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(); }
|
||||
|
||||
// const Keys& keys() const { return m_keys; }
|
||||
void setKeys(const KeyboardShortcuts& keys,
|
||||
const bool cloneKeys);
|
||||
|
||||
void clear();
|
||||
void importFile(TiXmlElement* rootElement, KeySource source);
|
||||
void importFile(const std::string& filename, KeySource source);
|
||||
@ -55,21 +60,21 @@ namespace app {
|
||||
WheelAction getWheelActionFromMouseMessage(const KeyContext context,
|
||||
const ui::Message* msg);
|
||||
bool hasMouseWheelCustomization() const;
|
||||
Keys getDefaultMouseWheelTable(const bool zoomWithWheel) const;
|
||||
void clearMouseWheelKeys();
|
||||
void addMissingMouseWheelKeys();
|
||||
void setDefaultMouseWheelKeys(const bool zoomWithWheel);
|
||||
|
||||
// Generated when the tooltips are modified by the user.
|
||||
void addMissingKeysForCommands();
|
||||
|
||||
// Generated when the keyboard shortcuts are modified by the user.
|
||||
// Useful to regenerate tooltips with shortcuts.
|
||||
obs::signal<void()> UserChange;
|
||||
|
||||
private:
|
||||
KeyboardShortcuts();
|
||||
|
||||
void exportKeys(TiXmlElement& parent, KeyType type);
|
||||
void exportAccel(TiXmlElement& parent, const Key* key, const ui::Accelerator& accel, bool removed);
|
||||
|
||||
Keys m_keys;
|
||||
|
||||
DISABLE_COPYING(KeyboardShortcuts);
|
||||
};
|
||||
|
||||
std::string key_tooltip(const char* str, const Key* key);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "app/ui/select_accelerator.h"
|
||||
|
||||
#include "app/ui/key.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "base/bind.h"
|
||||
#include "obs/signal.h"
|
||||
#include "ui/entry.h"
|
||||
@ -87,7 +88,7 @@ protected:
|
||||
|
||||
SelectAccelerator::SelectAccelerator(const ui::Accelerator& accel,
|
||||
const KeyContext keyContext,
|
||||
const Keys& currentKeys)
|
||||
const KeyboardShortcuts& currentKeys)
|
||||
: m_keyField(new KeyField(accel))
|
||||
, m_keyContext(keyContext)
|
||||
, m_currentKeys(currentKeys)
|
||||
|
@ -8,19 +8,20 @@
|
||||
#define APP_UI_SELECT_ACCELERATOR_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/key_context.h"
|
||||
#include "ui/accelerator.h"
|
||||
#include "ui/tooltips.h"
|
||||
|
||||
#include "select_accelerator.xml.h"
|
||||
|
||||
namespace app {
|
||||
class KeyboardShortcuts;
|
||||
|
||||
class SelectAccelerator : public app::gen::SelectAccelerator {
|
||||
public:
|
||||
SelectAccelerator(const ui::Accelerator& accelerator,
|
||||
const KeyContext keyContext,
|
||||
const Keys& currentKeys);
|
||||
const KeyboardShortcuts& currentKeys);
|
||||
|
||||
bool isOK() const { return m_ok; }
|
||||
bool isModified() const { return m_modified; }
|
||||
@ -40,7 +41,7 @@ namespace app {
|
||||
ui::TooltipManager m_tooltipManager;
|
||||
KeyField* m_keyField;
|
||||
KeyContext m_keyContext;
|
||||
const Keys& m_currentKeys;
|
||||
const KeyboardShortcuts& m_currentKeys;
|
||||
ui::Accelerator m_origAccel;
|
||||
ui::Accelerator m_accel;
|
||||
bool m_ok;
|
||||
|
Loading…
x
Reference in New Issue
Block a user