1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-02 16:49: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);
}
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

@ -30,6 +30,8 @@
#include "Experimental.h"
#include <wx/frame.h>
#include "AdornedRulerPanel.h"
#include "AudioIO.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;
// This will throw std::out_of_range if the constant NCommandFlags is too
// small
set( sNextReservedFlag++ );
RegisteredPredicates().emplace_back( predicate );
}
const ReservedCommandFlag
AudioIONotBusyFlag,
TimeSelectedFlag, // This is equivalent to check if there is a valid selection, so it's used for Zoom to Selection too
TracksSelectedFlag,
TracksExistFlag,
LabelTracksExistFlag,
WaveTracksSelectedFlag,
ClipboardFlag,
TextClipFlag, // Same as Clipboard flag for now.
UnsavedChangesFlag,
HasLastEffectFlag,
UndoAvailableFlag,
RedoAvailableFlag,
ZoomInAvailableFlag,
ZoomOutAvailableFlag,
StereoRequiredFlag, //lda
TopDockHasFocus, //lll
TrackPanelHasFocus, //lll
BotDockHasFocus, //lll
LabelsSelectedFlag,
AudioIOBusyFlag, //lll
PlayRegionLockedFlag, //msmeyer
PlayRegionNotLockedFlag, //msmeyer
CutCopyAvailableFlag,
WaveTracksExistFlag,
NoteTracksExistFlag, //gsw
NoteTracksSelectedFlag, //gsw
HaveRecentFiles,
IsNotSyncLockedFlag, //awd
IsSyncLockedFlag, //awd
IsRealtimeNotActiveFlag, //lll
CaptureNotBusyFlag,
CanStopAudioStreamFlag,
RulerHasFocus, // prl
NotMinimizedFlag, // prl
PausedFlag, // jkc
NotPausedFlag, // jkc
HasWaveDataFlag, // jkc
PlayableTracksExistFlag,
AudioTracksSelectedFlag,
NoAutoSelect // jkc
AudioIONotBusyFlag{
[](const AudacityProject &project ){
return !AudioIOBusyPred( project );
}
},
TimeSelectedFlag{
TimeSelectedPred
},
TracksSelectedFlag{
TracksSelectedPred
},
TracksExistFlag{
[](const AudacityProject &project){
return !TrackList::Get( project ).Any().empty();
}
},
LabelTracksExistFlag{
[](const AudacityProject &project){
return !TrackList::Get( project ).Any<const LabelTrack>().empty();
}
},
WaveTracksSelectedFlag{
[](const AudacityProject &project){
return !TrackList::Get( project ).Selected<const WaveTrack>().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()
;
}
},
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 )

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

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

@ -12,6 +12,9 @@
// Flags used in command handling.
#include <bitset>
#include <functional>
class AudacityProject;
// Increase the template parameter as needed to allow more flags
constexpr size_t NCommandFlags = 64;
@ -30,10 +33,12 @@ constexpr CommandFlag
NoFlagsSpecified{ ~0ULL }; // all ones
// Construct one statically to register (and reserve) a bit position in the set
// an associate it with a test function
class ReservedCommandFlag : public CommandFlag
{
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

View File

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

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.

View File

@ -1022,6 +1022,11 @@ ToolDock *ToolManager::GetTopDock()
return mTopDock;
}
const ToolDock *ToolManager::GetTopDock() const
{
return mTopDock;
}
//
// Return a pointer to the bottom dock
//
@ -1030,6 +1035,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

View File

@ -68,7 +68,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();