Skip to content

Commit

Permalink
#5180: Accelerator handling
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed May 11, 2020
1 parent 930786d commit b39df35
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 70 deletions.
24 changes: 21 additions & 3 deletions radiant/eventmanager/Accelerator.cpp
Expand Up @@ -9,15 +9,27 @@
namespace ui
{

Accelerator::Accelerator() :
_key(0),
_modifiers(0),
_isEmpty(true)
{}

// Construct an accelerator out of the key/modifier plus a command
Accelerator::Accelerator(const unsigned int key,
const unsigned int modifiers,
const IEventPtr& event) :
_key(key),
_modifiers(modifiers),
_event(event)
_key(key),
_modifiers(modifiers),
_event(event),
_isEmpty(false)
{}

Accelerator Accelerator::CreateEmpty()
{
return Accelerator();
}

// Returns true if the key/modifier combination matches this accelerator
bool Accelerator::match(const unsigned int key, const unsigned int modifiers) const {
return (_key == key && _modifiers == modifiers);
Expand Down Expand Up @@ -49,6 +61,7 @@ void Accelerator::setStatement(const std::string& statement)

void Accelerator::setKey(const unsigned int key) {
_key = key;
_isEmpty = _key != 0;
}

// Make the accelerator use the specified accelerators
Expand All @@ -66,6 +79,11 @@ void Accelerator::setEvent(const IEventPtr& ev)
_event = ev;
}

bool Accelerator::isEmpty() const
{
return _isEmpty;
}

std::string Accelerator::getString(bool forMenu) const
{
const std::string keyStr = _key != 0 ? Accelerator::getNameFromKeyCode(_key) : "";
Expand Down
11 changes: 11 additions & 0 deletions radiant/eventmanager/Accelerator.h
Expand Up @@ -17,6 +17,7 @@ namespace ui
class Accelerator :
public IAccelerator
{
private:
// The internally stored key/modifier combination
unsigned int _key;
unsigned int _modifiers;
Expand All @@ -27,6 +28,11 @@ class Accelerator :
// Alternative if event is null: the command to execute
std::string _statement;

bool _isEmpty;

// Private constructor creating an empty accelerator
Accelerator();

public:
typedef std::shared_ptr<Accelerator> Ptr;

Expand Down Expand Up @@ -59,6 +65,8 @@ class Accelerator :

std::string getString(bool forMenu) const override;

bool isEmpty() const;

/**
* Converts a string representation of a key to the corresponding
* wxKeyCode, e.g. "A" => 65, "TAB" => wxKeyCode::WXK_TAB.
Expand All @@ -78,6 +86,9 @@ class Accelerator :
* to its uppercase pendant if possible. 'a' => 'A'
*/
static std::string getNameFromKeyCode(unsigned int keyCode);

// Create an empty accelerator
static Accelerator CreateEmpty();
};

typedef std::list<Accelerator::Ptr> AcceleratorList;
Expand Down
118 changes: 57 additions & 61 deletions radiant/eventmanager/EventManager.cpp
Expand Up @@ -93,7 +93,7 @@ void EventManager::shutdownModule()
// Constructor
EventManager::EventManager() :
_emptyEvent(new Event()),
_emptyAccelerator(0, 0, _emptyEvent)
_emptyAccelerator(Accelerator::CreateEmpty())
{}

Accelerator& EventManager::addAccelerator(const std::string& key, const std::string& modifierStr)
Expand Down Expand Up @@ -176,10 +176,10 @@ IEventPtr EventManager::findEvent(const std::string& name)
IEventPtr EventManager::findEvent(wxKeyEvent& ev)
{
// Retrieve the accelerators for this eventkey
AcceleratorList accelList = findAccelerator(ev);
Accelerator& accel = findAccelerator(ev);

// Did we find any matching accelerators? If yes, take the first found accelerator
return !accelList.empty() ? (*accelList.begin())->getEvent() : _emptyEvent;
return accel.getEvent() ? accel.getEvent() : _emptyEvent;
}

std::string EventManager::getEventName(const IEventPtr& event)
Expand Down Expand Up @@ -471,22 +471,37 @@ void EventManager::loadAcceleratorFromList(const xml::NodeList& shortcutList)
// Check for a non-empty key string
if (key.empty()) continue;

// Check for duplicate accelerator mappings
const auto& existingAccel = findAccelerator(key, modifierStr);

if (existingAccel.getStatement() == cmd)
{
rWarning() << "Accelerator " << existingAccel.getString(false) <<
" is already mapped to " << cmd << std::endl;
continue;
}

// Create the accelerator object
Accelerator& accelerator = addAccelerator(key, modifierStr);

// Update all registered menu items
for (const auto& item : _menuItems)
{
if (item.second->getEvent() == cmd)
{
item.second->setAccelerator(accelerator.getString(true));
}
}

// Try to lookup the command
IEventPtr event = findEvent(cmd);

// Check for valid command definitions were found
if (!event->empty())
{
if (!duplicateAccelerator(key, modifierStr, event))
{
// Create the accelerator object
Accelerator& accelerator = addAccelerator(key, modifierStr);

// Connect the newly created accelerator to the command
event->connectAccelerator(accelerator);
accelerator.setEvent(event);
}

// Connect the newly created accelerator to the command
event->connectAccelerator(accelerator);
accelerator.setEvent(event);
continue;
}

Expand All @@ -498,19 +513,7 @@ void EventManager::loadAcceleratorFromList(const xml::NodeList& shortcutList)

if (signatureIsEmptyOrOptional(signature))
{
bool accelExists = !findAccelerator(key, modifierStr).empty();

if (accelExists)
{
rWarning() << "EventManager: Shortcut is already taken: "
<< modifierStr << "+" << key << std::endl;
continue;
}

Accelerator& accelerator = addAccelerator(key, modifierStr);

accelerator.setStatement(cmd);

continue;
}
}
Expand Down Expand Up @@ -583,8 +586,7 @@ void EventManager::saveEventListToRegistry()
foreachEvent(visitor);
}

AcceleratorList EventManager::findAccelerator(
const std::string& key, const std::string& modifierStr)
Accelerator& EventManager::findAccelerator(const std::string& key, const std::string& modifierStr)
{
unsigned int keyVal = Accelerator::getKeyCodeFromName(key);
unsigned int modifierFlags = wxutil::Modifier::GetStateFromModifierString(modifierStr);
Expand All @@ -596,7 +598,8 @@ bool EventManager::duplicateAccelerator(const std::string& key,
const std::string& modifiers,
const IEventPtr& event)
{
AcceleratorList accelList = findAccelerator(key, modifiers);
#if 0
Accelerator& accelerator = findAccelerator(key, modifiers);

for (const auto& accelerator : accelList)
{
Expand All @@ -606,29 +609,26 @@ bool EventManager::duplicateAccelerator(const std::string& key,
return true;
}
}

#endif
return false;
}

AcceleratorList EventManager::findAccelerator(unsigned int keyVal,
const unsigned int modifierFlags)
Accelerator& EventManager::findAccelerator(unsigned int keyVal, unsigned int modifierFlags)
{
AcceleratorList returnList;

// Cycle through the accelerators and check for matches
for (const auto& accelerator : _accelerators)
for (auto& accelerator : _accelerators)
{
if (accelerator->match(keyVal, modifierFlags))
{
// Add the pointer to the found accelerators
returnList.push_back(accelerator);
return *accelerator;
}
}

return returnList;
return _emptyAccelerator;
}

AcceleratorList EventManager::findAccelerator(wxKeyEvent& ev)
Accelerator& EventManager::findAccelerator(wxKeyEvent& ev)
{
int keyval = ev.GetKeyCode(); // is always uppercase

Expand All @@ -637,41 +637,37 @@ AcceleratorList EventManager::findAccelerator(wxKeyEvent& ev)

bool EventManager::handleKeyEvent(wxKeyEvent& keyEvent)
{
AcceleratorList accelList = findAccelerator(keyEvent);
Accelerator& accelerator = findAccelerator(keyEvent);

// Pass the execute() call to all found accelerators
for (const auto& accelerator : accelList)
{
const std::string& statement = accelerator->getStatement();
const std::string& statement = accelerator.getStatement();

if (!statement.empty())
if (!statement.empty())
{
if (keyEvent.GetEventType() == wxEVT_KEY_DOWN)
{
if (keyEvent.GetEventType() == wxEVT_KEY_DOWN)
{
GlobalCommandSystem().execute(statement);
}

continue;
GlobalCommandSystem().execute(statement);
}

auto ev = accelerator->getEvent();
return true;
}

auto ev = accelerator.getEvent();

if (ev)
if (ev)
{
if (keyEvent.GetEventType() == wxEVT_KEY_DOWN)
{
if (keyEvent.GetEventType() == wxEVT_KEY_DOWN)
{
ev->keyDown();
}
else
{
ev->keyUp();
}
ev->keyDown();
}
else
{
ev->keyUp();
}

// Found an accelerator with no event or statement
return true;
}

return !accelList.empty(); // accelerators found => true
return false;
}

bool EventManager::isModifier(wxKeyEvent& ev)
Expand Down
6 changes: 3 additions & 3 deletions radiant/eventmanager/EventManager.h
Expand Up @@ -91,7 +91,7 @@ class EventManager :
void foreachEvent(IEventVisitor& eventVisitor) override;

// Tries to locate an accelerator, that is connected to the given command
AcceleratorList findAccelerator(wxKeyEvent& ev);
Accelerator& findAccelerator(wxKeyEvent& ev);
bool handleKeyEvent(wxKeyEvent& keyEvent);

std::string getEventStr(wxKeyEvent& ev) override;
Expand All @@ -101,12 +101,12 @@ class EventManager :

Accelerator& findAccelerator(const IEventPtr& event);
Accelerator& findAccelerator(const std::string& commandName);
AcceleratorList findAccelerator(const std::string& key, const std::string& modifierStr);
Accelerator& findAccelerator(const std::string& key, const std::string& modifierStr);

bool duplicateAccelerator(const std::string& key, const std::string& modifiers, const IEventPtr& event);

// 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);
Accelerator& findAccelerator(unsigned int keyVal, const unsigned int modifierFlags);

void loadAcceleratorFromList(const xml::NodeList& shortcutList);

Expand Down
4 changes: 4 additions & 0 deletions radiant/eventmanager/Statement.cpp
Expand Up @@ -180,10 +180,12 @@ void Statement::onButtonClicked(wxCommandEvent& ev)

void Statement::connectAccelerator(IAccelerator& accel)
{
#if 0
for (wxMenuItem* item : _menuItems)
{
setMenuItemAccelerator(item, static_cast<Accelerator&>(accel));
}
#endif

for (wxToolBarToolBase* tool : _toolItems)
{
Expand All @@ -193,10 +195,12 @@ void Statement::connectAccelerator(IAccelerator& accel)

void Statement::disconnectAccelerators()
{
#if 0
for (wxMenuItem* item : _menuItems)
{
clearMenuItemAccelerator(item);
}
#endif

for (wxToolBarToolBase* tool : _toolItems)
{
Expand Down
8 changes: 5 additions & 3 deletions radiant/uimanager/menu/MenuItem.cpp
Expand Up @@ -50,9 +50,7 @@ void MenuItem::construct()

std::string caption = _caption;

#if 1
GlobalEventManager().registerMenuItem(_event, shared_from_this());
#else
#if 0
// Try to lookup the event name
IEventPtr event = GlobalEventManager().findEvent(_event);

Expand Down Expand Up @@ -94,6 +92,10 @@ void MenuItem::construct()
}
#endif

#if 1
GlobalEventManager().registerMenuItem(_event, shared_from_this());
#endif

MenuElement::constructChildren();
}

Expand Down

0 comments on commit b39df35

Please sign in to comment.