diff --git a/src/CommonCommandFlags.cpp b/src/CommonCommandFlags.cpp index 2cb2df38b..3e2b4edd4 100644 --- a/src/CommonCommandFlags.cpp +++ b/src/CommonCommandFlags.cpp @@ -41,16 +41,16 @@ cycles. */ -// Really means, some track is selected, that isn't a time track -bool TracksSelectedPred( const AudacityProject &project ) +// Strong predicate excludes tracks that do not support basic editing. +bool EditableTracksSelectedPred( const AudacityProject &project ) { auto range = TrackList::Get( project ).Selected() - []( const Track *pTrack ){ - return track_cast( pTrack ); }; + return !pTrack->SupportsBasicEditing(); }; return !range.empty(); }; -// This predicate includes time tracks too. +// Weaker predicate. bool AnyTracksSelectedPred( const AudacityProject &project ) { auto range = TrackList::Get( project ).Selected(); @@ -177,8 +177,8 @@ const ReservedCommandFlag& CommandFlagOptions{}.DisableDefaultMessage() }; return flag; } const ReservedCommandFlag& - TracksSelectedFlag() { static ReservedCommandFlag flag{ - TracksSelectedPred, // exclude TimeTracks + EditableTracksSelectedFlag() { static ReservedCommandFlag flag{ + EditableTracksSelectedPred, { []( const TranslatableString &Name ){ return // i18n-hint: %s will be replaced by the name of an action, such as "Remove Tracks". XO("\"%s\" requires one or more tracks to be selected.").Format( Name ); @@ -186,7 +186,7 @@ const ReservedCommandFlag& }; return flag; } const ReservedCommandFlag& AnyTracksSelectedFlag() { static ReservedCommandFlag flag{ - AnyTracksSelectedPred, // Allow TimeTracks + AnyTracksSelectedPred, { []( const TranslatableString &Name ){ return // i18n-hint: %s will be replaced by the name of an action, such as "Remove Tracks". XO("\"%s\" requires one or more tracks to be selected.").Format( Name ); diff --git a/src/CommonCommandFlags.h b/src/CommonCommandFlags.h index 357aab5c0..47ea21c63 100644 --- a/src/CommonCommandFlags.h +++ b/src/CommonCommandFlags.h @@ -15,7 +15,7 @@ Paul Licameli split from Menus.cpp #include "commands/CommandFlag.h" -bool TracksSelectedPred( const AudacityProject &project ); +bool EditableTracksSelectedPred( const AudacityProject &project ); bool AudioIOBusyPred( const AudacityProject &project ); bool TimeSelectedPred( const AudacityProject &project ); extern const CommandFlagOptions &cutCopyOptions(); @@ -27,7 +27,7 @@ extern AUDACITY_DLL_API const ReservedCommandFlag &TimeSelectedFlag(), // This is equivalent to check if there is a valid selection, so it's used for Zoom to Selection too &WaveTracksSelectedFlag(), &TracksExistFlag(), - &TracksSelectedFlag(), + &EditableTracksSelectedFlag(), &AnyTracksSelectedFlag(), &TrackPanelHasFocus(); //lll diff --git a/src/SelectUtilities.cpp b/src/SelectUtilities.cpp index db0db6037..f61e6e2d0 100644 --- a/src/SelectUtilities.cpp +++ b/src/SelectUtilities.cpp @@ -85,7 +85,7 @@ void SelectAllIfNone( AudacityProject &project ) { auto &viewInfo = ViewInfo::Get( project ); auto flags = MenuManager::Get( project ).GetUpdateFlags(); - if((flags & TracksSelectedFlag()).none() || + if((flags & EditableTracksSelectedFlag()).none() || viewInfo.selectedRegion.isPoint()) DoSelectAllAudio( project ); } @@ -98,7 +98,7 @@ bool SelectAllIfNoneAndAllowed( AudacityProject &project ) auto &viewInfo = ViewInfo::Get( project ); auto flags = MenuManager::Get( project ).GetUpdateFlags(); - if((flags & TracksSelectedFlag()).none() || + if((flags & EditableTracksSelectedFlag()).none() || viewInfo.selectedRegion.isPoint()) { if (!allowed) { return false; diff --git a/src/TimeTrack.cpp b/src/TimeTrack.cpp index c163fe58d..2863ecbb8 100644 --- a/src/TimeTrack.cpp +++ b/src/TimeTrack.cpp @@ -131,6 +131,11 @@ void TimeTrack::SetRangeUpper(double upper) mEnvelope->SetRangeUpper( upper ); } +bool TimeTrack::SupportsBasicEditing() const +{ + return false; +} + Track::Holder TimeTrack::Cut( double t0, double t1 ) { auto result = Copy( t0, t1, false ); diff --git a/src/TimeTrack.h b/src/TimeTrack.h index 6125ea9a6..aa04bb424 100644 --- a/src/TimeTrack.h +++ b/src/TimeTrack.h @@ -40,6 +40,8 @@ class TimeTrack final : public Track { virtual ~TimeTrack(); + bool SupportsBasicEditing() const override; + Holder Cut( double t0, double t1 ) override; Holder Copy( double t0, double t1, bool forClipboard ) const override; void Clear(double t0, double t1) override; diff --git a/src/Track.cpp b/src/Track.cpp index cabe7246b..fb4936bfb 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -1224,6 +1224,11 @@ std::shared_ptr Track::SubstituteOriginalTrack() const return SharedPointer(); } +bool Track::SupportsBasicEditing() const +{ + return true; +} + auto Track::GetIntervals() const -> ConstIntervals { return {}; diff --git a/src/Track.h b/src/Track.h index 4ee4aebc5..e3440f290 100644 --- a/src/Track.h +++ b/src/Track.h @@ -318,6 +318,9 @@ class AUDACITY_DLL_API Track /* not final */ using ConstInterval = ConstTrackInterval; using ConstIntervals = std::vector< ConstInterval >; + //! Whether this track type implements cut-copy-paste; by default, true + virtual bool SupportsBasicEditing() const; + //! Report times on the track where important intervals begin and end, for UI to snap to /*! Some intervals may be empty, and no ordering of the intervals is assumed. diff --git a/src/menus/EditMenus.cpp b/src/menus/EditMenus.cpp index ea9eb1f80..25f0721e9 100644 --- a/src/menus/EditMenus.cpp +++ b/src/menus/EditMenus.cpp @@ -1004,7 +1004,7 @@ static const ReservedCommandFlag if ( TimeSelectedPred( project ) && - TracksSelectedPred( project ) + EditableTracksSelectedPred( project ) ) return true; @@ -1020,7 +1020,7 @@ BaseItemSharedPtr EditMenu() using Options = CommandManager::Options; static const auto NotBusyTimeAndTracksFlags = - AudioIONotBusyFlag() | TimeSelectedFlag() | TracksSelectedFlag(); + AudioIONotBusyFlag() | TimeSelectedFlag() | EditableTracksSelectedFlag(); // The default shortcut key for Redo is different on different platforms. static constexpr auto redoKey = @@ -1065,7 +1065,7 @@ BaseItemSharedPtr EditMenu() AudioIONotBusyFlag() | CutCopyAvailableFlag() | NoAutoSelect(), wxT("Ctrl+X") ), Command( wxT("Delete"), XXO("&Delete"), FN(OnDelete), - AudioIONotBusyFlag() | TracksSelectedFlag() | TimeSelectedFlag() | NoAutoSelect(), + AudioIONotBusyFlag() | EditableTracksSelectedFlag() | TimeSelectedFlag() | NoAutoSelect(), wxT("Ctrl+K") ), /* i18n-hint: (verb)*/ Command( wxT("Copy"), XXO("&Copy"), FN(OnCopy), @@ -1160,7 +1160,7 @@ BaseItemSharedPtr ExtraEditMenu() { using Options = CommandManager::Options; static const auto flags = - AudioIONotBusyFlag() | TracksSelectedFlag() | TimeSelectedFlag(); + AudioIONotBusyFlag() | EditableTracksSelectedFlag() | TimeSelectedFlag(); static BaseItemSharedPtr menu{ ( FinderScope{ findCommandHandler }, Menu( wxT("Edit"), XXO("&Edit"), @@ -1184,7 +1184,7 @@ auto selectAll = []( AudacityProject &project, CommandFlag flagsRqd ){ RegisteredMenuItemEnabler selectTracks{{ []{ return TracksExistFlag(); }, - []{ return TracksSelectedFlag(); }, + []{ return EditableTracksSelectedFlag(); }, canSelectAll, selectAll }}; diff --git a/src/menus/SelectMenus.cpp b/src/menus/SelectMenus.cpp index e96068bb2..c44900dcc 100644 --- a/src/menus/SelectMenus.cpp +++ b/src/menus/SelectMenus.cpp @@ -1059,7 +1059,7 @@ BaseItemSharedPtr SelectMenu() , Command( wxT("SelSyncLockTracks"), XXO("In All &Sync-Locked Tracks"), FN(OnSelectSyncLockSel), - TracksSelectedFlag() | IsSyncLockedFlag(), + EditableTracksSelectedFlag() | IsSyncLockedFlag(), Options{ wxT("Ctrl+Shift+Y"), XO("Select Sync-Locked") } ) #endif ), @@ -1131,7 +1131,7 @@ BaseItemSharedPtr SelectMenu() Section( "", Command( wxT("ZeroCross"), XXO("At &Zero Crossings"), - FN(OnZeroCrossing), TracksSelectedFlag(), + FN(OnZeroCrossing), EditableTracksSelectedFlag(), Options{ wxT("Z"), XO("Select Zero Crossing") } ) ) ) ) }; @@ -1216,11 +1216,11 @@ BaseItemSharedPtr CursorMenu() Command( wxT("CursTrackStart"), XXO("Track &Start"), FN(OnCursorTrackStart), - TracksSelectedFlag(), + EditableTracksSelectedFlag(), Options{ wxT("J"), XO("Cursor to Track Start") } ), Command( wxT("CursTrackEnd"), XXO("Track &End"), FN(OnCursorTrackEnd), - TracksSelectedFlag(), + EditableTracksSelectedFlag(), Options{ wxT("K"), XO("Cursor to Track End") } ), Command( wxT("CursProjectStart"), XXO("&Project Start"), diff --git a/src/menus/TrackMenus.cpp b/src/menus/TrackMenus.cpp index ab8fc7c52..0abe11d1b 100644 --- a/src/menus/TrackMenus.cpp +++ b/src/menus/TrackMenus.cpp @@ -1356,9 +1356,9 @@ BaseItemSharedPtr TracksMenu() Command( wxT("UnmuteAllTracks"), XXO("&Unmute All Tracks"), FN(OnUnmuteAllTracks), TracksExistFlag(), wxT("Ctrl+Shift+U") ), Command( wxT("MuteTracks"), XXO("Mut&e Tracks"), - FN(OnMuteSelectedTracks), TracksSelectedFlag(), wxT("Ctrl+Alt+U") ), + FN(OnMuteSelectedTracks), EditableTracksSelectedFlag(), wxT("Ctrl+Alt+U") ), Command( wxT("UnmuteTracks"), XXO("U&nmute Tracks"), - FN(OnUnmuteSelectedTracks), TracksSelectedFlag(), wxT("Ctrl+Alt+Shift+U") ) + FN(OnUnmuteSelectedTracks), EditableTracksSelectedFlag(), wxT("Ctrl+Alt+Shift+U") ) ), Menu( wxT("Pan"), XXO("&Pan"), @@ -1367,13 +1367,13 @@ BaseItemSharedPtr TracksMenu() // in the project could very easily be lost unless we // require the tracks to be selected. Command( wxT("PanLeft"), XXO("&Left"), FN(OnPanLeft), - TracksSelectedFlag(), + EditableTracksSelectedFlag(), Options{}.LongName( XO("Pan Left") ) ), Command( wxT("PanRight"), XXO("&Right"), FN(OnPanRight), - TracksSelectedFlag(), + EditableTracksSelectedFlag(), Options{}.LongName( XO("Pan Right") ) ), Command( wxT("PanCenter"), XXO("&Center"), FN(OnPanCenter), - TracksSelectedFlag(), + EditableTracksSelectedFlag(), Options{}.LongName( XO("Pan Center") ) ) ) ), @@ -1387,14 +1387,14 @@ BaseItemSharedPtr TracksMenu() { wxT("EndToEnd"), XXO("&Align End to End") }, { wxT("Together"), XXO("Align &Together") }, }, - FN(OnAlignNoSync), AudioIONotBusyFlag() | TracksSelectedFlag()) + FN(OnAlignNoSync), AudioIONotBusyFlag() | EditableTracksSelectedFlag()) ), Section( "", // Alignment commands using selection or zero CommandGroup(wxT("Align"), alignLabels(), - FN(OnAlign), AudioIONotBusyFlag() | TracksSelectedFlag()) + FN(OnAlign), AudioIONotBusyFlag() | EditableTracksSelectedFlag()) ), Section( "", @@ -1411,7 +1411,7 @@ BaseItemSharedPtr TracksMenu() // Do we need this sub-menu at all? Menu( wxT("MoveSelectionAndTracks"), XO("Move Sele&ction and Tracks"), { CommandGroup(wxT("AlignMove"), alignLabels(), - FN(OnAlignMoveSel), AudioIONotBusyFlag() | TracksSelectedFlag()), + FN(OnAlignMoveSel), AudioIONotBusyFlag() | EditableTracksSelectedFlag()), } ), #endif