1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-10-24 07:13:48 +02:00

TryToMakeActionAllowed is also table driven...

... and also the logic for relaxing the conditions for enabling the menu items
This commit is contained in:
Paul Licameli
2019-06-13 17:19:38 -04:00
parent 9a4c18255e
commit 76996bf0cd
3 changed files with 103 additions and 62 deletions

View File

@@ -814,6 +814,55 @@ void MenuManager::ModifyToolbarMenus(AudacityProject &project)
commandManager.Check(wxT("TypeToCreateLabel"), active); commandManager.Check(wxT("TypeToCreateLabel"), active);
} }
namespace
{
using MenuItemEnablers = std::vector<MenuItemEnabler>;
MenuItemEnablers &Enablers()
{
static MenuItemEnablers enablers;
return enablers;
}
}
RegisteredMenuItemEnabler::RegisteredMenuItemEnabler(
const MenuItemEnabler &enabler )
{
Enablers().emplace_back( enabler );
}
RegisteredMenuItemEnabler stopIfPaused{{
PausedFlag,
AudioIONotBusyFlag,
[]( const AudacityProject &project ){
return MenuManager::Get( project ).mStopIfWasPaused; },
[]( AudacityProject &project, CommandFlag ){
if ( MenuManager::Get( project ).mStopIfWasPaused )
TransportActions::StopIfPaused( project );
}
}};
auto canSelectAll = [](const AudacityProject &project){
return MenuManager::Get( project ).mWhatIfNoSelection != 0; };
auto selectAll = []( AudacityProject &project, CommandFlag flagsRqd ){
if ( MenuManager::Get( project ).mWhatIfNoSelection == 1 &&
(flagsRqd & NoAutoSelect).none() )
SelectActions::DoSelectAllAudio(project);
};
RegisteredMenuItemEnabler selectTracks{{
TracksExistFlag,
TracksSelectedFlag,
canSelectAll,
selectAll
}};
RegisteredMenuItemEnabler selectWaveTracks{{
WaveTracksExistFlag,
TimeSelectedFlag | WaveTracksSelectedFlag | CutCopyAvailableFlag,
canSelectAll,
selectAll
}};
// checkActive is a temporary hack that should be removed as soon as we // checkActive is a temporary hack that should be removed as soon as we
// get multiple effect preview working // get multiple effect preview working
void MenuManager::UpdateMenus( bool checkActive ) void MenuManager::UpdateMenus( bool checkActive )
@@ -827,6 +876,12 @@ void MenuManager::UpdateMenus( bool checkActive )
return; return;
auto flags = GetUpdateFlags(checkActive); auto flags = GetUpdateFlags(checkActive);
// Return from this function if nothing's changed since
// the last time we were here.
if (flags == mLastFlags)
return;
mLastFlags = flags;
auto flags2 = flags; auto flags2 = flags;
// We can enable some extra items if we have select-all-on-none. // We can enable some extra items if we have select-all-on-none.
@@ -834,33 +889,15 @@ void MenuManager::UpdateMenus( bool checkActive )
//ANSWER: Because flags2 is used in the menu enable/disable. //ANSWER: Because flags2 is used in the menu enable/disable.
//The effect still needs flags to determine whether it will need //The effect still needs flags to determine whether it will need
//to actually do the 'select all' to make the command valid. //to actually do the 'select all' to make the command valid.
if (mWhatIfNoSelection != 0)
{
if ( (flags & TracksExistFlag).any() )
{
flags2 |= TracksSelectedFlag;
if ( (flags & WaveTracksExistFlag).any() )
{
flags2 |= TimeSelectedFlag
| WaveTracksSelectedFlag
| CutCopyAvailableFlag;
}
}
}
if( mStopIfWasPaused ) for ( const auto &enabler : Enablers() ) {
{ if (
if( (flags & PausedFlag).any() ){ enabler.applicable( project ) &&
flags2 |= AudioIONotBusyFlag; (flags & enabler.actualFlags) == enabler.actualFlags
} )
flags2 |= enabler.possibleFlags;
} }
// Return from this function if nothing's changed since
// the last time we were here.
if (flags == mLastFlags)
return;
mLastFlags = flags;
auto &commandManager = CommandManager::Get( project ); auto &commandManager = CommandManager::Get( project );
// With select-all-on-none, some items that we don't want enabled may have // With select-all-on-none, some items that we don't want enabled may have
@@ -908,7 +945,6 @@ bool MenuManager::ReportIfActionNotAllowed(
return false; return false;
} }
/// Determines if flags for command are compatible with current state. /// Determines if flags for command are compatible with current state.
/// If not, then try some recovery action to make it so. /// If not, then try some recovery action to make it so.
/// @return whether compatible or not after any actions taken. /// @return whether compatible or not after any actions taken.
@@ -921,42 +957,24 @@ bool MenuManager::TryToMakeActionAllowed(
if( flags.none() ) if( flags.none() )
flags = GetUpdateFlags(); flags = GetUpdateFlags();
bAllowed = ((flags & flagsRqd) == flagsRqd); // Visit the table of recovery actions
if( bAllowed ) auto &enablers = Enablers();
return true; auto iter = enablers.begin(), end = enablers.end();
while ((flags & flagsRqd) != flagsRqd && iter != end) {
// Why is action not allowed? const auto &enabler = *iter;
// 1's wherever a required flag is missing. auto MissingFlags = (~flags & flagsRqd);
auto MissingFlags = (~flags & flagsRqd); if (
// Do we have the right precondition?
if( mStopIfWasPaused && (MissingFlags & AudioIONotBusyFlag ).any() ){ (flags & enabler.actualFlags) == enabler.actualFlags
TransportActions::StopIfPaused( project ); &&
// Hope this will now reflect stopped audio. // Can we get the condition we need?
flags = GetUpdateFlags(); (MissingFlags & enabler.possibleFlags) == MissingFlags
bAllowed = ((flags & flagsRqd) == flagsRqd); ) {
if( bAllowed ) // Then try the function
return true; enabler.tryEnable( project, flagsRqd );
flags = GetUpdateFlags();
}
++iter;
} }
return (flags & flagsRqd) == flagsRqd;
//We can only make the action allowed if we select audio when no selection.
// IF not set up to select all audio when none, THEN return with failure.
if( mWhatIfNoSelection != 1 )
return false;
// Some effects disallow autoselection.
if( (flagsRqd & NoAutoSelect).any() )
return false;
// IF selecting all audio won't do any good, THEN return with failure.
if( (flags & WaveTracksExistFlag).none() )
return false;
// This was 'DoSelectSomething()'.
// This made autoselect more confusing.
// When autoselect triggers, it might not select all audio in all tracks.
// So changed to DoSelectAllAudio.
SelectActions::DoSelectAllAudio(project);
flags = GetUpdateFlags();
bAllowed = ((flags & flagsRqd) == flagsRqd);
return bAllowed;
} }

View File

@@ -91,6 +91,7 @@ private:
AudacityProject &mProject; AudacityProject &mProject;
public:
// 0 is grey out, 1 is Autoselect, 2 is Give warnings. // 0 is grey out, 1 is Autoselect, 2 is Give warnings.
int mWhatIfNoSelection; int mWhatIfNoSelection;
bool mStopIfWasPaused; bool mStopIfWasPaused;

View File

@@ -94,4 +94,26 @@ extern const ReservedCommandFlag
NoAutoSelect // jkc NoAutoSelect // jkc
; ;
// To describe auto-selection, stop-if-paused, etc.:
// A structure describing a set of conditions, another set that might be
// made true given the first, and the function that may make them true.
// If a menu item requires the second set, while the first set is true,
// then the enabler will be invoked (unless the menu item is constructed with
// the useStrictFlags option, or the applicability test first returns false).
// The item's full set of required flags is passed to the function.
struct MenuItemEnabler {
using Test = std::function< bool( const AudacityProject& ) >;
using Action = std::function< void( AudacityProject&, CommandFlag ) >;
const CommandFlag &actualFlags;
const CommandFlag &possibleFlags;
Test applicable;
Action tryEnable;
};
// Typically this is statically constructed:
struct RegisteredMenuItemEnabler{
RegisteredMenuItemEnabler( const MenuItemEnabler &enabler );
};
#endif #endif