diff --git a/src/app/commands/cmd_keyboard_shortcuts.cpp b/src/app/commands/cmd_keyboard_shortcuts.cpp index 2b4dd7196..cb0ac6a9f 100644 --- a/src/app/commands/cmd_keyboard_shortcuts.cpp +++ b/src/app/commands/cmd_keyboard_shortcuts.cpp @@ -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 -#include +#include #define KEYBOARD_FILENAME_EXTENSION "aseprite-keys" @@ -57,6 +55,8 @@ using namespace ui; namespace { +typedef std::map 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)); - } - } + 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; iaccels().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((WheelAction)wheelAction); - m_wheelKeys.push_back(key); - } - } - } - + app::KeyboardShortcuts& m_keys; + MenuKeys& m_menuKeys; std::vector m_listBoxes; - std::vector 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(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 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(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 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()); + } } } diff --git a/src/app/commands/filters/cmd_replace_color.cpp b/src/app/commands/filters/cmd_replace_color.cpp index 87d1b29c4..c5e249626 100644 --- a/src/app/commands/filters/cmd_replace_color.cpp +++ b/src/app/commands/filters/cmd_replace_color.cpp @@ -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(); diff --git a/src/app/modules/gui.cpp b/src/app/modules/gui.cpp index 85e2da9a9..8d5b6b483 100644 --- a/src/app/modules/gui.cpp +++ b/src/app/modules/gui.cpp @@ -365,7 +365,7 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg) } break; - case kKeyDownMessage: + case kKeyDownMessage: { #if ENABLE_DEVMODE if (onProcessDevModeKeyDown(static_cast(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(msg)->timer() == defered_invalid_timer) { diff --git a/src/app/ui/doc_view.cpp b/src/app/ui/doc_view.cpp index 71d6c2fe4..847b4177a 100644 --- a/src/app/ui/doc_view.cpp +++ b/src/app/ui/doc_view.cpp @@ -113,15 +113,17 @@ protected: case kKeyDownMessage: case kKeyUpMessage: if (static_cast(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()); diff --git a/src/app/ui/key.h b/src/app/ui/key.h index 4597e02f4..788a8996d 100644 --- a/src/app/ui/key.h +++ b/src/app/ui/key.h @@ -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; diff --git a/src/app/ui/keyboard_shortcuts.cpp b/src/app/ui/keyboard_shortcuts.cpp index fcc34713e..0c70d7e6d 100644 --- a/src/app/ui/keyboard_shortcuts.cpp +++ b/src/app/ui/keyboard_shortcuts.cpp @@ -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 +#include +#include + #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(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)); + } + 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((WheelAction)wheelAction); + m_keys.push_back(key); + } + } +} + +void KeyboardShortcuts::setDefaultMouseWheelKeys(const bool zoomWithWheel) +{ + clearMouseWheelKeys(); + + KeyPtr key; key = std::make_shared(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(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(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(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(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(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 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 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) diff --git a/src/app/ui/keyboard_shortcuts.h b/src/app/ui/keyboard_shortcuts.h index 2366bd87a..2bd04a863 100644 --- a/src/app/ui/keyboard_shortcuts.h +++ b/src/app/ui/keyboard_shortcuts.h @@ -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 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); diff --git a/src/app/ui/select_accelerator.cpp b/src/app/ui/select_accelerator.cpp index eb8b92af5..094cf05d2 100644 --- a/src/app/ui/select_accelerator.cpp +++ b/src/app/ui/select_accelerator.cpp @@ -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) diff --git a/src/app/ui/select_accelerator.h b/src/app/ui/select_accelerator.h index dd8b69e49..132b40cb0 100644 --- a/src/app/ui/select_accelerator.h +++ b/src/app/ui/select_accelerator.h @@ -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;