From e5052a1973ff89577bc268739457d1e54b4f907c Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Thu, 8 Feb 2018 21:16:13 -0500 Subject: [PATCH] Use a type distinction for key strings in normalized form... ... Such are not for display to the user. They are appended to menu item names to identify accelerators, and wxWidgets transforms them appropriately for the operating system. --- src/commands/CommandManager.cpp | 188 +++++++++++++++++--------------- src/commands/CommandManager.h | 48 ++++++-- src/commands/Keyboard.cpp | 16 +-- src/commands/Keyboard.h | 37 ++++++- src/prefs/KeyConfigPrefs.cpp | 107 +++++------------- src/prefs/KeyConfigPrefs.h | 15 +-- src/tracks/ui/SelectHandle.cpp | 10 +- src/tracks/ui/TrackControls.cpp | 13 ++- src/widgets/KeyView.cpp | 44 ++++---- src/widgets/KeyView.h | 14 +-- 10 files changed, 256 insertions(+), 236 deletions(-) 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);