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:
parent
36e3a03c7f
commit
705b4b28e7
@ -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;
|
||||
|
@ -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 ®ion, const wxString &title = {},
|
||||
|
315
src/Menus.cpp
315
src/Menus.cpp
@ -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 )
|
||||
|
@ -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
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
// recovery file
|
||||
void SetProjectTitle( int number = -1 );
|
||||
|
||||
bool IsProjectSaved();
|
||||
bool IsProjectSaved() const;
|
||||
|
||||
void Reset();
|
||||
|
||||
|
@ -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 );
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -824,7 +824,7 @@ void ControlToolBar::OnStop(wxCommandEvent & WXUNUSED(evt))
|
||||
}
|
||||
}
|
||||
|
||||
bool ControlToolBar::CanStopAudioStream()
|
||||
bool ControlToolBar::CanStopAudioStream() const
|
||||
{
|
||||
auto gAudioIO = AudioIO::Get();
|
||||
return (!gAudioIO->IsStreamActive() ||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user