1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-28 14:18:41 +02:00

Register a predicate with each CommandFlag bit

This commit is contained in:
Paul Licameli 2019-06-08 20:35:21 -04:00
parent 36e3a03c7f
commit 705b4b28e7
14 changed files with 308 additions and 57 deletions

View File

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

View File

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

View File

@ -30,6 +30,8 @@
#include "Experimental.h" #include "Experimental.h"
#include <wx/frame.h>
#include "AdornedRulerPanel.h" #include "AdornedRulerPanel.h"
#include "AudioIO.h" #include "AudioIO.h"
#include "LabelTrack.h" #include "LabelTrack.h"
@ -414,55 +416,286 @@ CommandFlag MenuManager::GetFocusedFrame(AudacityProject &project)
} }
ReservedCommandFlag::ReservedCommandFlag() // Really means, some track is selected, that isn't a time track
const auto TracksSelectedPred =
[](const AudacityProject &project){
auto range = TrackList::Get( project ).Selected()
- []( const Track *pTrack ){
return track_cast<const TimeTrack*>( pTrack ); };
return !range.empty();
};
const auto AudioIOBusyPred =
[](const AudacityProject &project ){
return AudioIOBase::Get()->IsAudioTokenActive(
ProjectAudioIO::Get( project ).GetAudioIOToken());
};
const auto 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();
};
namespace{
using Predicates = std::vector< ReservedCommandFlag::Predicate >;
Predicates &RegisteredPredicates()
{
static Predicates thePredicates;
return thePredicates;
}
}
ReservedCommandFlag::ReservedCommandFlag( const Predicate &predicate )
{ {
static size_t sNextReservedFlag = 0; static size_t sNextReservedFlag = 0;
// This will throw std::out_of_range if the constant NCommandFlags is too // This will throw std::out_of_range if the constant NCommandFlags is too
// small // small
set( sNextReservedFlag++ ); set( sNextReservedFlag++ );
RegisteredPredicates().emplace_back( predicate );
} }
const ReservedCommandFlag const ReservedCommandFlag
AudioIONotBusyFlag, AudioIONotBusyFlag{
TimeSelectedFlag, // This is equivalent to check if there is a valid selection, so it's used for Zoom to Selection too [](const AudacityProject &project ){
TracksSelectedFlag, return !AudioIOBusyPred( project );
TracksExistFlag, }
LabelTracksExistFlag, },
WaveTracksSelectedFlag, TimeSelectedFlag{
ClipboardFlag, TimeSelectedPred
TextClipFlag, // Same as Clipboard flag for now. },
UnsavedChangesFlag, TracksSelectedFlag{
HasLastEffectFlag, TracksSelectedPred
UndoAvailableFlag, },
RedoAvailableFlag, TracksExistFlag{
ZoomInAvailableFlag, [](const AudacityProject &project){
ZoomOutAvailableFlag, return !TrackList::Get( project ).Any().empty();
StereoRequiredFlag, //lda }
TopDockHasFocus, //lll },
TrackPanelHasFocus, //lll LabelTracksExistFlag{
BotDockHasFocus, //lll [](const AudacityProject &project){
LabelsSelectedFlag, return !TrackList::Get( project ).Any<const LabelTrack>().empty();
AudioIOBusyFlag, //lll }
PlayRegionLockedFlag, //msmeyer },
PlayRegionNotLockedFlag, //msmeyer WaveTracksSelectedFlag{
CutCopyAvailableFlag, [](const AudacityProject &project){
WaveTracksExistFlag, return !TrackList::Get( project ).Selected<const WaveTrack>().empty();
NoteTracksExistFlag, //gsw }
NoteTracksSelectedFlag, //gsw },
HaveRecentFiles, UnsavedChangesFlag{
IsNotSyncLockedFlag, //awd [](const AudacityProject &project){
IsSyncLockedFlag, //awd auto &undoManager = UndoManager::Get( project );
IsRealtimeNotActiveFlag, //lll return
CaptureNotBusyFlag, undoManager.UnsavedChanges()
CanStopAudioStreamFlag, ||
RulerHasFocus, // prl !ProjectFileIO::Get( project ).IsProjectSaved()
NotMinimizedFlag, // prl ;
PausedFlag, // jkc }
NotPausedFlag, // jkc },
HasWaveDataFlag, // jkc HasLastEffectFlag{
PlayableTracksExistFlag, [](const AudacityProject &project){
AudioTracksSelectedFlag, return !MenuManager::Get( project ).mLastEffect.empty();
NoAutoSelect // jkc }
},
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()
;
}
},
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();
}
}, //lda
TrackPanelHasFocus{
[](const AudacityProject &project){
for (auto w = wxWindow::FindFocus(); w; w = w->GetParent()) {
if (dynamic_cast<const NonKeystrokeInterceptingWindow*>(w))
return true;
}
return false;
}
}, //lll
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();
}
},
AudioIOBusyFlag{
AudioIOBusyPred
}, //lll
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
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;
}
},
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
IsRealtimeNotActiveFlag{
[](const AudacityProject &){
return !EffectManager::Get().RealtimeIsActive();
}
}, //lll
CaptureNotBusyFlag{
[](const AudacityProject &){
auto gAudioIO = AudioIO::Get();
return !(
gAudioIO->IsBusy() &&
gAudioIO->GetNumCaptureChannels() > 0
);
}
},
CanStopAudioStreamFlag{
[](const AudacityProject &project){
return ControlToolBar::Get( project ).CanStopAudioStream();
}
},
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()
);
}
}, // prl
PausedFlag{
[](const AudacityProject&){
return AudioIOBase::Get()->IsPaused();
}
},
HasWaveDataFlag{
[](const AudacityProject &project){
auto range = TrackList::Get( project ).Any<const WaveTrack>()
+ [](const WaveTrack *pTrack){
return pTrack->GetEndTime() > pTrack->GetStartTime();
};
return !range.empty();
}
}, // jkc
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 false; }
} // jkc
; ;
CommandFlag MenuManager::GetUpdateFlags( bool checkActive ) CommandFlag MenuManager::GetUpdateFlags( bool checkActive )

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,6 +12,9 @@
// Flags used in command handling. // Flags used in command handling.
#include <bitset> #include <bitset>
#include <functional>
class AudacityProject;
// Increase the template parameter as needed to allow more flags // Increase the template parameter as needed to allow more flags
constexpr size_t NCommandFlags = 64; constexpr size_t NCommandFlags = 64;
@ -30,10 +33,12 @@ constexpr CommandFlag
NoFlagsSpecified{ ~0ULL }; // all ones NoFlagsSpecified{ ~0ULL }; // all ones
// Construct one statically to register (and reserve) a bit position in the set // Construct one statically to register (and reserve) a bit position in the set
// an associate it with a test function
class ReservedCommandFlag : public CommandFlag class ReservedCommandFlag : public CommandFlag
{ {
public: public:
ReservedCommandFlag(); using Predicate = std::function< bool( const AudacityProject& ) >;
ReservedCommandFlag( const Predicate & );
}; };
// Widely used command flags, but this list need not be exhaustive. It may be // Widely used command flags, but this list need not be exhaustive. It may be

View File

@ -824,7 +824,7 @@ void ControlToolBar::OnStop(wxCommandEvent & WXUNUSED(evt))
} }
} }
bool ControlToolBar::CanStopAudioStream() bool ControlToolBar::CanStopAudioStream() const
{ {
auto gAudioIO = AudioIO::Get(); auto gAudioIO = AudioIO::Get();
return (!gAudioIO->IsStreamActive() || return (!gAudioIO->IsStreamActive() ||

View File

@ -99,7 +99,7 @@ class ControlToolBar final : public ToolBar {
bool IsRecordDown() const; bool IsRecordDown() const;
// A project is only allowed to stop an audio stream that it owns. // 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 currently selected region, or if nothing selected,
// play from current cursor. // play from current cursor.

View File

@ -1022,6 +1022,11 @@ ToolDock *ToolManager::GetTopDock()
return mTopDock; return mTopDock;
} }
const ToolDock *ToolManager::GetTopDock() const
{
return mTopDock;
}
// //
// Return a pointer to the bottom dock // Return a pointer to the bottom dock
// //
@ -1030,6 +1035,11 @@ ToolDock *ToolManager::GetBotDock()
return mBotDock; return mBotDock;
} }
const ToolDock *ToolManager::GetBotDock() const
{
return mBotDock;
}
// //
// Queues an EVT_TOOLBAR_UPDATED command event to notify any // Queues an EVT_TOOLBAR_UPDATED command event to notify any
// interest parties of an updated toolbar or dock layout // interest parties of an updated toolbar or dock layout

View File

@ -68,7 +68,9 @@ class ToolManager final
ToolBar *GetToolBar( int type ) const; ToolBar *GetToolBar( int type ) const;
ToolDock *GetTopDock(); ToolDock *GetTopDock();
const ToolDock *GetTopDock() const;
ToolDock *GetBotDock(); ToolDock *GetBotDock();
const ToolDock *GetBotDock() const;
void Reset(); void Reset();
void Destroy(); void Destroy();