Redo CommandFlags as std::bitset, allow registration of values

This commit is contained in:
Paul Licameli 2019-06-13 12:29:15 -04:00
parent 1f763984c9
commit 36e3a03c7f
10 changed files with 157 additions and 160 deletions

View File

@ -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()'.

View File

@ -15,6 +15,7 @@
#include <wx/string.h> // 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;

View File

@ -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 <bitset>
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<CommandFlag>( ~ static_cast<unsigned long long> (flag) );
}
inline constexpr CommandFlag operator & (CommandFlag lhs, CommandFlag rhs)
{
return static_cast<CommandFlag> (
static_cast<unsigned long long>(lhs) &
static_cast<unsigned long long>(rhs)
);
}
inline constexpr CommandFlag operator | (CommandFlag lhs, CommandFlag rhs)
{
return static_cast<CommandFlag> (
static_cast<unsigned long long>(lhs) |
static_cast<unsigned long long>(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<NCommandFlags>;
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

View File

@ -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;

View File

@ -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"

View File

@ -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),

View File

@ -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;

View File

@ -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"),

View File

@ -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?

View File

@ -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. */