Skip to content

Commit

Permalink
Added a dialog box that allows the user to customize almost all of th…
Browse files Browse the repository at this point in the history
…e key bindings in e.
  • Loading branch information
ajpalkovic committed Oct 21, 2010
1 parent 78b76e7 commit bd190cb
Show file tree
Hide file tree
Showing 13 changed files with 1,046 additions and 31 deletions.
89 changes: 74 additions & 15 deletions src/Accelerators.cpp
Expand Up @@ -14,6 +14,8 @@
#include "tmAction.h" #include "tmAction.h"
#include "tmBundle.h" #include "tmBundle.h"


#include "AcceleratorsDialog.h"

wxString normalize(wxString str) { wxString normalize(wxString str) {
str.Replace(wxT("&"), wxT("")); str.Replace(wxT("&"), wxT(""));
return str.Trim().MakeLower(); return str.Trim().MakeLower();
Expand All @@ -23,6 +25,24 @@ bool IsChord(wxString& accel) {
return accel.Trim().Find(' ') != wxNOT_FOUND; return accel.Trim().Find(' ') != wxNOT_FOUND;
} }


bool shouldIgnore(int code) {
switch(code) {
case WXK_CONTROL:
case WXK_ALT:
case WXK_SHIFT:
case WXK_WINDOWS_LEFT:
case WXK_WINDOWS_RIGHT:
return true;
}

return false;
}

/**
* For constant time access, each keystroke is mapped to an int.
* The first 8 bits are used to store the modifiers.
* The remaining 24 bits are used to store the actual wxKeyCode of the key to press.
*/
int makeHash(wxString& accel) { int makeHash(wxString& accel) {
int code, flags; int code, flags;
wxAcceleratorEntry::ParseAccel(wxT("\t")+accel, &flags, &code); wxAcceleratorEntry::ParseAccel(wxT("\t")+accel, &flags, &code);
Expand All @@ -45,21 +65,26 @@ KeyBinding::KeyBinding(wxMenuItem* menuItem) : menuItem(menuItem) {
id = menuItem->GetId(); id = menuItem->GetId();
} }


KeyChord::KeyChord(wxString chord) : key(chord) { }

Accelerators::Accelerators(EditorFrame* editorFrame) : Accelerators::Accelerators(EditorFrame* editorFrame) :
m_editorFrame(editorFrame), m_activeChord(NULL), m_activeBundleChord(NULL) { m_editorFrame(editorFrame), m_activeChord(NULL), m_activeBundleChord(NULL) {
ReadCustomShortcuts(); ReadCustomShortcuts();
Reset(); Reset();
} }


/**
* Traverses the menubar.
* For each menu item, it grabs the binding from the menu
* and it checks if there is a custom binding for that menu item.
*/
void Accelerators::ParseMenu() { void Accelerators::ParseMenu() {
m_chords.clear(); m_chords.clear();
m_bindings.clear(); m_bindings.clear();


m_needDefault = m_defaultBindings.size() == 0;

wxMenuBar* menuBar = m_editorFrame->GetMenuBar(); wxMenuBar* menuBar = m_editorFrame->GetMenuBar();
if(!menuBar) return; if(!menuBar) return;

const unsigned int bundles = menuBar->FindMenu(_("&Bundles")); const unsigned int bundles = menuBar->FindMenu(_("&Bundles"));
for(unsigned int c = 0; c < menuBar->GetMenuCount(); c++) { for(unsigned int c = 0; c < menuBar->GetMenuCount(); c++) {
if(c == bundles) ParseBundlesMenu(menuBar->GetMenu(c)); if(c == bundles) ParseBundlesMenu(menuBar->GetMenu(c));
Expand Down Expand Up @@ -91,6 +116,18 @@ void Accelerators::ParseMenu(wxMenuItem* item) {
} else { } else {
label = text.Mid(0, tab); label = text.Mid(0, tab);
accel = text.Mid(tab+1); accel = text.Mid(tab+1);

if(m_needDefault) {
m_defaultBindings[label] = accel;
} else {
// When reloading the accelerators, if the user removes a custom accelerator, it needs to reset to the original value
map<wxString, wxString>::iterator iterator;
iterator = m_defaultBindings.find(normalize(label));
if(iterator != m_defaultBindings.end()) {
accel = iterator->second;
}

}
} }


// now check if there is a custom shortcut // now check if there is a custom shortcut
Expand Down Expand Up @@ -138,6 +175,10 @@ void Accelerators::InsertBinding(wxMenuItem* item, wxString& accel) {
} }
} }


/**
* Traverses the bundles menu.
* For bundle menu items, their bindings are stored differently from other wxMenuItems
*/
void Accelerators::ParseBundlesMenu(wxMenu* menu) { void Accelerators::ParseBundlesMenu(wxMenu* menu) {
wxMenuItemList& items = menu->GetMenuItems(); wxMenuItemList& items = menu->GetMenuItems();
for(unsigned int c = 0; c < items.size(); c++) { for(unsigned int c = 0; c < items.size(); c++) {
Expand Down Expand Up @@ -166,7 +207,8 @@ void Accelerators::ParseBundlesMenu(wxMenuItem* item) {
if(iterator != m_customBindings.end()) { if(iterator != m_customBindings.end()) {
wxString accel = iterator->second.Trim(); wxString accel = iterator->second.Trim();
bItem->SetCustomAccel(accel); bItem->SetCustomAccel(accel);
//InsertBinding(item, accel); } else {
bItem->SetCustomAccel(wxT(""));
} }
} }


Expand All @@ -192,24 +234,35 @@ void Accelerators::ReadCustomShortcuts() {
return; return;
} }


wxArrayString keys = jsonRoot.GetMemberNames(); if(!jsonRoot.HasMember(wxT("bindings"))) return;
wxJSONValue bindings = jsonRoot[wxT("bindings")];

m_customBindings.clear();
wxArrayString keys = bindings.GetMemberNames();
for(unsigned int c = 0; c < keys.size(); c++) { for(unsigned int c = 0; c < keys.size(); c++) {
wxString key = keys[c]; wxString key = keys[c];
m_customBindings[normalize(key)] = jsonRoot[key].AsString(); m_customBindings[normalize(key)] = bindings[key].AsString();
} }
} }


bool shouldIgnore(int code) { void Accelerators::SaveCustomShortcuts(wxString& jsonString) {
switch(code) { wxJSONReader reader;
case WXK_CONTROL: wxJSONValue bindings;
case WXK_ALT: reader.Parse(jsonString, &bindings);
case WXK_SHIFT:
case WXK_WINDOWS_LEFT: wxJSONValue root;
case WXK_WINDOWS_RIGHT: root[wxT("bindings")] = bindings;
return true;
wxString path = eGetSettings().GetSettingsDir() + wxT("accelerators.cfg");
wxFileOutputStream fstream(path);
if (!fstream.IsOk()) {
wxMessageBox(_("Could not open accelerators settings file."), _("File error"), wxICON_ERROR|wxOK);
return;
} }


return false; // Write settings
wxJSONWriter writer(wxJSONWRITER_STYLED);
writer.Write(root, fstream);
} }


bool Accelerators::HandleKeyEvent(wxKeyEvent& event) { bool Accelerators::HandleKeyEvent(wxKeyEvent& event) {
Expand Down Expand Up @@ -375,6 +428,9 @@ void Accelerators::Reset() {
m_actionReturned = false; m_actionReturned = false;
m_searchBundleBindings = false; m_searchBundleBindings = false;
m_searchBundleChords = false; m_searchBundleChords = false;

m_bundleChords.clear();
m_bundleBindings.clear();
} }


/** /**
Expand All @@ -396,6 +452,9 @@ bool Accelerators::WasChordActivated() {
return ret; return ret;
} }


/**
* Finds the menu item that matches the given key bidning hash and runs its event.
*/
bool Accelerators::MatchMenus(int hash) { bool Accelerators::MatchMenus(int hash) {
if(m_activeChord) { if(m_activeChord) {
std::map<int, KeyBinding*>::iterator iterator; std::map<int, KeyBinding*>::iterator iterator;
Expand Down
9 changes: 7 additions & 2 deletions src/Accelerators.h
Expand Up @@ -8,6 +8,7 @@
class EditorFrame; class EditorFrame;
class tmAction; class tmAction;
int makeHash(wxString& accel); int makeHash(wxString& accel);
wxString normalize(wxString str);


class KeyBinding { class KeyBinding {
public: public:
Expand All @@ -20,7 +21,7 @@ class KeyBinding {


class KeyChord { class KeyChord {
public: public:
KeyChord(wxString chord); KeyChord(wxString chord) : key(chord) {}


wxString key; wxString key;
std::map<int, KeyBinding*> bindings; std::map<int, KeyBinding*> bindings;
Expand All @@ -41,6 +42,7 @@ class Accelerators {
Accelerators(EditorFrame* editorFrame); Accelerators(EditorFrame* editorFrame);


void ReadCustomShortcuts(); void ReadCustomShortcuts();
void SaveCustomShortcuts(wxString& jsonRoot);


void ParseMenu(); void ParseMenu();
void ParseMenu(wxMenu* menu); void ParseMenu(wxMenu* menu);
Expand All @@ -64,9 +66,11 @@ class Accelerators {


wxString StatusBarText(); wxString StatusBarText();


std::map<wxString, wxString> m_customBindings;
std::map<wxString, wxString> m_defaultBindings;

private: private:
EditorFrame* m_editorFrame; EditorFrame* m_editorFrame;
std::map<wxString, wxString> m_customBindings;
std::map<int, KeyChord*> m_chords; std::map<int, KeyChord*> m_chords;
std::map<int, KeyBinding*> m_bindings; std::map<int, KeyBinding*> m_bindings;


Expand All @@ -80,6 +84,7 @@ class Accelerators {
bool m_actionReturned; bool m_actionReturned;
bool m_searchBundleBindings; bool m_searchBundleBindings;
bool m_searchBundleChords; bool m_searchBundleChords;
bool m_needDefault;
}; };


#endif #endif

0 comments on commit bd190cb

Please sign in to comment.