1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-06 15:37:44 +02:00

Reduce dependencies of Menus, CommandManager, ToolManager...

... so that they and a few others will be in a small s.c.c. that breaks off
the big one -- when the dependencies of Track and its subclasses on TrackPanel
are severed.
This commit is contained in:
Paul Licameli 2019-06-15 23:15:09 -04:00
commit d84ab5948d
52 changed files with 1115 additions and 713 deletions

View File

@ -32,6 +32,7 @@ click from the menu into the actaul function to be called.
#include "ShuttleGui.h"
#include "Project.h"
#include "commands/CommandManager.h"
#include "CommonCommandFlags.h"
#if defined(__WXMSW__)
#include <wx/init.h>

View File

@ -24,6 +24,7 @@
#include <wx/toolbar.h>
#include "AudioIOBase.h"
#include "CommonCommandFlags.h"
#include "LabelTrack.h"
#include "Menus.h"
#include "ModuleManager.h"

View File

@ -62,6 +62,8 @@ src/CellularPanel.cpp
src/CellularPanel.h
src/Clipboard.cpp
src/Clipboard.h
src/CommonCommandFlags.cpp
src/CommonCommandFlags.h
src/CrashReport.cpp
src/CrashReport.h
src/ClassicThemeAsCeeCode.h

View File

@ -1216,9 +1216,9 @@
5E135A3C229EDF2E0076E983 /* ProjectManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E135A3A229EDF2E0076E983 /* ProjectManager.cpp */; };
5E135A45229EE4DE0076E983 /* ProjectFileIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E135A43229EE4DE0076E983 /* ProjectFileIO.cpp */; };
5E135A48229EE5530076E983 /* ProjectWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E135A46229EE5530076E983 /* ProjectWindow.cpp */; };
5E135A5122A93DC60076E983 /* ProjectAudioManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E135A4F22A93DC60076E983 /* ProjectAudioManager.cpp */; };
5E135A4B22A5F7560076E983 /* AudioIOBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E135A4922A5F7560076E983 /* AudioIOBase.cpp */; };
5E135A4E22A62B7E0076E983 /* MeterPanelBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E135A4C22A62B7E0076E983 /* MeterPanelBase.cpp */; };
5E135A5122A93DC60076E983 /* ProjectAudioManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E135A4F22A93DC60076E983 /* ProjectAudioManager.cpp */; };
5E15123D1DB000C000702E29 /* UIHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E15123B1DB000C000702E29 /* UIHandle.cpp */; };
5E15125A1DB000DC00702E29 /* LabelTrackControls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E1512401DB000DC00702E29 /* LabelTrackControls.cpp */; };
5E15125B1DB000DC00702E29 /* LabelTrackUI.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E1512421DB000DC00702E29 /* LabelTrackUI.cpp */; };
@ -1230,6 +1230,7 @@
5E15126E1DB0010C00702E29 /* TrackControls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E1512681DB0010C00702E29 /* TrackControls.cpp */; };
5E15126F1DB0010C00702E29 /* TrackUI.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E15126A1DB0010C00702E29 /* TrackUI.cpp */; };
5E1512701DB0010C00702E29 /* TrackVRulerControls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E15126B1DB0010C00702E29 /* TrackVRulerControls.cpp */; };
5E15A9AF22B3F7710007CC43 /* CommonCommandFlags.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E15A9AD22B3F7710007CC43 /* CommonCommandFlags.cpp */; };
5E16FF4D1FF9CE0B0085E1B8 /* LanguageNames.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5E16FF4C1FF9CE0B0085E1B8 /* LanguageNames.txt */; };
5E17EF712298372D00B47301 /* EnvelopeEditor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E17EF6F2298372D00B47301 /* EnvelopeEditor.cpp */; };
5E18CFF02291C31000E75250 /* ProjectFileIORegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E18CFEE2291C31000E75250 /* ProjectFileIORegistry.cpp */; };
@ -3191,12 +3192,12 @@
5E135A44229EE4DE0076E983 /* ProjectFileIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProjectFileIO.h; sourceTree = "<group>"; };
5E135A46229EE5530076E983 /* ProjectWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProjectWindow.cpp; sourceTree = "<group>"; };
5E135A47229EE5530076E983 /* ProjectWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProjectWindow.h; sourceTree = "<group>"; };
5E135A4F22A93DC60076E983 /* ProjectAudioManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProjectAudioManager.cpp; sourceTree = "<group>"; };
5E135A5022A93DC60076E983 /* ProjectAudioManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProjectAudioManager.h; sourceTree = "<group>"; };
5E135A4922A5F7560076E983 /* AudioIOBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioIOBase.cpp; sourceTree = "<group>"; };
5E135A4A22A5F7560076E983 /* AudioIOBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioIOBase.h; sourceTree = "<group>"; };
5E135A4C22A62B7E0076E983 /* MeterPanelBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MeterPanelBase.cpp; sourceTree = "<group>"; };
5E135A4D22A62B7E0076E983 /* MeterPanelBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MeterPanelBase.h; sourceTree = "<group>"; };
5E135A4F22A93DC60076E983 /* ProjectAudioManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProjectAudioManager.cpp; sourceTree = "<group>"; };
5E135A5022A93DC60076E983 /* ProjectAudioManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProjectAudioManager.h; sourceTree = "<group>"; };
5E1512381DB000C000702E29 /* HitTestResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HitTestResult.h; sourceTree = "<group>"; };
5E1512391DB000C000702E29 /* RefreshCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefreshCode.h; sourceTree = "<group>"; };
5E15123A1DB000C000702E29 /* TrackPanelMouseEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackPanelMouseEvent.h; sourceTree = "<group>"; };
@ -3219,6 +3220,8 @@
5E15126A1DB0010C00702E29 /* TrackUI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackUI.cpp; sourceTree = "<group>"; };
5E15126B1DB0010C00702E29 /* TrackVRulerControls.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrackVRulerControls.cpp; sourceTree = "<group>"; };
5E15126C1DB0010C00702E29 /* TrackVRulerControls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackVRulerControls.h; sourceTree = "<group>"; };
5E15A9AD22B3F7710007CC43 /* CommonCommandFlags.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CommonCommandFlags.cpp; sourceTree = "<group>"; };
5E15A9AE22B3F7710007CC43 /* CommonCommandFlags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonCommandFlags.h; sourceTree = "<group>"; };
5E16FF4C1FF9CE0B0085E1B8 /* LanguageNames.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LanguageNames.txt; path = ../locale/LanguageNames.txt; sourceTree = "<group>"; };
5E17EF6F2298372D00B47301 /* EnvelopeEditor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EnvelopeEditor.cpp; sourceTree = "<group>"; };
5E17EF702298372D00B47301 /* EnvelopeEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EnvelopeEditor.h; sourceTree = "<group>"; };
@ -4347,6 +4350,7 @@
1790AFE809883BFD008A330A /* BlockFile.cpp */,
5E0A1CDB20E95FF7001AAF8D /* CellularPanel.cpp */,
5EFEAD9C22723E390077DFF6 /* Clipboard.cpp */,
5E15A9AD22B3F7710007CC43 /* CommonCommandFlags.cpp */,
5EFEADA122733DD30077DFF6 /* CrashReport.cpp */,
1790AFF409883BFD008A330A /* CrossFade.cpp */,
2849B4600A7444BE00ECF12D /* Dependencies.cpp */,
@ -4464,6 +4468,7 @@
5E0D233E21B468BF0057D7C3 /* ClientData.h */,
5E6E060321BD98E700130DE0 /* ClientDataHelpers.h */,
5EFEAD9D22723E390077DFF6 /* Clipboard.h */,
5E15A9AE22B3F7710007CC43 /* CommonCommandFlags.h */,
1790AFF009883BFD008A330A /* configtemplate.h */,
5EFEADA222733DD30077DFF6 /* CrashReport.h */,
1790AFF509883BFD008A330A /* CrossFade.h */,
@ -8405,6 +8410,7 @@
1790B18009883BFD008A330A /* BatchPrefs.cpp in Sources */,
5E135A39229EDEBA0076E983 /* ProjectAudioIO.cpp in Sources */,
1790B18109883BFD008A330A /* DirectoriesPrefs.cpp in Sources */,
5E15A9AF22B3F7710007CC43 /* CommonCommandFlags.cpp in Sources */,
1790B18309883BFD008A330A /* GUIPrefs.cpp in Sources */,
1790B18409883BFD008A330A /* KeyConfigPrefs.cpp in Sources */,
2806EF7A1B32532A00D1AB9A /* FileDialogPrivate.mm in Sources */,

View File

@ -749,6 +749,41 @@ bool MacroCommands::ApplyEffectCommand(
return res;
}
bool MacroCommands::HandleTextualCommand( CommandManager &commandManager,
const CommandID & Str,
const CommandContext & context, CommandFlag flags, bool alwaysEnabled)
{
switch ( commandManager.HandleTextualCommand(
Str, context, flags, alwaysEnabled) ) {
case CommandManager::CommandSuccess:
return true;
case CommandManager::CommandFailure:
return false;
case CommandManager::CommandNotFound:
default:
break;
}
// Not one of the singleton commands.
// We could/should try all the list-style commands.
// instead we only try the effects.
PluginManager & pm = PluginManager::Get();
EffectManager & em = EffectManager::Get();
const PluginDescriptor *plug = pm.GetFirstPlugin(PluginTypeEffect);
while (plug)
{
if (em.GetCommandIdentifier(plug->GetID()) == Str)
{
return PluginActions::DoEffect(
plug->GetID(), context,
PluginActions::kConfigured);
}
plug = pm.GetNextPlugin(PluginTypeEffect);
}
return false;
}
bool MacroCommands::ApplyCommand( const wxString &friendlyCommand,
const CommandID & command, const wxString & params,
CommandContext const * pContext)
@ -778,7 +813,8 @@ bool MacroCommands::ApplyCommand( const wxString &friendlyCommand,
AudacityProject *project = GetActiveProject();
auto &manager = CommandManager::Get( *project );
if( pContext ){
if( manager.HandleTextualCommand( command, *pContext, AlwaysEnabledFlag, AlwaysEnabledFlag ) )
if( HandleTextualCommand(
manager, command, *pContext, AlwaysEnabledFlag, true ) )
return true;
pContext->Status( wxString::Format(
_("Your batch command of %s was not recognized."), friendlyCommand ));
@ -787,7 +823,8 @@ bool MacroCommands::ApplyCommand( const wxString &friendlyCommand,
else
{
const CommandContext context( *GetActiveProject() );
if( manager.HandleTextualCommand( command, context, AlwaysEnabledFlag, AlwaysEnabledFlag ) )
if( HandleTextualCommand(
manager, command, context, AlwaysEnabledFlag, true ) )
return true;
}

View File

@ -15,10 +15,12 @@
#include <wx/defs.h>
#include "export/Export.h"
#include "commands/CommandFlag.h"
class wxArrayString;
class Effect;
class CommandContext;
class CommandManager;
class AudacityProject;
class wxArrayStringEx;
@ -57,6 +59,9 @@ class MacroCommands final {
public:
bool ApplyMacro( const MacroCommandsCatalog &catalog,
const wxString & filename = {});
static bool HandleTextualCommand( CommandManager &commandManager,
const CommandID & Str,
const CommandContext & context, CommandFlag flags, bool alwaysEnabled);
bool ApplyCommand( const wxString &friendlyCommand,
const CommandID & command, const wxString & params,
CommandContext const * pContext=NULL );

356
src/CommonCommandFlags.cpp Normal file
View File

@ -0,0 +1,356 @@
/**********************************************************************
Audacity: A Digital Audio Editor
CommonCommandFlags.cpp
Paul Licameli split from Menus.cpp
**********************************************************************/
#include "Audacity.h"
#include "CommonCommandFlags.h"
#include "Experimental.h"
#include <wx/frame.h>
#include "AudioIO.h"
#include "LabelTrack.h"
#include "Menus.h"
#include "NoteTrack.h"
#include "Project.h"
#include "ProjectAudioIO.h"
#include "ProjectFileIO.h"
#include "ProjectHistory.h"
#include "ProjectSettings.h"
#include "UndoManager.h"
#include "ViewInfo.h"
#include "WaveTrack.h"
#include "commands/CommandManagerWindowClasses.h"
#include "toolbars/ControlToolBar.h"
/*
This file registers functions implementing many of the tests for enabling of
menu items. Sequence of a few of them has minor significance, but for most
there is little reason to keep them in one file. Flags used only by one
other file might instead be defined only where used.
They are collected here because Menus.cpp is too low level to have the
dependencies implied by the include directives above -- it would make dependency
cycles.
*/
// Really means, some track is selected, that isn't a time track
bool TracksSelectedPred( const AudacityProject &project )
{
auto range = TrackList::Get( project ).Selected()
- []( const Track *pTrack ){
return track_cast<const TimeTrack*>( pTrack ); };
return !range.empty();
};
bool AudioIOBusyPred( const AudacityProject &project )
{
return AudioIOBase::Get()->IsAudioTokenActive(
ProjectAudioIO::Get( project ).GetAudioIOToken());
};
bool TimeSelectedPred( const AudacityProject &project )
{
// This is equivalent to check if there is a valid selection,
// so it's used for Zoom to Selection too
return !ViewInfo::Get( project ).selectedRegion.isPoint();
};
const CommandFlagOptions cutCopyOptions{
// In reporting the issue with cut or copy, we don't tell the user they could also select some text in a label.
[]( const wxString &Name ) {
// PRL: These strings have hard-coded mention of a certain shortcut key,
// thus assuming the default shortcuts. That is questionable.
wxString format;
#ifdef EXPERIMENTAL_DA
// i18n-hint: %s will be replaced by the name of an action, such as Normalize, Cut, Fade.
format = _("You must first select some audio for '%s' to act on.\n\nCtrl + A selects all audio.");
#else
#ifdef __WXMAC__
// i18n-hint: %s will be replaced by the name of an action, such as Normalize, Cut, Fade.
format = _("Select the audio for %s to use (for example, Cmd + A to Select All) then try again."
// No need to explain what a help button is for.
// "\n\nClick the Help button to learn more about selection methods."
);
#else
// i18n-hint: %s will be replaced by the name of an action, such as Normalize, Cut, Fade.
format = _("Select the audio for %s to use (for example, Ctrl + A to Select All) then try again."
// No need to explain what a help button is for.
// "\n\nClick the Help button to learn more about selection methods."
);
#endif
return wxString::Format( format, Name );
#endif
},
"Selecting_Audio_-_the_basics",
XO("No Audio Selected")
};
const ReservedCommandFlag
// The sequence of these definitions has a minor significance in determining
// which user error message has precedence if more than one might apply, so
// they should be kept in this sequence in one .cpp file if it is important
// to preserve that behavior. If they are dispersed to more than one file,
// then the precedence will be unspecified.
// The ordering of the flags that only disable the default message is not
// significant.
AudioIONotBusyFlag{
[](const AudacityProject &project ){
return !AudioIOBusyPred( project );
},
CommandFlagOptions{ []( const wxString& ) { return
// This reason will not be shown, because options that require it will be greyed out.
_("You can only do this when playing and recording are\nstopped. (Pausing is not sufficient.)");
} }
.QuickTest()
.Priority( 1 )
}, //lll
StereoRequiredFlag{
[](const AudacityProject &project){
// True iff at least one stereo track is selected, i.e., at least
// one right channel is selected.
// TODO: more-than-two-channels
auto range = TrackList::Get( project ).Selected<const WaveTrack>()
- &Track::IsLeader;
return !range.empty();
},
{ []( const wxString& ) { return
// This reason will not be shown, because the stereo-to-mono is greyed out if not allowed.
_("You must first select some stereo audio to perform this\naction. (You cannot use this with mono.)");
} }
}, //lda
TimeSelectedFlag{
TimeSelectedPred,
cutCopyOptions
},
WaveTracksSelectedFlag{
[](const AudacityProject &project){
return !TrackList::Get( project ).Selected<const WaveTrack>().empty();
},
{ []( const wxString& ) { return
_("You must first select some audio to perform this action.\n(Selecting other kinds of track won't work.)");
} }
},
TracksExistFlag{
[](const AudacityProject &project){
return !TrackList::Get( project ).Any().empty();
},
CommandFlagOptions{}.DisableDefaultMessage()
},
TracksSelectedFlag{
TracksSelectedPred,
{ []( const wxString &Name ){ return wxString::Format(
// i18n-hint: %s will be replaced by the name of an action, such as "Remove Tracks".
_("\"%s\" requires one or more tracks to be selected."),
Name
); } }
},
TrackPanelHasFocus{
[](const AudacityProject &project){
for (auto w = wxWindow::FindFocus(); w; w = w->GetParent()) {
if (dynamic_cast<const NonKeystrokeInterceptingWindow*>(w))
return true;
}
return false;
},
CommandFlagOptions{}.DisableDefaultMessage()
}; //lll
const ReservedCommandFlag
AudioIOBusyFlag{
AudioIOBusyPred,
CommandFlagOptions{}.QuickTest()
}, //lll
CaptureNotBusyFlag{
[](const AudacityProject &){
auto gAudioIO = AudioIO::Get();
return !(
gAudioIO->IsBusy() &&
gAudioIO->GetNumCaptureChannels() > 0
);
}
},
HasWaveDataFlag{
[](const AudacityProject &project){
auto range = TrackList::Get( project ).Any<const WaveTrack>()
+ [](const WaveTrack *pTrack){
return pTrack->GetEndTime() > pTrack->GetStartTime();
};
return !range.empty();
}
}; // jkc
const ReservedCommandFlag
LabelTracksExistFlag{
[](const AudacityProject &project){
return !TrackList::Get( project ).Any<const LabelTrack>().empty();
}
},
UnsavedChangesFlag{
[](const AudacityProject &project){
auto &undoManager = UndoManager::Get( project );
return
undoManager.UnsavedChanges()
||
!ProjectFileIO::Get( project ).IsProjectSaved()
;
}
},
HasLastEffectFlag{
[](const AudacityProject &project){
return !MenuManager::Get( project ).mLastEffect.empty();
}
},
UndoAvailableFlag{
[](const AudacityProject &project){
return ProjectHistory::Get( project ).UndoAvailable();
}
},
RedoAvailableFlag{
[](const AudacityProject &project){
return ProjectHistory::Get( project ).RedoAvailable();
}
},
ZoomInAvailableFlag{
[](const AudacityProject &project){
return
ViewInfo::Get( project ).ZoomInAvailable()
&&
!TrackList::Get( project ).Any().empty()
;
}
},
ZoomOutAvailableFlag{
[](const AudacityProject &project){
return
ViewInfo::Get( project ).ZoomOutAvailable()
&&
!TrackList::Get( project ).Any().empty()
;
}
},
LabelsSelectedFlag{
[](const AudacityProject &project){
// At least one label track selected, having at least one label
// completely within the time selection.
const auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
const auto &test = [&]( const LabelTrack *pTrack ){
const auto &labels = pTrack->GetLabels();
return std::any_of( labels.begin(), labels.end(),
[&](const LabelStruct &label){
return
label.getT0() >= selectedRegion.t0()
&&
label.getT1() <= selectedRegion.t1()
;
}
);
};
auto range = TrackList::Get( project ).Selected<const LabelTrack>()
+ test;
return !range.empty();
}
},
PlayRegionLockedFlag{
[](const AudacityProject &project){
return ViewInfo::Get(project).playRegion.Locked();
}
}, //msmeyer
PlayRegionNotLockedFlag{
[](const AudacityProject &project){
const auto &playRegion = ViewInfo::Get(project).playRegion;
return !playRegion.Locked() && !playRegion.Empty();
}
}, //msmeyer
WaveTracksExistFlag{
[](const AudacityProject &project){
return !TrackList::Get( project ).Any<const WaveTrack>().empty();
}
},
NoteTracksExistFlag{
[](const AudacityProject &project){
return !TrackList::Get( project ).Any<const NoteTrack>().empty();
}
}, //gsw
NoteTracksSelectedFlag{
[](const AudacityProject &project){
return !TrackList::Get( project ).Selected<const NoteTrack>().empty();
}
}, //gsw
IsNotSyncLockedFlag{
[](const AudacityProject &project){
return !ProjectSettings::Get( project ).IsSyncLocked();
}
}, //awd
IsSyncLockedFlag{
[](const AudacityProject &project){
return ProjectSettings::Get( project ).IsSyncLocked();
}
}, //awd
NotMinimizedFlag{
[](const AudacityProject &project){
const wxWindow *focus = FindProjectFrame( &project );
if (focus) {
while (focus && focus->GetParent())
focus = focus->GetParent();
}
return (focus &&
!static_cast<const wxTopLevelWindow*>(focus)->IsIconized()
);
},
CommandFlagOptions{}.QuickTest()
}, // prl
PausedFlag{
[](const AudacityProject&){
return AudioIOBase::Get()->IsPaused();
},
CommandFlagOptions{}.QuickTest()
},
PlayableTracksExistFlag{
[](const AudacityProject &project){
auto &tracks = TrackList::Get( project );
return
#ifdef EXPERIMENTAL_MIDI_OUT
!tracks.Any<const NoteTrack>().empty()
||
#endif
!tracks.Any<const WaveTrack>().empty()
;
}
},
AudioTracksSelectedFlag{
[](const AudacityProject &project){
auto &tracks = TrackList::Get( project );
return
!tracks.Selected<const NoteTrack>().empty()
// even if not EXPERIMENTAL_MIDI_OUT
||
tracks.Selected<const WaveTrack>().empty()
;
}
},
NoAutoSelect{
[](const AudacityProject &){ return true; }
} // jkc
;
RegisteredMenuItemEnabler stopIfPaused{{
PausedFlag,
AudioIONotBusyFlag,
[]( const AudacityProject &project ){
return MenuManager::Get( project ).mStopIfWasPaused; },
[]( AudacityProject &project, CommandFlag ){
if ( MenuManager::Get( project ).mStopIfWasPaused )
TransportActions::StopIfPaused( project );
}
}};

58
src/CommonCommandFlags.h Normal file
View File

@ -0,0 +1,58 @@
/**********************************************************************
Audacity: A Digital Audio Editor
CommonCommandFlags.cpp
Paul Licameli split from Menus.cpp
**********************************************************************/
#ifndef __AUDACITY_COMMON_COMMAND_FLAGS__
#define __AUDACITY_COMMON_COMMAND_FLAGS__
#include "commands/CommandFlag.h"
bool TracksSelectedPred( const AudacityProject &project );
bool AudioIOBusyPred( const AudacityProject &project );
bool TimeSelectedPred( const AudacityProject &project );
extern const CommandFlagOptions cutCopyOptions;
extern const ReservedCommandFlag
AudioIONotBusyFlag,
StereoRequiredFlag, //lda
TimeSelectedFlag, // This is equivalent to check if there is a valid selection, so it's used for Zoom to Selection too
WaveTracksSelectedFlag,
TracksExistFlag,
TracksSelectedFlag,
TrackPanelHasFocus; //lll
extern const ReservedCommandFlag
AudioIOBusyFlag, // lll
CaptureNotBusyFlag,
HasWaveDataFlag; // jkc
extern const ReservedCommandFlag
LabelTracksExistFlag,
UnsavedChangesFlag,
HasLastEffectFlag,
UndoAvailableFlag,
RedoAvailableFlag,
ZoomInAvailableFlag,
ZoomOutAvailableFlag,
LabelsSelectedFlag,
PlayRegionLockedFlag, //msmeyer
PlayRegionNotLockedFlag, //msmeyer
WaveTracksExistFlag,
NoteTracksExistFlag, //gsw
NoteTracksSelectedFlag, //gsw
IsNotSyncLockedFlag, //awd
IsSyncLockedFlag, //awd
NotMinimizedFlag, // prl
PausedFlag, // jkc
PlayableTracksExistFlag,
AudioTracksSelectedFlag,
NoAutoSelect // jkc
;
#endif

View File

@ -1012,7 +1012,7 @@ void LabelTrack::calculateFontHeight(wxDC & dc) const
mFontHeight += CursorExtraHeight - (charLeading+charDescent);
}
bool LabelTrack::IsTextSelected()
bool LabelTrack::IsTextSelected() const
{
if (mSelIndex == -1)
return false;

View File

@ -117,7 +117,7 @@ class AUDACITY_DLL_API LabelTrack final : public Track
bool IsGoodLabelFirstKey(const wxKeyEvent & evt);
bool IsGoodLabelEditKey(const wxKeyEvent & evt);
bool IsTextSelected();
bool IsTextSelected() const;
void CreateCustomGlyphs();
LabelTrack(const std::shared_ptr<DirManager> &projDirManager);
@ -228,6 +228,7 @@ class AUDACITY_DLL_API LabelTrack final : public Track
int GetNumLabels() const;
const LabelStruct *GetLabel(int index) const;
const LabelArray &GetLabels() const { return mLabels; }
//This returns the index of the label we just added.
int AddLabel(const SelectedRegion &region, const wxString &title = {},

View File

@ -133,6 +133,8 @@ audacity_SOURCES = \
ClientDataHelpers.h \
Clipboard.cpp \
Clipboard.h \
CommonCommandFlags.cpp \
CommonCommandFlags.h \
CrashReport.cpp \
CrashReport.h \
Dependencies.cpp \

View File

@ -297,41 +297,42 @@ am__audacity_SOURCES_DIST = BlockFile.cpp BlockFile.h DirManager.cpp \
BatchCommands.h BatchProcessDialog.cpp BatchProcessDialog.h \
Benchmark.cpp Benchmark.h CellularPanel.cpp CellularPanel.h \
ClientData.h ClientDataHelpers.h Clipboard.cpp Clipboard.h \
CrashReport.cpp CrashReport.h Dependencies.cpp Dependencies.h \
DeviceChange.cpp DeviceChange.h DeviceManager.cpp \
DeviceManager.h Diags.cpp Diags.h Envelope.cpp Envelope.h \
EnvelopeEditor.cpp EnvelopeEditor.h Experimental.h FFmpeg.cpp \
FFmpeg.h FFT.cpp FFT.h FileException.cpp FileException.h \
FileIO.cpp FileIO.h FileNames.cpp FileNames.h float_cast.h \
FreqWindow.cpp FreqWindow.h HelpText.cpp HelpText.h \
HistoryWindow.cpp HistoryWindow.h HitTestResult.h \
ImageManipulation.cpp ImageManipulation.h \
InconsistencyException.cpp InconsistencyException.h \
InterpolateAudio.cpp InterpolateAudio.h KeyboardCapture.cpp \
KeyboardCapture.h LabelDialog.cpp LabelDialog.h LabelTrack.cpp \
LabelTrack.h LangChoice.cpp LangChoice.h Languages.cpp \
Languages.h Legacy.cpp Legacy.h Lyrics.cpp Lyrics.h \
LyricsWindow.cpp LyricsWindow.h MacroMagic.h Matrix.cpp \
Matrix.h MemoryX.h Menus.cpp Menus.h \
MissingAliasFileDialog.cpp MissingAliasFileDialog.h Mix.cpp \
Mix.h MixerBoard.cpp MixerBoard.h ModuleManager.cpp \
ModuleManager.h NumberScale.h PitchName.cpp PitchName.h \
PlatformCompatibility.cpp PlatformCompatibility.h \
PluginManager.cpp PluginManager.h Printing.cpp Printing.h \
Profiler.cpp Profiler.h Project.cpp Project.h \
ProjectAudioIO.cpp ProjectAudioIO.h ProjectAudioManager.cpp \
ProjectAudioManager.h ProjectFileIO.cpp ProjectFileIO.h \
ProjectFileIORegistry.cpp ProjectFileIORegistry.h \
ProjectFileManager.cpp ProjectFileManager.h ProjectFSCK.cpp \
ProjectFSCK.h ProjectHistory.cpp ProjectHistory.h \
ProjectManager.cpp ProjectManager.h \
ProjectSelectionManager.cpp ProjectSelectionManager.h \
ProjectSettings.cpp ProjectSettings.h ProjectWindow.cpp \
ProjectWindow.h RealFFTf.cpp RealFFTf.h RealFFTf48x.cpp \
RealFFTf48x.h RefreshCode.h Resample.cpp Resample.h \
RevisionIdent.h RingBuffer.cpp RingBuffer.h Screenshot.cpp \
Screenshot.h SelectedRegion.cpp SelectedRegion.h \
SelectionState.cpp SelectionState.h Shuttle.cpp Shuttle.h \
CommonCommandFlags.cpp CommonCommandFlags.h CrashReport.cpp \
CrashReport.h Dependencies.cpp Dependencies.h DeviceChange.cpp \
DeviceChange.h DeviceManager.cpp DeviceManager.h Diags.cpp \
Diags.h Envelope.cpp Envelope.h EnvelopeEditor.cpp \
EnvelopeEditor.h Experimental.h FFmpeg.cpp FFmpeg.h FFT.cpp \
FFT.h FileException.cpp FileException.h FileIO.cpp FileIO.h \
FileNames.cpp FileNames.h float_cast.h FreqWindow.cpp \
FreqWindow.h HelpText.cpp HelpText.h HistoryWindow.cpp \
HistoryWindow.h HitTestResult.h ImageManipulation.cpp \
ImageManipulation.h InconsistencyException.cpp \
InconsistencyException.h InterpolateAudio.cpp \
InterpolateAudio.h KeyboardCapture.cpp KeyboardCapture.h \
LabelDialog.cpp LabelDialog.h LabelTrack.cpp LabelTrack.h \
LangChoice.cpp LangChoice.h Languages.cpp Languages.h \
Legacy.cpp Legacy.h Lyrics.cpp Lyrics.h LyricsWindow.cpp \
LyricsWindow.h MacroMagic.h Matrix.cpp Matrix.h MemoryX.h \
Menus.cpp Menus.h MissingAliasFileDialog.cpp \
MissingAliasFileDialog.h Mix.cpp Mix.h MixerBoard.cpp \
MixerBoard.h ModuleManager.cpp ModuleManager.h NumberScale.h \
PitchName.cpp PitchName.h PlatformCompatibility.cpp \
PlatformCompatibility.h PluginManager.cpp PluginManager.h \
Printing.cpp Printing.h Profiler.cpp Profiler.h Project.cpp \
Project.h ProjectAudioIO.cpp ProjectAudioIO.h \
ProjectAudioManager.cpp ProjectAudioManager.h \
ProjectFileIO.cpp ProjectFileIO.h ProjectFileIORegistry.cpp \
ProjectFileIORegistry.h ProjectFileManager.cpp \
ProjectFileManager.h ProjectFSCK.cpp ProjectFSCK.h \
ProjectHistory.cpp ProjectHistory.h ProjectManager.cpp \
ProjectManager.h ProjectSelectionManager.cpp \
ProjectSelectionManager.h ProjectSettings.cpp \
ProjectSettings.h ProjectWindow.cpp ProjectWindow.h \
RealFFTf.cpp RealFFTf.h RealFFTf48x.cpp RealFFTf48x.h \
RefreshCode.h Resample.cpp Resample.h RevisionIdent.h \
RingBuffer.cpp RingBuffer.h Screenshot.cpp Screenshot.h \
SelectedRegion.cpp SelectedRegion.h SelectionState.cpp \
SelectionState.h Shuttle.cpp Shuttle.h \
ShuttleGetDefinition.cpp ShuttleGetDefinition.h ShuttleGui.cpp \
ShuttleGui.h ShuttlePrefs.cpp ShuttlePrefs.h Snap.cpp Snap.h \
SoundActivatedRecord.cpp SoundActivatedRecord.h Spectrum.cpp \
@ -644,8 +645,9 @@ am_audacity_OBJECTS = $(am__objects_1) audacity-AboutDialog.$(OBJEXT) \
audacity-BatchCommands.$(OBJEXT) \
audacity-BatchProcessDialog.$(OBJEXT) \
audacity-Benchmark.$(OBJEXT) audacity-CellularPanel.$(OBJEXT) \
audacity-Clipboard.$(OBJEXT) audacity-CrashReport.$(OBJEXT) \
audacity-Dependencies.$(OBJEXT) \
audacity-Clipboard.$(OBJEXT) \
audacity-CommonCommandFlags.$(OBJEXT) \
audacity-CrashReport.$(OBJEXT) audacity-Dependencies.$(OBJEXT) \
audacity-DeviceChange.$(OBJEXT) \
audacity-DeviceManager.$(OBJEXT) audacity-Diags.$(OBJEXT) \
audacity-Envelope.$(OBJEXT) audacity-EnvelopeEditor.$(OBJEXT) \
@ -1376,41 +1378,42 @@ audacity_SOURCES = $(libaudacity_la_SOURCES) AboutDialog.cpp \
BatchCommands.h BatchProcessDialog.cpp BatchProcessDialog.h \
Benchmark.cpp Benchmark.h CellularPanel.cpp CellularPanel.h \
ClientData.h ClientDataHelpers.h Clipboard.cpp Clipboard.h \
CrashReport.cpp CrashReport.h Dependencies.cpp Dependencies.h \
DeviceChange.cpp DeviceChange.h DeviceManager.cpp \
DeviceManager.h Diags.cpp Diags.h Envelope.cpp Envelope.h \
EnvelopeEditor.cpp EnvelopeEditor.h Experimental.h FFmpeg.cpp \
FFmpeg.h FFT.cpp FFT.h FileException.cpp FileException.h \
FileIO.cpp FileIO.h FileNames.cpp FileNames.h float_cast.h \
FreqWindow.cpp FreqWindow.h HelpText.cpp HelpText.h \
HistoryWindow.cpp HistoryWindow.h HitTestResult.h \
ImageManipulation.cpp ImageManipulation.h \
InconsistencyException.cpp InconsistencyException.h \
InterpolateAudio.cpp InterpolateAudio.h KeyboardCapture.cpp \
KeyboardCapture.h LabelDialog.cpp LabelDialog.h LabelTrack.cpp \
LabelTrack.h LangChoice.cpp LangChoice.h Languages.cpp \
Languages.h Legacy.cpp Legacy.h Lyrics.cpp Lyrics.h \
LyricsWindow.cpp LyricsWindow.h MacroMagic.h Matrix.cpp \
Matrix.h MemoryX.h Menus.cpp Menus.h \
MissingAliasFileDialog.cpp MissingAliasFileDialog.h Mix.cpp \
Mix.h MixerBoard.cpp MixerBoard.h ModuleManager.cpp \
ModuleManager.h NumberScale.h PitchName.cpp PitchName.h \
PlatformCompatibility.cpp PlatformCompatibility.h \
PluginManager.cpp PluginManager.h Printing.cpp Printing.h \
Profiler.cpp Profiler.h Project.cpp Project.h \
ProjectAudioIO.cpp ProjectAudioIO.h ProjectAudioManager.cpp \
ProjectAudioManager.h ProjectFileIO.cpp ProjectFileIO.h \
ProjectFileIORegistry.cpp ProjectFileIORegistry.h \
ProjectFileManager.cpp ProjectFileManager.h ProjectFSCK.cpp \
ProjectFSCK.h ProjectHistory.cpp ProjectHistory.h \
ProjectManager.cpp ProjectManager.h \
ProjectSelectionManager.cpp ProjectSelectionManager.h \
ProjectSettings.cpp ProjectSettings.h ProjectWindow.cpp \
ProjectWindow.h RealFFTf.cpp RealFFTf.h RealFFTf48x.cpp \
RealFFTf48x.h RefreshCode.h Resample.cpp Resample.h \
RevisionIdent.h RingBuffer.cpp RingBuffer.h Screenshot.cpp \
Screenshot.h SelectedRegion.cpp SelectedRegion.h \
SelectionState.cpp SelectionState.h Shuttle.cpp Shuttle.h \
CommonCommandFlags.cpp CommonCommandFlags.h CrashReport.cpp \
CrashReport.h Dependencies.cpp Dependencies.h DeviceChange.cpp \
DeviceChange.h DeviceManager.cpp DeviceManager.h Diags.cpp \
Diags.h Envelope.cpp Envelope.h EnvelopeEditor.cpp \
EnvelopeEditor.h Experimental.h FFmpeg.cpp FFmpeg.h FFT.cpp \
FFT.h FileException.cpp FileException.h FileIO.cpp FileIO.h \
FileNames.cpp FileNames.h float_cast.h FreqWindow.cpp \
FreqWindow.h HelpText.cpp HelpText.h HistoryWindow.cpp \
HistoryWindow.h HitTestResult.h ImageManipulation.cpp \
ImageManipulation.h InconsistencyException.cpp \
InconsistencyException.h InterpolateAudio.cpp \
InterpolateAudio.h KeyboardCapture.cpp KeyboardCapture.h \
LabelDialog.cpp LabelDialog.h LabelTrack.cpp LabelTrack.h \
LangChoice.cpp LangChoice.h Languages.cpp Languages.h \
Legacy.cpp Legacy.h Lyrics.cpp Lyrics.h LyricsWindow.cpp \
LyricsWindow.h MacroMagic.h Matrix.cpp Matrix.h MemoryX.h \
Menus.cpp Menus.h MissingAliasFileDialog.cpp \
MissingAliasFileDialog.h Mix.cpp Mix.h MixerBoard.cpp \
MixerBoard.h ModuleManager.cpp ModuleManager.h NumberScale.h \
PitchName.cpp PitchName.h PlatformCompatibility.cpp \
PlatformCompatibility.h PluginManager.cpp PluginManager.h \
Printing.cpp Printing.h Profiler.cpp Profiler.h Project.cpp \
Project.h ProjectAudioIO.cpp ProjectAudioIO.h \
ProjectAudioManager.cpp ProjectAudioManager.h \
ProjectFileIO.cpp ProjectFileIO.h ProjectFileIORegistry.cpp \
ProjectFileIORegistry.h ProjectFileManager.cpp \
ProjectFileManager.h ProjectFSCK.cpp ProjectFSCK.h \
ProjectHistory.cpp ProjectHistory.h ProjectManager.cpp \
ProjectManager.h ProjectSelectionManager.cpp \
ProjectSelectionManager.h ProjectSettings.cpp \
ProjectSettings.h ProjectWindow.cpp ProjectWindow.h \
RealFFTf.cpp RealFFTf.h RealFFTf48x.cpp RealFFTf48x.h \
RefreshCode.h Resample.cpp Resample.h RevisionIdent.h \
RingBuffer.cpp RingBuffer.h Screenshot.cpp Screenshot.h \
SelectedRegion.cpp SelectedRegion.h SelectionState.cpp \
SelectionState.h Shuttle.cpp Shuttle.h \
ShuttleGetDefinition.cpp ShuttleGetDefinition.h ShuttleGui.cpp \
ShuttleGui.h ShuttlePrefs.cpp ShuttlePrefs.h Snap.cpp Snap.h \
SoundActivatedRecord.cpp SoundActivatedRecord.h Spectrum.cpp \
@ -2539,6 +2542,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-BlockFile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-CellularPanel.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-Clipboard.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-CommonCommandFlags.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-CrashReport.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-Dependencies.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-DeviceChange.Po@am__quote@
@ -3506,6 +3510,20 @@ audacity-Clipboard.obj: Clipboard.cpp
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o audacity-Clipboard.obj `if test -f 'Clipboard.cpp'; then $(CYGPATH_W) 'Clipboard.cpp'; else $(CYGPATH_W) '$(srcdir)/Clipboard.cpp'; fi`
audacity-CommonCommandFlags.o: CommonCommandFlags.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-CommonCommandFlags.o -MD -MP -MF $(DEPDIR)/audacity-CommonCommandFlags.Tpo -c -o audacity-CommonCommandFlags.o `test -f 'CommonCommandFlags.cpp' || echo '$(srcdir)/'`CommonCommandFlags.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-CommonCommandFlags.Tpo $(DEPDIR)/audacity-CommonCommandFlags.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='CommonCommandFlags.cpp' object='audacity-CommonCommandFlags.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o audacity-CommonCommandFlags.o `test -f 'CommonCommandFlags.cpp' || echo '$(srcdir)/'`CommonCommandFlags.cpp
audacity-CommonCommandFlags.obj: CommonCommandFlags.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-CommonCommandFlags.obj -MD -MP -MF $(DEPDIR)/audacity-CommonCommandFlags.Tpo -c -o audacity-CommonCommandFlags.obj `if test -f 'CommonCommandFlags.cpp'; then $(CYGPATH_W) 'CommonCommandFlags.cpp'; else $(CYGPATH_W) '$(srcdir)/CommonCommandFlags.cpp'; fi`
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-CommonCommandFlags.Tpo $(DEPDIR)/audacity-CommonCommandFlags.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='CommonCommandFlags.cpp' object='audacity-CommonCommandFlags.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o audacity-CommonCommandFlags.obj `if test -f 'CommonCommandFlags.cpp'; then $(CYGPATH_W) 'CommonCommandFlags.cpp'; else $(CYGPATH_W) '$(srcdir)/CommonCommandFlags.cpp'; fi`
audacity-CrashReport.o: CrashReport.cpp
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-CrashReport.o -MD -MP -MF $(DEPDIR)/audacity-CrashReport.Tpo -c -o audacity-CrashReport.o `test -f 'CrashReport.cpp' || echo '$(srcdir)/'`CrashReport.cpp
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-CrashReport.Tpo $(DEPDIR)/audacity-CrashReport.Po

View File

@ -30,30 +30,17 @@
#include "Experimental.h"
#include "AdornedRulerPanel.h"
#include "AudioIO.h"
#include "Clipboard.h"
#include "LabelTrack.h"
#include <wx/frame.h>
#include "ModuleManager.h"
#ifdef USE_MIDI
#include "NoteTrack.h"
#endif // USE_MIDI
#include "Prefs.h"
#include "Project.h"
#include "ProjectAudioIO.h"
#include "ProjectFileIO.h"
#include "ProjectHistory.h"
#include "ProjectSettings.h"
#include "ProjectWindow.h"
#include "UndoManager.h"
#include "ViewInfo.h"
#include "commands/CommandManager.h"
#include "commands/CommandManagerWindowClasses.h"
#include "effects/EffectManager.h"
#include "prefs/TracksPrefs.h"
#include "toolbars/ControlToolBar.h"
#include "toolbars/ToolManager.h"
#include "widgets/FileHistory.h"
#include "widgets/ErrorDialog.h"
#include <wx/menu.h>
#include <wx/windowptr.h>
@ -364,6 +351,13 @@ void MenuManager::ModifyUndoMenuItems(AudacityProject &project)
}
}
// Get hackcess to a protected method
class wxFrameEx : public wxFrame
{
public:
using wxFrame::DetachMenuBar;
};
void MenuCreator::RebuildMenuBar(AudacityProject &project)
{
// On OSX, we can't rebuild the menus while a modal dialog is being shown
@ -380,7 +374,7 @@ void MenuCreator::RebuildMenuBar(AudacityProject &project)
// Delete the menus, since we will soon recreate them.
// Rather oddly, the menus don't vanish as a result of doing this.
{
auto &window = ProjectWindow::Get( project );
auto &window = static_cast<wxFrameEx&>( GetProjectFrame( project ) );
wxWindowPtr<wxMenuBar> menuBar{ window.GetMenuBar() };
window.DetachMenuBar();
// menuBar gets deleted here
@ -400,205 +394,66 @@ void MenuManager::OnUndoRedo( wxCommandEvent &evt )
UpdateMenus();
}
CommandFlag MenuManager::GetFocusedFrame(AudacityProject &project)
{
wxWindow *w = wxWindow::FindFocus();
while (w) {
if (w == ToolManager::Get( project ).GetTopDock()) {
return TopDockHasFocus;
}
if (w == &AdornedRulerPanel::Get( project ))
return RulerHasFocus;
if (dynamic_cast<NonKeystrokeInterceptingWindow*>(w)) {
return TrackPanelHasFocus;
}
if (w == ToolManager::Get( project ).GetBotDock()) {
return BotDockHasFocus;
}
w = w->GetParent();
namespace{
using Predicates = std::vector< ReservedCommandFlag::Predicate >;
Predicates &RegisteredPredicates()
{
static Predicates thePredicates;
return thePredicates;
}
std::vector< CommandFlagOptions > &Options()
{
static std::vector< CommandFlagOptions > options;
return options;
}
return AlwaysEnabledFlag;
}
ReservedCommandFlag::ReservedCommandFlag(
const Predicate &predicate, const CommandFlagOptions &options )
{
static size_t sNextReservedFlag = 0;
// This will throw std::out_of_range if the constant NCommandFlags is too
// small
set( sNextReservedFlag++ );
RegisteredPredicates().emplace_back( predicate );
Options().emplace_back( options );
}
CommandFlag MenuManager::GetUpdateFlags( bool checkActive )
{
auto &project = mProject;
// This method determines all of the flags that determine whether
// certain menu items and commands should be enabled or disabled,
// and returns them in a bitfield. Note that if none of the flags
// have changed, it's not necessary to even check for updates.
auto flags = AlwaysEnabledFlag;
// static variable, used to remember flags for next time.
static auto lastFlags = flags;
static CommandFlag lastFlags;
// if (auto focus = wxWindow::FindFocus()) {
auto &window = GetProjectFrame( project );
if (wxWindow * focus = &window) {
while (focus && focus->GetParent())
focus = focus->GetParent();
if (focus && !static_cast<wxTopLevelWindow*>(focus)->IsIconized())
flags |= NotMinimizedFlag;
CommandFlag flags, quickFlags;
const auto &options = Options();
size_t ii = 0;
for ( const auto &predicate : RegisteredPredicates() ) {
if ( options[ii].quickTest ) {
quickFlags[ii] = true;
if( predicate( mProject ) )
flags[ii] = true;
}
++ii;
}
// These flags are cheap to calculate.
auto gAudioIO = AudioIO::Get();
if (!gAudioIO->IsAudioTokenActive(ProjectAudioIO::Get( project )
.GetAudioIOToken()))
flags |= AudioIONotBusyFlag;
else
flags |= AudioIOBusyFlag;
if( gAudioIO->IsPaused() )
flags |= PausedFlag;
else
flags |= NotPausedFlag;
// quick 'short-circuit' return.
if ( checkActive && !window.IsActive() ){
const auto checkedFlags =
NotMinimizedFlag | AudioIONotBusyFlag | AudioIOBusyFlag |
PausedFlag | NotPausedFlag;
// short cirucit return should preserve flags that have not been calculated.
flags = (lastFlags & ~checkedFlags) | flags;
lastFlags = flags;
return flags;
}
auto &viewInfo = ViewInfo::Get( project );
const auto &selectedRegion = viewInfo.selectedRegion;
if (!selectedRegion.isPoint())
flags |= TimeSelectedFlag;
auto &tracks = TrackList::Get( project );
auto trackRange = tracks.Any();
if ( trackRange )
flags |= TracksExistFlag;
trackRange.Visit(
[&](LabelTrack *lt) {
flags |= LabelTracksExistFlag;
if (lt->GetSelected()) {
flags |= TracksSelectedFlag;
for (int i = 0; i < lt->GetNumLabels(); i++) {
const LabelStruct *ls = lt->GetLabel(i);
if (ls->getT0() >= selectedRegion.t0() &&
ls->getT1() <= selectedRegion.t1()) {
flags |= LabelsSelectedFlag;
break;
}
}
}
if (lt->IsTextSelected()) {
flags |= CutCopyAvailableFlag;
}
},
[&](WaveTrack *t) {
flags |= WaveTracksExistFlag;
flags |= PlayableTracksExistFlag;
if (t->GetSelected()) {
flags |= TracksSelectedFlag;
// TODO: more-than-two-channels
if (TrackList::Channels(t).size() > 1) {
flags |= StereoRequiredFlag;
}
flags |= WaveTracksSelectedFlag;
flags |= AudioTracksSelectedFlag;
}
if( t->GetEndTime() > t->GetStartTime() )
flags |= HasWaveDataFlag;
}
#if defined(USE_MIDI)
,
[&](NoteTrack *nt) {
flags |= NoteTracksExistFlag;
#ifdef EXPERIMENTAL_MIDI_OUT
flags |= PlayableTracksExistFlag;
#endif
if (nt->GetSelected()) {
flags |= TracksSelectedFlag;
flags |= NoteTracksSelectedFlag;
flags |= AudioTracksSelectedFlag; // even if not EXPERIMENTAL_MIDI_OUT
}
}
#endif
);
if( Clipboard::Get().Duration() > 0 )
flags |= ClipboardFlag;
auto &undoManager = UndoManager::Get( project );
if (undoManager.UnsavedChanges() ||
!ProjectFileIO::Get( project ).IsProjectSaved())
flags |= UnsavedChangesFlag;
if (!mLastEffect.empty())
flags |= HasLastEffectFlag;
auto &history = ProjectHistory::Get( project );
if (history.UndoAvailable())
flags |= UndoAvailableFlag;
if (history.RedoAvailable())
flags |= RedoAvailableFlag;
if (ViewInfo::Get( project ).ZoomInAvailable() && (flags & TracksExistFlag))
flags |= ZoomInAvailableFlag;
if (ViewInfo::Get( project ).ZoomOutAvailable() && (flags & TracksExistFlag))
flags |= ZoomOutAvailableFlag;
// TextClipFlag is currently unused (Jan 2017, 2.1.3 alpha)
// and LabelTrack::IsTextClipSupported() is quite slow on Linux,
// so disable for now (See bug 1575).
// if ((flags & LabelTracksExistFlag) && LabelTrack::IsTextClipSupported())
// flags |= TextClipFlag;
flags |= GetFocusedFrame(project);
const auto &playRegion = viewInfo.playRegion;
if (playRegion.Locked())
flags |= PlayRegionLockedFlag;
else if (!playRegion.Empty())
flags |= PlayRegionNotLockedFlag;
if (flags & AudioIONotBusyFlag) {
if (flags & TimeSelectedFlag) {
if (flags & TracksSelectedFlag) {
flags |= CutCopyAvailableFlag;
}
if ( checkActive && !GetProjectFrame( mProject ).IsActive() )
// quick 'short-circuit' return.
flags = (lastFlags & ~quickFlags) | flags;
else {
ii = 0;
for ( const auto &predicate : RegisteredPredicates() ) {
if ( !options[ii].quickTest && predicate( mProject ) )
flags[ii] = true;
++ii;
}
}
if (FileHistory::Global().GetCount() > 0)
flags |= HaveRecentFiles;
const auto &settings = ProjectSettings::Get( project );
if (settings.IsSyncLocked())
flags |= IsSyncLockedFlag;
else
flags |= IsNotSyncLockedFlag;
if (!EffectManager::Get().RealtimeIsActive())
flags |= IsRealtimeNotActiveFlag;
if ( !( gAudioIO->IsBusy() && gAudioIO->GetNumCaptureChannels() > 0 ) )
flags |= CaptureNotBusyFlag;
auto &bar = ControlToolBar::Get( project );
if (bar.ControlToolBar::CanStopAudioStream())
flags |= CanStopAudioStreamFlag;
lastFlags = flags;
return flags;
}
@ -685,6 +540,22 @@ void MenuManager::ModifyToolbarMenus(AudacityProject &project)
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 );
}
// checkActive is a temporary hack that should be removed as soon as we
// get multiple effect preview working
void MenuManager::UpdateMenus( bool checkActive )
@ -698,6 +569,12 @@ void MenuManager::UpdateMenus( bool checkActive )
return;
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;
// We can enable some extra items if we have select-all-on-none.
@ -705,68 +582,24 @@ void MenuManager::UpdateMenus( bool checkActive )
//ANSWER: Because flags2 is used in the menu enable/disable.
//The effect still needs flags to determine whether it will need
//to actually do the 'select all' to make the command valid.
if (mWhatIfNoSelection != 0)
{
if ((flags & TracksExistFlag))
{
flags2 |= TracksSelectedFlag;
if ((flags & WaveTracksExistFlag))
{
flags2 |= TimeSelectedFlag
| WaveTracksSelectedFlag
| CutCopyAvailableFlag;
}
}
}
if( mStopIfWasPaused )
{
if( flags & PausedFlag ){
flags2 |= AudioIONotBusyFlag;
}
for ( const auto &enabler : Enablers() ) {
if (
enabler.applicable( project ) &&
(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 );
commandManager.EnableUsingFlags(flags2 , NoFlagsSpecified);
// With select-all-on-none, some items that we don't want enabled may have
// been enabled, since we changed the flags. Here we manually disable them.
// 0 is grey out, 1 is Autoselect, 2 is Give warnings.
if (mWhatIfNoSelection != 0)
{
if (!(flags & TimeSelectedFlag) | !(flags & TracksSelectedFlag))
{
commandManager.Enable(wxT("SplitCut"), false);
commandManager.Enable(wxT("SplitDelete"), false);
}
if (!(flags & WaveTracksSelectedFlag))
{
commandManager.Enable(wxT("Split"), false);
}
if (!(flags & TimeSelectedFlag) | !(flags & WaveTracksSelectedFlag))
{
commandManager.Enable(wxT("ExportSel"), false);
commandManager.Enable(wxT("SplitNew"), false);
}
if (!(flags & TimeSelectedFlag) | !(flags & AudioTracksSelectedFlag))
{
commandManager.Enable(wxT("Trim"), false);
}
}
#if 0
if (flags & CutCopyAvailableFlag) {
GetCommandManager()->Enable(wxT("Copy"), true);
GetCommandManager()->Enable(wxT("Cut"), true);
}
#endif
commandManager.EnableUsingFlags(
flags2, // the "lax" flags
(mWhatIfNoSelection == 0 ? flags2 : flags) // the "strict" flags
);
MenuManager::ModifyToolbarMenus(project);
}
@ -794,74 +627,123 @@ void MenuCreator::RebuildAllMenuBars()
}
bool MenuManager::ReportIfActionNotAllowed(
const wxString & Name, CommandFlag & flags, CommandFlag flagsRqd, CommandFlag mask )
const wxString & Name, CommandFlag & flags, CommandFlag flagsRqd )
{
auto &project = mProject;
bool bAllowed = TryToMakeActionAllowed( flags, flagsRqd, mask );
bool bAllowed = TryToMakeActionAllowed( flags, flagsRqd );
if( bAllowed )
return true;
auto &cm = CommandManager::Get( project );
cm.TellUserWhyDisallowed( Name, flags & mask, flagsRqd & mask);
TellUserWhyDisallowed( Name, flags & flagsRqd, flagsRqd);
return false;
}
/// Determines if flags for command are compatible with current state.
/// If not, then try some recovery action to make it so.
/// @return whether compatible or not after any actions taken.
bool MenuManager::TryToMakeActionAllowed(
CommandFlag & flags, CommandFlag flagsRqd, CommandFlag mask )
CommandFlag & flags, CommandFlag flagsRqd )
{
auto &project = mProject;
bool bAllowed;
if( !flags )
if( flags.none() )
flags = GetUpdateFlags();
bAllowed = ((flags & mask) == (flagsRqd & mask));
if( bAllowed )
return true;
// Why is action not allowed?
// 1's wherever a required flag is missing.
auto MissingFlags = (~flags & flagsRqd) & mask;
if( mStopIfWasPaused && (MissingFlags & AudioIONotBusyFlag ) ){
TransportActions::StopIfPaused( project );
// Hope this will now reflect stopped audio.
flags = GetUpdateFlags();
bAllowed = ((flags & mask) == (flagsRqd & mask));
if( bAllowed )
return true;
// Visit the table of recovery actions
auto &enablers = Enablers();
auto iter = enablers.begin(), end = enablers.end();
while ((flags & flagsRqd) != flagsRqd && iter != end) {
const auto &enabler = *iter;
auto MissingFlags = (~flags & flagsRqd);
if (
// Do we have the right precondition?
(flags & enabler.actualFlags) == enabler.actualFlags
&&
// Can we get the condition we need?
(MissingFlags & enabler.possibleFlags) == MissingFlags
) {
// Then try the function
enabler.tryEnable( project, flagsRqd );
flags = GetUpdateFlags();
}
++iter;
}
//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 )
return false;
// Why is action still not allowed?
// 0's wherever a required flag is missing (or is don't care)
MissingFlags = (flags & ~flagsRqd) & mask;
// IF selecting all audio won't do any good, THEN return with failure.
if( !(flags & WaveTracksExistFlag) )
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)) )
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 & mask) == (flagsRqd & mask));
return bAllowed;
return (flags & flagsRqd) == flagsRqd;
}
void MenuManager::TellUserWhyDisallowed(
const wxString & Name, CommandFlag flagsGot, CommandFlag flagsRequired )
{
// The default string for 'reason' is a catch all. I hope it won't ever be seen
// and that we will get something more specific.
auto reason = _("There was a problem with your last action. If you think\nthis is a bug, please tell us exactly where it occurred.");
// The default title string is 'Disallowed'.
auto untranslatedTitle = XO("Disallowed");
wxString helpPage;
bool enableDefaultMessage = true;
bool defaultMessage = true;
auto doOption = [&](const CommandFlagOptions &options) {
if ( options.message ) {
reason = options.message( Name );
defaultMessage = false;
if ( !options.title.empty() )
untranslatedTitle = options.title;
helpPage = options.helpPage;
return true;
}
else {
enableDefaultMessage =
enableDefaultMessage && options.enableDefaultMessage;
return false;
}
};
const auto &alloptions = Options();
auto missingFlags = flagsRequired & ~flagsGot;
// Find greatest priority
unsigned priority = 0;
for ( const auto &options : alloptions )
priority = std::max( priority, options.priority );
// Visit all unsatisfied conditions' options, by descending priority,
// stopping when we find a message
++priority;
while( priority-- ) {
size_t ii = 0;
for ( const auto &options : alloptions ) {
if (
priority == options.priority
&&
missingFlags[ii]
&&
doOption( options ) )
goto done;
++ii;
}
}
done:
if (
// didn't find a message
defaultMessage
&&
// did find a condition that suppresses the default message
!enableDefaultMessage
)
return;
// Message is already translated but title is not yet
auto title = ::GetCustomTranslation( untranslatedTitle );
// Does not have the warning icon...
ShowErrorDialog(
NULL,
title,
reason,
helpPage);
}

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;
@ -81,19 +81,20 @@ public:
// Command Handling
bool ReportIfActionNotAllowed(
const wxString & Name, CommandFlag & flags, CommandFlag flagsRqd,
CommandFlag mask );
const wxString & Name, CommandFlag & flags, CommandFlag flagsRqd );
bool TryToMakeActionAllowed(
CommandFlag & flags, CommandFlag flagsRqd, CommandFlag mask );
CommandFlag & flags, CommandFlag flagsRqd );
private:
void OnUndoRedo( wxCommandEvent &evt );
void TellUserWhyDisallowed(const wxString & Name, CommandFlag flagsGot,
CommandFlag flagsRequired);
CommandFlag GetFocusedFrame(AudacityProject &project);
void OnUndoRedo( wxCommandEvent &evt );
AudacityProject &mProject;
public:
// 0 is grey out, 1 is Autoselect, 2 is Give warnings.
int mWhatIfNoSelection;
bool mStopIfWasPaused;

View File

@ -642,7 +642,7 @@ void ProjectFileIO::DeleteCurrentAutoSaveFile()
}
}
bool ProjectFileIO::IsProjectSaved() {
bool ProjectFileIO::IsProjectSaved() const {
auto &project = mProject;
auto &dirManager = DirManager::Get( project );
// This is true if a project was opened from an .aup

View File

@ -40,7 +40,7 @@ public:
// recovery file
void SetProjectTitle( int number = -1 );
bool IsProjectSaved();
bool IsProjectSaved() const;
void Reset();

View File

@ -59,7 +59,7 @@ void ProjectHistory::InitialState()
undoManager.StateSaved();
}
bool ProjectHistory::UndoAvailable()
bool ProjectHistory::UndoAvailable() const
{
auto &project = mProject;
auto &tracks = TrackList::Get( project );
@ -68,7 +68,7 @@ bool ProjectHistory::UndoAvailable()
!tracks.HasPendingTracks();
}
bool ProjectHistory::RedoAvailable()
bool ProjectHistory::RedoAvailable() const
{
auto &project = mProject;
auto &tracks = TrackList::Get( project );

View File

@ -31,8 +31,8 @@ public:
void InitialState();
void SetStateTo(unsigned int n);
bool UndoAvailable();
bool RedoAvailable();
bool UndoAvailable() const;
bool RedoAvailable() const;
void PushState(const wxString &desc, const wxString &shortDesc); // use UndoPush::AUTOSAVE
void PushState(const wxString &desc, const wxString &shortDesc, UndoPush flags);
void RollbackState();

View File

@ -1513,7 +1513,7 @@ void ProjectWindow::OnMenu(wxCommandEvent & event)
auto &commandManager = CommandManager::Get( project );
bool handled = commandManager.HandleMenuID(
event.GetId(), MenuManager::Get( project ).GetUpdateFlags(),
NoFlagsSpecified);
false);
if (handled)
event.Skip(false);
@ -1887,3 +1887,12 @@ void ProjectWindow::ZoomOutByFactor( double ZoomFactor )
// newh = (newh > 0) ? newh : 0;
TP_ScrollWindow(newh);
}
static struct InstallTopPanelHook{ InstallTopPanelHook() {
ToolManager::SetGetTopPanelHook(
[]( wxWindow &window ){
auto pProjectWindow = dynamic_cast< ProjectWindow* >( &window );
return pProjectWindow ? pProjectWindow->GetTopPanel() : nullptr;
}
);
}} installTopPanelHook;

View File

@ -79,8 +79,6 @@ public:
};
PlaybackScroller &GetPlaybackScroller() { return *mPlaybackScroller; }
using wxFrame::DetachMenuBar;
void SetNormalizedWindowState(wxRect pSizeAndLocation) { mNormalizedWindowState = pSizeAndLocation; }
wxRect GetNormalizedWindowState() const { return mNormalizedWindowState; }

View File

@ -388,7 +388,7 @@ void UndoManager::Redo(const Consumer &consumer)
mProject.QueueEvent( safenew wxCommandEvent{ EVT_UNDO_OR_REDO } );
}
bool UndoManager::UnsavedChanges()
bool UndoManager::UnsavedChanges() const
{
return (saved != current) || HasODChangesFlag();
}
@ -418,7 +418,7 @@ void UndoManager::SetODChangesFlag()
mODChangesMutex.Unlock();
}
bool UndoManager::HasODChangesFlag()
bool UndoManager::HasODChangesFlag() const
{
bool ret;
mODChangesMutex.Lock();

View File

@ -152,7 +152,7 @@ class AUDACITY_DLL_API UndoManager
bool UndoAvailable();
bool RedoAvailable();
bool UnsavedChanges();
bool UnsavedChanges() const;
void StateSaved();
// Return value must first be calculated by CalculateSpaceUsage():
@ -167,7 +167,7 @@ class AUDACITY_DLL_API UndoManager
///to mark as unsaved changes without changing the state/tracks.
void SetODChangesFlag();
bool HasODChangesFlag();
bool HasODChangesFlag() const;
void ResetODChangesFlag();
private:
@ -184,7 +184,7 @@ class AUDACITY_DLL_API UndoManager
unsigned long long mClipboardSpaceUsage {};
bool mODChanges;
ODLock mODChangesMutex;//mODChanges is accessed from many threads.
mutable ODLock mODChangesMutex;//mODChanges is accessed from many threads.
};

View File

@ -11,134 +11,109 @@
// 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>
#include <functional>
#include <utility>
#include <wx/string.h>
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,
ClipboardFlag = 0x00000040,
TextClipFlag = 0x00000040, // Same as Clipboard flag for now.
UnsavedChangesFlag = 0x00000080,
HasLastEffectFlag = 0x00000100,
UndoAvailableFlag = 0x00000200,
RedoAvailableFlag = 0x00000400,
ZoomInAvailableFlag = 0x00000800,
ZoomOutAvailableFlag = 0x00001000,
StereoRequiredFlag = 0x00002000, //lda
TopDockHasFocus = 0x00004000, //lll
TrackPanelHasFocus = 0x00008000, //lll
BotDockHasFocus = 0x00010000, //lll
LabelsSelectedFlag = 0x00020000,
AudioIOBusyFlag = 0x00040000, //lll
PlayRegionLockedFlag = 0x00080000, //msmeyer
PlayRegionNotLockedFlag= 0x00100000, //msmeyer
CutCopyAvailableFlag = 0x00200000,
WaveTracksExistFlag = 0x00400000,
NoteTracksExistFlag = 0x00800000, //gsw
NoteTracksSelectedFlag = 0x01000000, //gsw
HaveRecentFiles = 0x02000000,
IsNotSyncLockedFlag = 0x04000000, //awd
IsSyncLockedFlag = 0x08000000, //awd
IsRealtimeNotActiveFlag= 0x10000000, //lll
CaptureNotBusyFlag = 0x20000000,
CanStopAudioStreamFlag = 0x40000000,
RulerHasFocus = 0x80000000ULL, // prl
NotMinimizedFlag = 0x100000000ULL, // prl
PausedFlag = 0x200000000ULL, // jkc
NotPausedFlag = 0x400000000ULL, // jkc
HasWaveDataFlag = 0x800000000ULL, // jkc
PlayableTracksExistFlag = 0x1000000000ULL,
AudioTracksSelectedFlag = 0x2000000000ULL,
NoAutoSelect = 0x4000000000ULL, // jkc
class AudacityProject;
NoFlagsSpecified = ~0ULL
// 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>;
// Special constant values
constexpr CommandFlag
AlwaysEnabledFlag{}, // all zeroes
NoFlagsSpecified{ ~0ULL }; // all ones
struct CommandFlagOptions{
// Supplied the translated name of the command, returns a translated
// error message
using MessageFormatter = std::function< wxString( const wxString& ) >;
CommandFlagOptions() = default;
CommandFlagOptions(
const MessageFormatter &message_,
const wxString &helpPage_ = {},
const wxString &title_ = {}
) : message{ message_ }, helpPage{ helpPage_ }, title{ title_ }
{}
CommandFlagOptions && QuickTest() &&
{ quickTest = true; return std::move( *this ); }
CommandFlagOptions && DisableDefaultMessage() &&
{ enableDefaultMessage = false; return std::move( *this ); }
CommandFlagOptions && Priority( unsigned priority_ ) &&
{ priority = priority_; return std::move( *this ); }
// null, or else computes non-default message for the dialog box when the
// condition is not satisfied for the selected command
MessageFormatter message;
// Title and help page are used only if a message function is given
wxString helpPage;
// Empty, or non-default title for the dialog box when the
// condition is not satisfied for the selected command
// This string must be given UN-translated.
wxString title;
// Conditions with higher "priority" are preferred over others in choosing
// the help message
unsigned priority = 0;
// If false, and no other condition with a message is unsatisfied, then
// display no dialog box at all when this condition is not satisfied
bool enableDefaultMessage = true;
// If true, assume this is a cheap test to be done always. If false, the
// test may be skipped and the condition assumed to be unchanged since the
// last more comprehensive testing
bool quickTest = false;
};
// 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)
// Construct one statically to register (and reserve) a bit position in the set
// an associate it with a test function; those with quickTest = true are cheap
// to compute and always checked
class ReservedCommandFlag : public CommandFlag
{
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;
}
public:
using Predicate = std::function< bool( const AudacityProject& ) >;
ReservedCommandFlag( const Predicate &predicate,
const CommandFlagOptions &options = {} );
};
using CommandMask = CommandFlag;
// 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
// 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

View File

@ -96,12 +96,9 @@ CommandManager. It holds the callback for one command.
#include "../Menus.h"
#include "../PluginManager.h"
#include "../Project.h"
#include "../effects/EffectManager.h"
#include "../widgets/LinkingHtmlWindow.h"
#include "../widgets/AudacityMessageBox.h"
#include "../widgets/ErrorDialog.h"
#include "../widgets/HelpSystem.h"
@ -525,10 +522,6 @@ void CommandManager::AddItem(const CommandID &name,
wxASSERT( flags != NoFlagsSpecified );
auto mask = options.mask;
if (mask == NoFlagsSpecified)
mask = flags;
CommandParameter cookedParameter;
const auto &parameter = options.parameter;
if( parameter.empty() )
@ -542,10 +535,11 @@ void CommandManager::AddItem(const CommandID &name,
hasDialog,
options.accel, CurrentMenu(), finder, callback,
{}, 0, 0, options.bIsEffect, cookedParameter);
entry->useStrictFlags = options.useStrictFlags;
int ID = entry->id;
wxString label = GetLabelWithDisabledAccel(entry);
SetCommandFlags(name, flags, mask);
SetCommandFlags(name, flags);
auto checkmark = options.check;
@ -588,7 +582,7 @@ void CommandManager::AddItemList(const CommandID & name,
i,
cnt,
bIsEffect);
entry->mask = entry->flags = flags;
entry->flags = flags;
CurrentMenu()->Append(entry->id, GetLabel(entry));
mbSeparatorAllowed = true;
}
@ -617,7 +611,7 @@ void CommandManager::AddCommand(const CommandID &name,
NewIdentifier(name, label_in, label_in, false, accel, NULL, finder, callback, {}, 0, 0, false, {});
SetCommandFlags(name, flags, flags);
SetCommandFlags(name, flags);
}
void CommandManager::AddGlobalCommand(const CommandID &name,
@ -634,7 +628,6 @@ void CommandManager::AddGlobalCommand(const CommandID &name,
entry->enabled = false;
entry->isGlobal = true;
entry->flags = AlwaysEnabledFlag;
entry->mask = AlwaysEnabledFlag;
}
void CommandManager::AddSeparator()
@ -763,7 +756,7 @@ CommandListEntry *CommandManager::NewIdentifier(const CommandID & nameIn,
entry->multi = multi;
entry->index = index;
entry->count = count;
entry->flags = entry->mask = AlwaysEnabledFlag;
entry->flags = AlwaysEnabledFlag;
entry->enabled = true;
entry->skipKeydown = (accel.Find(wxT("\tskipKeydown")) != wxNOT_FOUND);
entry->wantKeyup = (accel.Find(wxT("\twantKeyup")) != wxNOT_FOUND) || entry->skipKeydown;
@ -955,18 +948,25 @@ void CommandManager::Enable(const wxString &name, bool enabled)
Enable(entry, enabled);
}
void CommandManager::EnableUsingFlags(CommandFlag flags, CommandMask mask)
void CommandManager::EnableUsingFlags(
CommandFlag flags, CommandFlag strictFlags)
{
// strictFlags are a subset of flags. strictFlags represent the real
// conditions now, but flags are the conditions that could be made true.
// Some commands use strict flags only, refusing the chance to fix
// conditions
wxASSERT( (strictFlags & ~flags).none() );
for(const auto &entry : mCommandList) {
if (entry->multi && entry->index != 0)
continue;
if( entry->isOccult )
continue;
auto combinedMask = (mask & entry->mask);
if (combinedMask) {
bool enable = ((flags & combinedMask) ==
(entry->flags & combinedMask));
auto useFlags = entry->useStrictFlags ? strictFlags : flags;
if (entry->flags.any()) {
bool enable = ((useFlags & entry->flags) == entry->flags);
Enable(entry.get(), enable);
}
}
@ -1018,69 +1018,6 @@ void CommandManager::SetKeyFromIndex(int i, const NormalizedKeyString &key)
entry->key = key;
}
void CommandManager::TellUserWhyDisallowed( const wxString & Name, CommandFlag flagsGot, CommandMask flagsRequired )
{
// The default string for 'reason' is a catch all. I hope it won't ever be seen
// and that we will get something more specific.
wxString reason = _("There was a problem with your last action. If you think\nthis is a bug, please tell us exactly where it occurred.");
// The default title string is 'Disallowed'.
wxString title = _("Disallowed");
wxString helpPage;
auto missingFlags = flagsRequired & (~flagsGot );
if( missingFlags & AudioIONotBusyFlag )
// 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 )
// 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 )){
title = _("No Audio Selected");
#ifdef EXPERIMENTAL_DA
// i18n-hint: %s will be replaced by the name of an action, such as Normalize, Cut, Fade.
reason = wxString::Format( _("You must first select some audio for '%s' to act on.\n\nCtrl + A selects all audio."), Name );
#else
#ifdef __WXMAC__
// i18n-hint: %s will be replaced by the name of an action, such as Normalize, Cut, Fade.
reason = wxString::Format( _("Select the audio for %s to use (for example, Cmd + A to Select All) then try again."
// No need to explain what a help button is for.
// "\n\nClick the Help button to learn more about selection methods."
), Name );
#else
// i18n-hint: %s will be replaced by the name of an action, such as Normalize, Cut, Fade.
reason = wxString::Format( _("Select the audio for %s to use (for example, Ctrl + A to Select All) then try again."
// No need to explain what a help button is for.
// "\n\nClick the Help button to learn more about selection methods."
), Name );
#endif
#endif
helpPage = "Selecting_Audio_-_the_basics";
}
else if( missingFlags & WaveTracksSelectedFlag)
reason = _("You must first select some audio to perform this action.\n(Selecting other kinds of track won't work.)");
else if ( missingFlags & TracksSelectedFlag )
// 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
else if( missingFlags == TracksExistFlag )
return;
// Likewise return if it was just no tracks, and track panel did not have focus. (e.g. up-arrow to move track)
else if( missingFlags == (TracksExistFlag | TrackPanelHasFocus) )
return;
// Likewise as above too...
else if( missingFlags == TrackPanelHasFocus )
return;
// Does not have the warning icon...
ShowErrorDialog(
NULL,
title,
reason,
helpPage);
}
wxString CommandManager::DescribeCommandsAndShortcuts
(const TranslatedInternalString commands[], size_t nCommands) const
{
@ -1153,7 +1090,7 @@ bool CommandManager::FilterKeyEvent(AudacityProject *project, const wxKeyEvent &
// LL: Why do they need to be disabled???
entry->enabled = false;
auto cleanup = valueRestorer( entry->enabled, true );
return HandleCommandEntry(entry, NoFlagsSpecified, NoFlagsSpecified, &evt);
return HandleCommandEntry(entry, NoFlagsSpecified, false, &evt);
}
wxWindow * pFocus = wxWindow::FindFocus();
@ -1227,12 +1164,12 @@ bool CommandManager::FilterKeyEvent(AudacityProject *project, const wxKeyEvent &
{
return true;
}
return HandleCommandEntry(entry, flags, NoFlagsSpecified, &temp);
return HandleCommandEntry(entry, flags, false, &temp);
}
if (type == wxEVT_KEY_UP && entry->wantKeyup)
{
return HandleCommandEntry(entry, flags, NoFlagsSpecified, &temp);
return HandleCommandEntry(entry, flags, false, &temp);
}
return false;
@ -1243,7 +1180,7 @@ bool CommandManager::FilterKeyEvent(AudacityProject *project, const wxKeyEvent &
///the command won't be executed unless the flags are compatible
///with the command's flags.
bool CommandManager::HandleCommandEntry(const CommandListEntry * entry,
CommandFlag flags, CommandMask mask, const wxEvent * evt)
CommandFlag flags, bool alwaysEnabled, const wxEvent * evt)
{
if (!entry )
return false;
@ -1253,8 +1190,7 @@ bool CommandManager::HandleCommandEntry(const CommandListEntry * entry,
auto proj = GetActiveProject();
auto combinedMask = (mask & entry->mask);
if (combinedMask) {
if (!alwaysEnabled && entry->flags.any()) {
wxASSERT( proj );
if( !proj )
@ -1266,7 +1202,7 @@ bool CommandManager::HandleCommandEntry(const CommandListEntry * entry,
// NB: The call may have the side effect of changing flags.
bool allowed =
MenuManager::Get(*proj).ReportIfActionNotAllowed(
NiceName, flags, entry->flags, combinedMask );
NiceName, flags, entry->flags );
// If the function was disallowed, it STILL should count as having been
// handled (by doing nothing or by telling the user of the problem).
// Otherwise we may get other handlers having a go at obeying the command.
@ -1286,7 +1222,7 @@ bool CommandManager::HandleCommandEntry(const CommandListEntry * entry,
///CommandManagerListener function. If you pass any flags,
///the command won't be executed unless the flags are compatible
///with the command's flags.
bool CommandManager::HandleMenuID(int id, CommandFlag flags, CommandMask mask)
bool CommandManager::HandleMenuID(int id, CommandFlag flags, bool alwaysEnabled)
{
CommandListEntry *entry = mCommandNumericIDHash[id];
@ -1294,16 +1230,18 @@ bool CommandManager::HandleMenuID(int id, CommandFlag flags, CommandMask mask)
if (hook && hook(entry->name))
return true;
return HandleCommandEntry( entry, flags, mask );
return HandleCommandEntry( entry, flags, alwaysEnabled );
}
/// HandleTextualCommand() allows us a limitted version of script/batch
/// behavior, since we can get from a string command name to the actual
/// code to run.
bool CommandManager::HandleTextualCommand(const CommandID & Str, const CommandContext & context, CommandFlag flags, CommandMask mask)
CommandManager::TextualCommandResult
CommandManager::HandleTextualCommand(const CommandID & Str,
const CommandContext & context, CommandFlag flags, bool alwaysEnabled)
{
if( Str.empty() )
return false;
return CommandFailure;
// Linear search for now...
for (const auto &entry : mCommandList)
{
@ -1316,7 +1254,8 @@ bool CommandManager::HandleTextualCommand(const CommandID & Str, const CommandCo
// sub-menu name)
Str == entry->labelPrefix )
{
return HandleCommandEntry( entry.get(), flags, mask);
return HandleCommandEntry( entry.get(), flags, alwaysEnabled)
? CommandSuccess : CommandFailure;
}
}
else
@ -1324,34 +1263,12 @@ bool CommandManager::HandleTextualCommand(const CommandID & Str, const CommandCo
// Handle multis too...
if( Str == entry->name )
{
return HandleCommandEntry( entry.get(), flags, mask);
return HandleCommandEntry( entry.get(), flags, alwaysEnabled)
? CommandSuccess : CommandFailure;
}
}
}
// Not one of the singleton commands.
// We could/should try all the list-style commands.
// instead we only try the effects.
AudacityProject * proj = GetActiveProject();
if( !proj )
{
return false;
}
PluginManager & pm = PluginManager::Get();
EffectManager & em = EffectManager::Get();
const PluginDescriptor *plug = pm.GetFirstPlugin(PluginTypeEffect);
while (plug)
{
if (em.GetCommandIdentifier(plug->GetID()) == Str)
{
return PluginActions::DoEffect(
plug->GetID(), context,
PluginActions::kConfigured);
}
plug = pm.GetNextPlugin(PluginTypeEffect);
}
return false;
return CommandNotFound;
}
void CommandManager::GetCategories(wxArrayString &cats)
@ -1609,13 +1526,11 @@ void CommandManager::EndOccultCommands()
}
void CommandManager::SetCommandFlags(const CommandID &name,
CommandFlag flags, CommandMask mask)
CommandFlag flags)
{
CommandListEntry *entry = mCommandNameHash[name];
if (entry) {
if (entry)
entry->flags = flags;
entry->mask = mask;
}
}
#if defined(__WXDEBUG__)
@ -1671,3 +1586,4 @@ static struct InstallHandlers
} );
}
} installHandlers;

View File

@ -81,7 +81,7 @@ struct CommandListEntry
bool isEffect;
bool hasDialog;
CommandFlag flags;
CommandMask mask;
bool useStrictFlags{ false };
};
using MenuBarList = std::vector < MenuBarListEntry >;
@ -158,20 +158,20 @@ class AUDACITY_DLL_API CommandManager final
{ bIsEffect = true; return std::move(*this); }
Options &&Parameter (const CommandParameter &value) &&
{ parameter = value; return std::move(*this); }
Options &&Mask (CommandMask value) &&
{ mask = value; return std::move(*this); }
Options &&LongName (const wxString &value) &&
{ longName = value; return std::move(*this); }
Options &&IsGlobal () &&
{ global = true; return std::move(*this); }
Options &&UseStrictFlags () &&
{ useStrictFlags = true; return std::move(*this); }
const wxChar *accel{ wxT("") };
int check{ -1 }; // default value means it's not a check item
bool bIsEffect{ false };
CommandParameter parameter{};
CommandMask mask{ NoFlagsSpecified };
wxString longName{}; // translated
bool global{ false };
bool useStrictFlags{ false };
};
void AddItemList(const CommandID & name,
@ -212,13 +212,14 @@ class AUDACITY_DLL_API CommandManager final
void EndOccultCommands();
void SetCommandFlags(const CommandID &name, CommandFlag flags, CommandMask mask);
void SetCommandFlags(const CommandID &name, CommandFlag flags);
//
// Modifying menus
//
void EnableUsingFlags(CommandFlag flags, CommandMask mask);
void EnableUsingFlags(
CommandFlag flags, CommandFlag strictFlags);
void Enable(const wxString &name, bool enabled);
void Check(const CommandID &name, bool checked);
void Modify(const wxString &name, const wxString &newLabel);
@ -242,8 +243,17 @@ class AUDACITY_DLL_API CommandManager final
// "permit" allows filtering even if the active window isn't a child of the project.
// Lyrics and MixerTrackCluster classes use it.
bool FilterKeyEvent(AudacityProject *project, const wxKeyEvent & evt, bool permit = false);
bool HandleMenuID(int id, CommandFlag flags, CommandMask mask);
bool HandleTextualCommand(const CommandID & Str, const CommandContext & context, CommandFlag flags, CommandMask mask);
bool HandleMenuID(int id, CommandFlag flags, bool alwaysEnabled);
enum TextualCommandResult {
CommandFailure,
CommandSuccess,
CommandNotFound
};
TextualCommandResult
HandleTextualCommand(const CommandID & Str,
const CommandContext & context, CommandFlag flags, bool alwaysEnabled);
//
// Accessing
@ -285,7 +295,6 @@ class AUDACITY_DLL_API CommandManager final
//
void WriteXML(XMLWriter &xmlFile) const /* not override */;
void TellUserWhyDisallowed(const wxString & Name, CommandFlag flagsGot, CommandFlag flagsRequired);
///
/// Formatting summaries that include shortcut keys
@ -342,7 +351,8 @@ private:
// Executing commands
//
bool HandleCommandEntry(const CommandListEntry * entry, CommandFlag flags, CommandMask mask, const wxEvent * evt = NULL);
bool HandleCommandEntry(const CommandListEntry * entry, CommandFlag flags,
bool alwaysEnabled, const wxEvent * evt = NULL);
//
// Modifying

View File

@ -32,6 +32,7 @@ small calculations of rectangles.
#include <wx/valgen.h>
#include "../AdornedRulerPanel.h"
#include "../BatchCommands.h"
#include "../TrackPanel.h"
#include "../effects/Effect.h"
#include "../toolbars/ToolManager.h"
@ -454,7 +455,8 @@ void ScreenshotCommand::CapturePreferences(
gPrefs->Flush();
CommandID Command{ wxT("Preferences") };
const CommandContext projectContext( *pProject );
if( !commandManager.HandleTextualCommand( Command, projectContext, AlwaysEnabledFlag, AlwaysEnabledFlag ) )
if( !MacroCommands::HandleTextualCommand( commandManager,
Command, projectContext, AlwaysEnabledFlag, true ) )
{
// using GET in a log message for devs' eyes only
wxLogDebug("Command %s not found", Command.GET() );
@ -614,7 +616,7 @@ void ScreenshotCommand::CaptureCommands(
SetIdleHandler( IdleHandler );
Str = Commands[i];
const CommandContext projectContext( *pProject );
if( !manager.HandleTextualCommand( Str, projectContext, AlwaysEnabledFlag, AlwaysEnabledFlag ) )
if( !manager.HandleTextualCommand( Str, projectContext, AlwaysEnabledFlag, true ) )
{
wxLogDebug("Command %s not found", Str);
}

View File

@ -49,6 +49,7 @@ greater use in future.
#include "EffectManager.h"
#include "../AudioIO.h"
#include "../CommonCommandFlags.h"
#include "../LabelTrack.h"
#include "../Menus.h"
#include "../Mix.h"
@ -57,13 +58,11 @@ greater use in future.
#include "../Project.h"
#include "../ProjectAudioManager.h"
#include "../ProjectSettings.h"
#include "../PluginManager.h"
#include "../ShuttleGui.h"
#include "../Shuttle.h"
#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"
@ -3279,7 +3278,6 @@ void EffectUIHost::OnApply(wxCommandEvent & evt)
MenuManager::Get(*mProject).ReportIfActionNotAllowed(
mEffect->GetTranslatedName(),
flags,
WaveTracksSelectedFlag | TimeSelectedFlag,
WaveTracksSelectedFlag | TimeSelectedFlag);
if (!allowed)
return;

View File

@ -1,3 +1,4 @@
#include "../CommonCommandFlags.h"
#include "../ProjectHistory.h"
#include "../ProjectSettings.h"
#include "../TrackPanel.h"

View File

@ -1,6 +1,7 @@
#include "../Audacity.h" // for USE_* macros
#include "../AdornedRulerPanel.h"
#include "../Clipboard.h"
#include "../CommonCommandFlags.h"
#include "../LabelTrack.h"
#include "../Menus.h"
#include "../NoteTrack.h"
@ -1090,12 +1091,34 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &) {
MenuTable::BaseItemPtr LabelEditMenus( AudacityProject &project );
const ReservedCommandFlag
CutCopyAvailableFlag{
[](const AudacityProject &project){
auto range = TrackList::Get( project ).Any<const LabelTrack>()
+ &LabelTrack::IsTextSelected;
if ( !range.empty() )
return true;
if (
!AudioIOBusyPred( project )
&&
TimeSelectedPred( project )
&&
TracksSelectedPred( project )
)
return true;
return false;
},
cutCopyOptions
};
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.
@ -1135,12 +1158,10 @@ MenuTable::BaseItemPtr EditMenu( AudacityProject & )
/* i18n-hint: (verb)*/
Command( wxT("Cut"), XXO("Cu&t"), FN(OnCut),
AudioIONotBusyFlag | CutCopyAvailableFlag | NoAutoSelect,
Options{ wxT("Ctrl+X") }
.Mask( AudioIONotBusyFlag | CutCopyAvailableFlag ) ),
wxT("Ctrl+X") ),
Command( wxT("Delete"), XXO("&Delete"), FN(OnDelete),
AudioIONotBusyFlag | NoAutoSelect,
Options{ wxT("Ctrl+K") }
.Mask( AudioIONotBusyFlag ) ),
wxT("Ctrl+K") ),
/* i18n-hint: (verb)*/
Command( wxT("Copy"), XXO("&Copy"), FN(OnCopy),
AudioIONotBusyFlag | CutCopyAvailableFlag, wxT("Ctrl+C") ),
@ -1156,10 +1177,12 @@ MenuTable::BaseItemPtr EditMenu( AudacityProject & )
Menu( _("R&emove Special"),
/* i18n-hint: (verb) Do a special kind of cut*/
Command( wxT("SplitCut"), XXO("Spl&it Cut"), FN(OnSplitCut),
NotBusyTimeAndTracksFlags, wxT("Ctrl+Alt+X") ),
NotBusyTimeAndTracksFlags,
Options{ wxT("Ctrl+Alt+X") }.UseStrictFlags() ),
/* i18n-hint: (verb) Do a special kind of DELETE*/
Command( wxT("SplitDelete"), XXO("Split D&elete"), FN(OnSplitDelete),
NotBusyTimeAndTracksFlags, wxT("Ctrl+Alt+K") ),
NotBusyTimeAndTracksFlags,
Options{ wxT("Ctrl+Alt+K") }.UseStrictFlags() ),
Separator(),
@ -1170,7 +1193,7 @@ MenuTable::BaseItemPtr EditMenu( AudacityProject & )
/* i18n-hint: (verb)*/
Command( wxT("Trim"), XXO("Tri&m Audio"), FN(OnTrim),
AudioIONotBusyFlag | TimeSelectedFlag | AudioTracksSelectedFlag,
wxT("Ctrl+T") )
Options{ wxT("Ctrl+T") }.UseStrictFlags() )
),
Separator(),
@ -1180,10 +1203,11 @@ MenuTable::BaseItemPtr EditMenu( AudacityProject & )
Menu( _("Clip B&oundaries"),
/* i18n-hint: (verb) It's an item on a menu. */
Command( wxT("Split"), XXO("Sp&lit"), FN(OnSplit),
AudioIONotBusyFlag | WaveTracksSelectedFlag, wxT("Ctrl+I") ),
AudioIONotBusyFlag | WaveTracksSelectedFlag,
Options{ wxT("Ctrl+I") }.UseStrictFlags() ),
Command( wxT("SplitNew"), XXO("Split Ne&w"), FN(OnSplitNew),
AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag,
wxT("Ctrl+Alt+I") ),
Options{ wxT("Ctrl+Alt+I") }.UseStrictFlags() ),
Separator(),
@ -1216,17 +1240,39 @@ 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),
(flags | NoAutoSelect),
Options{ wxT("Backspace") }.Mask( flags ) ),
wxT("Backspace") ),
Command( wxT("DeleteKey2"), XXO("Delete Key&2"), FN(OnDelete),
(flags | NoAutoSelect),
Options{ wxT("Delete") }.Mask( flags ) )
wxT("Delete") )
);
}
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
}};
#undef XXO
#undef FN

View File

@ -1,3 +1,4 @@
#include "../CommonCommandFlags.h"
#include "../Prefs.h"
#include "../Project.h"
#include "../commands/CommandContext.h"

View File

@ -2,6 +2,7 @@
#include "../Experimental.h"
#include "../BatchCommands.h"
#include "../CommonCommandFlags.h"
#include "../FileNames.h"
#include "../LabelTrack.h"
#include "../MissingAliasFileDialog.h"
@ -589,6 +590,7 @@ static CommandHandlerObject &findCommandHandler(AudacityProject &) {
MenuTable::BaseItemPtr FileMenu( AudacityProject& )
{
using namespace MenuTable;
using Options = CommandManager::Options;
return Menu( _("&File"),
/*i18n-hint: "New" is an action (verb) to create a NEW project*/
@ -683,7 +685,8 @@ MenuTable::BaseItemPtr FileMenu( AudacityProject& )
// Enable Export Selection commands only when there's a selection.
Command( wxT("ExportSel"), XXO("Expo&rt Selected Audio..."),
FN(OnExportSelection),
AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag ),
AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag,
Options{}.UseStrictFlags() ),
Command( wxT("ExportLabels"), XXO("Export &Labels..."),
FN(OnExportLabels),

View File

@ -9,6 +9,7 @@
#include "../AllThemeResources.h"
#include "../AudacityLogger.h"
#include "../AudioIOBase.h"
#include "../CommonCommandFlags.h"
#include "../CrashReport.h"
#include "../Dependencies.h"
#include "../FileNames.h"

View File

@ -1,5 +1,6 @@
#include "../AudioIOBase.h"
#include "../Clipboard.h"
#include "../CommonCommandFlags.h"
#include "../LabelTrack.h"
#include "../Menus.h"
#include "../Prefs.h"
@ -586,7 +587,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

@ -1,5 +1,6 @@
#include "../Audacity.h"
#include "../CommonCommandFlags.h"
#include "../Menus.h"
#include "../Prefs.h"
#include "../Project.h"
@ -580,7 +581,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

@ -4,6 +4,7 @@
#include "../AudioIO.h"
#include "../BatchProcessDialog.h"
#include "../Benchmark.h"
#include "../CommonCommandFlags.h"
#include "../FreqWindow.h"
#include "../Menus.h"
#include "../MissingAliasFileDialog.h"
@ -923,6 +924,13 @@ MenuTable::BaseItemPtr GenerateMenu( AudacityProject & )
);
}
const ReservedCommandFlag
IsRealtimeNotActiveFlag{
[](const AudacityProject &){
return !EffectManager::Get().RealtimeIsActive();
}
}; //lll
MenuTable::BaseItemPtr EffectMenu( AudacityProject &project )
{
using namespace MenuTable;

View File

@ -3,6 +3,7 @@
#include "../AdornedRulerPanel.h"
#include "../AudioIO.h"
#include "../CommonCommandFlags.h"
#include "../FreqWindow.h"
#include "../Menus.h" // for PrefsListener
#include "../Prefs.h"
@ -513,7 +514,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 +1333,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

@ -1,6 +1,7 @@
#include "../Audacity.h"
#include "../Experimental.h"
#include "../CommonCommandFlags.h"
#include "../LabelTrack.h"
#include "../Menus.h"
#include "../MissingAliasFileDialog.h"

View File

@ -3,6 +3,7 @@
#include "../AdornedRulerPanel.h"
#include "../AudioIO.h"
#include "../CommonCommandFlags.h"
#include "../DeviceManager.h"
#include "../LabelTrack.h"
#include "../Menus.h"
@ -208,8 +209,7 @@ namespace TransportActions {
// Stop playing or recording, if paused.
void StopIfPaused( AudacityProject &project )
{
auto flags = MenuManager::Get( project ).GetUpdateFlags();
if( flags & PausedFlag )
if( AudioIOBase::Get()->IsPaused() )
DoStop( project );
}
@ -1076,7 +1076,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. */

View File

@ -1,6 +1,7 @@
#include "../Audacity.h"
#include "../Experimental.h"
#include "../CommonCommandFlags.h"
#include "../HistoryWindow.h"
#include "../LyricsWindow.h"
#include "../Menus.h"

View File

@ -7,6 +7,7 @@
#ifdef __WXMAC__
#include "../CommonCommandFlags.h"
#include "../Menus.h"
#include "../Project.h"
#include "../commands/CommandContext.h"

View File

@ -60,6 +60,7 @@
#include "../AdornedRulerPanel.h"
#include "../AllThemeResources.h"
#include "../AudioIO.h"
#include "../CommonCommandFlags.h"
#include "../ImageManipulation.h"
#include "../Menus.h"
#include "../Prefs.h"
@ -824,7 +825,7 @@ void ControlToolBar::OnStop(wxCommandEvent & WXUNUSED(evt))
}
}
bool ControlToolBar::CanStopAudioStream()
bool ControlToolBar::CanStopAudioStream() const
{
auto gAudioIO = AudioIO::Get();
return (!gAudioIO->IsStreamActive() ||
@ -1082,7 +1083,6 @@ bool ControlToolBar::DoRecord(AudacityProject &project,
// NB: The call may have the side effect of changing flags.
bool allowed = MenuManager::Get(project).TryToMakeActionAllowed(
flags,
AudioIONotBusyFlag | CanStopAudioStreamFlag,
AudioIONotBusyFlag | CanStopAudioStreamFlag);
if (!allowed)
@ -1563,3 +1563,10 @@ static RegisteredToolbarFactory factory{ TransportBarID,
[]( AudacityProject &project ){
return ToolBar::Holder{ safenew ControlToolBar{ project } }; }
};
const ReservedCommandFlag
CanStopAudioStreamFlag{
[](const AudacityProject &project){
return ControlToolBar::Get( project ).CanStopAudioStream();
}
};

View File

@ -99,7 +99,7 @@ class ControlToolBar final : public ToolBar {
bool IsRecordDown() const;
// A project is only allowed to stop an audio stream that it owns.
bool CanStopAudioStream ();
bool CanStopAudioStream () const;
// Play currently selected region, or if nothing selected,
// play from current cursor.
@ -210,5 +210,10 @@ class ControlToolBar final : public ToolBar {
DECLARE_EVENT_TABLE()
};
#include "../commands/CommandFlag.h"
extern const ReservedCommandFlag
CanStopAudioStreamFlag;
#endif

View File

@ -49,6 +49,7 @@
#endif
#include "../AllThemeResources.h"
#include "../BatchCommands.h"
#include "../ImageManipulation.h"
#include "../Menus.h"
#include "../Prefs.h"
@ -299,7 +300,8 @@ void EditToolBar::OnButton(wxCommandEvent &event)
auto flags = MenuManager::Get(*p).GetUpdateFlags();
const CommandContext context( *p );
cm.HandleTextualCommand(EditToolbarButtonList[id].commandName, context, flags, NoFlagsSpecified);
MacroCommands::HandleTextualCommand( cm,
EditToolbarButtonList[id].commandName, context, flags, false);
}
static RegisteredToolbarFactory factory{ EditBarID,

View File

@ -57,10 +57,9 @@
#include "../ImageManipulation.h"
#include "../Prefs.h"
#include "../Project.h"
#include "../ProjectWindow.h"
#include "../widgets/AButton.h"
#include "../widgets/ASlider.h"
#include "../widgets/Meter.h"
#include "../widgets/MeterPanelBase.h"
#include "../widgets/Grabber.h"
////////////////////////////////////////////////////////////
@ -73,7 +72,7 @@
//
ToolFrame::ToolFrame
( AudacityProject *parent, ToolManager *manager, ToolBar *bar, wxPoint pos )
: wxFrame( ProjectWindow::Find( parent ),
: wxFrame( FindProjectFrame( parent ),
bar->GetId(),
wxEmptyString,
pos,
@ -312,10 +311,26 @@ BEGIN_EVENT_TABLE( ToolManager, wxEvtHandler )
EVT_TIMER( wxID_ANY, ToolManager::OnTimer )
END_EVENT_TABLE()
static ToolManager::GetTopPanelHook &getTopPanelHook()
{
static ToolManager::GetTopPanelHook theHook;
return theHook;
}
auto ToolManager::SetGetTopPanelHook( const GetTopPanelHook &hook )
-> GetTopPanelHook
{
auto &theHook = getTopPanelHook();
auto result = theHook;
theHook = hook;
return result;
}
static const AudacityProject::AttachedObjects::RegisteredFactory key{
[]( AudacityProject &parent ){
auto &window = ProjectWindow::Get( parent );
return std::make_shared< ToolManager >( &parent, window.GetTopPanel() ); }
auto &window = GetProjectFrame( parent );
return std::make_shared< ToolManager >(
&parent, getTopPanelHook()( window ) ); }
};
ToolManager &ToolManager::Get( AudacityProject &project )
@ -334,7 +349,10 @@ const ToolManager &ToolManager::Get( const AudacityProject &project )
ToolManager::ToolManager( AudacityProject *parent, wxWindow *topDockParent )
: wxEvtHandler()
{
auto &window = ProjectWindow::Get( *parent );
if ( !topDockParent )
THROW_INCONSISTENCY_EXCEPTION;
auto &window = GetProjectFrame( *parent );
wxPoint pt[ 3 ];
#if defined(__WXMAC__)
@ -653,7 +671,7 @@ int ToolManager::FilterEvent(wxEvent &event)
if ( window &&
!dynamic_cast<Grabber*>( window ) &&
!dynamic_cast<ToolFrame*>( window ) &&
top == ProjectWindow::Find( mParent ) )
top == FindProjectFrame( mParent ) )
// Note this is a dangle-proof wxWindowRef:
mLastFocus = window;
}
@ -1022,6 +1040,11 @@ ToolDock *ToolManager::GetTopDock()
return mTopDock;
}
const ToolDock *ToolManager::GetTopDock() const
{
return mTopDock;
}
//
// Return a pointer to the bottom dock
//
@ -1030,6 +1053,11 @@ ToolDock *ToolManager::GetBotDock()
return mBotDock;
}
const ToolDock *ToolManager::GetBotDock() const
{
return mBotDock;
}
//
// Queues an EVT_TOOLBAR_UPDATED command event to notify any
// interest parties of an updated toolbar or dock layout
@ -1517,7 +1545,7 @@ bool ToolManager::RestoreFocus()
if (mLastFocus) {
auto temp1 = AButton::TemporarilyAllowFocus();
auto temp2 = ASlider::TemporarilyAllowFocus();
auto temp3 = MeterPanel::TemporarilyAllowFocus();
auto temp3 = MeterPanelBase::TemporarilyAllowFocus();
mLastFocus->SetFocus();
return true;
}

View File

@ -13,6 +13,8 @@
#ifndef __AUDACITY_TOOLMANAGER__
#define __AUDACITY_TOOLMANAGER__
#include <functional>
#include <wx/defs.h>
#include <wx/eventfilter.h> // to inherit
#include <wx/frame.h> // to inherit
@ -48,6 +50,9 @@ class ToolManager final
{
public:
// a hook function to break dependency of ToolManager on ProjectWindow
using GetTopPanelHook = std::function< wxWindow*( wxWindow& ) >;
static GetTopPanelHook SetGetTopPanelHook( const GetTopPanelHook& );
static ToolManager &Get( AudacityProject &project );
static const ToolManager &Get( const AudacityProject &project );
@ -68,7 +73,9 @@ class ToolManager final
ToolBar *GetToolBar( int type ) const;
ToolDock *GetTopDock();
const ToolDock *GetTopDock() const;
ToolDock *GetBotDock();
const ToolDock *GetBotDock() const;
void Reset();
void Destroy();

View File

@ -17,6 +17,7 @@ Paul Licameli split from TrackPanel.cpp
#include "../../AdornedRulerPanel.h"
#include "../../AudioIO.h"
#include "../../CommonCommandFlags.h"
#include "../../Menus.h"
#include "../../Project.h"
#include "../../ProjectAudioIO.h"

View File

@ -268,7 +268,7 @@ enum {
OnPreferencesID
};
BEGIN_EVENT_TABLE(MeterPanel, wxPanelWrapper)
BEGIN_EVENT_TABLE(MeterPanel, MeterPanelBase)
EVT_TIMER(OnMeterUpdateID, MeterPanel::OnMeterUpdate)
EVT_MOUSE_EVENTS(MeterPanel::OnMouse)
EVT_CONTEXT_MENU(MeterPanel::OnContext)
@ -2123,13 +2123,6 @@ wxString MeterPanel::Key(const wxString & key) const
return wxT("/Meter/Output/") + key;
}
bool MeterPanel::s_AcceptsFocus{ false };
auto MeterPanel::TemporarilyAllowFocus() -> TempAllowFocus {
s_AcceptsFocus = true;
return TempAllowFocus{ &s_AcceptsFocus };
}
// This compensates for a but in wxWidgets 3.0.2 for mac:
// Couldn't set focus from keyboard when AcceptsFocus returns false;
// this bypasses that limitation

View File

@ -117,9 +117,6 @@ class MeterPanel final : public MeterPanelBase, private PrefsListener
Style style = HorizontalStereo,
float fDecayRate = 60.0f);
bool AcceptsFocus() const override { return s_AcceptsFocus; }
bool AcceptsFocusFromKeyboard() const override { return true; }
void SetFocusFromKbd() override;
void Clear() override;
@ -192,13 +189,6 @@ class MeterPanel final : public MeterPanelBase, private PrefsListener
void UpdatePrefs() override;
void UpdateSelectedPrefs( int ) override;
static bool s_AcceptsFocus;
struct Resetter { void operator () (bool *p) const { if(p) *p = false; } };
using TempAllowFocus = std::unique_ptr<bool, Resetter>;
public:
static TempAllowFocus TemporarilyAllowFocus();
private:
//
// Event handlers

View File

@ -13,3 +13,10 @@ Paul Licameli split from Meter.cpp
MeterPanelBase::~MeterPanelBase()
{
}
bool MeterPanelBase::s_AcceptsFocus{ false };
auto MeterPanelBase::TemporarilyAllowFocus() -> TempAllowFocus {
s_AcceptsFocus = true;
return TempAllowFocus{ &s_AcceptsFocus };
}

View File

@ -26,7 +26,17 @@ public:
int numFrames, float *sampleData) = 0;
virtual bool IsMeterDisabled() const = 0;
virtual float GetMaxPeak() const = 0;
bool AcceptsFocus() const override { return s_AcceptsFocus; }
bool AcceptsFocusFromKeyboard() const override { return true; }
private:
static bool s_AcceptsFocus;
struct Resetter { void operator () (bool *p) const { if(p) *p = false; } };
using TempAllowFocus = std::unique_ptr<bool, Resetter>;
public:
static TempAllowFocus TemporarilyAllowFocus();
};
#endif

View File

@ -140,6 +140,7 @@
<ClCompile Include="..\..\..\src\blockfile\NotYetAvailableException.cpp" />
<ClCompile Include="..\..\..\src\CellularPanel.cpp" />
<ClCompile Include="..\..\..\src\Clipboard.cpp" />
<ClCompile Include="..\..\..\src\CommonCommandFlags.cpp" />
<ClCompile Include="..\..\..\src\CrashReport.cpp" />
<ClCompile Include="..\..\..\src\commands\AudacityCommand.cpp" />
<ClCompile Include="..\..\..\src\commands\CommandContext.cpp" />
@ -522,6 +523,7 @@
<ClInclude Include="..\..\..\src\Clipboard.h" />
<ClInclude Include="..\..\..\src\ClientData.h" />
<ClInclude Include="..\..\..\src\ClientDataHelpers.h" />
<ClInclude Include="..\..\..\src\CommonCommandFlags.h" />
<ClInclude Include="..\..\..\src\CrashReport.h" />
<ClInclude Include="..\..\..\src\commands\AudacityCommand.h" />
<ClInclude Include="..\..\..\src\commands\CommandContext.h" />

View File

@ -1148,6 +1148,9 @@
<ClCompile Include="..\..\..\src\Clipboard.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\CommonCommandFlags.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\src\CrashReport.cpp">
<Filter>src</Filter>
</ClCompile>
@ -2314,6 +2317,9 @@
<ClInclude Include="..\..\..\src\ClientDataHelpers.h">
<Filter>src</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\CommonCommandFlags.h">
<Filter>src</Filter>
</ClInclude>
<ClInclude Include="..\..\..\src\CrashReport.h">
<Filter>src</Filter>
</ClInclude>