diff --git a/include/ieventmanager.h b/include/ieventmanager.h index 5666a0da73..e8e121a23d 100644 --- a/include/ieventmanager.h +++ b/include/ieventmanager.h @@ -126,11 +126,14 @@ class IEventManager : * @returns: the pointer to the newly created accelerator object */ virtual IAccelerator& addAccelerator(const std::string& key, const std::string& modifierStr) = 0; - // The same as above, but with GDK event values as argument (event->keyval, event->state) + // The same as above, but with event values as argument (event->keyval, event->state) virtual IAccelerator& addAccelerator(wxKeyEvent& ev) = 0; virtual IAccelerator& findAccelerator(const IEventPtr& event) = 0; virtual std::string getAcceleratorStr(const IEventPtr& event, bool forMenu) = 0; + // Loads all accelerator bindings from the defaults in the stock input.xml + virtual void resetAcceleratorBindings() = 0; + // Add a command and specify the statement to execute when triggered virtual IEventPtr addCommand(const std::string& name, const std::string& statement, bool reactOnKeyUp = false) = 0; diff --git a/plugins/eventmanager/EventManager.cpp b/plugins/eventmanager/EventManager.cpp index 0bebca7b90..99e55ce4a8 100644 --- a/plugins/eventmanager/EventManager.cpp +++ b/plugins/eventmanager/EventManager.cpp @@ -106,6 +106,11 @@ Accelerator& EventManager::addAccelerator(wxKeyEvent& ev) return _accelerators.back(); } +void EventManager::resetAcceleratorBindings() +{ + +} + IEventPtr EventManager::findEvent(const std::string& name) { // Try to lookup the command @@ -336,65 +341,66 @@ void EventManager::loadAccelerators() { // Register all custom statements as events too to make them shortcut-bindable // before going ahead - GlobalCommandSystem().foreachStatement([&] (const std::string& statementName) + GlobalCommandSystem().foreachStatement([&](const std::string& statementName) { addCommand(statementName, statementName, false); }, true); // custom statements only xml::NodeList shortcutSets = GlobalRegistry().findXPath("user/ui/input//shortcuts"); - // If we have two sets of shortcuts, delete the default ones - if (shortcutSets.size() > 1) + // If we have two sets of shortcuts, don't select the stock ones + std::string xPathQuery = shortcutSets.size() > 1 ? + "user/ui/input/shortcuts[not(@name)]//shortcut" : // find all without name attribute + "user/ui/input/shortcuts//shortcut"; // find all shortcuts + + xml::NodeList shortcutList = GlobalRegistry().findXPath(xPathQuery); + + if (shortcutList.empty()) { - GlobalRegistry().deleteXPath("user/ui/input//shortcuts[@name='default']"); + // No accelerator definitions found! + rWarning() << "EventManager: No shortcut definitions found..." << std::endl; + return; } - // Find all accelerators - xml::NodeList shortcutList = GlobalRegistry().findXPath("user/ui/input/shortcuts//shortcut"); + rMessage() << "EventManager: Shortcuts found in Registry: " << shortcutList.size() << std::endl; - if (!shortcutList.empty()) + loadAcceleratorFromList(shortcutList); +} + +void EventManager::loadAcceleratorFromList(const xml::NodeList& shortcutList) +{ + for (const xml::Node& shortcutNode : shortcutList) { - rMessage() << "EventManager: Shortcuts found in Registry: " << shortcutList.size() << std::endl; + const std::string key = shortcutNode.getAttributeValue("key"); + const std::string cmd = shortcutNode.getAttributeValue("command"); - for (const xml::Node& shortcutNode : shortcutList) - { - const std::string key = shortcutNode.getAttributeValue("key"); - const std::string cmd = shortcutNode.getAttributeValue("command"); + // Try to lookup the command + IEventPtr event = findEvent(cmd); + + // Check for a non-empty key string + if (key.empty()) continue; - // Try to lookup the command - IEventPtr event = findEvent(cmd); + // Check for valid command definitions were found + if (!event->empty()) + { + // Get the modifier string (e.g. "SHIFT+ALT") + const std::string modifierStr = shortcutNode.getAttributeValue("modifiers"); - // Check for a non-empty key string - if (!key.empty()) + if (!duplicateAccelerator(key, modifierStr, event)) { - // Check for valid command definitions were found - if (!event->empty()) - { - // Get the modifier string (e.g. "SHIFT+ALT") - const std::string modifierStr = shortcutNode.getAttributeValue("modifiers"); - - if (!duplicateAccelerator(key, modifierStr, event)) - { - // Create the accelerator object - IAccelerator& accelerator = addAccelerator(key, modifierStr); - - // Connect the newly created accelerator to the command - event->connectAccelerator(accelerator); - static_cast(accelerator).setEvent(event); - } - } - else - { - rWarning() << "EventManager: Cannot load shortcut definition (command invalid): " - << cmd << std::endl; - } + // Create the accelerator object + IAccelerator& accelerator = addAccelerator(key, modifierStr); + + // Connect the newly created accelerator to the command + event->connectAccelerator(accelerator); + static_cast(accelerator).setEvent(event); } } - } - else - { - // No accelerator definitions found! - rWarning() << "EventManager: No shortcut definitions found..." << std::endl; + else + { + rWarning() << "EventManager: Cannot load shortcut definition (command invalid): " + << cmd << std::endl; + } } } diff --git a/plugins/eventmanager/EventManager.h b/plugins/eventmanager/EventManager.h index 83025e7c36..fb14119f78 100644 --- a/plugins/eventmanager/EventManager.h +++ b/plugins/eventmanager/EventManager.h @@ -6,6 +6,7 @@ #include #include +#include "xmlutil/Node.h" #include "Accelerator.h" #include "GlobalKeyEventFilter.h" @@ -52,6 +53,8 @@ class EventManager : std::string getAcceleratorStr(const IEventPtr& event, bool forMenu) override; + void resetAcceleratorBindings() override; + // Checks if the eventName is already registered and writes to rMessage, if so bool alreadyRegistered(const std::string& eventName); @@ -88,7 +91,6 @@ class EventManager : std::string getEventStr(wxKeyEvent& ev) override; private: - void saveEventListToRegistry(); AcceleratorList findAccelerator(const std::string& key, const std::string& modifierStr); @@ -98,6 +100,8 @@ class EventManager : // Returns the pointer to the accelerator for the given event, but convert the key to uppercase before passing it AcceleratorList findAccelerator(unsigned int keyVal, const unsigned int modifierFlags); + void loadAcceleratorFromList(const xml::NodeList& shortcutList); + bool isModifier(wxKeyEvent& ev); }; diff --git a/radiant/ui/commandlist/CommandList.cpp b/radiant/ui/commandlist/CommandList.cpp index 8dfcb6693b..ffbee367d5 100644 --- a/radiant/ui/commandlist/CommandList.cpp +++ b/radiant/ui/commandlist/CommandList.cpp @@ -7,6 +7,8 @@ #include #include +#include "wxutil/dialog/MessageBox.h" + #include "CommandListPopulator.h" #include "ShortcutChooser.h" @@ -84,6 +86,11 @@ void CommandList::populateWindow() _clearButton->Connect(wxEVT_BUTTON, wxCommandEventHandler(CommandList::onClear), NULL, this); _clearButton->Enable(false); + // Create the clear shortcut button + wxButton* resetButton = new wxButton(this, wxID_ANY, _("Reset to Default")); + resetButton->Connect(wxEVT_BUTTON, wxCommandEventHandler(CommandList::onResetToDefault), NULL, this); + + buttonVBox->Add(resetButton, 0, wxEXPAND | wxBOTTOM, 12); buttonVBox->Add(_clearButton, 0, wxEXPAND | wxBOTTOM, 6); buttonVBox->Add(_assignButton, 0, wxEXPAND | wxBOTTOM, 6); buttonVBox->Add(closeButton, 0, wxEXPAND); @@ -170,6 +177,21 @@ void CommandList::onClear(wxCommandEvent& ev) } } +void CommandList::onResetToDefault(wxCommandEvent& ev) +{ + IDialog::Result result = wxutil::Messagebox::Show(_("Reset to default?"), + _("Really clear all bindings and reload\nthem from the default settings?"), IDialog::MESSAGE_ASK); + + if (result == IDialog::RESULT_YES) + { + // Reset and reload + GlobalEventManager().resetAcceleratorBindings(); + + reloadList(); + updateButtonState(); + } +} + void CommandList::onClose(wxCommandEvent& ev) { EndModal(wxCLOSE); diff --git a/radiant/ui/commandlist/CommandList.h b/radiant/ui/commandlist/CommandList.h index 702a35c440..7b35b27e2e 100644 --- a/radiant/ui/commandlist/CommandList.h +++ b/radiant/ui/commandlist/CommandList.h @@ -74,6 +74,7 @@ class CommandList : void onClose(wxCommandEvent& ev); void onClear(wxCommandEvent& ev); void onAssign(wxCommandEvent& ev); + void onResetToDefault(wxCommandEvent& ev); // The callback to catch the double click on a treeview row void onItemDoubleClicked(wxDataViewEvent& ev);