diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index e2a0547eb..e7568a411 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -2372,13 +2372,32 @@ bool WaveTrack::CanOffsetClip(WaveClip* clip, double amount, return true; } -bool WaveTrack::CanInsertClip(WaveClip* clip, double slideBy) +bool WaveTrack::CanInsertClip(WaveClip* clip, double &slideBy, double &tolerance) { for (const auto &c : mClips) { - if (c->GetStartTime() < (clip->GetEndTime()+slideBy) && - c->GetEndTime() > (clip->GetStartTime()+slideBy)) - return false; // clips overlap + double d1 = c->GetStartTime() - (clip->GetEndTime()+slideBy); + double d2 = (clip->GetStartTime()+slideBy) - c->GetEndTime(); + if ( (d1<0) && (d2<0) ) + { + // clips overlap. + // Try to rescue it. + // The rescue logic is not perfect, but + // a) will not move the clip by more than once + // b) is OK in simple scenarios. + if( -d1 < tolerance ){ + slideBy +=d1; + d2 += d1; + tolerance /=1000; + } + + if( -d2 < tolerance ){ + slideBy -= d2; + tolerance /=1000; + } + else + return false; // clips overlap No tolerance left. + } } return true; diff --git a/src/WaveTrack.h b/src/WaveTrack.h index b69b46933..73dd722bf 100644 --- a/src/WaveTrack.h +++ b/src/WaveTrack.h @@ -491,7 +491,7 @@ class AUDACITY_DLL_API WaveTrack final : public PlayableTrack { // Before moving a clip into a track (or inserting a clip), use this // function to see if the times are valid (i.e. don't overlap with // existing clips). - bool CanInsertClip(WaveClip* clip, double slideBy=0.0); + bool CanInsertClip(WaveClip* clip, double &slideBy, double &tolerance); // Remove the clip from the track and return a SMART pointer to it. // You assume responsibility for its memory! diff --git a/src/tracks/ui/TimeShiftHandle.cpp b/src/tracks/ui/TimeShiftHandle.cpp index a42a85f93..0f89cad5c 100644 --- a/src/tracks/ui/TimeShiftHandle.cpp +++ b/src/tracks/ui/TimeShiftHandle.cpp @@ -707,25 +707,39 @@ UIHandle::Result TimeShiftHandle::Drag // Now check that the move is possible bool ok = true; + // The test for tolerance will need review with FishEye! + // The tolerance is supposed to be the time for one pixel, i.e. one pixel tolerance + // at current zoom. + double slide = desiredSlideAmount; // remember amount requested. + double tolerance = viewInfo.PositionToTime(event.m_x+1) - viewInfo.PositionToTime(event.m_x+1); + + // The desiredSlideAmount may change and the tolerance may get used up. for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size(); ok && ii < nn; ++ii) { TrackClip &trackClip = mClipMoveState.capturedClipArray[ii]; WaveClip *const pSrcClip = trackClip.clip; if (pSrcClip) - ok = trackClip.dstTrack->CanInsertClip(pSrcClip, desiredSlideAmount); + ok = trackClip.dstTrack->CanInsertClip(pSrcClip, desiredSlideAmount, tolerance); } if (!ok) { + // Failure, even with using tolerance. // Failure -- put clips back where they were for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size(); ii < nn; ++ii) { TrackClip &trackClip = mClipMoveState.capturedClipArray[ii]; WaveClip *const pSrcClip = trackClip.clip; - if (pSrcClip) + if (pSrcClip){ + // Attempt to move to a new track did not work. + // Put the clip back appropriately shifted! + trackClip.holder->Offset(slide); // Assume track is wave because it has a clip static_cast(trackClip.track)-> AddClip(std::move(trackClip.holder)); + } } + // Make the offset permanent; start from a "clean slate" + mMouseClickX = event.m_x; return RefreshAll; } else {