From 633b2e28bce2c36fdd68e7f7a770261b5b2f6705 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 16 Sep 2020 08:10:13 -0400 Subject: [PATCH] Different procedure, same results, to find corresponding tracks... ... for shifting of clips among tracks But this (temporarily) breaks the behavior of dragging back to the original clip without first releasing the mouse --- .../wavetrack/ui/WaveTrackView.cpp | 5 + src/tracks/ui/TimeShiftHandle.cpp | 148 ++++++++++-------- src/tracks/ui/TimeShiftHandle.h | 9 ++ 3 files changed, 97 insertions(+), 65 deletions(-) diff --git a/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp b/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp index 80de1288f..33555e9c9 100644 --- a/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp +++ b/src/tracks/playabletrack/wavetrack/ui/WaveTrackView.cpp @@ -1344,6 +1344,11 @@ public: bool SyncLocks() override { return true; } + bool MayMigrateTo(Track &other) override + { + return TrackShifter::CommonMayMigrateTo(other); + } + double HintOffsetLarger(double desiredOffset) override { // set it to a sample point, and minimum of 1 sample point diff --git a/src/tracks/ui/TimeShiftHandle.cpp b/src/tracks/ui/TimeShiftHandle.cpp index b9feeec4b..6d2f17960 100644 --- a/src/tracks/ui/TimeShiftHandle.cpp +++ b/src/tracks/ui/TimeShiftHandle.cpp @@ -164,46 +164,6 @@ namespace viewInfo.selectedRegion.t1() ); } - WaveTrack *NthChannel(WaveTrack &leader, int nn) - { - if (nn < 0) - return nullptr; - return *TrackList::Channels( &leader ).begin().advance(nn); - } - - int ChannelPosition(const Track *pChannel) - { - return static_cast( - TrackList::Channels( pChannel ) - .EndingAfter( pChannel ).size() - ) - 1; - } - - // Don't count right channels. - WaveTrack *NthAudioTrack(TrackList &list, int nn) - { - if (nn >= 0) { - for ( auto pTrack : list.Leaders< WaveTrack >() ) - if (nn -- == 0) - return pTrack; - } - - return NULL; - } - - // Don't count right channels. - int TrackPosition(TrackList &list, const Track *pFindTrack) - { - pFindTrack = *list.FindLeader(pFindTrack); - int nn = 0; - for ( auto pTrack : list.Leaders< const WaveTrack >() ) { - if (pTrack == pFindTrack) - return nn; - ++nn; - } - return -1; - } - WaveClip *FindClipAtTime(WaveTrack *pTrack, double time) { if (pTrack) { @@ -279,6 +239,42 @@ double TrackShifter::HintOffsetLarger(double desiredOffset) return desiredOffset; } +bool TrackShifter::MayMigrateTo(Track &) +{ + return false; +} + +bool TrackShifter::CommonMayMigrateTo(Track &otherTrack) +{ + auto &track = GetTrack(); + + // Both tracks need to be owned to decide this + auto pMyList = track.GetOwner().get(); + auto pOtherList = otherTrack.GetOwner().get(); + if (pMyList && pOtherList) { + + // Can migrate to another track of the same kind... + if ( otherTrack.SameKindAs( track ) ) { + + // ... with the same number of channels ... + auto myChannels = TrackList::Channels( &track ); + auto otherChannels = TrackList::Channels( &otherTrack ); + if (myChannels.size() == otherChannels.size()) { + + // ... and where this track and the other have corresponding + // positions + return myChannels.size() == 1 || + std::distance(myChannels.first, pMyList->Find(&track)) == + std::distance(otherChannels.first, pOtherList->Find(&otherTrack)); + + } + + } + + } + return false; +} + void TrackShifter::InitIntervals() { mMoving.clear(); @@ -724,41 +720,62 @@ namespace { } } + using Correspondence = std::unordered_map< Track*, Track* >; + bool FindCorrespondence( + Correspondence &correspondence, TrackList &trackList, Track &track, ClipMoveState &state) { - Track &capturedTrack = *state.mCapturedTrack; - const int diff = - TrackPosition(trackList, &track) - - TrackPosition(trackList, &capturedTrack); - for ( auto &trackClip : state.capturedClipArray ) { - if (trackClip.clip) { - // Move all clips up or down by an equal count of audio tracks. - // Can only move between tracks with equal numbers of channels, - // and among corresponding channels. + auto &capturedTrack = state.mCapturedTrack; + auto sameType = [&]( auto pTrack ){ + return capturedTrack->SameKindAs( *pTrack ); + }; + if (!sameType(&track)) + return false; + + // All tracks of the same kind as the captured track + auto range = trackList.Any() + sameType; - Track *const pSrcTrack = trackClip.track; - auto pDstTrack = NthAudioTrack(trackList, - diff + TrackPosition(trackList, pSrcTrack)); - if (!pDstTrack) + // Find how far this track would shift down among those (signed) + const auto myPosition = + std::distance( range.first, trackList.Find( capturedTrack.get() ) ); + const auto otherPosition = + std::distance( range.first, trackList.Find( &track ) ); + auto diff = otherPosition - myPosition; + + // Point to destination track + auto iter = range.first.advance( diff > 0 ? diff : 0 ); + + for (auto pTrack : range) { + auto &pShifter = state.shifters[pTrack]; + if ( !pShifter->MovingIntervals().empty() ) { + // One of the interesting tracks + + auto pOther = *iter; + if ( diff < 0 || !pOther ) + // No corresponding track return false; - if (TrackList::Channels(pSrcTrack).size() != - TrackList::Channels(pDstTrack).size()) + if ( !pShifter->MayMigrateTo(*pOther) ) + // Rejected for other reason return false; - auto pDstChannel = NthChannel( - *pDstTrack, ChannelPosition(pSrcTrack)); - - if (!pDstChannel) { - wxASSERT(false); - return false; - } - - trackClip.dstTrack = pDstChannel; + correspondence[ pTrack ] = pOther; } + + if ( diff < 0 ) + ++diff; // Still consuming initial tracks + else + ++iter; // Safe to increment TrackIter even at end of range } + + // Record the correspondence in TrackClip + for ( auto &trackClip: state.capturedClipArray ) + if ( trackClip.clip ) + trackClip.dstTrack = + dynamic_cast(correspondence[ trackClip.track ]); + return true; } @@ -841,7 +858,8 @@ bool TimeShiftHandle::DoSlideVertical ClipMoveState &state, TrackList &trackList, Track &dstTrack, double &desiredSlideAmount ) { - if (!FindCorrespondence( trackList, dstTrack, state )) + Correspondence correspondence; + if (!FindCorrespondence( correspondence, trackList, dstTrack, state )) return false; // Having passed that test, remove clips temporarily from their diff --git a/src/tracks/ui/TimeShiftHandle.h b/src/tracks/ui/TimeShiftHandle.h index e3c403512..a7fac692e 100644 --- a/src/tracks/ui/TimeShiftHandle.h +++ b/src/tracks/ui/TimeShiftHandle.h @@ -75,10 +75,19 @@ public: */ virtual double HintOffsetLarger( double desiredOffset ); + //! Whether intervals may migrate to the other track, not yet checking all placement constraints */ + /*! Default implementation returns false */ + virtual bool MayMigrateTo( Track &otherTrack ); + protected: /*! Unfix any of the intervals that intersect the given one; may be useful to override `SelectInterval()` */ void CommonSelectInterval( const TrackInterval &interval ); + /*! May be useful to override `MayMigrateTo()`, if certain other needed overrides are given. + Returns true, iff: tracks have same type, and corresponding positions in their channel groups, + which have same size */ + bool CommonMayMigrateTo( Track &otherTrack ); + //! Derived class constructor can initialize all intervals reported by the track as fixed, none moving /*! This can't be called by the base class constructor, when GetTrack() isn't yet callable */ void InitIntervals();