1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-10-21 14:02:57 +02:00

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.
This commit is contained in:
Paul Licameli
2018-02-08 21:16:13 -05:00
parent 19014f22b7
commit e5052a1973
10 changed files with 256 additions and 236 deletions

View File

@@ -440,6 +440,71 @@ CommandManager::~CommandManager()
PurgeData();
}
const std::vector<NormalizedKeyString> &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<NormalizedKeyString> 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<NormalizedKeyString> &keys,
std::vector<NormalizedKeyString> &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<CommandManager*>(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);

View File

@@ -18,6 +18,7 @@
#include "CommandFlag.h"
#include "../MemoryX.h"
#include "Keyboard.h"
#include <vector>
#include <wx/string.h>
#include <wx/menu.h>
@@ -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<SubMenuListEntry> >;
// so we don't want the structures to relocate with vector operations.
using CommandList = std::vector<movable_ptr<CommandListEntry>>;
namespace std
{
#ifdef __AUDACITY_OLD_STD__
namespace tr1
{
#endif
template<typename T> 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<NormalizedKeyString, CommandListEntry*>;
using CommandNameHash = std::unordered_map<wxString, CommandListEntry*>;
using CommandIDHash = std::unordered_map<int, CommandListEntry*>;
@@ -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<NormalizedKeyString> &keys,
std::vector<NormalizedKeyString> &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<NormalizedKeyString> &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<NormalizedKeyString> mMaxListOnly;
MenuBarList mMenuBarList;
SubMenuList mSubMenuList;
CommandList mCommandList;
CommandNameHash mCommandNameHash;
CommandNameHash mCommandKeyHash;
CommandKeyHash mCommandKeyHash;
CommandIDHash mCommandIDHash;
int mCurrentID;
int mXMLKeysRead;

View File

@@ -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 };
}

View File

@@ -9,10 +9,41 @@
**********************************************************************/
#ifndef __AUDACITY_KEYBOARD__
#define __AUDACITY_KEYBOARD__
#include <wx/defs.h>
#include <wx/event.h>
#include <wx/string.h>
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