1 //
2 //  CommandFlag.h
3 //  Audacity
4 //
5 //  Created by Paul Licameli on 11/22/16.
6 //
7 //
8 
9 #ifndef __AUDACITY_COMMAND_FLAG__
10 #define __AUDACITY_COMMAND_FLAG__
11 
12 // Flags used in command handling.
13 
14 #include <bitset>
15 #include <functional>
16 #include <utility>
17 #include <wx/string.h>
18 
19 #include "audacity/Types.h"
20 
21 class AudacityProject;
22 
23 // Increase the template parameter as needed to allow more flags
24 constexpr size_t NCommandFlags = 64;
25 static_assert(
26    NCommandFlags <= 8 * sizeof( unsigned long long ),
27    "NoFlagsSpecified may have incorrect value"
28 );
29 
30 // Type to specify conditions for enabling of a menu item
31 using CommandFlag = std::bitset<NCommandFlags>;
32 
33 // Special constant values
34 constexpr CommandFlag
35    AlwaysEnabledFlag{},      // all zeroes
36    NoFlagsSpecified{ ~0ULL }; // all ones
37 
38 struct CommandFlagOptions{
39    // Supplied the translated name of the command, returns a translated
40    // error message
41    using MessageFormatter =
42       std::function< TranslatableString( const TranslatableString& ) >;
43 
44    CommandFlagOptions() = default;
45    CommandFlagOptions(
46       const MessageFormatter &message_,
47       const wxString &helpPage_ = {},
48       const TranslatableString &title_ = {}
49    ) : message{ message_ }, helpPage{ helpPage_ }, title{ title_ }
50    {}
51 
QuickTestCommandFlagOptions52    CommandFlagOptions && QuickTest() &&
53    { quickTest = true; return std::move( *this ); }
DisableDefaultMessageCommandFlagOptions54    CommandFlagOptions && DisableDefaultMessage() &&
55    { enableDefaultMessage = false; return std::move( *this ); }
PriorityCommandFlagOptions56    CommandFlagOptions && Priority( unsigned priority_ ) &&
57    { priority = priority_; return std::move( *this ); }
58 
59    // null, or else computes non-default message for the dialog box when the
60    // condition is not satisfied for the selected command
61    MessageFormatter message;
62 
63    // Title and help page are used only if a message function is given
64    wxString helpPage;
65 
66    // Empty, or non-default title for the dialog box when the
67    // condition is not satisfied for the selected command
68    // This string must be given UN-translated.
69    TranslatableString title;
70 
71    // Conditions with higher "priority" are preferred over others in choosing
72    // the help message
73    unsigned priority = 0;
74 
75    // If false, and no other condition with a message is unsatisfied, then
76    // display no dialog box at all when this condition is not satisfied
77    bool enableDefaultMessage = true;
78 
79    // If true, assume this is a cheap test to be done always.  If false, the
80    // test may be skipped and the condition assumed to be unchanged since the
81    // last more comprehensive testing
82    bool quickTest = false;
83 };
84 
85 // Construct one statically to register (and reserve) a bit position in the set
86 // an associate it with a test function; those with quickTest = true are cheap
87 // to compute and always checked
88 class AUDACITY_DLL_API ReservedCommandFlag : public CommandFlag
89 {
90 public:
91    using Predicate = std::function< bool( const AudacityProject& ) >;
92    ReservedCommandFlag( const Predicate &predicate,
93       const CommandFlagOptions &options = {} );
94 };
95 
96 // To describe auto-selection, stop-if-paused, etc.:
97 // A structure describing a set of conditions, another set that might be
98 // made true given the first, and the function that may make them true.
99 // If a menu item requires the second set, while the first set is true,
100 // then the enabler will be invoked (unless the menu item is constructed with
101 // the useStrictFlags option, or the applicability test first returns false).
102 // The item's full set of required flags is passed to the function.
103 
104 // Computation of the flags is delayed inside a function -- because often you
105 // need to name a statically allocated CommandFlag, or a bitwise OR of some,
106 // while they may not have been initialized yet, during static initialization.
107 struct MenuItemEnabler {
108    using Flags = std::function< CommandFlag() >;
109    using Test = std::function< bool( const AudacityProject& ) >;
110    using Action = std::function< void( AudacityProject&, CommandFlag ) >;
111 
112    const Flags actualFlags;
113    const Flags possibleFlags;
114    Test applicable;
115    Action tryEnable;
116 };
117 
118 // Typically this is statically constructed:
119 struct AUDACITY_DLL_API RegisteredMenuItemEnabler{
120    RegisteredMenuItemEnabler( const MenuItemEnabler &enabler );
121 };
122 
123 // Unnecessary #include to indicate otherwise hidden link dependencies
124 #include "Menus.h"
125 
126 #endif
127