Audacity 3.2.0
MenuRegistry.h
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 MenuRegistry.h
6
7 Brian Gunlogson
8 Dominic Mazzoni
9
10 Paul Licameli split from CommandManager.h
11
12**********************************************************************/
13#ifndef __AUDACITY_MENU_REGISTRY__
14#define __AUDACITY_MENU_REGISTRY__
15
16#include "Callable.h"
17#include "MemoryX.h"
18#include "CommandFunctors.h"
19#include "CommandFlag.h"
20#include "Registry.h"
21#include <functional>
22
23class AudacityProject;
25
26// Define items that populate tables that specifically describe menu trees
27namespace MenuRegistry {
28 struct Traits;
29 template<typename MenuTraits> struct Visitor;
30
31 template<typename MenuTraits> struct Visitor;
32
33 // type of a function that determines checkmark state
34 using CheckFn = std::function< bool(AudacityProject&) >;
35
36 struct MENUS_API Options
37 {
39 // Allow implicit construction from an accelerator string, which is
40 // a very common case
41 Options( const wxChar *accel_ ) : accel{ accel_ } {}
42 // A two-argument constructor for another common case
44 const wxChar *accel_,
45 const TranslatableString &longName_ )
46 : accel{ accel_ }, longName{ longName_ } {}
47
48 Options &&Accel (const wxChar *value) &&
49 { accel = value; return std::move(*this); }
50 Options &&IsEffect (bool value = true) &&
51 { bIsEffect = value; return std::move(*this); }
53 { parameter = value; return std::move(*this); }
54 Options &&LongName (const TranslatableString &value ) &&
55 { longName = value; return std::move(*this); }
57 { global = true; return std::move(*this); }
59 { useStrictFlags = true; return std::move(*this); }
61 { wantKeyUp = true; return std::move(*this); }
63 { skipKeyDown = true; return std::move(*this); }
64
65 // This option affects debugging only:
67 { allowDup = true; return std::move(*this); }
68
69 Options &&AllowInMacros ( int value = 1 ) &&
70 { allowInMacros = value; return std::move(*this); }
71
72 // CheckTest is overloaded
73 // Take arbitrary predicate
75 { checker = fn; return std::move(*this); }
76 // Take a preference path
77 Options &&CheckTest (const wxChar *key, bool defaultValue) && {
78 checker = MakeCheckFn( key, defaultValue );
79 return std::move(*this);
80 }
81 // Take a BoolSetting
82 Options &&CheckTest ( const BoolSetting &setting ) && {
83 checker = MakeCheckFn( setting );
84 return std::move(*this);
85 }
86
87 const wxChar *accel{ wxT("") };
88 CheckFn checker; // default value means it's not a check item
89 bool bIsEffect{ false };
90 CommandParameter parameter{};
92 bool global{ false };
93 bool useStrictFlags{ false };
94 bool wantKeyUp{ false };
95 bool skipKeyDown{ false };
96 bool allowDup{ false };
97 // 0 = never, 1 = always, -1 = deduce from label
98 int allowInMacros{ -1 };
99
100 private:
101 static CheckFn MakeCheckFn(const wxString key, bool defaultValue);
102 static CheckFn MakeCheckFn(const BoolSetting &setting);
103 };
104
106 struct MENUS_API ItemProperties {
113 };
114 virtual ~ItemProperties() = default;
115 virtual Properties GetProperties() const = 0;
116 };
117
118 namespace detail {
119 struct MENUS_API VisitorBase {
120 std::pair<bool, bool>
121 ShouldBeginGroup(const ItemProperties *pProperties);
122 void AfterBeginGroup(const ItemProperties *pProperties);
123 bool ShouldEndGroup(const ItemProperties *pProperties);
124 bool ShouldDoSeparator();
125
126 std::vector<bool> firstItem;
127 std::vector<bool> needSeparator;
128 };
129 }
130
131 using namespace Registry;
132
135 template<typename MenuTraits> struct Visitor
136 : VisitorFunctions<MenuTraits>
138 {
140 std::function<void()> doSeparator
141 ) : VisitorFunctions<MenuTraits>{ std::tuple{
142
143 [this](const GroupItem<MenuTraits> &item, const Path &path)
144 {
145 using namespace MenuRegistry;
146 const auto pProperties = dynamic_cast<const ItemProperties*>(&item);
147 auto [begin, separate] = ShouldBeginGroup(pProperties);
148 if (separate)
149 mDoSeparator();
150 if (begin)
151 mWrapped.BeginGroup(item, path);
152 AfterBeginGroup(pProperties);
153 },
154
155 [this](const Registry::SingleItem &item, const Path &path)
156 {
157 if (ShouldDoSeparator())
158 mDoSeparator();
159 mWrapped.Visit(item, path);
160 },
161
162 [this](const GroupItem<MenuTraits> &item, const Path &path)
163 {
164 using namespace MenuRegistry;
165 const auto pProperties = dynamic_cast<const ItemProperties*>(&item);
166 if (ShouldEndGroup(pProperties))
167 mWrapped.EndGroup(item, path);
168 }
169
170 }}
171 , mWrapped{ move(functions) }
172 , mDoSeparator{ move(doSeparator) }
173 {}
174
175 private:
177 const std::function<void()> mDoSeparator;
178 };
179
180 struct CommandItem;
181 struct CommandGroupItem;
183 struct MenuItem;
184 struct MenuItems;
185 struct SpecialItem;
186 struct MenuPart;
187
194 };
195
196 template<typename RegistryTraits>
197 static inline bool IsSection(const GroupItem<RegistryTraits> &item) {
198 auto pProperties = dynamic_cast<const ItemProperties *>(&item);
199 return pProperties && pProperties->GetProperties() ==
201 }
202
206 };
207}
208
209#ifdef _WIN32
210template struct __declspec(dllexport) Composite::Extension<
213>;
214#endif
215
216namespace MenuRegistry {
217 // Describes a main menu in the toolbar, or a sub-menu
218 struct MENUS_API MenuItem final
220 GroupItem<Traits>, MenuItemData, const Identifier&
221 >
223 {
224 using Extension::Extension;
225 ~MenuItem() override;
226 const auto &GetTitle() const { return mTitle; }
227 Properties GetProperties() const override;
228 };
229
230 using Condition = std::function<bool()>;
231}
232
233#ifdef _WIN32
234template struct __declspec(dllexport) Composite::Extension<
237>;
238#endif
239
240namespace MenuRegistry {
241
242 // Collects other items that are conditionally shown or hidden, but are
243 // always available to macro programming
244 struct MENUS_API ConditionalGroupItem final
246 GroupItem<Traits>, Condition, const Identifier &
247 >
248 {
249 using Extension::Extension;
250 ~ConditionalGroupItem() override;
251 using Condition::operator();
252 };
253
254 // usage:
255 // auto scope = FinderScope( findCommandHandler );
256 // return Items( ... );
257 //
258 // or:
259 // return ( FinderScope( findCommandHandler ), Items( ... ) );
260 //
261 // where findCommandHandler names a function.
262 // This is used before a sequence of many calls to Command() and
263 // CommandGroup(), so that the finder argument need not be specified
264 // in each call.
265 class MENUS_API FinderScope : ValueRestorer< CommandHandlerFinder >
266 {
268
269 public:
271 static CommandHandlerFinder DefaultFinder() { return sFinder; }
272
274 explicit
276 : ValueRestorer( sFinder, finder )
277 { assert(finder); }
278 };
279
280 // Describes one command in a menu
281 struct MENUS_API CommandItem final : SingleItem {
282 CommandItem(const CommandID &name_,
283 const TranslatableString &label_in_,
284 CommandFunctorPointer callback_,
285 CommandFlag flags_,
286 const Options &options_,
287 CommandHandlerFinder finder_);
288
289 // Takes a pointer to member function directly, and delegates to the
290 // previous constructor; useful within the lifetime of a FinderScope
294 template< typename Handler >
296 const TranslatableString &label_in,
297 void (Handler::*pmf)(const CommandContext&),
298 CommandFlag flags,
299 const Options &options = {},
301 : CommandItem(name, label_in,
303 static_cast<CommandFunctorPointer::MemberFn>(pmf) },
304 flags, options, finder)
305 { assert(finder); }
306
307 // Takes a pointer to nonmember function and delegates to the first
308 // constructor
310 const TranslatableString &label_in,
312 CommandFlag flags,
313 const Options &options = {})
314 : CommandItem(name, label_in,
315 CommandFunctorPointer{ callback },
316 flags, options, nullptr)
317 {}
318
319 ~CommandItem() override;
320
326 };
327
328 // Describes several successive commands in a menu that are closely related
329 // and dispatch to one common callback, which will be passed a number
330 // in the CommandContext identifying the command
331 struct MENUS_API CommandGroupItem final : SingleItem {
332 CommandGroupItem(const Identifier &name_,
333 std::vector<ComponentInterfaceSymbol> items_,
334 CommandFunctorPointer callback_,
335 CommandFlag flags_,
336 bool isEffect_,
337 CommandHandlerFinder finder_);
338
339 // Takes a pointer to member function directly, and delegates to the
340 // previous constructor; useful within the lifetime of a FinderScope
344 template< typename Handler >
346 std::vector<ComponentInterfaceSymbol> items_,
347 void (Handler::*pmf)(const CommandContext&),
348 CommandFlag flags_,
349 bool isEffect_,
351 : CommandGroupItem(name_, move(items_),
353 static_cast<CommandFunctorPointer::MemberFn>(pmf) },
354 flags_, isEffect_, finder)
355 { assert(finder); }
356
357 // Takes a pointer to nonmember function and delegates to the first
358 // constructor
360 std::vector< ComponentInterfaceSymbol > items,
362 CommandFlag flags,
363 bool isEffect = false)
364 : CommandGroupItem(name, move(items),
366 flags, isEffect, nullptr)
367 {}
368
369 ~CommandGroupItem() override;
370
371 const std::vector<ComponentInterfaceSymbol> items;
376 };
377
378 // For manipulating the enclosing menu or sub-menu directly,
379 // adding any number of items, not using the CommandManager
380 struct MENUS_API SpecialItem : SingleItem
381 {
382 using SingleItem::SingleItem;
383 ~SpecialItem() override;
384 };
385
388 struct MENUS_API MenuItems
390 GroupItem<Traits>, void, const Identifier &
391 >
393 {
394 using Extension::Extension;
395 ~MenuItems() override;
397 Ordering GetOrdering() const override;
398 Properties GetProperties() const override;
399 };
400
401 struct MENUS_API MenuPart
403 GroupItem<Traits>, void, const Identifier &
404 >
406 {
407 using Extension::Extension;
408 ~MenuPart() override;
409 Properties GetProperties() const override;
410 };
411
417
420
427 constexpr auto Items = Callable::UniqueMaker<MenuItems>();
428
432
436 constexpr auto Section = Callable::UniqueMaker<MenuPart>();
437
439
445 constexpr auto Menu = Callable::UniqueMaker<MenuItem>();
446
449
454 constexpr auto ConditionalItems = Callable::UniqueMaker<ConditionalGroupItem>();
455
456 constexpr auto Command = Callable::UniqueMaker<CommandItem>();
457
459 const Identifier &, std::vector<ComponentInterfaceSymbol>>();
460
462
463 struct MENUS_API ItemRegistry {
464 static GroupItem<Traits> &Registry();
465 };
466
467 // Typically you make a static object of this type in the .cpp file that
468 // also defines the added menu actions.
469 // pItem can be specified by an expression using the inline functions above.
471
472 MENUS_API void Visit(Visitor<Traits> &visitor, AudacityProject &project);
473}
474
475#endif
wxT("CloseDown"))
Functions and classes that generate callable objects.
std::bitset< NCommandFlags > CommandFlag
Definition: CommandFlag.h:30
std::function< CommandHandlerObject &(AudacityProject &) > CommandHandlerFinder
TaggedIdentifier< CommandIdTag, false > CommandID
Identifies a menu command or macro. Case-insensitive comparison.
Definition: Identifier.h:232
static const AudacityProject::AttachedObjects::RegisteredFactory key
static const auto title
wxString name
Definition: TagsEditor.cpp:166
const auto project
static const auto fn
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
This specialization of Setting for bool adds a Toggle method to negate the saved value.
Definition: Prefs.h:346
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
An explicitly nonlocalized string, not meant for the user to see.
Definition: Identifier.h:22
FinderScope(CommandHandlerFinder finder)
Definition: MenuRegistry.h:275
static CommandHandlerFinder DefaultFinder()
Definition: MenuRegistry.h:271
static CommandHandlerFinder sFinder
Definition: MenuRegistry.h:267
Generates classes whose instances register items at construction.
Definition: Registry.h:388
Holds a msgid for the translation catalog; may also bind format arguments.
Set a variable temporarily in a scope.
Definition: MemoryX.h:214
constexpr auto UniqueMaker()
Generate variadic factory functions.
Definition: Callable.h:122
constexpr auto Section
Definition: MenuRegistry.h:436
constexpr auto Items
Definition: MenuRegistry.h:427
constexpr auto CommandGroup
Definition: MenuRegistry.h:458
static bool IsSection(const GroupItem< RegistryTraits > &item)
Definition: MenuRegistry.h:197
constexpr auto Command
Definition: MenuRegistry.h:456
std::function< bool(AudacityProject &) > CheckFn
Definition: MenuRegistry.h:34
constexpr auto Menu
Items will appear in a main toolbar menu or in a sub-menu.
Definition: MenuRegistry.h:445
std::function< bool()> Condition
Definition: MenuRegistry.h:230
MENUS_API void Visit(Visitor< Traits > &visitor, AudacityProject &project)
constexpr auto ConditionalItems
Definition: MenuRegistry.h:454
std::vector< Identifier > Path
Definition: Registry.h:71
std::vector< MenuItem > MenuItems
Definition: Scrubbing.cpp:258
const char * begin(const char *str) noexcept
Definition: StringUtils.h:101
STL namespace.
Extend Base with extra fields, in a second, protected base class.
Definition: Composite.h:177
CommandGroupItem(const CommandID &name, std::vector< ComponentInterfaceSymbol > items, CommandFunctorPointer::NonMemberFn fn, CommandFlag flags, bool isEffect=false)
Definition: MenuRegistry.h:359
CommandGroupItem(const Identifier &name_, std::vector< ComponentInterfaceSymbol > items_, void(Handler::*pmf)(const CommandContext &), CommandFlag flags_, bool isEffect_, CommandHandlerFinder finder=FinderScope::DefaultFinder())
Definition: MenuRegistry.h:345
CommandFunctorPointer callback
Definition: MenuRegistry.h:373
CommandHandlerFinder finder
Definition: MenuRegistry.h:372
const std::vector< ComponentInterfaceSymbol > items
Definition: MenuRegistry.h:371
CommandHandlerFinder finder
Definition: MenuRegistry.h:322
CommandItem(const CommandID &name, const TranslatableString &label_in, void(Handler::*pmf)(const CommandContext &), CommandFlag flags, const Options &options={}, CommandHandlerFinder finder=FinderScope::DefaultFinder())
Definition: MenuRegistry.h:295
CommandFunctorPointer callback
Definition: MenuRegistry.h:323
const TranslatableString label_in
Definition: MenuRegistry.h:321
CommandItem(const CommandID &name, const TranslatableString &label_in, CommandFunctorPointer::NonMemberFn callback, CommandFlag flags, const Options &options={})
Definition: MenuRegistry.h:309
A mix-in discovered by dynamic_cast; independent of the Traits.
Definition: MenuRegistry.h:106
virtual ~ItemProperties()=default
virtual Properties GetProperties() const =0
MenuItemData(TranslatableString title)
Definition: MenuRegistry.h:204
const TranslatableString mTitle
Definition: MenuRegistry.h:205
const auto & GetTitle() const
Definition: MenuRegistry.h:226
Options && IsGlobal() &&
Definition: MenuRegistry.h:56
Options && AllowInMacros(int value=1) &&
Definition: MenuRegistry.h:69
Options && UseStrictFlags() &&
Definition: MenuRegistry.h:58
Options && SkipKeyDown() &&
Definition: MenuRegistry.h:62
Options && CheckTest(const CheckFn &fn) &&
Definition: MenuRegistry.h:74
Options && CheckTest(const BoolSetting &setting) &&
Definition: MenuRegistry.h:82
Options && IsEffect(bool value=true) &&
Definition: MenuRegistry.h:50
Options(const wxChar *accel_)
Definition: MenuRegistry.h:41
Options && LongName(const TranslatableString &value) &&
Definition: MenuRegistry.h:54
Options && CheckTest(const wxChar *key, bool defaultValue) &&
Definition: MenuRegistry.h:77
Options && AllowDup() &&
Definition: MenuRegistry.h:66
Options && WantKeyUp() &&
Definition: MenuRegistry.h:60
Options(const wxChar *accel_, const TranslatableString &longName_)
Definition: MenuRegistry.h:43
Options && Accel(const wxChar *value) &&
Definition: MenuRegistry.h:48
Options && Parameter(const CommandParameter &value) &&
Definition: MenuRegistry.h:52
Visitor(VisitorFunctions< MenuTraits > functions, std::function< void()> doSeparator)
Definition: MenuRegistry.h:139
const VisitorFunctions< MenuTraits > mWrapped
Definition: MenuRegistry.h:176
const std::function< void()> mDoSeparator
Definition: MenuRegistry.h:177
std::vector< bool > needSeparator
Definition: MenuRegistry.h:127
void AfterBeginGroup(const ItemProperties *pProperties)
bool ShouldEndGroup(const ItemProperties *pProperties)
std::pair< bool, bool > ShouldBeginGroup(const ItemProperties *pProperties)
Has variadic and range constructors that check types.
Definition: Registry.h:292
Common abstract base class for items that are not groups.
Definition: Registry.h:224
void BeginGroup(const GroupItem< RegistryTraits > &item, const Path &path) const
Call-through for a decorating pre-visitor.
Definition: Registry.h:505
void EndGroup(const GroupItem< RegistryTraits > &item, const Path &path) const
Call-through for a decorating post-visitor.
Definition: Registry.h:522
void Visit(const SingleItem &item, const Path &path) const
Call-through for a decorating leaf-visitor.
Definition: Registry.h:511
Primary template for a list of arbitrary types.
Definition: TypeList.h:61
void(*)(const CommandContext &context) NonMemberFn
void(CommandHandlerObject::*)(const CommandContext &context) MemberFn