37#include <wx/evtloop.h>
41#include <wx/windowptr.h>
60 std::unique_ptr<wxMenu>
menu;
63MenuBarListEntry::MenuBarListEntry(
const wxString &
name, wxMenuBar *menubar)
73 : menu{
std::make_unique<wxMenu>() }
113 [this](const auto &item, const auto&) {
114 const auto pCurrentMenu = CurrentMenu();
120 else TypeSwitch::VDispatch<void, LeafTypes>(item,
124 pSpecial->fn(mProject, *pCurrentMenu);
126 [
this](
auto &item){ DoVisit(item); }
131 if (mbSeparatorAllowed)
132 CurrentMenu()->AppendSeparator();
133 Populator::DoSeparator();
137 auto menubar = AddMenuBar(
wxT(
"appmenu"));
151 bool GetEnabled() const final;
152 void Check(
bool checked) final;
153 void Enable(
bool enabled) final;
154 void EnableMultiItem(
bool enabled) final;
160 std::unique_ptr<CommandManager::CommandListEntry>
170 void BeginOccultCommands() final;
171 void EndOccultCommands() final;
173 std::unique_ptr<wxMenuBar> AddMenuBar(const wxString & sMenu);
174 wxMenuBar * CurrentMenuBar() const;
175 wxMenuBar * GetMenuBar(const wxString & sMenu) const;
176 wxMenu * CurrentSubMenu() const;
177 wxMenu * CurrentMenu() const;
181 std::unique_ptr<wxMenuBar> mTempMenuBar;
182 std::unique_ptr<wxMenu> uCurrentMenu;
183 wxMenu *mCurrentMenu {};
186MenuItemVisitor::CommandListEntryEx::~CommandListEntryEx() =
default;
191 if (menu && checkmarkFn && !isOccult) {
192 menu->Check(
id, checkmarkFn(
project));
201 menu->SetLabel(
id, FormatLabelForMenu());
205bool MenuItemVisitor::CommandListEntryEx::GetEnabled()
const
212void MenuItemVisitor::CommandListEntryEx::Check(
bool checked)
214 if (!menu || isOccult)
216 menu->Check(
id, checked);
219void MenuItemVisitor::CommandListEntryEx::Enable(
bool b)
229 enabled = menu->IsEnabled(
id);
234 enabled = menu->IsEnabled(
id);
238void MenuItemVisitor::CommandListEntryEx::EnableMultiItem(
bool b)
241 const auto item = menu->FindItem(
id);
248 wxLogDebug(
wxT(
"Warning: Menu entry with id %i in %s not found"),
253 -> std::unique_ptr<CommandManager::CommandListEntry>
255 auto result = std::make_unique<CommandListEntryEx>();
257 result->menu = CurrentMenu();
273 if (!
entry.key.empty())
280 Accel = wxString(
"\t ") +
key;
281 if(
key.StartsWith(
"Left" ))
break;
282 if(
key.StartsWith(
"Right"))
break;
283 if(
key.StartsWith(
"Up" ))
break;
284 if(
key.StartsWith(
"Down"))
break;
285 if(
key.StartsWith(
"Return"))
break;
286 if(
key.StartsWith(
"Tab"))
break;
287 if(
key.StartsWith(
"Shift+Tab"))
break;
288 if(
key.StartsWith(
"0"))
break;
289 if(
key.StartsWith(
"1"))
break;
290 if(
key.StartsWith(
"2"))
break;
291 if(
key.StartsWith(
"3"))
break;
292 if(
key.StartsWith(
"4"))
break;
293 if(
key.StartsWith(
"5"))
break;
294 if(
key.StartsWith(
"6"))
break;
295 if(
key.StartsWith(
"7"))
break;
296 if(
key.StartsWith(
"8"))
break;
297 if(
key.StartsWith(
"9"))
break;
302 if(
key.StartsWith(
"NUMPAD_ENTER" ))
break;
303 if(
key.StartsWith(
"Backspace" ))
break;
304 if(
key.StartsWith(
"Delete" ))
break;
310 if(
key.StartsWith(
",") )
break;
311 if(
key.StartsWith(
".") )
break;
317 if (
key.StartsWith(
"[") )
break;
318 if (
key.StartsWith(
"]") )
break;
324 Accel = wxString(
"\t") +
entry.key.GET();
337 CurrentMenu()->Append(
entry.id,
entry.FormatLabelForMenu());
338 else if (pOptions->
global)
343 auto &checker = pOptions->
checker;
345 CurrentMenu()->AppendCheckItem(ID,
label);
346 CurrentMenu()->Check(ID, checker(mProject));
349 CurrentMenu()->Append(ID,
label);
353MenuItemVisitor::~MenuItemVisitor() =
default;
358 return BeginSubMenu(tName);
360 return BeginMainMenu(tName);
365void MenuItemVisitor::EndMenu()
367 if (mSubMenuList.empty())
375 uCurrentMenu = std::make_unique<wxMenu>();
376 mCurrentMenu = uCurrentMenu.get();
380void MenuItemVisitor::EndMainMenu()
385 assert(uCurrentMenu);
386 CurrentMenuBar()->Append(
387 uCurrentMenu.release(), MenuNames()[0].Translation());
388 mCurrentMenu =
nullptr;
395 mSubMenuList.emplace_back();
396 mbSeparatorAllowed =
false;
402void MenuItemVisitor::EndSubMenu()
405 SubMenuListEntry tmpSubMenu{ std::move( mSubMenuList.back() ) };
408 mSubMenuList.pop_back();
411 auto name = MenuNames().back().Translation();
412 CurrentMenu()->Append(0,
name, tmpSubMenu.menu.release(),
414 mbSeparatorAllowed =
true;
417void MenuItemVisitor::BeginOccultCommands()
421 assert(!CurrentMenu());
426 mTempMenuBar = AddMenuBar(
wxT(
"ext-menu"));
429void MenuItemVisitor::EndOccultCommands()
431 auto iter = mMenuBarList.end();
432 if (iter != mMenuBarList.begin())
433 mMenuBarList.erase(--iter);
436 mTempMenuBar.reset();
444 MenuItemVisitor visitor{
mProject };
458 using wxFrame::DetachMenuBar;
467#if defined(__WXMAC__) && defined(_DEBUG)
471 assert((!dlg || !dlg->IsModal()));
479 wxWindowPtr<wxMenuBar> menuBar{ window.GetMenuBar() };
480 window.DetachMenuBar();
512#if defined(__WXGTK__)
519 wxRect r = window.GetRect();
520 window.SetSize(wxSize(1,1));
521 window.SetSize(r.GetSize());
529 if (!disabledShortcuts.Translation().empty()) {
531 " because their default shortcut is new or changed, and is the same shortcut"
532 " that you have assigned to another command.")
541static CommandManager::Factory::SubstituteInShared<MenuCreator>
scope;
551 bool handled =
false;
552 if ( fields.size() == 2 ) {
557 auto &command = fields[1];
559 pManager->HandleTextualCommand( command, context, flags,
false );
580 int type = evt.GetEventType();
583 if (
entry->isGlobal && type == wxEVT_KEY_DOWN)
589 entry->enabled =
false;
595 wxWindow * pParent = wxGetTopLevelParent( pFocus );
596 bool validTarget = pParent == pWindow;
599 if( pParent && pParent->GetParent() == pWindow ){
601 validTarget = keystrokeHandlingWindow->HandleCommandKeystrokes();
603 validTarget = validTarget && wxEventLoop::GetActive()->IsMain();
606 if (!permit && !validTarget )
611 auto flags = cm.GetUpdateFlags();
613 wxKeyEvent temp = evt;
617 if((type == wxEVT_KEY_DOWN) || (type == wxEVT_KEY_UP ))
629 switch( evt.GetKeyCode() ){
642 case WXK_NUMPAD_ENTER:
657 if (!evt.HasAnyModifiers())
663 if (type == wxEVT_KEY_DOWN)
665 if (
entry->skipKeydown)
669 return cm.HandleCommandEntry(
entry, flags,
false, &temp);
672 if (type == wxEVT_KEY_UP &&
entry->wantKeyup)
674 return cm.HandleCommandEntry(
entry, flags,
false, &temp);
688[]( wxKeyEvent &
key ) {
702 long key =
event.GetKeyCode();
704 if (event.ControlDown())
705 newStr +=
wxT(
"Ctrl+");
708 newStr +=
wxT(
"Alt+");
710 if (event.ShiftDown())
711 newStr +=
wxT(
"Shift+");
713#if defined(__WXMAC__)
714 if (event.RawControlDown())
715 newStr +=
wxT(
"RawCtrl+");
718 if (event.RawControlDown() &&
key >= 1 &&
key <= 26)
719 newStr += (wxChar)(64 +
key);
720 else if (
key >= 33 &&
key <= 255 &&
key != 127)
721 newStr += (wxChar)
key;
727 newStr +=
wxT(
"Backspace");
730 newStr +=
wxT(
"Delete");
733 newStr +=
wxT(
"Space");
736 newStr +=
wxT(
"Tab");
739 newStr +=
wxT(
"Return");
742 newStr +=
wxT(
"PageUp");
745 newStr +=
wxT(
"PageDown");
748 newStr +=
wxT(
"End");
751 newStr +=
wxT(
"Home");
754 newStr +=
wxT(
"Left");
760 newStr +=
wxT(
"Right");
763 newStr +=
wxT(
"Down");
766 newStr +=
wxT(
"Escape");
769 newStr +=
wxT(
"Insert");
772 newStr +=
wxT(
"NUMPAD0");
775 newStr +=
wxT(
"NUMPAD1");
778 newStr +=
wxT(
"NUMPAD2");
781 newStr +=
wxT(
"NUMPAD3");
784 newStr +=
wxT(
"NUMPAD4");
787 newStr +=
wxT(
"NUMPAD5");
790 newStr +=
wxT(
"NUMPAD6");
793 newStr +=
wxT(
"NUMPAD7");
796 newStr +=
wxT(
"NUMPAD8");
799 newStr +=
wxT(
"NUMPAD9");
844 newStr +=
wxT(
"F10");
847 newStr +=
wxT(
"F11");
850 newStr +=
wxT(
"F12");
853 newStr +=
wxT(
"F13");
856 newStr +=
wxT(
"F14");
859 newStr +=
wxT(
"F15");
862 newStr +=
wxT(
"F16");
865 newStr +=
wxT(
"F17");
868 newStr +=
wxT(
"F18");
871 newStr +=
wxT(
"F19");
874 newStr +=
wxT(
"F20");
877 newStr +=
wxT(
"F21");
880 newStr +=
wxT(
"F22");
883 newStr +=
wxT(
"F23");
886 newStr +=
wxT(
"F24");
888 case WXK_NUMPAD_ENTER:
889 newStr +=
wxT(
"NUMPAD_ENTER");
892 newStr +=
wxT(
"NUMPAD_F1");
895 newStr +=
wxT(
"NUMPAD_F2");
898 newStr +=
wxT(
"NUMPAD_F3");
901 newStr +=
wxT(
"NUMPAD_F4");
903 case WXK_NUMPAD_HOME:
904 newStr +=
wxT(
"NUMPAD_HOME");
906 case WXK_NUMPAD_LEFT:
907 newStr +=
wxT(
"NUMPAD_LEFT");
910 newStr +=
wxT(
"NUMPAD_UP");
912 case WXK_NUMPAD_RIGHT:
913 newStr +=
wxT(
"NUMPAD_RIGHT");
915 case WXK_NUMPAD_DOWN:
916 newStr +=
wxT(
"NUMPAD_DOWN");
918 case WXK_NUMPAD_PAGEUP:
919 newStr +=
wxT(
"NUMPAD_PAGEUP");
921 case WXK_NUMPAD_PAGEDOWN:
922 newStr +=
wxT(
"NUMPAD_PAGEDOWN");
925 newStr +=
wxT(
"NUMPAD_END");
927 case WXK_NUMPAD_BEGIN:
928 newStr +=
wxT(
"NUMPAD_HOME");
930 case WXK_NUMPAD_INSERT:
931 newStr +=
wxT(
"NUMPAD_INSERT");
933 case WXK_NUMPAD_DELETE:
934 newStr +=
wxT(
"NUMPAD_DELETE");
936 case WXK_NUMPAD_EQUAL:
937 newStr +=
wxT(
"NUMPAD_EQUAL");
939 case WXK_NUMPAD_MULTIPLY:
940 newStr +=
wxT(
"NUMPAD_MULTIPLY");
943 newStr +=
wxT(
"NUMPAD_ADD");
945 case WXK_NUMPAD_SUBTRACT:
946 newStr +=
wxT(
"NUMPAD_SUBTRACT");
948 case WXK_NUMPAD_DECIMAL:
949 newStr +=
wxT(
"NUMPAD_DECIMAL");
951 case WXK_NUMPAD_DIVIDE:
952 newStr +=
wxT(
"NUMPAD_DIVIDE");
967std::unique_ptr<wxMenuBar> MenuItemVisitor::AddMenuBar(
const wxString & sMenu)
969 wxMenuBar *menuBar = GetMenuBar(sMenu);
975 auto result = std::make_unique<wxMenuBar>();
976 mMenuBarList.emplace_back(sMenu, result.get());
984wxMenuBar *MenuItemVisitor::GetMenuBar(
const wxString & sMenu)
const
986 for (
const auto &
entry : mMenuBarList)
988 if(
entry.name == sMenu)
989 return entry.menubar;
998wxMenuBar *MenuItemVisitor::CurrentMenuBar()
const
1000 if(mMenuBarList.empty())
1003 return mMenuBarList.back().menubar;
1008wxMenu *MenuItemVisitor::CurrentSubMenu()
const
1010 if(mSubMenuList.empty())
1013 return mSubMenuList.back().menu.get();
1020wxMenu * MenuItemVisitor::CurrentMenu()
const
1025 wxMenu * tmpCurrentSubMenu = CurrentSubMenu();
1027 if(!tmpCurrentSubMenu)
1029 return mCurrentMenu;
1032 return tmpCurrentSubMenu;
AUDACITY_DLL_API std::weak_ptr< AudacityProject > GetActiveProject()
Handle changing of active project and keep global project pointer.
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
constexpr CommandFlag AlwaysEnabledFlag
constexpr CommandFlag NoFlagsSpecified
static ProjectFileIORegistry::AttributeWriterEntry entry
The output stream of the journal system.
Journal system's error status, command dictionary, initializers.
ValueRestorer< T > valueRestorer(T &var)
inline functions provide convenient parameter type deduction
audacity::BasicSettings * gPrefs
wxFrame * FindProjectFrame(AudacityProject *project)
Get a pointer to the window associated with a project, or null if the given pointer is null,...
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
accessors for certain important windows associated with each project
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
CommandManager implements a system for organizing all user-callable commands.
AudacityProject & mProject
static CommandManager & Get(AudacityProject &project)
TranslatableString ReportDuplicateShortcuts()
CommandFlag GetUpdateFlags(bool quick=false) const
virtual void ExecuteCommand(const CommandContext &context, const wxEvent *evt, const CommandListEntry &entry)
typename GlobalVariable< PreFilter, const std::function< bool(wxKeyEvent &) >, nullptr, Options... >::Scope Scope
Holds a msgid for the translation catalog; may also bind format arguments.
virtual bool Flush() noexcept=0
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
std::unique_ptr< WindowPlacement > FindFocus()
Find the window that is accepting keyboard input, if any.
void Output(const wxString &string)
~CommandListEntryEx() final