Audacity  3.0.3
PopupMenuTable.h
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 PopupMenuTable.h
6 
7 Paul Licameli
8 
9 This file defines PopupMenuTable, which inherits from wxEventHandler,
10 
11 associated macros simplifying the population of tables,
12 
13 and PopupMenuTable::Menu which is buildable from one or more such
14 tables, and automatically attaches and detaches the event handlers.
15 
16 **********************************************************************/
17 
18 #ifndef __AUDACITY_POPUP_MENU_TABLE__
19 #define __AUDACITY_POPUP_MENU_TABLE__
20 
21 class wxCommandEvent;
22 
23 #include <functional>
24 #include <vector>
25 #include <wx/menu.h> // to inherit wxMenu
26 #include <memory>
27 
28 #include "Internat.h"
29 #include "../commands/CommandManager.h"
30 
31 class PopupMenuHandler;
32 class PopupMenuTable;
33 
34 struct AUDACITY_DLL_API PopupMenuTableEntry : Registry::SingleItem
35 {
36  enum Type { Item, RadioItem, CheckItem };
37  using InitFunction =
38  std::function< void( PopupMenuHandler &handler, wxMenu &menu, int id ) >;
39 
41  int id;
43  wxCommandEventFunction func;
46 
48  PopupMenuTableEntry( const Identifier &stringId,
49  Type type_, int id_, const TranslatableString &caption_,
50  wxCommandEventFunction func_, PopupMenuHandler &handler_,
51  InitFunction init_ = {} )
52  : SingleItem{ stringId }
53  , type(type_)
54  , id(id_)
55  , caption(caption_)
56  , func(func_)
57  , handler( handler_ )
58  , init( init_ )
59  {
60  wxASSERT(func);
61  }
62 
63  ~PopupMenuTableEntry() override;
64 };
65 
66 struct AUDACITY_DLL_API PopupSubMenu : Registry::ConcreteGroupItem< false >
68 {
71 
72  PopupSubMenu( const Identifier &stringId,
73  const TranslatableString &caption_, PopupMenuTable &table );
74 
75  ~PopupSubMenu() override;
76 };
77 
81  using ConcreteGroupItem< false >::ConcreteGroupItem;
82 };
83 
84 class PopupMenuHandler : public wxEvtHandler
85 {
86 public:
87  PopupMenuHandler() = default;
88  PopupMenuHandler( const PopupMenuHandler& ) = delete;
90 
92 
98  virtual void InitUserData(void *pUserData) = 0;
99 };
100 
101 struct PopupMenuVisitor : public MenuVisitor {
102  explicit PopupMenuVisitor( PopupMenuTable &table ) : mTable{ table } {}
104 };
105 
106 // Opaque structure built by PopupMenuTable::BuildMenu
107 class AUDACITY_DLL_API PopupMenu
108 {
109 public:
110  virtual ~PopupMenu();
111  virtual void Popup( wxWindow &window, const wxPoint &pos ) = 0;
112 };
113 
114 class AUDACITY_DLL_API PopupMenuTable : public PopupMenuHandler
115 {
116 public:
118 
119  // Supply a nonempty caption for sub-menu tables
120  PopupMenuTable( const Identifier &id, const TranslatableString &caption = {} )
121  : mId{ id }
122  , mCaption{ caption }
123  , mRegistry{ std::make_unique<Registry::TransparentGroupItem<>>( mId ) }
124  {}
125 
126  // Optional pUserData gets passed to the InitUserData routines of tables.
127  // No memory management responsibility is assumed by this function.
128  static std::unique_ptr<PopupMenu> BuildMenu(
129  PopupMenuTable *pTable, void *pUserData = NULL);
130 
131  const Identifier &Id() const { return mId; }
132  const TranslatableString &Caption() const { return mCaption; }
133  const Registry::GroupItem *GetRegistry() const { return mRegistry.get(); }
134 
135  // Typically statically constructed:
136  struct AttachedItem {
138  const Registry::Placement &placement, Registry::BaseItemPtr pItem )
139  { table.RegisterItem( placement, std::move( pItem ) ); }
140  };
141 
142  // menu must have been built by BuildMenu
143  // More items get added to the end of it
144  static void ExtendMenu( PopupMenu &menu, PopupMenuTable &otherTable );
145 
146  const std::shared_ptr< Registry::GroupItem > &Get( void *pUserData )
147  {
148  if ( pUserData )
149  this->InitUserData( pUserData );
150  if (!mTop)
151  Populate();
152  return mTop;
153  }
154 
155  void Clear()
156  {
157  mTop.reset();
158  }
159 
160  // Forms a computed item, which may be omitted when function returns null
161  // and thus can be a conditional item
162  template< typename Table >
164  const std::function< Registry::BaseItemPtr( Table& ) > &factory )
165  {
166  using namespace Registry;
167  return std::make_unique< ComputedItem >(
168  [factory]( Visitor &baseVisitor ){
169  auto &visitor = static_cast< PopupMenuVisitor& >( baseVisitor );
170  auto &table = static_cast< Table& >( visitor.mTable );
171  return factory( table );
172  }
173  );
174  }
175 
176 private:
177  void RegisterItem(
178  const Registry::Placement &placement, Registry::BaseItemPtr pItem );
179 
180 protected:
181  // This convenience function composes a label, with the following optional
182  // part put in parentheses if useExtra is true
184  bool useExtra, const TranslatableString &extra )
185  {
186  return useExtra
187  ? XXO("%s (%s)").Format( label, extra )
188  : label;
189  }
190 
191  virtual void Populate() = 0;
192 
193  // To be used in implementations of Populate():
194  void Append( Registry::BaseItemPtr pItem );
195 
196  void Append(
197  const Identifier &stringId, PopupMenuTableEntry::Type type, int id,
198  const TranslatableString &string, wxCommandEventFunction memFn,
199  // This callback might check or disable a menu item:
200  const PopupMenuTableEntry::InitFunction &init );
201 
202  void AppendItem( const Identifier &stringId, int id,
203  const TranslatableString &string, wxCommandEventFunction memFn,
204  // This callback might check or disable a menu item:
205  const PopupMenuTableEntry::InitFunction &init = {} )
206  { Append( stringId, PopupMenuTableEntry::Item, id, string, memFn, init ); }
207 
208  void AppendRadioItem( const Identifier &stringId, int id,
209  const TranslatableString &string, wxCommandEventFunction memFn,
210  // This callback might check or disable a menu item:
211  const PopupMenuTableEntry::InitFunction &init = {} )
212  { Append( stringId, PopupMenuTableEntry::RadioItem, id, string, memFn, init ); }
213 
214  void AppendCheckItem( const Identifier &stringId, int id,
215  const TranslatableString &string, wxCommandEventFunction memFn,
216  const PopupMenuTableEntry::InitFunction &init = {} )
217  { Append( stringId, PopupMenuTableEntry::CheckItem, id, string, memFn, init ); }
218 
219  void BeginSection( const Identifier &name );
220  void EndSection();
221 
222  std::shared_ptr< Registry::GroupItem > mTop;
223  std::vector< Registry::GroupItem* > mStack;
226  std::unique_ptr<Registry::GroupItem> mRegistry;
227 };
228 
229 // A "CRTP" class that injects a convenience function, which appends a menu item
230 // computed lazily by a function that is passed the table (after it has stored
231 // its user data)
232 template< typename Derived, typename Base = PopupMenuTable >
233 class ComputedPopupMenuTable : public Base
234 {
235 public:
236  using Base::Base;
237  using Base::Append;
238 
239  // Appends a computed item, which may be omitted when function returns null
240  // and thus can be a conditional item
241  using Factory = std::function< Registry::BaseItemPtr( Derived& ) >;
243  {
244  return Base::Computed( factory );
245  }
246 
247  void Append( const Factory &factory )
248  {
249  Append( Computed( factory ) );
250  }
251 };
252 
253 /*
254 The following macros make it easy to attach a popup menu to a window.
255 
256 Example of usage:
257 
258 In class MyTable (maybe in the private section),
259 which inherits from PopupMenuTable,
260 
261 DECLARE_POPUP_MENU(MyTable);
262 virtual void InitUserData(void *pUserData);
263 virtual void DestroyMenu();
264 
265 Then in MyTable.cpp,
266 
267 void MyTable::InitUserData(void *pUserData)
268 {
269  // Remember pData
270  auto pData = static_cast<MyData*>(pUserData);
271 }
272 
273 void MyTable::DestroyMenu()
274 {
275  // Do cleanup
276 }
277 
278 BEGIN_POPUP_MENU(MyTable)
279  // This is inside a function and can contain arbitrary code. But usually
280  // you only need a sequence of calls:
281 
282  AppendItem("Cut",
283  OnCutSelectedTextID, XO("Cu&t"), POPUP_MENU_FN( OnCutSelectedText ),
284  // optional argument:
285  [](PopupMenuHandler &handler, wxMenu &menu, int id)
286  {
287  auto data = static_cast<MyTable&>( handler ).pData;
288  // maybe enable or disable the menu item
289  }
290  );
291  // etc.
292 
293 END_POPUP_MENU()
294 
295 where OnCutSelectedText is a (maybe private) member function of MyTable.
296 
297 Elsewhere,
298 
299 MyTable myTable;
300 MyData data;
301 auto pMenu = PopupMenuTable::BuildMenu(pParent, &myTable, &data);
302 
303 // Optionally:
304 OtherTable otherTable;
305 PopupMenuTable::ExtendMenu( *pMenu, otherTable );
306 
307 pMenu->Popup( *pParent, { event.m_x, event.m_y } );
308 
309 That's all!
310 */
311 
312 #define DECLARE_POPUP_MENU(HandlerClass) \
313  void Populate() override;
314 
315 // begins function
316 #define BEGIN_POPUP_MENU(HandlerClass) \
317 void HandlerClass::Populate() { \
318  using My = HandlerClass; \
319  mTop = std::make_shared< PopupSubMenu >( \
320  Id(), Caption(), *this ); \
321  mStack.clear(); \
322  mStack.push_back( mTop.get() );
323 
324 #define POPUP_MENU_FN( memFn ) ( (wxCommandEventFunction) (&My::memFn) )
325 
326 #define POPUP_MENU_SUB_MENU(stringId, classname, pUserData ) \
327  mStack.back()->items.push_back( \
328  Registry::Shared( classname::Instance().Get( pUserData ) ) );
329 
330 // ends function
331 #define END_POPUP_MENU() }
332 
333 #endif
PopupMenuTable::mRegistry
std::unique_ptr< Registry::GroupItem > mRegistry
Definition: PopupMenuTable.h:226
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
Registry::RegisterItem
void RegisterItem(GroupItem &registry, const Placement &placement, BaseItemPtr pItem)
Definition: Registry.cpp:750
Registry::SingleItem
Definition: Registry.h:120
Registry
Definition: Menus.h:35
PopupMenuTable
Definition: PopupMenuTable.h:115
PopupMenuHandler::PopupMenuHandler
PopupMenuHandler(const PopupMenuHandler &)=delete
ComputedPopupMenuTable::Append
void Append(const Factory &factory)
Definition: PopupMenuTable.h:247
PopupMenuTableEntry::InitFunction
std::function< void(PopupMenuHandler &handler, wxMenu &menu, int id) > InitFunction
Definition: PopupMenuTable.h:38
PopupMenuTable::mStack
std::vector< Registry::GroupItem * > mStack
Definition: PopupMenuTable.h:223
MenuVisitor
Definition: CommandManager.h:390
PopupMenuVisitor::mTable
PopupMenuTable & mTable
Definition: PopupMenuTable.h:103
PopupMenuTable::Populate
virtual void Populate()=0
PopupMenuTable::Id
const Identifier & Id() const
Definition: PopupMenuTable.h:131
PopupMenuTableEntry::init
InitFunction init
Definition: PopupMenuTable.h:45
ComputedPopupMenuTable::Computed
static Registry::BaseItemPtr Computed(const Factory &factory)
Definition: PopupMenuTable.h:242
PopupMenuTable::AppendRadioItem
void AppendRadioItem(const Identifier &stringId, int id, const TranslatableString &string, wxCommandEventFunction memFn, const PopupMenuTableEntry::InitFunction &init={})
Definition: PopupMenuTable.h:208
PopupMenuHandler::PopupMenuHandler
PopupMenuHandler()=default
PopupMenuVisitor::PopupMenuVisitor
PopupMenuVisitor(PopupMenuTable &table)
Definition: PopupMenuTable.h:102
PopupMenuSection
Definition: PopupMenuTable.h:80
PopupMenuTableEntry::caption
TranslatableString caption
Definition: PopupMenuTable.h:42
PopupMenuTableEntry::Item
@ Item
Definition: PopupMenuTable.h:36
PopupMenuTableEntry::RadioItem
@ RadioItem
Definition: PopupMenuTable.h:36
Registry::Placement
Definition: Registry.h:219
PopupMenu::Popup
virtual void Popup(wxWindow &window, const wxPoint &pos)=0
PopupMenuTable::RegisterItem
void RegisterItem(const Registry::Placement &placement, Registry::BaseItemPtr pItem)
Definition: PopupMenuTable.cpp:156
PopupMenuTableEntry
Definition: PopupMenuTable.h:35
Identifier
An explicitly nonlocalized string, not meant for the user to see.
Definition: Identifier.h:22
Registry::Visitor
Definition: Registry.h:242
PopupMenuTable::Caption
const TranslatableString & Caption() const
Definition: PopupMenuTable.h:132
XXO
#define XXO(s)
Definition: Internat.h:44
Registry::BaseItemPtr
std::unique_ptr< BaseItem > BaseItemPtr
Definition: Registry.h:71
factory
static RegisteredToolbarFactory factory
Definition: ControlToolBar.cpp:817
label
TranslatableString label
Definition: Tags.cpp:756
PopupMenuHandler::operator=
PopupMenuHandler & operator=(const PopupMenuHandler &)=delete
PopupMenuVisitor
Definition: PopupMenuTable.h:101
PopupMenuTable::Computed
static Registry::BaseItemPtr Computed(const std::function< Registry::BaseItemPtr(Table &) > &factory)
Definition: PopupMenuTable.h:163
Append
Append([](My &table) -> Registry::BaseItemPtr { if(WaveTrackSubViews::slots() > 1) return std::make_unique< Entry >("MultiView", Entry::CheckItem, OnMultiViewID, XXO("&Multi-view"), POPUP_MENU_FN(OnMultiView), table, [](PopupMenuHandler &handler, wxMenu &menu, int id){ auto &table=static_cast< WaveTrackMenuTable & >(handler);auto &track=table.FindWaveTrack();const auto &view=WaveTrackView::Get(track);menu.Check(id, view.GetMultiView());});else return nullptr;})
PopupMenuTable::Get
const std::shared_ptr< Registry::GroupItem > & Get(void *pUserData)
Definition: PopupMenuTable.h:146
PopupMenuTableEntry::func
wxCommandEventFunction func
Definition: PopupMenuTable.h:43
PopupMenuTable::AppendItem
void AppendItem(const Identifier &stringId, int id, const TranslatableString &string, wxCommandEventFunction memFn, const PopupMenuTableEntry::InitFunction &init={})
Definition: PopupMenuTable.h:202
PopupMenuTable::AppendCheckItem
void AppendCheckItem(const Identifier &stringId, int id, const TranslatableString &string, wxCommandEventFunction memFn, const PopupMenuTableEntry::InitFunction &init={})
Definition: PopupMenuTable.h:214
name
const TranslatableString name
Definition: Distortion.cpp:98
PopupMenuHandler::InitUserData
virtual void InitUserData(void *pUserData)=0
Called before the menu items are appended.
PopupMenuTableEntry::CheckItem
@ CheckItem
Definition: PopupMenuTable.h:36
ComputedPopupMenuTable< WaveTrackMenuTable, WaveTrackPopupMenuTable >::Factory
std::function< Registry::BaseItemPtr(WaveTrackMenuTable &) > Factory
Definition: PopupMenuTable.h:241
PopupMenu
Definition: PopupMenuTable.h:108
PopupMenuTable::mTop
std::shared_ptr< Registry::GroupItem > mTop
Definition: PopupMenuTable.h:222
PopupMenuTable::Clear
void Clear()
Definition: PopupMenuTable.h:155
PopupMenuTableEntry::type
Type type
Definition: PopupMenuTable.h:40
Internat.h
id
int id
Definition: WaveTrackControls.cpp:577
EndSection
EndSection()
PopupMenuTable::AttachedItem::AttachedItem
AttachedItem(PopupMenuTable &table, const Registry::Placement &placement, Registry::BaseItemPtr pItem)
Definition: PopupMenuTable.h:137
PopupMenuHandler
Definition: PopupMenuTable.h:85
PopupSubMenu::table
PopupMenuTable & table
Definition: PopupMenuTable.h:70
PopupMenuTableEntry::Type
Type
Definition: PopupMenuTable.h:36
Registry::ConcreteGroupItem
Definition: Registry.h:198
PopupMenuTable::mId
Identifier mId
Definition: PopupMenuTable.h:224
PopupMenuTableEntry::PopupMenuTableEntry
PopupMenuTableEntry(const Identifier &stringId, Type type_, int id_, const TranslatableString &caption_, wxCommandEventFunction func_, PopupMenuHandler &handler_, InitFunction init_={})
Definition: PopupMenuTable.h:48
Registry::GroupItem
Definition: Registry.h:126
ComputedPopupMenuTable
Definition: PopupMenuTable.h:234
PopupMenuTable::AttachedItem
Definition: PopupMenuTable.h:136
PopupMenuTable::mCaption
TranslatableString mCaption
Definition: PopupMenuTable.h:225
PopupSubMenu::caption
TranslatableString caption
Definition: PopupMenuTable.h:69
PopupMenuTableEntry::handler
PopupMenuHandler & handler
Definition: PopupMenuTable.h:44
PopupMenuTable::MakeLabel
static TranslatableString MakeLabel(const TranslatableString &label, bool useExtra, const TranslatableString &extra)
Definition: PopupMenuTable.h:183
MenuTable::MenuSection
Definition: CommandManager.h:420
PopupMenu::~PopupMenu
virtual ~PopupMenu()
BeginSection
BeginSection("Basic")
PopupMenuTable::GetRegistry
const Registry::GroupItem * GetRegistry() const
Definition: PopupMenuTable.h:133
PopupMenuTableEntry::id
int id
Definition: PopupMenuTable.h:41
PopupSubMenu
Definition: PopupMenuTable.h:68
MenuTable::WholeMenu
Definition: CommandManager.h:423