diff --git a/src/commands/CommandManager.cpp b/src/commands/CommandManager.cpp index 53b1ef21f..1bc86b34c 100644 --- a/src/commands/CommandManager.cpp +++ b/src/commands/CommandManager.cpp @@ -440,6 +440,71 @@ CommandManager::~CommandManager() PurgeData(); } +const std::vector &CommandManager::ExcludedList() +{ + static const auto list = [] { + // These short cuts are for the max list only.... + const char *const strings[] = { + "Ctrl+I", + "Ctrl+Alt+I", + "Ctrl+J", + "Ctrl+Alt+J", + "Ctrl+Alt+V", + "Alt+X", + "Alt+K", + "Shift+Alt+X", + "Shift+Alt+K", + "Alt+L", + "Shift+Alt+C", + "Alt+I", + "Alt+J", + "Shift+Alt+J", + "Ctrl+Shift+A", + "Q", + //"Shift+J", + //"Shift+K", + //"Shift+Home", + //"Shift+End", + "Ctrl+[", + "Ctrl+]", + "1", + "Shift+F5", + "Shift+F6", + "Shift+F7", + "Shift+F8", + "Ctrl+Shift+F5", + "Ctrl+Shift+F7", + "Ctrl+Shift+N", + "Ctrl+Shift+M", + "Ctrl+Home", + "Ctrl+End", + "Shift+C", + "Alt+Shift+Up", + "Alt+Shift+Down", + "Shift+P", + "Alt+Shift+Left", + "Alt+Shift+Right", + "Ctrl+Shift+T", + //"Command+M", + //"Option+Command+M", + "Shift+H", + "Shift+O", + "Shift+I", + "Shift+N", + "D", + "A", + "Alt+Shift+F6", + "Alt+F6", + }; + + std::vector result( + strings, strings + sizeof(strings)/sizeof(*strings) ); + std::sort( result.begin(), result.end() ); + return result; + }(); + return list; +} + // CommandManager needs to know which defaults are standard and which are in the // full (max) list. void CommandManager::SetMaxList() @@ -452,68 +517,14 @@ void CommandManager::SetMaxList() // instead use flags in the menu entrys to indicate whether the default // shortcut is standard or full. - mMaxListOnly.Clear(); + mMaxListOnly.clear(); // if the full list, don't exclude any. bool bFull = gPrefs->ReadBool(wxT("/GUI/Shortcuts/FullDefaults"),false); if( bFull ) return; - // These short cuts are for the max list only.... - //mMaxListOnly.Add( "Ctrl+I" ); - mMaxListOnly.Add( "Ctrl+Alt+I" ); - mMaxListOnly.Add( "Ctrl+J" ); - mMaxListOnly.Add( "Ctrl+Alt+J" ); - mMaxListOnly.Add( "Ctrl+Alt+V" ); - mMaxListOnly.Add( "Alt+X" ); - mMaxListOnly.Add( "Alt+K" ); - mMaxListOnly.Add( "Shift+Alt+X" ); - mMaxListOnly.Add( "Shift+Alt+K" ); - mMaxListOnly.Add( "Alt+L" ); - mMaxListOnly.Add( "Shift+Alt+C" ); - mMaxListOnly.Add( "Alt+I" ); - mMaxListOnly.Add( "Alt+J" ); - mMaxListOnly.Add( "Shift+Alt+J" ); - mMaxListOnly.Add( "Ctrl+Shift+A" ); - mMaxListOnly.Add( "Q" ); - //mMaxListOnly.Add( "Shift+J" ); - //mMaxListOnly.Add( "Shift+K" ); - //mMaxListOnly.Add( "Shift+Home" ); - //mMaxListOnly.Add( "Shift+End" ); - mMaxListOnly.Add( "Ctrl+[" ); - mMaxListOnly.Add( "Ctrl+]" ); - mMaxListOnly.Add( "1" ); - mMaxListOnly.Add( "Shift+F5" ); - mMaxListOnly.Add( "Shift+F6" ); - mMaxListOnly.Add( "Shift+F7" ); - mMaxListOnly.Add( "Shift+F8" ); - mMaxListOnly.Add( "Ctrl+Shift+F5" ); - mMaxListOnly.Add( "Ctrl+Shift+F7" ); - mMaxListOnly.Add( "Ctrl+Shift+N" ); - mMaxListOnly.Add( "Ctrl+Shift+M" ); - mMaxListOnly.Add( "Ctrl+Home" ); - mMaxListOnly.Add( "Ctrl+End" ); - mMaxListOnly.Add( "Shift+C" ); - mMaxListOnly.Add( "Alt+Shift+Up" ); - mMaxListOnly.Add( "Alt+Shift+Down" ); - mMaxListOnly.Add( "Shift+P" ); - mMaxListOnly.Add( "Alt+Shift+Left" ); - mMaxListOnly.Add( "Alt+Shift+Right" ); - mMaxListOnly.Add( "Ctrl+Shift+T" ); - //mMaxListOnly.Add( "Command+M" ); - //mMaxListOnly.Add( "Option+Command+M" ); - mMaxListOnly.Add( "Shift+H" ); - mMaxListOnly.Add( "Shift+O" ); - mMaxListOnly.Add( "Shift+I" ); - mMaxListOnly.Add( "Shift+N" ); - mMaxListOnly.Add( "D" ); - mMaxListOnly.Add( "A" ); - mMaxListOnly.Add( "Alt+Shift+F6" ); - mMaxListOnly.Add( "Alt+F6" ); - - std::transform( mMaxListOnly.begin(), mMaxListOnly.end(), mMaxListOnly.begin(), - KeyStringNormalize ); - mMaxListOnly.Sort(); + mMaxListOnly = ExcludedList(); } @@ -1013,7 +1024,7 @@ CommandListEntry *CommandManager::NewIdentifier(const wxString & nameIn, entry->name = name; entry->label = label; - entry->key = KeyStringNormalize(accel.BeforeFirst(wxT('\t'))); + entry->key = NormalizedKeyString{ accel.BeforeFirst(wxT('\t')) }; entry->defaultKey = entry->key; entry->labelPrefix = labelPrefix; entry->labelTop = wxMenuItem::GetLabelText(mCurrentMenuName); @@ -1035,13 +1046,15 @@ CommandListEntry *CommandManager::NewIdentifier(const wxString & nameIn, // Note that the default is unaffected, intentionally so. // There are effectively two levels of default, the full (max) list // and the normal reduced list. - if( mMaxListOnly.Index( entry->key ) !=-1) - entry->key = wxT(""); + if( std::binary_search( mMaxListOnly.begin(), mMaxListOnly.end(), + entry->key ) ) + entry->key = {}; - // Key from preferences overridse the default key given + // Key from preferences overrides the default key given gPrefs->SetPath(wxT("/NewKeys")); if (gPrefs->HasEntry(entry->name)) { - entry->key = KeyStringNormalize(gPrefs->Read(entry->name, entry->key)); + entry->key = + NormalizedKeyString{ gPrefs->Read(entry->name, entry->key.Raw()) }; } gPrefs->SetPath(wxT("/")); @@ -1074,7 +1087,7 @@ CommandListEntry *CommandManager::NewIdentifier(const wxString & nameIn, #endif mCommandNameHash[entry->name] = entry; - if (entry->key != wxT("")) { + if (!entry->key.empty()) { mCommandKeyHash[entry->key] = entry; } @@ -1084,9 +1097,9 @@ CommandListEntry *CommandManager::NewIdentifier(const wxString & nameIn, wxString CommandManager::GetLabel(const CommandListEntry *entry) const { wxString label = entry->label; - if (!entry->key.IsEmpty()) + if (!entry->key.empty()) { - label += wxT("\t") + entry->key; + label += wxT("\t") + entry->key.Raw(); } return label; @@ -1103,7 +1116,7 @@ wxString CommandManager::GetLabelWithDisabledAccel(const CommandListEntry *entry #if 1 wxString Accel = ""; do{ - if (!entry->key.IsEmpty()) + if (!entry->key.empty()) { // Dummy accelerator that looks Ok in menus but is non functional. // Note the space before the key. @@ -1136,7 +1149,7 @@ wxString CommandManager::GetLabelWithDisabledAccel(const CommandListEntry *entry #endif //wxLogDebug("Added Accel:[%s][%s]", entry->label, entry->key ); // Normal accelerator. - Accel = wxString("\t") + entry->key; + Accel = wxString("\t") + entry->key.Raw(); } } while (false ); label += Accel; @@ -1251,18 +1264,19 @@ void CommandManager::Modify(const wxString &name, const wxString &newLabel) } } -void CommandManager::SetKeyFromName(const wxString &name, const wxString &key) +void CommandManager::SetKeyFromName(const wxString &name, + const NormalizedKeyString &key) { CommandListEntry *entry = mCommandNameHash[name]; if (entry) { - entry->key = KeyStringNormalize(key); + entry->key = key; } } -void CommandManager::SetKeyFromIndex(int i, const wxString &key) +void CommandManager::SetKeyFromIndex(int i, const NormalizedKeyString &key) { const auto &entry = mCommandList[i]; - entry->key = KeyStringNormalize(key); + entry->key = key; } void CommandManager::TellUserWhyDisallowed( const wxString & Name, CommandFlag flagsGot, CommandMask flagsRequired ) @@ -1352,7 +1366,7 @@ wxString CommandManager::DescribeCommandsAndShortcuts if (!name.empty()) { auto keyStr = GetKeyFromName(name); if (!keyStr.empty()){ - auto keyString = KeyStringDisplay(keyStr, true); + auto keyString = keyStr.Display(true); auto format = wxT("%s %s(%s)"); #ifdef __WXMAC__ // The unicode controls push and pop left-to-right embedding. @@ -1649,8 +1663,8 @@ void CommandManager::GetAllCommandLabels(wxArrayString &names, void CommandManager::GetAllCommandData( wxArrayString &names, - wxArrayString &keys, - wxArrayString &default_keys, + std::vector &keys, + std::vector &default_keys, wxArrayString &labels, wxArrayString &categories, #if defined(EXPERIMENTAL_KEY_VIEW) @@ -1662,8 +1676,8 @@ void CommandManager::GetAllCommandData( if (!entry->multi) { names.Add(entry->name); - keys.Add(entry->key); - default_keys.Add(entry->defaultKey); + keys.push_back(entry->key); + default_keys.push_back(entry->defaultKey); labels.Add(entry->label); categories.Add(entry->labelTop); #if defined(EXPERIMENTAL_KEY_VIEW) @@ -1673,8 +1687,8 @@ void CommandManager::GetAllCommandData( else if( includeMultis ) { names.Add(entry->name); - keys.Add(entry->key); - default_keys.Add(entry->defaultKey); + keys.push_back(entry->key); + default_keys.push_back(entry->defaultKey); labels.Add(entry->label); categories.Add(entry->labelTop); #if defined(EXPERIMENTAL_KEY_VIEW) @@ -1727,22 +1741,22 @@ wxString CommandManager::GetCategoryFromName(const wxString &name) return entry->labelTop; } -wxString CommandManager::GetKeyFromName(const wxString &name) const +NormalizedKeyString CommandManager::GetKeyFromName(const wxString &name) const { CommandListEntry *entry = // May create a NULL entry const_cast(this)->mCommandNameHash[name]; if (!entry) - return wxT(""); + return {}; return entry->key; } -wxString CommandManager::GetDefaultKeyFromName(const wxString &name) +NormalizedKeyString CommandManager::GetDefaultKeyFromName(const wxString &name) { CommandListEntry *entry = mCommandNameHash[name]; if (!entry) - return wxT(""); + return {}; return entry->defaultKey; } @@ -1755,7 +1769,7 @@ bool CommandManager::HandleXMLTag(const wxChar *tag, const wxChar **attrs) if (!wxStrcmp(tag, wxT("command"))) { wxString name; - wxString key; + NormalizedKeyString key; while(*attrs) { const wxChar *attr = *attrs++; @@ -1767,12 +1781,12 @@ bool CommandManager::HandleXMLTag(const wxChar *tag, const wxChar **attrs) if (!wxStrcmp(attr, wxT("name")) && XMLValueChecker::IsGoodString(value)) name = value; if (!wxStrcmp(attr, wxT("key")) && XMLValueChecker::IsGoodString(value)) - key = KeyStringNormalize(value); + key = NormalizedKeyString{ value }; } if (mCommandNameHash[name]) { if (GetDefaultKeyFromName(name) != key) { - mCommandNameHash[name]->key = KeyStringNormalize(key); + mCommandNameHash[name]->key = key; mXMLKeysRead++; } } @@ -1809,7 +1823,7 @@ void CommandManager::WriteXML(XMLWriter &xmlFile) const xmlFile.StartTag(wxT("command")); xmlFile.WriteAttr(wxT("name"), entry->name); xmlFile.WriteAttr(wxT("label"), label); - xmlFile.WriteAttr(wxT("key"), entry->key); + xmlFile.WriteAttr(wxT("key"), entry->key.Raw()); xmlFile.EndTag(wxT("command")); } @@ -1865,7 +1879,7 @@ void CommandManager::CheckDups() { int cnt = mCommandList.size(); for (size_t j = 0; (int)j < cnt; j++) { - if (mCommandList[j]->key.IsEmpty()) { + if (mCommandList[j]->key.empty()) { continue; } @@ -1881,7 +1895,7 @@ void CommandManager::CheckDups() if (mCommandList[i]->key == mCommandList[j]->key) { wxString msg; msg.Printf(wxT("key combo '%s' assigned to '%s' and '%s'"), - mCommandList[i]->key, + mCommandList[i]->key.Raw(), mCommandList[i]->label.BeforeFirst(wxT('\t')), mCommandList[j]->label.BeforeFirst(wxT('\t'))); wxASSERT_MSG(mCommandList[i]->key != mCommandList[j]->key, msg); diff --git a/src/commands/CommandManager.h b/src/commands/CommandManager.h index add7e2c82..5f7c075bd 100644 --- a/src/commands/CommandManager.h +++ b/src/commands/CommandManager.h @@ -18,6 +18,7 @@ #include "CommandFlag.h" #include "../MemoryX.h" +#include "Keyboard.h" #include #include #include @@ -63,8 +64,8 @@ struct CommandListEntry { int id; wxString name; - wxString key; - wxString defaultKey; + NormalizedKeyString key; + NormalizedKeyString defaultKey; wxString label; wxString labelPrefix; wxString labelTop; @@ -93,6 +94,27 @@ using SubMenuList = std::vector < movable_ptr >; // so we don't want the structures to relocate with vector operations. using CommandList = std::vector>; +namespace std +{ +#ifdef __AUDACITY_OLD_STD__ + namespace tr1 + { +#endif + template struct hash; + template<> struct hash< NormalizedKeyString > { + size_t operator () (const NormalizedKeyString &str) const // noexcept + { + auto &stdstr = str.Raw(); // no allocations, a cheap fetch + using Hasher = hash< wxString >; + return Hasher{}( stdstr ); + } + }; +#ifdef __AUDACITY_OLD_STD__ + } +#endif +} + +using CommandKeyHash = std::unordered_map; using CommandNameHash = std::unordered_map; using CommandIDHash = std::unordered_map; @@ -234,8 +256,8 @@ class AUDACITY_DLL_API CommandManager final : public XMLTagHandler // Modifying accelerators // - void SetKeyFromName(const wxString &name, const wxString &key); - void SetKeyFromIndex(int i, const wxString &key); + void SetKeyFromName(const wxString &name, const NormalizedKeyString &key); + void SetKeyFromIndex(int i, const NormalizedKeyString &key); // // Executing commands @@ -255,7 +277,9 @@ class AUDACITY_DLL_API CommandManager final : public XMLTagHandler void GetAllCommandNames(wxArrayString &names, bool includeMultis); void GetAllCommandLabels(wxArrayString &labels, bool includeMultis); void GetAllCommandData( - wxArrayString &names, wxArrayString &keys, wxArrayString &default_keys, + wxArrayString &names, + std::vector &keys, + std::vector &default_keys, wxArrayString &labels, wxArrayString &categories, #if defined(EXPERIMENTAL_KEY_VIEW) wxArrayString &prefixes, @@ -266,8 +290,8 @@ class AUDACITY_DLL_API CommandManager final : public XMLTagHandler wxString GetLabelFromName(const wxString &name); wxString GetPrefixedLabelFromName(const wxString &name); wxString GetCategoryFromName(const wxString &name); - wxString GetKeyFromName(const wxString &name) const; - wxString GetDefaultKeyFromName(const wxString &name); + NormalizedKeyString GetKeyFromName(const wxString &name) const; + NormalizedKeyString GetDefaultKeyFromName(const wxString &name); bool GetEnabled(const wxString &name); @@ -294,6 +318,9 @@ class AUDACITY_DLL_API CommandManager final : public XMLTagHandler // user-visible string. const LocalizedCommandNameVector &commands) const; + // Sorted list of the shortcut keys to be exluded from the standard defaults + static const std::vector &ExcludedList(); + protected: // @@ -352,14 +379,15 @@ protected: XMLTagHandler *HandleXMLChild(const wxChar *tag) override; private: - // mMaxList only holds shortcuts that should not be added (by default). - wxSortedArrayString mMaxListOnly; + // mMaxList only holds shortcuts that should not be added (by default) + // and is sorted. + std::vector mMaxListOnly; MenuBarList mMenuBarList; SubMenuList mSubMenuList; CommandList mCommandList; CommandNameHash mCommandNameHash; - CommandNameHash mCommandKeyHash; + CommandKeyHash mCommandKeyHash; CommandIDHash mCommandIDHash; int mCurrentID; int mXMLKeysRead; diff --git a/src/commands/Keyboard.cpp b/src/commands/Keyboard.cpp index 4e0458a37..8072d7731 100644 --- a/src/commands/Keyboard.cpp +++ b/src/commands/Keyboard.cpp @@ -13,7 +13,7 @@ #include "Keyboard.h" -wxString KeyStringNormalize(const wxString & key) +NormalizedKeyString::NormalizedKeyString(const wxString & key) { #if defined(__WXMAC__) wxString newkey; @@ -44,16 +44,16 @@ wxString KeyStringNormalize(const wxString & key) newkey += wxT("Ctrl+"); } - return newkey + temp.AfterLast(wxT('+')); + (wxString&)*this = newkey + temp.AfterLast(wxT('+')); #else - return key; + (wxString&)*this = key; #endif } -wxString KeyStringDisplay(const wxString & key, bool usesSpecialChars) +wxString NormalizedKeyString::Display(bool usesSpecialChars) const { (void)usesSpecialChars;//compiler food - wxString newkey = KeyStringNormalize(key); + wxString newkey = *this; #if defined(__WXMAC__) if (!usesSpecialChars) { @@ -75,7 +75,7 @@ wxString KeyStringDisplay(const wxString & key, bool usesSpecialChars) return newkey; } -wxString KeyEventToKeyString(const wxKeyEvent & event) +NormalizedKeyString KeyEventToKeyString(const wxKeyEvent & event) { wxString newStr = wxT(""); @@ -332,9 +332,9 @@ wxString KeyEventToKeyString(const wxKeyEvent & event) newStr += wxT("NUMPAD_DIVIDE"); break; default: - return wxT(""); // Don't do anything if we don't recognize the key + return {}; // Don't do anything if we don't recognize the key } } - return KeyStringNormalize(newStr); + return NormalizedKeyString{ newStr }; } diff --git a/src/commands/Keyboard.h b/src/commands/Keyboard.h index 4f39e6663..6b9b7222d 100644 --- a/src/commands/Keyboard.h +++ b/src/commands/Keyboard.h @@ -9,10 +9,41 @@ **********************************************************************/ +#ifndef __AUDACITY_KEYBOARD__ +#define __AUDACITY_KEYBOARD__ + #include #include #include -wxString KeyStringNormalize(const wxString & key); -wxString KeyStringDisplay(const wxString & key, bool useSpecialChars = false); -wxString KeyEventToKeyString(const wxKeyEvent & keyEvent); +struct NormalizedKeyString : private wxString +{ + NormalizedKeyString() = default; + + explicit NormalizedKeyString( const wxString &str ); + + wxString Display(bool usesSpecialChars = false) const; + + const wxString &Raw() const { return *this; } + + bool NoCaseEqual( const NormalizedKeyString &other ) const + { return 0 == this->Raw() .CmpNoCase( other.Raw() ); } + + using wxString::empty; +}; + +inline bool operator == +( const NormalizedKeyString &a, const NormalizedKeyString &b) +{ return a.Raw () == b.Raw(); } + +inline bool operator != +( const NormalizedKeyString &a, const NormalizedKeyString &b) +{ return a.Raw () != b.Raw(); } + +inline bool operator < +( const NormalizedKeyString &a, const NormalizedKeyString &b) +{ return a.Raw () < b.Raw(); } + +NormalizedKeyString KeyEventToKeyString(const wxKeyEvent & keyEvent); + +#endif diff --git a/src/prefs/KeyConfigPrefs.cpp b/src/prefs/KeyConfigPrefs.cpp index 8e3d17dc4..789d303b5 100644 --- a/src/prefs/KeyConfigPrefs.cpp +++ b/src/prefs/KeyConfigPrefs.cpp @@ -271,9 +271,9 @@ void KeyConfigPrefs::RefreshBindings(bool bSort) wxArrayString Prefixes; mNames.Clear(); - mKeys.Clear(); - mDefaultKeys.Clear(); - mStandardDefaultKeys.Clear(); + mKeys.clear(); + mDefaultKeys.clear(); + mStandardDefaultKeys.clear(); mManager->GetAllCommandData( mNames, mKeys, @@ -363,69 +363,14 @@ void KeyConfigPrefs::OnDefaults(wxCommandEvent & WXUNUSED(event)) PopupMenu(&Menu);//, wxPoint(0, 0)); } -void KeyConfigPrefs::FilterKeys( wxArrayString & arr ) +void KeyConfigPrefs::FilterKeys( std::vector & arr ) { - wxSortedArrayString MaxListOnly; + const auto &MaxListOnly = CommandManager::ExcludedList(); - // These short cuts are for the max list only.... - //MaxListOnly.Add( "Ctrl+I" ); - MaxListOnly.Add( "Ctrl+Alt+I" ); - MaxListOnly.Add( "Ctrl+J" ); - MaxListOnly.Add( "Ctrl+Alt+J" ); - MaxListOnly.Add( "Ctrl+Alt+V" ); - MaxListOnly.Add( "Alt+X" ); - MaxListOnly.Add( "Alt+K" ); - MaxListOnly.Add( "Shift+Alt+X" ); - MaxListOnly.Add( "Shift+Alt+K" ); - MaxListOnly.Add( "Alt+L" ); - MaxListOnly.Add( "Shift+Alt+C" ); - MaxListOnly.Add( "Alt+I" ); - MaxListOnly.Add( "Alt+J" ); - MaxListOnly.Add( "Shift+Alt+J" ); - MaxListOnly.Add( "Ctrl+Shift+A" ); - MaxListOnly.Add( "Q" ); - //MaxListOnly.Add( "Shift+J" ); - //MaxListOnly.Add( "Shift+K" ); - //MaxListOnly.Add( "Shift+Home" ); - //MaxListOnly.Add( "Shift+End" ); - MaxListOnly.Add( "Ctrl+[" ); - MaxListOnly.Add( "Ctrl+]" ); - MaxListOnly.Add( "1" ); - MaxListOnly.Add( "Shift+F5" ); - MaxListOnly.Add( "Shift+F6" ); - MaxListOnly.Add( "Shift+F7" ); - MaxListOnly.Add( "Shift+F8" ); - MaxListOnly.Add( "Ctrl+Shift+F5" ); - MaxListOnly.Add( "Ctrl+Shift+F7" ); - MaxListOnly.Add( "Ctrl+Shift+N" ); - MaxListOnly.Add( "Ctrl+Shift+M" ); - MaxListOnly.Add( "Ctrl+Home" ); - MaxListOnly.Add( "Ctrl+End" ); - MaxListOnly.Add( "Shift+C" ); - MaxListOnly.Add( "Alt+Shift+Up" ); - MaxListOnly.Add( "Alt+Shift+Down" ); - MaxListOnly.Add( "Shift+P" ); - MaxListOnly.Add( "Alt+Shift+Left" ); - MaxListOnly.Add( "Alt+Shift+Right" ); - MaxListOnly.Add( "Ctrl+Shift+T" ); - //MaxListOnly.Add( "Command+M" ); - //MaxListOnly.Add( "Option+Command+M" ); - MaxListOnly.Add( "Shift+H" ); - MaxListOnly.Add( "Shift+O" ); - MaxListOnly.Add( "Shift+I" ); - MaxListOnly.Add( "Shift+N" ); - MaxListOnly.Add( "D" ); - MaxListOnly.Add( "A" ); - MaxListOnly.Add( "Alt+Shift+F6" ); - MaxListOnly.Add( "Alt+F6" ); - - std::transform( MaxListOnly.begin(), MaxListOnly.end(), MaxListOnly.begin(), - KeyStringNormalize ); - MaxListOnly.Sort(); // Remove items that are in MaxList. - for (size_t i = 0; i < arr.GetCount(); i++) { - if( MaxListOnly.Index( arr[i] ) != wxNOT_FOUND ) - arr[i]= wxT(""); + for (size_t i = 0; i < arr.size(); i++) { + if( std::binary_search(MaxListOnly.begin(), MaxListOnly.end(), arr[i]) ) + arr[i] = {}; } } @@ -438,7 +383,7 @@ void KeyConfigPrefs::OnImportDefaults(wxCommandEvent & event) if( event.GetId() == 1 ) FilterKeys( mNewKeys ); - for (size_t i = 0; i < mNewKeys.GetCount(); i++) { + for (size_t i = 0; i < mNewKeys.size(); i++) { mManager->SetKeyFromIndex(i, mNewKeys[i]); } @@ -464,7 +409,7 @@ void KeyConfigPrefs::OnHotkeyKeyDown(wxKeyEvent & e) return; } - t->SetValue(KeyStringDisplay(KeyEventToKeyString(e))); + t->SetValue(KeyEventToKeyString(e).Display()); } void KeyConfigPrefs::OnHotkeyChar(wxKeyEvent & WXUNUSED(e)) @@ -475,7 +420,7 @@ void KeyConfigPrefs::OnHotkeyChar(wxKeyEvent & WXUNUSED(e)) void KeyConfigPrefs::OnHotkeyKillFocus(wxFocusEvent & e) { if (mKey->GetValue().IsEmpty() && mCommandSelected != wxNOT_FOUND) { - mKey->AppendText(mView->GetKey(mCommandSelected)); + mKey->AppendText(mView->GetKey(mCommandSelected).Display()); } e.Skip(); @@ -511,7 +456,7 @@ void KeyConfigPrefs::OnFilterKeyDown(wxKeyEvent & e) } if (mViewType == ViewByKey) { - wxString key = KeyStringDisplay(KeyEventToKeyString(e)); + wxString key = KeyEventToKeyString(e).Display(); t->SetValue(key); if (key != wxEmptyString) { @@ -543,14 +488,14 @@ void KeyConfigPrefs::OnFilterChar(wxKeyEvent & e) // Given a hotkey combination, returns the name (description) of the // corresponding command, or the empty string if none is found. -wxString KeyConfigPrefs::NameFromKey(const wxString & key) +wxString KeyConfigPrefs::NameFromKey(const NormalizedKeyString & key) { return mView->GetNameByKey(key); } // Sets the selected command to have this key // This is not yet a committed change, which will happen on a save. -void KeyConfigPrefs::SetKeyForSelected(const wxString & key) +void KeyConfigPrefs::SetKeyForSelected(const NormalizedKeyString & key) { wxString name = mView->GetName(mCommandSelected); @@ -575,7 +520,7 @@ void KeyConfigPrefs::OnSet(wxCommandEvent & WXUNUSED(event)) return; } - wxString key = mKey->GetValue(); + NormalizedKeyString key { mKey->GetValue() }; wxString oldname = mView->GetNameByKey(key); wxString newname = mView->GetName(mCommandSelected); @@ -595,7 +540,7 @@ void KeyConfigPrefs::OnSet(wxCommandEvent & WXUNUSED(event)) if (AudacityMessageBox( wxString::Format( _("The keyboard shortcut '%s' is already assigned to:\n\n\t'%s'\n\nClick OK to assign the shortcut to\n\n\t'%s'\n\ninstead. Otherwise, click Cancel."), - key, + mKey->GetValue(), oldlabel, newlabel), _("Error"), wxOK | wxCANCEL | wxICON_STOP | wxCENTRE, this) == wxCANCEL) @@ -603,9 +548,9 @@ void KeyConfigPrefs::OnSet(wxCommandEvent & WXUNUSED(event)) return; } - mView->SetKeyByName(oldname, wxEmptyString); - mManager->SetKeyFromName(oldname, wxEmptyString); - mNewKeys[mNames.Index(oldname)].Empty(); + mView->SetKeyByName(oldname, {}); + mManager->SetKeyFromName(oldname, {}); + mNewKeys[mNames.Index(oldname)] = {}; } @@ -617,7 +562,7 @@ void KeyConfigPrefs::OnClear(wxCommandEvent& WXUNUSED(event)) mKey->Clear(); if (mCommandSelected != wxNOT_FOUND) { - SetKeyForSelected(wxEmptyString); + SetKeyForSelected({}); } } @@ -629,7 +574,7 @@ void KeyConfigPrefs::OnSelected(wxCommandEvent & WXUNUSED(e)) if (mCommandSelected != wxNOT_FOUND) { bool canset = mView->CanSetKey(mCommandSelected); if (canset) { - mKey->AppendText(mView->GetKey(mCommandSelected)); + mKey->AppendText(mView->GetKey(mCommandSelected).Display()); } mKey->Enable(canset); @@ -678,13 +623,13 @@ bool KeyConfigPrefs::Commit() bool bFull = gPrefs->ReadBool(wxT("/GUI/Shortcuts/FullDefaults"), false); for (size_t i = 0; i < mNames.GetCount(); i++) { - wxString dkey = bFull ? KeyStringNormalize(mDefaultKeys[i]) : KeyStringNormalize(mStandardDefaultKeys[i]); + const auto &dkey = bFull ? mDefaultKeys[i] : mStandardDefaultKeys[i]; wxString name = wxT("/NewKeys/") + mNames[i]; - wxString key = KeyStringNormalize(mNewKeys[i]); + const auto &key = mNewKeys[i]; if (gPrefs->HasEntry(name)) { - if (key != KeyStringNormalize(gPrefs->Read(name, key))) { - gPrefs->Write(name, key); + if (key != NormalizedKeyString{ gPrefs->Read(name, key.Raw()) } ) { + gPrefs->Write(name, key.Raw()); } if (key == dkey) { gPrefs->DeleteEntry(name); @@ -692,7 +637,7 @@ bool KeyConfigPrefs::Commit() } else { if (key != dkey) { - gPrefs->Write(name, key); + gPrefs->Write(name, key.Raw()); } } } diff --git a/src/prefs/KeyConfigPrefs.h b/src/prefs/KeyConfigPrefs.h index 8f924d83a..a69d92045 100644 --- a/src/prefs/KeyConfigPrefs.h +++ b/src/prefs/KeyConfigPrefs.h @@ -31,6 +31,7 @@ class ShuttleGui; #include "PrefsPanel.h" class wxStaticText; +struct NormalizedKeyString; class KeyConfigPrefs final : public PrefsPanel { @@ -44,9 +45,9 @@ private: void Populate(); void PopulateOrExchange(ShuttleGui & S); void RefreshBindings(bool bSort); - void FilterKeys( wxArrayString & arr ); - wxString NameFromKey(const wxString & key); - void SetKeyForSelected(const wxString & key); + void FilterKeys( std::vector & arr ); + wxString NameFromKey(const NormalizedKeyString & key); + void SetKeyForSelected(const NormalizedKeyString & key); void OnViewBy(wxCommandEvent & e); void OnDefaults(wxCommandEvent & e); @@ -84,10 +85,10 @@ private: int mCommandSelected; wxArrayString mNames; - wxArrayString mDefaultKeys; // The full set. - wxArrayString mStandardDefaultKeys; // The reduced set. - wxArrayString mKeys; - wxArrayString mNewKeys; // Used for work in progress. + std::vector mDefaultKeys; // The full set. + std::vector mStandardDefaultKeys; // The reduced set. + std::vector mKeys; + std::vector mNewKeys; // Used for work in progress. DECLARE_EVENT_TABLE() }; diff --git a/src/tracks/ui/SelectHandle.cpp b/src/tracks/ui/SelectHandle.cpp index 1275e19c4..d999da35d 100644 --- a/src/tracks/ui/SelectHandle.cpp +++ b/src/tracks/ui/SelectHandle.cpp @@ -913,14 +913,14 @@ HitTestPreview SelectHandle::Preview if (bMultiToolMode) { // Look up the current key binding for Preferences. // (Don't assume it's the default!) - wxString keyStr - (pProject->GetCommandManager()->GetKeyFromName(wxT("Preferences"))); - if (keyStr.IsEmpty()) + auto keyStr = + pProject->GetCommandManager()->GetKeyFromName(wxT("Preferences")) + .Display( true ); + if (keyStr.empty()) // No keyboard preference defined for opening Preferences dialog /* i18n-hint: These are the names of a menu and a command in that menu */ keyStr = _("Edit, Preferences..."); - else - keyStr = KeyStringDisplay(keyStr); + /* i18n-hint: %s is usually replaced by "Ctrl+P" for Windows/Linux, "Command+," for Mac */ tip = wxString::Format( _("Multi-Tool Mode: %s for Mouse and Keyboard Preferences."), diff --git a/src/tracks/ui/TrackControls.cpp b/src/tracks/ui/TrackControls.cpp index 94e1c28b7..4db8dd017 100644 --- a/src/tracks/ui/TrackControls.cpp +++ b/src/tracks/ui/TrackControls.cpp @@ -125,30 +125,31 @@ BEGIN_POPUP_MENU(TrackMenuTable) POPUP_MENU_ITEM(OnSetNameID, _("&Name..."), OnSetName) POPUP_MENU_SEPARATOR() POPUP_MENU_ITEM( - // It is not correct to use KeyStringDisplay here -- wxWidgets will apply - // its equivalent to the key names passed to menu functions. + // It is not correct to use NormalizedKeyString::Display here -- + // wxWidgets will apply its equivalent to the key names passed to menu + // functions. OnMoveUpID, _("Move Track &Up") + wxT("\t") + (GetActiveProject()->GetCommandManager()-> - GetKeyFromName(wxT("TrackMoveUp"))), + GetKeyFromName(wxT("TrackMoveUp")).Raw()), OnMoveTrack) POPUP_MENU_ITEM( OnMoveDownID, _("Move Track &Down") + wxT("\t") + (GetActiveProject()->GetCommandManager()-> - GetKeyFromName(wxT("TrackMoveDown"))), + GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM( OnMoveTopID, _("Move Track to &Top") + wxT("\t") + (GetActiveProject()->GetCommandManager()-> - GetKeyFromName(wxT("TrackMoveTop"))), + GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM( OnMoveBottomID, _("Move Track to &Bottom") + wxT("\t") + (GetActiveProject()->GetCommandManager()-> - GetKeyFromName(wxT("TrackMoveBottom"))), + GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack) END_POPUP_MENU() diff --git a/src/widgets/KeyView.cpp b/src/widgets/KeyView.cpp index 038068102..5491b9cd7 100644 --- a/src/widgets/KeyView.cpp +++ b/src/widgets/KeyView.cpp @@ -178,14 +178,14 @@ KeyView::GetName(int index) const // Returns the command manager index for the given key combination // wxString -KeyView::GetNameByKey(const wxString & key) const +KeyView::GetNameByKey(const NormalizedKeyString & key) const { int cnt = (int) mNodes.size(); // Search the nodes for the key for (int i = 0; i < cnt; i++) { - if (key.CmpNoCase(mNodes[i].key) == 0) + if (key.NoCaseEqual( mNodes[i].key)) { return mNodes[i].name; } @@ -198,14 +198,14 @@ KeyView::GetNameByKey(const wxString & key) const // Returns the index for the given key // int -KeyView::GetIndexByKey(const wxString & key) const +KeyView::GetIndexByKey(const NormalizedKeyString & key) const { int cnt = (int) mNodes.size(); // Search the nodes for the key for (int i = 0; i < cnt; i++) { - if (key.CmpNoCase(mNodes[i].key) == 0) + if (key.NoCaseEqual( mNodes[i].key)) { return mNodes[i].index; } @@ -217,14 +217,14 @@ KeyView::GetIndexByKey(const wxString & key) const // // Returns the key for the given index // -wxString +NormalizedKeyString KeyView::GetKey(int index) const { // Make sure index is valid if (index < 0 || index >= (int) mNodes.size()) { wxASSERT(false); - return wxEmptyString; + return {}; } return mNodes[index].key; @@ -251,7 +251,7 @@ KeyView::CanSetKey(int index) const // Sets the key for the given index // bool -KeyView::SetKey(int index, const wxString & key) +KeyView::SetKey(int index, const NormalizedKeyString & key) { // Make sure index is valid if (index < 0 || index >= (int) mNodes.size()) @@ -274,7 +274,7 @@ KeyView::SetKey(int index, const wxString & key) // Check to see if the key column needs to be expanded int x, y; - GetTextExtent(node.key, &x, &y); + GetTextExtent(node.key.Display(), &x, &y); if (x > mKeyWidth || y > mLineHeight) { // New key is wider than column so recalc extents (will refresh view) @@ -292,7 +292,7 @@ KeyView::SetKey(int index, const wxString & key) // Sets the key for the given name // bool -KeyView::SetKeyByName(const wxString & name, const wxString & key) +KeyView::SetKeyByName(const wxString & name, const NormalizedKeyString & key) { int index = GetIndexByName(name); @@ -465,7 +465,7 @@ KeyView::RecalcExtents() else { // Measure the key - GetTextExtent(node.key, &x, &y); + GetTextExtent(node.key.Display(), &x, &y); mLineHeight = wxMax(mLineHeight, y); mKeyWidth = wxMax(mKeyWidth, x); @@ -531,7 +531,7 @@ KeyView::RefreshBindings(const wxArrayString & names, const wxArrayString & categories, const wxArrayString & prefixes, const wxArrayString & labels, - const wxArrayString & keys, + const std::vector & keys, bool bSort ) { @@ -676,7 +676,7 @@ KeyView::RefreshBindings(const wxArrayString & names, // Fill in remaining info node.name = name; - node.key = KeyStringDisplay(keys[i]); + node.key = keys[i]; node.index = nodecnt++; node.depth = depth; @@ -684,7 +684,7 @@ KeyView::RefreshBindings(const wxArrayString & names, mNodes.push_back(node); // Measure key - GetTextExtent(node.key, &x, &y); + GetTextExtent(node.key.Display(), &x, &y); mLineHeight = wxMax(mLineHeight, y); mKeyWidth = wxMax(mKeyWidth, x); @@ -767,7 +767,7 @@ KeyView::RefreshLines(bool bSort) case ViewByTree: searchit = node.label.Lower() + wxT("\01x") + - node.key.Lower(); + node.key.Display().Lower(); break; case ViewByName: @@ -775,7 +775,7 @@ KeyView::RefreshLines(bool bSort) break; case ViewByKey: - searchit = node.key.Lower(); + searchit = node.key.Display().Lower(); break; } if (searchit.Find(mFilter) == wxNOT_FOUND) @@ -1175,7 +1175,7 @@ KeyView::OnDrawItem(wxDC & dc, const wxRect & rect, size_t line) const x += KV_LEFT_MARGIN; // Draw the key and command columns - dc.DrawText(node->key, x , rect.y); + dc.DrawText(node->key.Display(), x , rect.y); dc.DrawText(label, x + mKeyWidth + KV_COLUMN_SPACER + node->depth * KV_BITMAP_SIZE, rect.y); } else @@ -1193,7 +1193,7 @@ KeyView::OnDrawItem(wxDC & dc, const wxRect & rect, size_t line) const if((mViewType == ViewByName) || (mViewType == ViewByKey)) { // Draw key columnd and then command column - dc.DrawText(node->key, x, rect.y); + dc.DrawText(node->key.Display(), x, rect.y); dc.DrawText(label, x + mKeyWidth + KV_COLUMN_SPACER, rect.y); } } @@ -1446,7 +1446,7 @@ KeyView::OnKeyDown(wxKeyEvent & event) } else if (mViewType == ViewByKey) { - label = GetKey(LineToIndex(i)); + label = GetKey(LineToIndex(i)).Display(); } // Move selection if they match @@ -1480,7 +1480,7 @@ KeyView::OnKeyDown(wxKeyEvent & event) } else if (mViewType == ViewByKey) { - label = GetKey(LineToIndex(i)); + label = GetKey(LineToIndex(i)).Display(); } // Move selection if they match @@ -1638,8 +1638,8 @@ KeyView::CmpKeyNodeByName(KeyNode *t1, KeyNode *t2) bool KeyView::CmpKeyNodeByKey(KeyNode *t1, KeyNode *t2) { - wxString k1 = t1->key; - wxString k2 = t2->key; + wxString k1 = t1->key.Display(); + wxString k2 = t2->key.Display(); // Left node is unassigned, so prefix it if(k1.IsEmpty()) @@ -1748,7 +1748,7 @@ KeyView::GetValue(int line) { value = GetFullLabel(index); } - wxString key = GetKey(index); + wxString key = GetKey(index).Display(); // Add the key if it isn't empty if (!key.IsEmpty()) diff --git a/src/widgets/KeyView.h b/src/widgets/KeyView.h index 70d92c795..740c83f62 100644 --- a/src/widgets/KeyView.h +++ b/src/widgets/KeyView.h @@ -41,7 +41,7 @@ public: wxString category; wxString prefix; wxString label; - wxString key; + NormalizedKeyString key; int index; int line; int depth; @@ -83,7 +83,7 @@ public: const wxArrayString & categories, const wxArrayString & prefixes, const wxArrayString & labels, - const wxArrayString & keys, + const std::vector & keys, bool bSort); int GetSelected() const; @@ -93,13 +93,13 @@ public: int GetIndexByName(const wxString & name) const; wxString GetName(int index) const; - wxString GetNameByKey(const wxString & key) const; + wxString GetNameByKey(const NormalizedKeyString & key) const; - int GetIndexByKey(const wxString & key) const; - wxString GetKey(int index) const; + int GetIndexByKey(const NormalizedKeyString & key) const; + NormalizedKeyString GetKey(int index) const; bool CanSetKey(int index) const; - bool SetKey(int index, const wxString & key); - bool SetKeyByName(const wxString & name, const wxString & key); + bool SetKey(int index, const NormalizedKeyString & key); + bool SetKeyByName(const wxString & name, const NormalizedKeyString & key); void SetView(ViewByType type);