31#include <wx/radiobut.h>
32#include <wx/stattext.h>
33#include <wx/statbox.h>
34#include <wx/textctrl.h>
39#include "../ProjectWindows.h"
40#include "../commands/CommandManager.h"
48#include "../widgets/BasicMenu.h"
49#include "../widgets/KeyView.h"
53#if wxUSE_ACCESSIBILITY
60#define AssignDefaultsButtonID 17001
61#define CurrentComboID 17002
62#define SetButtonID 17003
63#define ClearButtonID 17004
64#define CommandsListID 17005
65#define ExportButtonID 17006
66#define ImportButtonID 17007
68#define ViewByTreeID 17009
69#define ViewByNameID 17010
70#define ViewByKeyID 17011
71#define FilterTimerID 17012
74#define EMPTY_SHORTCUT ("")
76#define NO_SHORTCUT (wxString)((wxChar)7)
100 mFilterPending(false)
101 , mProject{ pProject }
105 auto index = mView->GetIndexByName(
name);
106 mView->SelectNode(index);
121 return XO(
"Preferences for KeyConfig");
126 return "Keyboard_Preferences";
134 S.StartVerticalLay(
true);
136 S.StartStatic( {},
true);
138 S.AddTitle(
XO(
"Keyboard preferences currently unavailable."));
139 S.AddTitle(
XO(
"Open a new project to modify keyboard shortcuts."));
181 {
wxT(
"tree"),
XXO(
"&Tree") },
182 {
wxT(
"name"),
XXO(
"&Name") },
183 {
wxT(
"key"),
XXO(
"&Key") },
190 S.StartStatic(
XO(
"Key Bindings"), 1);
192 S.StartHorizontalLay(wxEXPAND, 0);
194 S.Position(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL).AddTitle(
XO(
"View by:"));
200 S.StartHorizontalLay();
205 .Name(
XO(
"View by tree"))
208 .Name(
XO(
"View by name"))
211 .Name(
XO(
"View by key"))
213#if !defined(__WXMAC__) && wxUSE_ACCESSIBILITY
220 S.EndRadioButtonGroup();
222 S.EndHorizontalLay();
226 S.AddSpace(wxDefaultCoord, wxDefaultCoord, 1);
228 S.StartHorizontalLay(wxALIGN_CENTER_VERTICAL, 0);
230 mFilterLabel =
S.Position(wxALIGN_CENTER_VERTICAL).AddVariableText(
XO(
"Searc&h:"));
237#
if defined(__WXMAC__)
245 S.Position(wxALIGN_NOT | wxALIGN_LEFT)
246 .ConnectRoot(wxEVT_KEY_DOWN,
248 .ConnectRoot(wxEVT_CHAR,
252 S.EndHorizontalLay();
254 S.EndHorizontalLay();
256 S.AddSpace(wxDefaultCoord, 2);
258 S.StartHorizontalLay(wxEXPAND, 1);
262 mView->SetName(
_(
"Bindings"));
268 S.EndHorizontalLay();
270 S.StartThreeColumn();
277#
if defined(__WXMAC__)
283#if !defined(__WXMAC__) && wxUSE_ACCESSIBILITY
287 mKey->SetName(
_(
"Short cut"));
290 .ConnectRoot(wxEVT_KEY_DOWN,
292 .ConnectRoot(wxEVT_CHAR,
294 .ConnectRoot(wxEVT_KILL_FOCUS,
296 .ConnectRoot(wxEVT_CONTEXT_MENU,
307#if defined(__WXMAC__)
308 S.AddFixedText(
XO(
"Note: Pressing Cmd+Q will quit. All other keys are valid."));
311 S.StartThreeColumn();
376 for (
const auto & command :
mNames)
388 using IndexesArray = std::vector<int>;
389 std::unordered_map<NormalizedKeyString, IndexesArray> seen;
391 for (
size_t i{ 0 }; i <
mKeys.size(); i++)
396 if (seen.count(
mKeys[i]) == 0)
397 seen.insert({
mKeys[i], {(int)i} });
400 IndexesArray checkMe{ seen.at(
mKeys[i]) };
401 for (
int index : checkMe)
411 seen.at(
mKeys[i]).push_back(index);
426 const std::vector<NormalizedKeyString> &toAdd)
430 auto searchAddInKeys = [&](
size_t index)
432 for (
size_t k{ 0 }; k < toAdd.size(); k++)
435 else if (toAdd[index] ==
mKeys[k] &&
445 for (
size_t i{ 0 }; i < toAdd.size(); i++)
453 int sRes{ searchAddInKeys(i) };
463"\n * \"%s\" (because the shortcut \'%s\' is used by \"%s\")\n")
474 return disabledShortcuts;
485 if (event.IsShown() &&
mView !=
nullptr)
493 wxString file =
wxT(
"Audacity-keys.xml");
496 XO(
"Select an XML file containing Audacity keyboard shortcuts..."),
513 const std::vector<NormalizedKeyString> oldKeys{
mKeys };
523 XO(
"Error Importing Keyboard Shortcuts"),
538 for (
size_t k{ 0 }; k <
mNames.size(); k++)
545"The file with the shortcuts contains illegal shortcut duplicates for \"%s\" and \"%s\".\nNothing is imported.")
546 .
Format( fMatching, sMatching ),
547 XO(
"Error Importing Keyboard Shortcuts"),
548 wxICON_ERROR | wxCENTRE,
this);
562 if (disabledShortcuts.Translation() != (
""))
563 message +=
XO(
"\nThe following commands are not mentioned in the imported file, "
564 "but have their shortcuts removed because of the conflict with other new shortcuts:\n") +
572 wxString file =
wxT(
"Audacity-keys.xml");
574 file =
SelectFile(FileNames::Operation::Export,
575 XO(
"Export Keyboard Shortcuts As:"),
580 wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
588 XMLFileWriter prefFile{ file,
XO(
"Error Exporting Keyboard Shortcuts") };
601 Menu.Append( 1,
_(
"Standard") );
602 Menu.Append( 2,
_(
"Full") );
612 for (
size_t i = 0; i < arr.size(); i++) {
613 if( std::binary_search(MaxListOnly.begin(), MaxListOnly.end(), arr[i]) )
624 if( event.GetId() == 1 )
627 for (
size_t i = 0; i <
mNewKeys.size(); i++) {
636 wxTextCtrl *t = (wxTextCtrl *)e.GetEventObject();
646 if (e.GetKeyCode() == WXK_TAB) {
647 t->Navigate(e.ShiftDown()
648 ? wxNavigationKeyEvent::IsBackward
649 : wxNavigationKeyEvent::IsForward);
687 wxTextCtrl *t = (wxTextCtrl *)e.GetEventObject();
688 int keycode = e.GetKeyCode();
693 if (keycode == WXK_TAB) {
694 wxNavigationKeyEvent nevent;
695 nevent.SetWindowChange(e.ControlDown());
696 nevent.SetDirection(!e.ShiftDown());
697 nevent.SetEventObject(t);
698 nevent.SetCurrentFocus(t);
699 t->GetParent()->GetEventHandler()->ProcessEvent(nevent);
714 if (keycode == WXK_RETURN) {
751 XO(
"You may not assign a key to this entry"),
753 wxICON_ERROR | wxCENTRE,
768 XO(
"You must select a binding before assigning a shortcut"),
770 wxICON_WARNING | wxCENTRE,
782 for (
size_t i{ 0 }; i <
mNames.size(); i++)
787 if (
mNames[i] == newCommand)
793 oldCommands.push_back(
mNames[i]);
799 if (!oldCommands.empty()) {
809 for (
size_t i{ 1 }; i < oldCommands.size(); i++)
810 oldlabel +=
XO(
"\n\n\t and\n\n\t") +
817"The keyboard shortcut '%s' is already assigned to:\n\n\t%s\n\n\nClick OK to assign the shortcut to\n\n\t%s\n\ninstead. Otherwise, click Cancel.")
824 wxOK | wxCANCEL | wxICON_STOP | wxCENTRE,
830 for (
const auto & command : oldCommands)
861 mKey->Enable(canset);
862 mSet->Enable(canset);
905 bool bFull =
gPrefs->ReadBool(
wxT(
"/GUI/Shortcuts/FullDefaults"),
false);
906 for (
size_t i = 0; i <
mNames.size(); i++) {
933 for (
size_t i = 0; i <
mNames.size(); i++) {
943 return [=](wxWindow *parent, wxWindowID winid,
AudacityProject *pProject)
Handle changing of active project and keep global project pointer.
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), F3 delayedHandler=DefaultDelayedHandlerAction) noexcept(noexcept(handler(std::declval< AudacityException * >())) &&noexcept(handler(nullptr)) &&noexcept(std::function< void(AudacityException *)>{std::move(delayedHandler)}))
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
static const AudacityProject::AttachedObjects::RegisteredFactory key
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString name
XXO("&Cut/Copy/Paste Toolbar")
std::vector< CommandID > CommandIDs
PrefsPanel::Factory KeyConfigPrefsFactory(const CommandID &name)
#define AssignDefaultsButtonID
#define KEY_CONFIG_PREFS_PLUGIN_SYMBOL
NormalizedKeyString KeyEventToKeyString(const wxKeyEvent &event)
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::vector< TranslatableString > TranslatableStrings
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
void Popup(const BasicUI::WindowPlacement &window, const Point &pos={})
Display the menu at pos, invoke at most one action, then hide it.
void WriteXML(XMLWriter &xmlFile) const
static CommandManager & Get(AudacityProject &project)
TranslatableString GetCategoryFromName(const CommandID &name)
void GetAllCommandData(CommandIDs &names, std::vector< NormalizedKeyString > &keys, std::vector< NormalizedKeyString > &default_keys, TranslatableStrings &labels, TranslatableStrings &categories, bool includeMultis)
static const std::vector< NormalizedKeyString > & ExcludedList()
void SetKeyFromName(const CommandID &name, const NormalizedKeyString &key)
NormalizedKeyString GetKeyFromName(const CommandID &name) const
NormalizedKeyString GetDefaultKeyFromName(const CommandID &name)
void SetKeyFromIndex(int i, const NormalizedKeyString &key)
int GetNumberOfKeysRead() const
TranslatableString GetPrefixedLabelFromName(const CommandID &name)
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
virtual bool DeleteEntry(const wxString &key, bool bDeleteGroupIfEmpty=true) wxOVERRIDE
virtual bool HasEntry(const wxString &strName) const wxOVERRIDE
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
FILES_API const FileType XMLFiles
FILES_API const FileType AllFiles
const wxString & GET() const
Explicit conversion to wxString, meant to be ugly-looking and demanding of a comment why it's correct...
A PrefsPanel for keybindings.
void OnFilterKeyDown(wxKeyEvent &e)
void OnImport(wxCommandEvent &e)
void OnHotkeyChar(wxEvent &e)
void OnImportDefaults(wxCommandEvent &e)
TranslatableString MergeWithExistingKeys(const std::vector< NormalizedKeyString > &toAdd)
void OnHotkeyKillFocus(wxEvent &e)
wxStaticText * mFilterLabel
TranslatableString GetDescription() const override
CommandManager * mManager
void PopulateOrExchange(ShuttleGui &S) override
std::vector< NormalizedKeyString > mDefaultKeys
AudacityProject * mProject
ComponentInterfaceSymbol GetSymbol() const override
void FilterKeys(std::vector< NormalizedKeyString > &arr)
void OnSet(wxCommandEvent &e)
bool ContainsIllegalDups(TranslatableString &fMatching, TranslatableString &sMatching) const
void OnHotkeyContext(wxEvent &e)
void OnFilterChar(wxEvent &e)
ManualPageID HelpPageName() override
If not empty string, the Help button is added below the panel.
void OnFilterTimer(wxTimerEvent &e)
CommandID NameFromKey(const NormalizedKeyString &key)
std::vector< NormalizedKeyString > mStandardDefaultKeys
std::vector< NormalizedKeyString > mNewKeys
std::vector< NormalizedKeyString > mKeys
void OnClear(wxCommandEvent &e)
wxRadioButton * mViewByKey
wxRadioButton * mViewByTree
void OnExport(wxCommandEvent &e)
void OnSelected(wxCommandEvent &e)
wxRadioButton * mViewByName
void OnViewBy(wxCommandEvent &e)
void OnDefaults(wxCommandEvent &e)
void RefreshBindings(bool bSort)
void OnShow(wxShowEvent &e)
void OnHotkeyKeyDown(wxKeyEvent &e)
void SetKeyForSelected(const NormalizedKeyString &key)
Provides multiple views of keyboard shortcuts.
bool CanSetKey(int index) const
bool SetKey(int index, const NormalizedKeyString &key)
void SetView(ViewByType type)
void SetFilter(const wxString &filter)
NormalizedKeyString GetKey(int index) const
void RefreshBindings(const CommandIDs &names, const TranslatableStrings &categories, const TranslatableStrings &prefixes, const TranslatableStrings &labels, const std::vector< NormalizedKeyString > &keys, bool bSort)
bool SetKeyByName(const CommandID &name, const NormalizedKeyString &key)
wxString GetName() const override
CommandID GetNameByKey(const NormalizedKeyString &key) const
Base class for a panel in the PrefsDialog. Classes derived from this class include BatchPrefs,...
std::function< PrefsPanel *(wxWindow *parent, wxWindowID winid, AudacityProject *) > Factory
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Holds a msgid for the translation catalog; may also bind format arguments.
TranslatableString & Format(Args &&...args) &
Capture variadic format arguments (by copy) when there is no plural.
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
Reads a file and passes the results through an XMLTagHandler.
const TranslatableString & GetErrorStr() const
bool Parse(XMLTagHandler *baseHandler, const FilePath &fname)
Wrapper to output XML data to files.
PrefsPanel::Registration sAttachment
wxString Display(bool usesSpecialChars=false) const