diff --git a/src/tracks/playabletrack/notetrack/ui/NoteTrackView.cpp b/src/tracks/playabletrack/notetrack/ui/NoteTrackView.cpp index 655d2631d..09f4dc42f 100644 --- a/src/tracks/playabletrack/notetrack/ui/NoteTrackView.cpp +++ b/src/tracks/playabletrack/notetrack/ui/NoteTrackView.cpp @@ -729,4 +729,27 @@ void NoteTrackView::Draw( } CommonTrackView::Draw( context, rect, iPass ); } + +#include "../../../ui/TimeShiftHandle.h" + +class NoteTrackShifter final : public TrackShifter { +public: + NoteTrackShifter( NoteTrack &track ) + : mpTrack{ track.SharedPointer() } + {} + ~NoteTrackShifter() override {} + Track &GetTrack() const override { return *mpTrack; } + +private: + std::shared_ptr mpTrack; +}; + +using MakeNoteTrackShifter = MakeTrackShifter::Override; +template<> template<> auto MakeNoteTrackShifter::Implementation() -> Function { + return [](NoteTrack &track) { + return std::make_unique(track); + }; +} +static MakeNoteTrackShifter registerMakeNoteTrackShifter; + #endif diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp b/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp index 892a1b1cf..8739a62dd 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp +++ b/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp @@ -1301,3 +1301,24 @@ void WaveTrackView::Draw( CommonTrackView::Draw( context, rect, iPass ); } + +class WaveTrackShifter final : public TrackShifter { +public: + WaveTrackShifter( WaveTrack &track ) + : mpTrack{ track.SharedPointer() } + { + } + ~WaveTrackShifter() override {} + Track &GetTrack() const override { return *mpTrack; } + +private: + std::shared_ptr mpTrack; +}; + +using MakeWaveTrackShifter = MakeTrackShifter::Override; +template<> template<> auto MakeWaveTrackShifter::Implementation() -> Function { + return [](WaveTrack &track) { + return std::make_unique(track); + }; +} +static MakeWaveTrackShifter registerMakeWaveTrackShifter; diff --git a/src/tracks/ui/TimeShiftHandle.cpp b/src/tracks/ui/TimeShiftHandle.cpp index 17ebcc2a7..acc58dbd9 100644 --- a/src/tracks/ui/TimeShiftHandle.cpp +++ b/src/tracks/ui/TimeShiftHandle.cpp @@ -244,6 +244,20 @@ namespace } } +TrackShifter::~TrackShifter() = default; + +CoarseTrackShifter::CoarseTrackShifter( Track &track ) + : mpTrack{ track.SharedPointer() } +{} + +CoarseTrackShifter::~CoarseTrackShifter() = default; + +template<> auto MakeTrackShifter::Implementation() -> Function { + return [](Track &track) { + return std::make_unique(track); + }; +} + void TimeShiftHandle::CreateListOfCapturedClips ( ClipMoveState &state, const ViewInfo &viewInfo, Track &capturedTrack, TrackList &trackList, bool syncLocked, double clickTime ) @@ -456,6 +470,8 @@ UIHandle::Result TimeShiftHandle::Click bool ok = true; bool captureClips = false; + auto pShifter = MakeTrackShifter::Call( *pTrack ); + if (!event.ShiftDown()) pTrack->TypeSwitch( [&](WaveTrack *wt) { @@ -474,10 +490,21 @@ UIHandle::Result TimeShiftHandle::Click if ( ! ok ) return Cancelled; - else if ( captureClips ) + + if ( captureClips ) { + mClipMoveState.shifters[pTrack] = std::move( pShifter ); + + // Collect TrackShifters for the rest of the tracks + for ( auto track : trackList.Any() ) { + auto &pShifter = mClipMoveState.shifters[track]; + if (!pShifter) + pShifter = MakeTrackShifter::Call( *track ); + } + CreateListOfCapturedClips( mClipMoveState, viewInfo, *pTrack, trackList, ProjectSettings::Get( *pProject ).IsSyncLocked(), clickTime ); + } mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive; mRect = rect; diff --git a/src/tracks/ui/TimeShiftHandle.h b/src/tracks/ui/TimeShiftHandle.h index 7c3ec0c0a..8e68354ba 100644 --- a/src/tracks/ui/TimeShiftHandle.h +++ b/src/tracks/ui/TimeShiftHandle.h @@ -11,12 +11,41 @@ Paul Licameli #ifndef __AUDACITY_TIMESHIFT_HANDLE__ #define __AUDACITY_TIMESHIFT_HANDLE__ +#include + +#include "../../AttachedVirtualFunction.h" #include "../../UIHandle.h" class SnapManager; class Track; using TrackArray = std::vector; class TrackList; + +class Track; + +//! Abstract base class for policies to manipulate a track type with the Time Shift tool +class TrackShifter { +public: + virtual ~TrackShifter() = 0; + //! There is always an associated track + virtual Track &GetTrack() const = 0; +}; + +//! Used in default of other reimplementations to shift any track as a whole, invoking Track::Offset() +class CoarseTrackShifter final : public TrackShifter { +public: + CoarseTrackShifter( Track &track ); + ~CoarseTrackShifter() override; + Track &GetTrack() const override { return *mpTrack; } + +private: + std::shared_ptr mpTrack; +}; + +struct MakeTrackShifterTag; +using MakeTrackShifter = AttachedVirtualFunction< + MakeTrackShifterTag, std::unique_ptr, Track>; + class ViewInfo; class WaveClip; class WaveTrack; @@ -40,12 +69,15 @@ public: using TrackClipArray = std::vector ; struct ClipMoveState { + using ShifterMap = std::unordered_map>; + // non-NULL only if click was in a WaveTrack and without Shift key: WaveClip *capturedClip {}; bool capturedClipIsSelection {}; TrackArray trackExclusions {}; double hSlideAmount {}; + ShifterMap shifters; TrackClipArray capturedClipArray {}; wxInt64 snapLeft { -1 }, snapRight { -1 }; @@ -57,6 +89,7 @@ struct ClipMoveState { capturedClipIsSelection = false; trackExclusions.clear(); hSlideAmount = 0; + shifters.clear(); capturedClipArray.clear(); snapLeft = snapRight = -1; mMouseClickX = 0; @@ -73,7 +106,7 @@ public: explicit TimeShiftHandle ( const std::shared_ptr &pTrack, bool gripHit ); - TimeShiftHandle &operator=(const TimeShiftHandle&) = default; + TimeShiftHandle &operator=(TimeShiftHandle&&) = default; bool IsGripHit() const { return mGripHit; } std::shared_ptr GetTrack() const { return mCapturedTrack; }