diff --git a/src/Menus.cpp b/src/Menus.cpp index 68b019d89..a97079400 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -414,6 +414,57 @@ CommandFlag MenuManager::GetFocusedFrame(AudacityProject &project) } +ReservedCommandFlag::ReservedCommandFlag() +{ + static size_t sNextReservedFlag = 0; + // This will throw std::out_of_range if the constant NCommandFlags is too + // small + set( sNextReservedFlag++ ); +} + +const ReservedCommandFlag + AudioIONotBusyFlag, + TimeSelectedFlag, // This is equivalent to check if there is a valid selection, so it's used for Zoom to Selection too + TracksSelectedFlag, + TracksExistFlag, + LabelTracksExistFlag, + WaveTracksSelectedFlag, + ClipboardFlag, + TextClipFlag, // Same as Clipboard flag for now. + UnsavedChangesFlag, + HasLastEffectFlag, + UndoAvailableFlag, + RedoAvailableFlag, + ZoomInAvailableFlag, + ZoomOutAvailableFlag, + StereoRequiredFlag, //lda + TopDockHasFocus, //lll + TrackPanelHasFocus, //lll + BotDockHasFocus, //lll + LabelsSelectedFlag, + AudioIOBusyFlag, //lll + PlayRegionLockedFlag, //msmeyer + PlayRegionNotLockedFlag, //msmeyer + CutCopyAvailableFlag, + WaveTracksExistFlag, + NoteTracksExistFlag, //gsw + NoteTracksSelectedFlag, //gsw + HaveRecentFiles, + IsNotSyncLockedFlag, //awd + IsSyncLockedFlag, //awd + IsRealtimeNotActiveFlag, //lll + CaptureNotBusyFlag, + CanStopAudioStreamFlag, + RulerHasFocus, // prl + NotMinimizedFlag, // prl + PausedFlag, // jkc + NotPausedFlag, // jkc + HasWaveDataFlag, // jkc + PlayableTracksExistFlag, + AudioTracksSelectedFlag, + NoAutoSelect // jkc +; + CommandFlag MenuManager::GetUpdateFlags( bool checkActive ) { auto &project = mProject; @@ -535,10 +586,12 @@ CommandFlag MenuManager::GetUpdateFlags( bool checkActive ) if (history.RedoAvailable()) flags |= RedoAvailableFlag; - if (ViewInfo::Get( project ).ZoomInAvailable() && (flags & TracksExistFlag)) + if (ViewInfo::Get( project ).ZoomInAvailable() && + (flags & TracksExistFlag).any()) flags |= ZoomInAvailableFlag; - if (ViewInfo::Get( project ).ZoomOutAvailable() && (flags & TracksExistFlag)) + if (ViewInfo::Get( project ).ZoomOutAvailable() && + (flags & TracksExistFlag).any()) flags |= ZoomOutAvailableFlag; flags |= GetFocusedFrame(project); @@ -549,9 +602,9 @@ CommandFlag MenuManager::GetUpdateFlags( bool checkActive ) else if (!playRegion.Empty()) flags |= PlayRegionNotLockedFlag; - if (flags & AudioIONotBusyFlag) { - if (flags & TimeSelectedFlag) { - if (flags & TracksSelectedFlag) { + if ( (flags & AudioIONotBusyFlag).any() ) { + if ( (flags & TimeSelectedFlag).any() ) { + if ( (flags & TracksSelectedFlag).any() ) { flags |= CutCopyAvailableFlag; } } @@ -681,10 +734,10 @@ void MenuManager::UpdateMenus( bool checkActive ) //to actually do the 'select all' to make the command valid. if (mWhatIfNoSelection != 0) { - if ((flags & TracksExistFlag)) + if ( (flags & TracksExistFlag).any() ) { flags2 |= TracksSelectedFlag; - if ((flags & WaveTracksExistFlag)) + if ( (flags & WaveTracksExistFlag).any() ) { flags2 |= TimeSelectedFlag | WaveTracksSelectedFlag @@ -695,7 +748,7 @@ void MenuManager::UpdateMenus( bool checkActive ) if( mStopIfWasPaused ) { - if( flags & PausedFlag ){ + if( (flags & PausedFlag).any() ){ flags2 |= AudioIONotBusyFlag; } } @@ -715,28 +768,31 @@ void MenuManager::UpdateMenus( bool checkActive ) // 0 is grey out, 1 is Autoselect, 2 is Give warnings. if (mWhatIfNoSelection != 0) { - if (!(flags & TimeSelectedFlag) | !(flags & TracksSelectedFlag)) + if ( (flags & TimeSelectedFlag).none() || + (flags & TracksSelectedFlag).none ()) { commandManager.Enable(wxT("SplitCut"), false); commandManager.Enable(wxT("SplitDelete"), false); } - if (!(flags & WaveTracksSelectedFlag)) + if ( (flags & WaveTracksSelectedFlag).none() ) { commandManager.Enable(wxT("Split"), false); } - if (!(flags & TimeSelectedFlag) | !(flags & WaveTracksSelectedFlag)) + if ( (flags & TimeSelectedFlag).none() || + (flags & WaveTracksSelectedFlag).none() ) { commandManager.Enable(wxT("ExportSel"), false); commandManager.Enable(wxT("SplitNew"), false); } - if (!(flags & TimeSelectedFlag) | !(flags & AudioTracksSelectedFlag)) + if ( (flags & TimeSelectedFlag).none() || + (flags & AudioTracksSelectedFlag).none() ) { commandManager.Enable(wxT("Trim"), false); } } #if 0 - if (flags & CutCopyAvailableFlag) { + if ( (flags & CutCopyAvailableFlag).any() ) { GetCommandManager()->Enable(wxT("Copy"), true); GetCommandManager()->Enable(wxT("Cut"), true); } @@ -789,7 +845,7 @@ bool MenuManager::TryToMakeActionAllowed( auto &project = mProject; bool bAllowed; - if( !flags ) + if( flags.none() ) flags = GetUpdateFlags(); bAllowed = ((flags & mask) == (flagsRqd & mask)); @@ -800,7 +856,7 @@ bool MenuManager::TryToMakeActionAllowed( // 1's wherever a required flag is missing. auto MissingFlags = (~flags & flagsRqd) & mask; - if( mStopIfWasPaused && (MissingFlags & AudioIONotBusyFlag ) ){ + if( mStopIfWasPaused && (MissingFlags & AudioIONotBusyFlag ).any() ){ TransportActions::StopIfPaused( project ); // Hope this will now reflect stopped audio. flags = GetUpdateFlags(); @@ -815,7 +871,7 @@ bool MenuManager::TryToMakeActionAllowed( return false; // Some effects disallow autoselection. - if( flagsRqd & NoAutoSelect ) + if( (flagsRqd & NoAutoSelect).any() ) return false; // Why is action still not allowed? @@ -823,11 +879,13 @@ bool MenuManager::TryToMakeActionAllowed( MissingFlags = (flags & ~flagsRqd) & mask; // IF selecting all audio won't do any good, THEN return with failure. - if( !(flags & WaveTracksExistFlag) ) + if( (flags & WaveTracksExistFlag).none() ) return false; // returns if mask wants a zero in some flag and that's not present. // logic seems a bit peculiar and worth revisiting. - if( (MissingFlags & ~( TimeSelectedFlag | WaveTracksSelectedFlag)) ) + if( (MissingFlags & + ~( TimeSelectedFlag | WaveTracksSelectedFlag ) + ).any() ) return false; // This was 'DoSelectSomething()'. diff --git a/src/Menus.h b/src/Menus.h index 3ba1e79c7..280551629 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -15,6 +15,7 @@ #include // member variable #include "Prefs.h" #include "ClientData.h" +#include "commands/CommandFlag.h" class wxArrayString; class wxCommandEvent; @@ -29,7 +30,6 @@ class ViewInfo; class WaveClip; class WaveTrack; -enum CommandFlag : unsigned long long; enum EffectType : int; typedef wxString PluginID; diff --git a/src/commands/CommandFlag.h b/src/commands/CommandFlag.h index 204e44f95..f570abaa6 100644 --- a/src/commands/CommandFlag.h +++ b/src/commands/CommandFlag.h @@ -11,133 +11,69 @@ // Flags used in command handling. -// These flags represent the majority of the states that affect -// whether or not items in menus are enabled or disabled. -enum CommandFlag : unsigned long long -{ - AlwaysEnabledFlag = 0x00000000, +#include - AudioIONotBusyFlag = 0x00000001, - TimeSelectedFlag = 0x00000002, // This is equivalent to check if there is a valid selection, so it's used for Zoom to Selection too - TracksSelectedFlag = 0x00000004, - TracksExistFlag = 0x00000008, - LabelTracksExistFlag = 0x00000010, - WaveTracksSelectedFlag = 0x00000020, - - UnsavedChangesFlag = 0x00000080, - HasLastEffectFlag = 0x00000100, - UndoAvailableFlag = 0x00000200, - RedoAvailableFlag = 0x00000400, - ZoomInAvailableFlag = 0x00000800, - ZoomOutAvailableFlag = 0x00001000, - StereoRequiredFlag = 0x00002000, //lda - - TrackPanelHasFocus = 0x00008000, //lll - - LabelsSelectedFlag = 0x00020000, - AudioIOBusyFlag = 0x00040000, //lll - PlayRegionLockedFlag = 0x00080000, //msmeyer - PlayRegionNotLockedFlag= 0x00100000, //msmeyer - CutCopyAvailableFlag = 0x00200000, - WaveTracksExistFlag = 0x00400000, - NoteTracksExistFlag = 0x00800000, //gsw - NoteTracksSelectedFlag = 0x01000000, //gsw - - IsNotSyncLockedFlag = 0x04000000, //awd - IsSyncLockedFlag = 0x08000000, //awd - IsRealtimeNotActiveFlag= 0x10000000, //lll - CaptureNotBusyFlag = 0x20000000, - CanStopAudioStreamFlag = 0x40000000, - - NotMinimizedFlag = 0x100000000ULL, // prl - PausedFlag = 0x200000000ULL, // jkc - - HasWaveDataFlag = 0x800000000ULL, // jkc - PlayableTracksExistFlag = 0x1000000000ULL, - AudioTracksSelectedFlag = 0x2000000000ULL, - NoAutoSelect = 0x4000000000ULL, // jkc - - NoFlagsSpecified = ~0ULL -}; - -// Prevent accidental misuse with narrower types - -bool operator == (CommandFlag, unsigned long) PROHIBITED; -bool operator == (CommandFlag, long) PROHIBITED; -bool operator == (unsigned long, CommandFlag) PROHIBITED; -bool operator == (long, CommandFlag) PROHIBITED; - -bool operator != (CommandFlag, unsigned long) PROHIBITED; -bool operator != (CommandFlag, long) PROHIBITED; -bool operator != (unsigned long, CommandFlag) PROHIBITED; -bool operator != (long, CommandFlag) PROHIBITED; - -CommandFlag operator & (CommandFlag, unsigned long) PROHIBITED; -CommandFlag operator & (CommandFlag, long) PROHIBITED; -CommandFlag operator & (unsigned long, CommandFlag) PROHIBITED; -CommandFlag operator & (long, CommandFlag) PROHIBITED; - -CommandFlag operator | (CommandFlag, unsigned long) PROHIBITED; -CommandFlag operator | (CommandFlag, long) PROHIBITED; -CommandFlag operator | (unsigned long, CommandFlag) PROHIBITED; -CommandFlag operator | (long, CommandFlag) PROHIBITED; - -CommandFlag operator ^ (CommandFlag, unsigned long) PROHIBITED; -CommandFlag operator ^ (CommandFlag, long) PROHIBITED; -CommandFlag operator ^ (unsigned long, CommandFlag) PROHIBITED; -CommandFlag operator ^ (long, CommandFlag) PROHIBITED; - -bool operator == (CommandFlag, unsigned int) PROHIBITED; -bool operator == (CommandFlag, int) PROHIBITED; -bool operator == (unsigned int, CommandFlag) PROHIBITED; -bool operator == (int, CommandFlag) PROHIBITED; - -bool operator != (CommandFlag, unsigned int) PROHIBITED; -bool operator != (CommandFlag, int) PROHIBITED; -bool operator != (unsigned int, CommandFlag) PROHIBITED; -bool operator != (int, CommandFlag) PROHIBITED; - -CommandFlag operator & (CommandFlag, unsigned int) PROHIBITED; -CommandFlag operator & (CommandFlag, int) PROHIBITED; -CommandFlag operator & (unsigned int, CommandFlag) PROHIBITED; -CommandFlag operator & (int, CommandFlag) PROHIBITED; - -CommandFlag operator | (CommandFlag, unsigned int) PROHIBITED; -CommandFlag operator | (CommandFlag, int) PROHIBITED; -CommandFlag operator | (unsigned int, CommandFlag) PROHIBITED; -CommandFlag operator | (int, CommandFlag) PROHIBITED; - -CommandFlag operator ^ (CommandFlag, unsigned int) PROHIBITED; -CommandFlag operator ^ (CommandFlag, int) PROHIBITED; -CommandFlag operator ^ (unsigned int, CommandFlag) PROHIBITED; -CommandFlag operator ^ (int, CommandFlag) PROHIBITED; - -// Supply the bitwise operations - -inline constexpr CommandFlag operator ~ (CommandFlag flag) -{ - return static_cast( ~ static_cast (flag) ); -} -inline constexpr CommandFlag operator & (CommandFlag lhs, CommandFlag rhs) -{ - return static_cast ( - static_cast(lhs) & - static_cast(rhs) - ); -} -inline constexpr CommandFlag operator | (CommandFlag lhs, CommandFlag rhs) -{ - return static_cast ( - static_cast(lhs) | - static_cast(rhs) - ); -} -inline CommandFlag & operator |= (CommandFlag &lhs, CommandFlag rhs) -{ - lhs = lhs | rhs; - return lhs; -} +// Increase the template parameter as needed to allow more flags +constexpr size_t NCommandFlags = 64; +static_assert( + NCommandFlags <= 8 * sizeof( unsigned long long ), + "NoFlagsSpecified may have incorrect value" +); +// Type to specify conditions for enabling of a menu item +using CommandFlag = std::bitset; using CommandMask = CommandFlag; +// Special constant values +constexpr CommandFlag + AlwaysEnabledFlag{}, // all zeroes + NoFlagsSpecified{ ~0ULL }; // all ones + +// Construct one statically to register (and reserve) a bit position in the set +class ReservedCommandFlag : public CommandFlag +{ +public: + ReservedCommandFlag(); +}; + +// Widely used command flags, but this list need not be exhaustive. It may be +// extended, with special purpose flags of limited use, by constucting static +// ReservedCommandFlag values + +extern const ReservedCommandFlag + AudioIONotBusyFlag, + TimeSelectedFlag, // This is equivalent to check if there is a valid selection, so it's used for Zoom to Selection too + TracksSelectedFlag, + TracksExistFlag, + LabelTracksExistFlag, + WaveTracksSelectedFlag, + UnsavedChangesFlag, + HasLastEffectFlag, + UndoAvailableFlag, + RedoAvailableFlag, + ZoomInAvailableFlag, + ZoomOutAvailableFlag, + StereoRequiredFlag, //lda + TrackPanelHasFocus, //lll + LabelsSelectedFlag, + AudioIOBusyFlag, //lll + PlayRegionLockedFlag, //msmeyer + PlayRegionNotLockedFlag, //msmeyer + CutCopyAvailableFlag, + WaveTracksExistFlag, + NoteTracksExistFlag, //gsw + NoteTracksSelectedFlag, //gsw + IsNotSyncLockedFlag, //awd + IsSyncLockedFlag, //awd + IsRealtimeNotActiveFlag, //lll + CaptureNotBusyFlag, + CanStopAudioStreamFlag, + NotMinimizedFlag, // prl + PausedFlag, // jkc + HasWaveDataFlag, // jkc + PlayableTracksExistFlag, + AudioTracksSelectedFlag, + NoAutoSelect // jkc +; + #endif diff --git a/src/commands/CommandManager.cpp b/src/commands/CommandManager.cpp index 8b17d02c9..7d1caeacc 100644 --- a/src/commands/CommandManager.cpp +++ b/src/commands/CommandManager.cpp @@ -964,7 +964,7 @@ void CommandManager::EnableUsingFlags(CommandFlag flags, CommandMask mask) continue; auto combinedMask = (mask & entry->mask); - if (combinedMask) { + if (combinedMask.any()) { bool enable = ((flags & combinedMask) == (entry->flags & combinedMask)); Enable(entry.get(), enable); @@ -1027,15 +1027,18 @@ void CommandManager::TellUserWhyDisallowed( const wxString & Name, CommandFlag f wxString title = _("Disallowed"); wxString helpPage; - auto missingFlags = flagsRequired & (~flagsGot ); - if( missingFlags & AudioIONotBusyFlag ) + auto missingFlags = flagsRequired & ~flagsGot; + if( (missingFlags & AudioIONotBusyFlag).any() ) // This reason will not be shown, because options that require it will be greyed our. reason = _("You can only do this when playing and recording are\nstopped. (Pausing is not sufficient.)"); - else if( missingFlags & StereoRequiredFlag ) + else if( (missingFlags & StereoRequiredFlag).any() ) // This reason will not be shown, because the stereo-to-mono is greyed out if not allowed. reason = _("You must first select some stereo audio to perform this\naction. (You cannot use this with mono.)"); // In reporting the issue with cut or copy, we don't tell the user they could also select some text in a label. - else if(( missingFlags & TimeSelectedFlag ) || (missingFlags &CutCopyAvailableFlag )){ + else if( ( + ( missingFlags & TimeSelectedFlag ) | + ( missingFlags & CutCopyAvailableFlag ) + ).any() ){ title = _("No Audio Selected"); #ifdef EXPERIMENTAL_DA // i18n-hint: %s will be replaced by the name of an action, such as Normalize, Cut, Fade. @@ -1058,9 +1061,9 @@ void CommandManager::TellUserWhyDisallowed( const wxString & Name, CommandFlag f #endif helpPage = "Selecting_Audio_-_the_basics"; } - else if( missingFlags & WaveTracksSelectedFlag) + else if( (missingFlags & WaveTracksSelectedFlag).any() ) reason = _("You must first select some audio to perform this action.\n(Selecting other kinds of track won't work.)"); - else if ( missingFlags & TracksSelectedFlag ) + else if ( (missingFlags & TracksSelectedFlag).any() ) // i18n-hint: %s will be replaced by the name of an action, such as "Remove Tracks". reason = wxString::Format(_("\"%s\" requires one or more tracks to be selected."), Name); // If the only thing wrong was no tracks, we do nothing and don't report a problem @@ -1254,7 +1257,7 @@ bool CommandManager::HandleCommandEntry(const CommandListEntry * entry, auto proj = GetActiveProject(); auto combinedMask = (mask & entry->mask); - if (combinedMask) { + if (combinedMask.any()) { wxASSERT( proj ); if( !proj ) @@ -1671,3 +1674,4 @@ static struct InstallHandlers } ); } } installHandlers; + diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index e0482a09e..4090cd362 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -63,7 +63,6 @@ greater use in future. #include "../ViewInfo.h" #include "../WaveTrack.h" #include "../commands/Command.h" -#include "../commands/CommandFlag.h" #include "../toolbars/ControlToolBar.h" #include "../widgets/AButton.h" #include "../widgets/ProgressDialog.h" diff --git a/src/menus/EditMenus.cpp b/src/menus/EditMenus.cpp index 501ea396c..0ce0641e3 100644 --- a/src/menus/EditMenus.cpp +++ b/src/menus/EditMenus.cpp @@ -1095,7 +1095,7 @@ MenuTable::BaseItemPtr EditMenu( AudacityProject & ) using namespace MenuTable; using Options = CommandManager::Options; - constexpr auto NotBusyTimeAndTracksFlags = + static const auto NotBusyTimeAndTracksFlags = AudioIONotBusyFlag | TimeSelectedFlag | TracksSelectedFlag; // The default shortcut key for Redo is different on different platforms. @@ -1216,7 +1216,7 @@ MenuTable::BaseItemPtr ExtraEditMenu( AudacityProject & ) { using namespace MenuTable; using Options = CommandManager::Options; - constexpr auto flags = + static const auto flags = AudioIONotBusyFlag | TracksSelectedFlag | TimeSelectedFlag; return Menu( _("&Edit"), Command( wxT("DeleteKey"), XXO("&Delete Key"), FN(OnDelete), diff --git a/src/menus/LabelMenus.cpp b/src/menus/LabelMenus.cpp index 30212029b..7b2dd4a23 100644 --- a/src/menus/LabelMenus.cpp +++ b/src/menus/LabelMenus.cpp @@ -586,7 +586,7 @@ MenuTable::BaseItemPtr LabelEditMenus( AudacityProject & ) static const auto checkOff = Options{}.CheckState( false ); - constexpr auto NotBusyLabelsAndWaveFlags = + static const auto NotBusyLabelsAndWaveFlags = AudioIONotBusyFlag | LabelsSelectedFlag | WaveTracksExistFlag | TimeSelectedFlag; diff --git a/src/menus/NavigationMenus.cpp b/src/menus/NavigationMenus.cpp index e385e3aa6..045fc743b 100644 --- a/src/menus/NavigationMenus.cpp +++ b/src/menus/NavigationMenus.cpp @@ -580,7 +580,7 @@ MenuTable::BaseItemPtr ExtraGlobalCommands( AudacityProject & ) MenuTable::BaseItemPtr ExtraFocusMenu( AudacityProject & ) { using namespace MenuTable; - constexpr auto FocusedTracksFlags = TracksExistFlag | TrackPanelHasFocus; + static const auto FocusedTracksFlags = TracksExistFlag | TrackPanelHasFocus; return Menu( _("F&ocus"), Command( wxT("PrevFrame"), diff --git a/src/menus/SelectMenus.cpp b/src/menus/SelectMenus.cpp index 282a8c7fe..ad2c63dfc 100644 --- a/src/menus/SelectMenus.cpp +++ b/src/menus/SelectMenus.cpp @@ -513,7 +513,7 @@ void SelectAllIfNone( AudacityProject &project ) { auto &viewInfo = ViewInfo::Get( project ); auto flags = MenuManager::Get( project ).GetUpdateFlags(); - if(!(flags & TracksSelectedFlag) || + if((flags & TracksSelectedFlag).none() || viewInfo.selectedRegion.isPoint()) DoSelectAllAudio( project ); } @@ -1332,7 +1332,7 @@ MenuTable::BaseItemPtr CursorMenu( AudacityProject & ) { using namespace MenuTable; using Options = CommandManager::Options; - constexpr auto CanStopFlags = AudioIONotBusyFlag | CanStopAudioStreamFlag; + static const auto CanStopFlags = AudioIONotBusyFlag | CanStopAudioStreamFlag; // JKC: ANSWER-ME: How is 'cursor to' different to 'Skip To' and how is it // useful? diff --git a/src/menus/TransportMenus.cpp b/src/menus/TransportMenus.cpp index 67d8c61bd..f1a600c6e 100644 --- a/src/menus/TransportMenus.cpp +++ b/src/menus/TransportMenus.cpp @@ -1075,7 +1075,7 @@ MenuTable::BaseItemPtr TransportMenu( AudacityProject &project ) static const auto checkOff = Options{}.CheckState( false ); static const auto checkOn = Options{}.CheckState( true ); - constexpr auto CanStopFlags = AudioIONotBusyFlag | CanStopAudioStreamFlag; + static const auto CanStopFlags = AudioIONotBusyFlag | CanStopAudioStreamFlag; /* i18n-hint: 'Transport' is the name given to the set of controls that play, record, pause etc. */