Audacity 3.2.0
PopupMenuTable.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5PopupMenuTable.cpp
6
7Paul Licameli split from TrackPanel.cpp
8
9**********************************************************************/
10
11
12#include "PopupMenuTable.h"
13#include "widgets/BasicMenu.h"
15
17{}
18
20 const TranslatableString &caption, PopupMenuTable &table
21) : GroupItem{ stringId }
22 , caption{ caption }
23 , table{ table }
24{
25}
26
28{}
29
31{ return caption.empty() ? Extension : Whole; }
32
34{}
35
36PopupMenu::~PopupMenu() = default;
37
38namespace {
39struct PopupMenuImpl : PopupMenu, wxMenu
40{
41 PopupMenuImpl(void *pUserData_)
42 : pUserData{ pUserData_ } {}
43
44 ~PopupMenuImpl() override;
45
46 void Popup( wxWindow &window, const wxPoint &pos ) override;
47
48 void Extend(PopupMenuTable *pTable);
49
50 void *pUserData;
51};
52
53class PopupMenuBuilder : public MenuRegistry::Visitor<PopupMenuTableTraits> {
54public:
55 PopupMenuBuilder(PopupMenuTable &table, PopupMenuImpl &menu, void *pUserData)
56 : MenuRegistry::Visitor<PopupMenuTableTraits>{ std::tuple{
57 [this](const PopupSubMenu &item, const auto &){
58 if (!item.caption.empty()) {
59 auto newMenu =
60 std::make_unique<PopupMenuImpl>(mMenu->pUserData);
61 mMenu = newMenu.get();
62 mMenus.push_back(std::move(newMenu));
63 }
64 },
65
66 [this](const PopupMenuTableEntry &entry, const auto &){
67 switch (entry.type) {
69 {
70 mMenu->Append(entry.id, entry.caption.Translation());
71 break;
72 }
74 {
75 mMenu->AppendRadioItem(entry.id, entry.caption.Translation());
76 break;
77 }
79 {
80 mMenu->AppendCheckItem(entry.id, entry.caption.Translation());
81 break;
82 }
83 default:
84 assert(false);
85 break;
86 }
87
88 // This call is necessary for externally registered items, else
89 // harmlessly redundant
90 entry.handler.InitUserData(mpUserData);
91
92 if (entry.init)
93 entry.init(entry.handler, *mMenu, entry.id);
94
95 mMenu->Bind(
96 wxEVT_COMMAND_MENU_SELECTED, entry.func, &entry.handler, entry.id);
97 },
98
99 [this](const PopupSubMenu &item, const auto &){
100 if (!item.caption.empty()) {
101 auto subMenu = std::move(mMenus.back());
102 mMenus.pop_back();
103 mMenu = mMenus.empty() ? mRoot : mMenus.back().get();
104 mMenu->AppendSubMenu(subMenu.release(), item.caption.Translation());
105 }
106 }},
107
108 [this]() {
109 mMenu->AppendSeparator();
110 }
111 }
112 , mMenu{ &menu }
113 , mRoot{ mMenu }
114 , mpUserData{ pUserData }
115 {}
116
117 std::vector< std::unique_ptr<PopupMenuImpl> > mMenus;
119 void *const mpUserData;
120};
121
122PopupMenuImpl::~PopupMenuImpl()
123{
124 // Event connections between the parent window and the singleton table
125 // object must be broken when this menu is destroyed.
126 Disconnect();
127}
128
129void PopupMenuImpl::Popup( wxWindow &window, const wxPoint &pos )
130{
131 BasicMenu::Handle{ this }.Popup(
132 wxWidgetsWindowPlacement{ &window }, { pos.x, pos.y }
133 );
134}
135}
136
138{
139 auto &theMenu = dynamic_cast<PopupMenuImpl&>(menu);
140
141 PopupMenuBuilder visitor{ table, theMenu, theMenu.pUserData };
142 Registry::VisitWithFunctions(visitor, table.Get(theMenu.pUserData).get(),
143 table.GetRegistry(), table);
144}
145
147 const Identifier &stringId, PopupMenuTableEntry::Type type, int id,
148 const TranslatableString &string, wxCommandEventFunction memFn,
150{
151 Append( std::make_unique<Entry>(
152 stringId, type, id, string, memFn, *this, init ) );
153}
154
156{
157 auto uSection = std::make_unique< PopupMenuSection >( name );
158 auto section = uSection.get();
159 mStack.back()->push_back( std::move( uSection ) );
160 mStack.push_back( section );
161}
162
164{
165 mStack.pop_back();
166}
167
168// static
169std::unique_ptr< PopupMenu > PopupMenuTable::BuildMenu(
170 PopupMenuTable *pTable, void *pUserData )
171{
172 // Rebuild as needed each time. That makes it safe in case of language change.
173 auto theMenu = std::make_unique<PopupMenuImpl>( pUserData );
174 ExtendMenu( *theMenu, *pTable );
175 return theMenu;
176}
177
Abstractions of menus and their items.
const TranslatableString name
Definition: Distortion.cpp:76
static ProjectFileIORegistry::AttributeWriterEntry entry
void Popup(const BasicUI::WindowPlacement &window, const Point &pos={})
Display the menu at pos, invoke at most one action, then hide it.
Definition: BasicMenu.cpp:209
An explicitly nonlocalized string, not meant for the user to see.
Definition: Identifier.h:22
virtual ~PopupMenu()
void Append(Ptr pItem)
static void ExtendMenu(PopupMenu &menu, PopupMenuTable &otherTable)
const auto * GetRegistry() const
void BeginSection(const Identifier &name)
static std::unique_ptr< PopupMenu > BuildMenu(PopupMenuTable *pTable, void *pUserData=NULL)
std::vector< PopupMenuGroupItem * > mStack
const auto & Get(void *pUserData)
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
PopupMenuBuilder(PopupMenuTable &table, PopupMenuImpl &menu, void *pUserData)
std::vector< std::unique_ptr< PopupMenuImpl > > mMenus
void VisitWithFunctions(const VisitorFunctions< RegistryTraits > &visitors, const GroupItem< RegistryTraits > *pTopItem, const GroupItem< RegistryTraits > *pRegistry={}, typename RegistryTraits::ComputedItemContextType &computedItemContext=RegistryTraits::ComputedItemContextType::Instance)
Definition: Registry.h:623
~PopupMenuSection() override
Type
@ Item
@ CheckItem
@ RadioItem
~PopupMenuTableEntry() override
std::function< void(PopupMenuHandler &handler, wxMenu &menu, int id) > InitFunction
TranslatableString caption
~PopupSubMenu() override
PopupSubMenu(const Identifier &stringId, const TranslatableString &caption_, PopupMenuTable &table)
Properties GetProperties() const override
Window placement information for wxWidgetsBasicUI can be constructed from a wxWindow pointer.