From 329221b3925ae0b1d6ee77a9e2fe81711560cb38 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sat, 12 Sep 2020 12:49:02 -0400 Subject: [PATCH] Lower more into Init(); ClipMenus uses ClipMoveState opaquely --- src/menus/ClipMenus.cpp | 42 +++++++----- src/tracks/ui/TimeShiftHandle.cpp | 108 +++++++++++++++++------------- src/tracks/ui/TimeShiftHandle.h | 27 ++++---- 3 files changed, 103 insertions(+), 74 deletions(-) diff --git a/src/menus/ClipMenus.cpp b/src/menus/ClipMenus.cpp index 733d886b2..63d9d5d09 100644 --- a/src/menus/ClipMenus.cpp +++ b/src/menus/ClipMenus.cpp @@ -639,22 +639,25 @@ double DoClipMove auto t0 = selectedRegion.t0(); + std::unique_ptr uShifter; + // Find the first channel that has a clip at time t0 for (auto channel : TrackList::Channels(wt) ) { - if( nullptr != (state.capturedClip = channel->GetClipAtTime( t0 )) ) { + uShifter = MakeTrackShifter::Call( *wt ); + if( uShifter->HitTest( t0 ) == TrackShifter::HitTestResult::Miss ) + uShifter.reset(); + else { wt = channel; break; } } - if (state.capturedClip == nullptr) + if (!uShifter) return 0.0; + auto pShifter = uShifter.get(); - state.capturedClipIsSelection = - track->GetSelected() && !selectedRegion.isPoint(); - - TimeShiftHandle::Init( - state, viewInfo, *track, trackList, syncLocked, t0 ); + state.Init( *track, std::move( uShifter ), + t0, viewInfo, trackList, syncLocked ); auto desiredT0 = viewInfo.OffsetTimeByPixels( t0, ( right ? 1 : -1 ) ); auto desiredSlideAmount = desiredT0 - t0; @@ -668,21 +671,26 @@ double DoClipMove if (!right) desiredSlideAmount *= -1; - state.hSlideAmount = desiredSlideAmount; - TimeShiftHandle::DoSlideHorizontal( state, trackList, *track ); + auto hSlideAmount = state.DoSlideHorizontal( + desiredSlideAmount, trackList, *track ); // update t0 and t1. There is the possibility that the updated // t0 may no longer be within the clip due to rounding errors, // so t0 is adjusted so that it is. - double newT0 = t0 + state.hSlideAmount; - if (newT0 < state.capturedClip->GetStartTime()) - newT0 = state.capturedClip->GetStartTime(); - if (newT0 > state.capturedClip->GetEndTime()) - newT0 = state.capturedClip->GetEndTime(); - double diff = selectedRegion.duration(); - selectedRegion.setTimes(newT0, newT0 + diff); + double newT0 = t0 + hSlideAmount; + // pShifter is still undestroyed in the ClipMoveState + auto &intervals = pShifter->MovingIntervals(); + if ( !intervals.empty() ) { + auto &interval = intervals[0]; + if (newT0 < interval.Start()) + newT0 = interval.Start(); + if (newT0 > interval.End()) + newT0 = interval.End(); + double diff = selectedRegion.duration(); + selectedRegion.setTimes(newT0, newT0 + diff); + } - return state.hSlideAmount; + return hSlideAmount; } ); return 0.0; } diff --git a/src/tracks/ui/TimeShiftHandle.cpp b/src/tracks/ui/TimeShiftHandle.cpp index 4ab1e987a..7ea7e3ee6 100644 --- a/src/tracks/ui/TimeShiftHandle.cpp +++ b/src/tracks/ui/TimeShiftHandle.cpp @@ -304,19 +304,57 @@ template<> auto MakeTrackShifter::Implementation() -> Function { }; } -void TimeShiftHandle::Init - ( ClipMoveState &state, const ViewInfo &viewInfo, Track &capturedTrack, - TrackList &trackList, bool syncLocked, double clickTime, - bool capturedAClip ) +void ClipMoveState::Init( + Track &capturedTrack, + std::unique_ptr pHit, + double clickTime, + const ViewInfo &viewInfo, + TrackList &trackList, bool syncLocked ) { + capturedClipArray.clear(); + shifters.clear(); + auto cleanup = finally([&]{ + // In transition, this class holds two representations of what to shift. + // Be sure each is filled only if the other is. + wxASSERT( capturedClipArray.empty() == shifters.empty() ); + }); + + auto &state = *this; + + state.movingSelection = capturedTrack.IsSelected() && + clickTime >= viewInfo.selectedRegion.t0() && + clickTime < viewInfo.selectedRegion.t1(); + + if (!pHit) + return; + + const bool capturedAClip = + pHit && !pHit->MovingIntervals().empty(); + if ( capturedAClip ) { + // There is still some code special to WaveTracks here that + // needs to go elsewhere + auto &interval = pHit->MovingIntervals()[0]; + auto pInfo = + dynamic_cast(interval.Extra()); + if ( pInfo ) + state.capturedClip = pInfo->GetClip().get(); + } + + state.shifters[&capturedTrack] = std::move( pHit ); + + // Collect TrackShifters for the rest of the tracks + for ( auto track : trackList.Any() ) { + auto &pShifter = state.shifters[track]; + if (!pShifter) + pShifter = MakeTrackShifter::Call( *track ); + } + // The captured clip is the focus, but we need to create a list // of all clips that have to move, also... - state.capturedClipArray.clear(); - // First, if click was in selection, capture selected clips; otherwise // just the clicked-on clip - if ( state.capturedClipIsSelection ) + if ( state.movingSelection ) // All selected tracks may move some intervals for (auto t : trackList.Selected()) AddClipsToCaptured( state, viewInfo, t ); @@ -372,7 +410,7 @@ void TimeShiftHandle::Init // Analogy of the steps above, but with TrackShifters, follows below - if ( state.capturedClipIsSelection ) { + if ( state.movingSelection ) { // All selected tracks may move some intervals const TrackInterval interval{ viewInfo.selectedRegion.t0(), @@ -435,9 +473,12 @@ void TimeShiftHandle::Init } } -void TimeShiftHandle::DoSlideHorizontal - ( ClipMoveState &state, TrackList &trackList, Track &capturedTrack ) +double ClipMoveState::DoSlideHorizontal( + double desiredSlideAmount, TrackList &trackList, Track &capturedTrack ) { + auto &state = *this; + state.hSlideAmount = desiredSlideAmount; + // Given a signed slide distance, move clips, but subject to constraint of // non-overlapping with other clips, so the distance may be adjusted toward // zero. @@ -486,6 +527,8 @@ void TimeShiftHandle::DoSlideHorizontal // For Shift key down, or // For non wavetracks, specifically label tracks ... DoOffset( state, &capturedTrack, state.hSlideAmount ); + + return state.hSlideAmount; } namespace { @@ -536,16 +579,11 @@ UIHandle::Result TimeShiftHandle::Click const double clickTime = viewInfo.PositionToTime(event.m_x, rect.x); - mClipMoveState.capturedClipIsSelection = - (pTrack->GetSelected() && - clickTime >= viewInfo.selectedRegion.t0() && - clickTime < viewInfo.selectedRegion.t1()); mClipMoveState.capturedClip = NULL; mClipMoveState.capturedClipArray.clear(); bool captureClips = false; - bool capturedAClip = false; auto pShifter = MakeTrackShifter::Call( *pTrack ); @@ -555,17 +593,6 @@ UIHandle::Result TimeShiftHandle::Click return Cancelled; case TrackShifter::HitTestResult::Intervals: { captureClips = true; - if ( !pShifter->MovingIntervals().empty() ) { - capturedAClip = true; - - // There is still some code special to WaveTracks here that - // needs to go elsewhere - auto &interval = pShifter->MovingIntervals()[0]; - auto pInfo = - dynamic_cast(interval.Extra()); - if ( pInfo ) - mClipMoveState.capturedClip = pInfo->GetClip().get(); - } break; } case TrackShifter::HitTestResult::Track: @@ -577,20 +604,12 @@ UIHandle::Result TimeShiftHandle::Click // As in the default above: just do shifting of one whole track } - if ( captureClips ) { - mClipMoveState.shifters[pTrack] = std::move( pShifter ); + mClipMoveState.Init( *pTrack, + captureClips ? std::move( pShifter ) : nullptr, + clickTime, - // Collect TrackShifters for the rest of the tracks - for ( auto track : trackList.Any() ) { - auto &pShifter = mClipMoveState.shifters[track]; - if (!pShifter) - pShifter = MakeTrackShifter::Call( *track ); - } - - Init( - mClipMoveState, viewInfo, *pTrack, trackList, - ProjectSettings::Get( *pProject ).IsSyncLocked(), clickTime, capturedAClip ); - } + viewInfo, trackList, + ProjectSettings::Get( *pProject ).IsSyncLocked() ); mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive; mRect = rect; @@ -836,7 +855,7 @@ bool TimeShiftHandle::DoSlideVertical // Make the offset permanent; start from a "clean slate" if( ok ) { state.mMouseClickX = xx; - if (state.capturedClipIsSelection) { + if (state.movingSelection) { // Slide the selection, too viewInfo.selectedRegion.move( slide ); } @@ -897,7 +916,7 @@ UIHandle::Result TimeShiftHandle::Drag DoOffset( mClipMoveState, mCapturedTrack.get(), -mClipMoveState.hSlideAmount ); - if ( mClipMoveState.capturedClipIsSelection ) { + if ( mClipMoveState.movingSelection ) { // Slide the selection, too viewInfo.selectedRegion.move( -mClipMoveState.hSlideAmount ); } @@ -939,11 +958,10 @@ UIHandle::Result TimeShiftHandle::Drag if (desiredSlideAmount == 0.0) return RefreshAll; - mClipMoveState.hSlideAmount = desiredSlideAmount; + mClipMoveState.DoSlideHorizontal( + desiredSlideAmount, trackList, *mCapturedTrack ); - DoSlideHorizontal( mClipMoveState, trackList, *mCapturedTrack ); - - if (mClipMoveState.capturedClipIsSelection) { + if (mClipMoveState.movingSelection) { // Slide the selection, too viewInfo.selectedRegion.move( mClipMoveState.hSlideAmount ); } diff --git a/src/tracks/ui/TimeShiftHandle.h b/src/tracks/ui/TimeShiftHandle.h index 5f0fdd220..f1106ab23 100644 --- a/src/tracks/ui/TimeShiftHandle.h +++ b/src/tracks/ui/TimeShiftHandle.h @@ -122,10 +122,23 @@ using TrackClipArray = std::vector ; struct ClipMoveState { using ShifterMap = std::unordered_map>; + //! Will associate a TrackShifter with each track in the list + void Init( + Track &capturedTrack, // pHit, /*!< + If null, only capturedTrack (with any sister channels) shifts, as a whole */ + double clickTime, + const ViewInfo &viewInfo, + TrackList &trackList, bool syncLocked ); + + /*! @return actual slide amount, maybe adjusted toward zero from desired */ + double DoSlideHorizontal( + double desiredSlideAmount, TrackList &trackList, Track &capturedTrack ); + // non-NULL only if click was in a WaveTrack and without Shift key: WaveClip *capturedClip {}; - bool capturedClipIsSelection {}; + bool movingSelection {}; double hSlideAmount {}; ShifterMap shifters; TrackClipArray capturedClipArray {}; @@ -136,7 +149,7 @@ struct ClipMoveState { void clear() { capturedClip = nullptr; - capturedClipIsSelection = false; + movingSelection = false; hSlideAmount = 0; shifters.clear(); capturedClipArray.clear(); @@ -160,16 +173,6 @@ public: bool IsGripHit() const { return mGripHit; } std::shared_ptr GetTrack() const { return mCapturedTrack; } - // A utility function also used by menu commands - static void Init - ( ClipMoveState &state, const ViewInfo &viewInfo, Track &capturedTrack, - TrackList &trackList, bool syncLocked, double clickTime, - bool capturedAClip = true ); - - // A utility function also used by menu commands - static void DoSlideHorizontal - ( ClipMoveState &state, TrackList &trackList, Track &capturedTrack ); - // Try to move clips from one WaveTrack to another, before also moving // by some horizontal amount, which may be slightly adjusted to fit the // destination tracks.