From 6510b859f336d4b8264974a55cc8f7cf3612f4e2 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 9 Sep 2020 07:35:58 -0400 Subject: [PATCH 1/5] Define new virtual functions Track::GetIntervals (const and non-const) --- src/LabelTrack.cpp | 22 +++++++++++++++++ src/LabelTrack.h | 7 ++++++ src/NoteTrack.cpp | 14 +++++++++++ src/NoteTrack.h | 3 +++ src/Track.cpp | 12 +++++++++ src/Track.h | 61 ++++++++++++++++++++++++++++++++++++++++++++++ src/WaveTrack.cpp | 21 ++++++++++++++++ src/WaveTrack.h | 14 +++++++++++ 8 files changed, 154 insertions(+) diff --git a/src/LabelTrack.cpp b/src/LabelTrack.cpp index 0992b3b9d..de304be82 100644 --- a/src/LabelTrack.cpp +++ b/src/LabelTrack.cpp @@ -84,6 +84,28 @@ LabelTrack::LabelTrack(const LabelTrack &orig) : } } +template< typename Container > +static Container MakeIntervals(const LabelArray &labels) +{ + Container result; + size_t ii = 0; + for (const auto &label : labels) + result.emplace_back( + label.getT0(), label.getT1(), + std::make_unique( ii++ ) ); + return result; +} + +auto LabelTrack::GetIntervals() const -> ConstIntervals +{ + return MakeIntervals(mLabels); +} + +auto LabelTrack::GetIntervals() -> Intervals +{ + return MakeIntervals(mLabels); +} + void LabelTrack::SetLabel( size_t iLabel, const LabelStruct &newLabel ) { if( iLabel >= mLabels.size() ) { diff --git a/src/LabelTrack.h b/src/LabelTrack.h index 98f334f02..09cdd78a0 100644 --- a/src/LabelTrack.h +++ b/src/LabelTrack.h @@ -155,6 +155,13 @@ public: int FindNextLabel(const SelectedRegion& currentSelection); int FindPrevLabel(const SelectedRegion& currentSelection); + struct IntervalData final : Track::IntervalData { + size_t index; + explicit IntervalData(size_t index) : index{index} {}; + }; + ConstIntervals GetIntervals() const override; + Intervals GetIntervals() override; + public: void SortLabels(); diff --git a/src/NoteTrack.cpp b/src/NoteTrack.cpp index 4e113903f..789a1ff8e 100644 --- a/src/NoteTrack.cpp +++ b/src/NoteTrack.cpp @@ -683,6 +683,20 @@ QuantizedTimeAndBeat NoteTrack::NearestBeatTime( double time ) const return { seq_time + GetOffset(), beat }; } +auto NoteTrack::GetIntervals() const -> ConstIntervals +{ + ConstIntervals results; + results.emplace_back( GetStartTime(), GetEndTime() ); + return results; +} + +auto NoteTrack::GetIntervals() -> Intervals +{ + Intervals results; + results.emplace_back( GetStartTime(), GetEndTime() ); + return results; +} + void NoteTrack::AddToDuration( double delta ) { auto &seq = GetSeq(); diff --git a/src/NoteTrack.h b/src/NoteTrack.h index 91295ce81..f1cf21658 100644 --- a/src/NoteTrack.h +++ b/src/NoteTrack.h @@ -185,6 +185,9 @@ public: mVisibleChannels = CHANNEL_BIT(c); } + ConstIntervals GetIntervals() const override; + Intervals GetIntervals() override; + private: TrackKind GetKind() const override { return TrackKind::Note; } diff --git a/src/Track.cpp b/src/Track.cpp index 0caaed327..1f9a14869 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -1224,6 +1224,16 @@ std::shared_ptr Track::SubstituteOriginalTrack() const return SharedPointer(); } +auto Track::GetIntervals() const -> ConstIntervals +{ + return {}; +} + +auto Track::GetIntervals() -> Intervals +{ + return {}; +} + // Serialize, not with tags of its own, but as attributes within a tag. void Track::WriteCommonXMLAttributes( XMLWriter &xmlFile, bool includeNameAndSelected) const @@ -1269,6 +1279,8 @@ void Track::AdjustPositions() } } +TrackIntervalData::~TrackIntervalData() = default; + bool TrackList::HasPendingTracks() const { if ( !mPendingUpdates.empty() ) diff --git a/src/Track.h b/src/Track.h index d8637ddf6..15a7eff57 100644 --- a/src/Track.h +++ b/src/Track.h @@ -181,6 +181,50 @@ private: long mValue; }; +//! Optional extra information about an interval, appropriate to a subtype of Track +struct TrackIntervalData { + virtual ~TrackIntervalData(); +}; + +//! A start and an end time, and non-mutative access to optional extra information +/*! @invariant `Start() <= End()` */ +class ConstTrackInterval { +public: + + /*! @pre `start <= end` */ + ConstTrackInterval( double start, double end, + std::unique_ptr pExtra = {} ) + : start{ start }, end{ end }, pExtra{ std::move( pExtra ) } + { + wxASSERT( start <= end ); + } + + ConstTrackInterval( ConstTrackInterval&& ) = default; + ConstTrackInterval &operator=( ConstTrackInterval&& ) = default; + + double Start() const { return start; } + double End() const { return end; } + const TrackIntervalData *Extra() const { return pExtra.get(); } + +private: + double start, end; +protected: + // TODO C++17: use std::any instead + std::unique_ptr< TrackIntervalData > pExtra; +}; + +//! A start and an end time, and mutative access to optional extra information +/*! @invariant `Start() <= End()` */ +class TrackInterval : public ConstTrackInterval { +public: + using ConstTrackInterval::ConstTrackInterval; + + TrackInterval(TrackInterval&&) = default; + TrackInterval &operator= (TrackInterval&&) = default; + + TrackIntervalData *Extra() const { return pExtra.get(); } +}; + //! Template generated base class for Track lets it host opaque UI related objects using AttachedTrackObjects = ClientData::Site< Track, ClientData::Base, ClientData::SkipCopying, std::shared_ptr @@ -268,6 +312,23 @@ class AUDACITY_DLL_API Track /* not final */ // original; else return this track std::shared_ptr SubstituteOriginalTrack() const; + using IntervalData = TrackIntervalData; + using Interval = TrackInterval; + using Intervals = std::vector< Interval >; + using ConstInterval = ConstTrackInterval; + using ConstIntervals = std::vector< ConstInterval >; + + //! 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. + */ + virtual ConstIntervals GetIntervals() const; + + /*! @copydoc GetIntervals() + This overload exposes the extra data of the intervals as non-const + */ + virtual Intervals GetIntervals(); + public: mutable wxSize vrulerSize; diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp index 18b48c7d3..d86a4960d 100644 --- a/src/WaveTrack.cpp +++ b/src/WaveTrack.cpp @@ -323,6 +323,27 @@ int WaveTrack::ZeroLevelYCoordinate(wxRect rect) const (int)((mDisplayMax / (mDisplayMax - mDisplayMin)) * rect.height); } +template< typename Container > +static Container MakeIntervals(const std::vector &clips) +{ + Container result; + for (const auto &clip: clips) { + result.emplace_back( clip->GetStartTime(), clip->GetEndTime(), + std::make_unique( clip ) ); + } + return result; +} + +auto WaveTrack::GetIntervals() const -> ConstIntervals +{ + return MakeIntervals( mClips ); +} + +auto WaveTrack::GetIntervals() -> Intervals +{ + return MakeIntervals( mClips ); +} + Track::Holder WaveTrack::Clone() const { return std::make_shared( *this ); diff --git a/src/WaveTrack.h b/src/WaveTrack.h index a209ca02d..4ac2a45b5 100644 --- a/src/WaveTrack.h +++ b/src/WaveTrack.h @@ -523,6 +523,20 @@ private: // bottom and top. Maybe that is out of bounds. int ZeroLevelYCoordinate(wxRect rect) const; + class IntervalData final : public Track::IntervalData { + public: + explicit IntervalData( const std::shared_ptr &pClip ) + : pClip{ pClip } + {} + std::shared_ptr GetClip() const { return pClip; } + std::shared_ptr &GetClip() { return pClip; } + private: + std::shared_ptr pClip; + }; + + ConstIntervals GetIntervals() const override; + Intervals GetIntervals() override; + protected: // // Protected variables From 6337e1ccf4a75baf95a6e2d4b06a490cbcf9ae9c Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 9 Sep 2020 07:43:57 -0400 Subject: [PATCH 2/5] Reordered SnapManager ctor arguments, added AudacityProject & --- src/AdornedRulerPanel.cpp | 3 ++- src/Snap.cpp | 17 +++++++++-------- src/Snap.h | 11 ++++++----- src/tracks/ui/SelectHandle.cpp | 3 ++- src/tracks/ui/TimeShiftHandle.cpp | 12 +++++++----- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/AdornedRulerPanel.cpp b/src/AdornedRulerPanel.cpp index 50b61c8d7..788e7e59d 100644 --- a/src/AdornedRulerPanel.cpp +++ b/src/AdornedRulerPanel.cpp @@ -1900,7 +1900,8 @@ void AdornedRulerPanel::HandleSnapping() if (handle) { auto &pSnapManager = handle->mSnapManager; if (! pSnapManager) - pSnapManager = std::make_unique(mTracks, mViewInfo); + pSnapManager = + std::make_unique(*mProject, *mTracks, *mViewInfo); auto results = pSnapManager->Snap(NULL, mQuickPlayPos, false); mQuickPlayPos = results.outTime; diff --git a/src/Snap.cpp b/src/Snap.cpp index 944494f2f..df4fd20e9 100644 --- a/src/Snap.cpp +++ b/src/Snap.cpp @@ -39,22 +39,23 @@ TrackClip::~TrackClip() } -SnapManager::SnapManager(const TrackList *tracks, - const ZoomInfo *zoomInfo, - const TrackClipArray *clipExclusions, - const TrackArray *trackExclusions, +SnapManager::SnapManager(const AudacityProject &project, + const TrackList &tracks, + const ZoomInfo &zoomInfo, bool noTimeSnap, - int pixelTolerance) + int pixelTolerance, + const TrackClipArray *clipExclusions, + const TrackArray *trackExclusions) : mConverter(NumericConverter::TIME) { - mTracks = tracks; - mZoomInfo = zoomInfo; + mTracks = &tracks; + mZoomInfo = &zoomInfo; mClipExclusions = clipExclusions; mTrackExclusions = trackExclusions; mPixelTolerance = pixelTolerance; mNoTimeSnap = noTimeSnap; - mProject = tracks->GetOwner(); + mProject = &project; wxASSERT(mProject); mSnapTo = 0; diff --git a/src/Snap.h b/src/Snap.h index 7f8c4bac1..5a962c88e 100644 --- a/src/Snap.h +++ b/src/Snap.h @@ -77,12 +77,13 @@ struct SnapResults { class SnapManager { public: - SnapManager(const TrackList *tracks, - const ZoomInfo *zoomInfo, - const TrackClipArray *clipExclusions = NULL, - const TrackArray *trackExclusions = NULL, + SnapManager(const AudacityProject &project, + const TrackList &tracks, + const ZoomInfo &zoomInfo, bool noTimeSnap = false, - int pixelTolerance = kPixelTolerance); + int pixelTolerance = kPixelTolerance, + const TrackClipArray *clipExclusions = NULL, + const TrackArray *trackExclusions = NULL); ~SnapManager(); // The track may be NULL. diff --git a/src/tracks/ui/SelectHandle.cpp b/src/tracks/ui/SelectHandle.cpp index f39b0725f..1cbdbb0fa 100644 --- a/src/tracks/ui/SelectHandle.cpp +++ b/src/tracks/ui/SelectHandle.cpp @@ -432,7 +432,8 @@ SelectHandle::SelectHandle const TrackList &trackList, const TrackPanelMouseState &st, const ViewInfo &viewInfo ) : mpView{ pTrackView } - , mSnapManager{ std::make_shared(&trackList, &viewInfo) } + , mSnapManager{ std::make_shared( + *trackList.GetOwner(), trackList, viewInfo) } { const wxMouseState &state = st.state; mRect = st.rect; diff --git a/src/tracks/ui/TimeShiftHandle.cpp b/src/tracks/ui/TimeShiftHandle.cpp index 2a7f22a79..54a039519 100644 --- a/src/tracks/ui/TimeShiftHandle.cpp +++ b/src/tracks/ui/TimeShiftHandle.cpp @@ -414,11 +414,13 @@ UIHandle::Result TimeShiftHandle::Click mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive; mRect = rect; mClipMoveState.mMouseClickX = event.m_x; - mSnapManager = std::make_shared(&trackList, - &viewInfo, - &mClipMoveState.capturedClipArray, - &mClipMoveState.trackExclusions, - true); // don't snap to time + mSnapManager = + std::make_shared(*trackList.GetOwner(), trackList, + viewInfo, + true, // don't snap to time + kPixelTolerance, + &mClipMoveState.capturedClipArray, + &mClipMoveState.trackExclusions); mClipMoveState.snapLeft = -1; mClipMoveState.snapRight = -1; mSnapPreferRightEdge = From aa4b80871473c2528043905db46f97ae1b8385b6 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 9 Sep 2020 08:04:40 -0400 Subject: [PATCH 3/5] More constructors for SnapManager... one taking candidate list directly, the others delegating to it. Some members removed, some in-class initializers. The special constructor for TimeShift only has extra arguments. It will go away. --- src/Snap.cpp | 179 +++++++++++++++++++++++++++++++-------------------- src/Snap.h | 29 ++++++--- 2 files changed, 128 insertions(+), 80 deletions(-) diff --git a/src/Snap.cpp b/src/Snap.cpp index df4fd20e9..2753b22a0 100644 --- a/src/Snap.cpp +++ b/src/Snap.cpp @@ -39,6 +39,108 @@ TrackClip::~TrackClip() } +SnapManager::SnapManager(const AudacityProject &project, + SnapPointArray candidates, + const ZoomInfo &zoomInfo, + bool noTimeSnap, + int pixelTolerance) +: mProject{ &project } +, mZoomInfo{ &zoomInfo } +, mPixelTolerance{ pixelTolerance } +, mNoTimeSnap{ noTimeSnap } +, mCandidates{ std::move( candidates ) } +, mSnapPoints{} +, mConverter{ NumericConverter::TIME } +{ + Reinit(); +} + +namespace { +SnapPointArray FindCandidates( const TrackList &tracks ) +{ + SnapPointArray candidates; + for ( const auto track : tracks.Any() ) { + auto intervals = track->GetIntervals(); + for (const auto &interval : intervals) { + candidates.emplace_back( interval.Start(), track ); + if ( interval.Start() != interval.End() ) + candidates.emplace_back( interval.End(), track ); + } + } + return candidates; +} + +SnapPointArray FindCandidates( + const TrackList &tracks, + const TrackClipArray *clipExclusions, const TrackArray *trackExclusions ) +{ + // Special case restricted candidates for time shift + SnapPointArray candidates; + auto trackRange = + tracks.Any() + - [&](const Track *pTrack){ + return trackExclusions && + make_iterator_range( *trackExclusions ).contains( pTrack ); + }; + trackRange.Visit( + [&](const LabelTrack *labelTrack) { + for (int i = 0, cnt = labelTrack->GetNumLabels(); i < cnt; ++i) + { + const LabelStruct *label = labelTrack->GetLabel(i); + const double t0 = label->getT0(); + const double t1 = label->getT1(); + candidates.emplace_back(t0, labelTrack); + if (t1 != t0) + candidates.emplace_back(t1, labelTrack); + } + }, + [&](const WaveTrack *waveTrack) { + for (const auto &clip: waveTrack->GetClips()) + { + if (clipExclusions) + { + bool skip = false; + for (size_t j = 0, cnt = clipExclusions->size(); j < cnt; ++j) + { + if ((*clipExclusions)[j].track == waveTrack && + (*clipExclusions)[j].clip == clip.get()) + { + skip = true; + break; + } + } + + if (skip) + continue; + } + + candidates.emplace_back(clip->GetStartTime(), waveTrack); + candidates.emplace_back(clip->GetEndTime(), waveTrack); + } + } +#ifdef USE_MIDI + , + [&](const NoteTrack *track) { + candidates.emplace_back(track->GetStartTime(), track); + candidates.emplace_back(track->GetEndTime(), track); + } +#endif + ); + return candidates; +} +} + +SnapManager::SnapManager(const AudacityProject &project, + const TrackList &tracks, + const ZoomInfo &zoomInfo, + bool noTimeSnap, + int pixelTolerance) + : SnapManager{ project, + FindCandidates( tracks ), + zoomInfo, noTimeSnap, pixelTolerance } +{ +} + SnapManager::SnapManager(const AudacityProject &project, const TrackList &tracks, const ZoomInfo &zoomInfo, @@ -46,26 +148,10 @@ SnapManager::SnapManager(const AudacityProject &project, int pixelTolerance, const TrackClipArray *clipExclusions, const TrackArray *trackExclusions) -: mConverter(NumericConverter::TIME) + : SnapManager{ project, + FindCandidates( tracks, clipExclusions, trackExclusions ), + zoomInfo, noTimeSnap, pixelTolerance } { - mTracks = &tracks; - mZoomInfo = &zoomInfo; - mClipExclusions = clipExclusions; - mTrackExclusions = trackExclusions; - mPixelTolerance = pixelTolerance; - mNoTimeSnap = noTimeSnap; - - mProject = &project; - wxASSERT(mProject); - - mSnapTo = 0; - mRate = 0.0; - mFormat = {}; - - // Two time points closer than this are considered the same - mEpsilon = 1 / 44100.0; - - Reinit(); } SnapManager::~SnapManager() @@ -106,58 +192,9 @@ void SnapManager::Reinit() // Add a SnapPoint at t=0 mSnapPoints.push_back(SnapPoint{}); - auto trackRange = - mTracks->Any() - - [&](const Track *pTrack){ - return mTrackExclusions && - make_iterator_range( *mTrackExclusions ).contains( pTrack ); - }; - trackRange.Visit( - [&](const LabelTrack *labelTrack) { - for (int i = 0, cnt = labelTrack->GetNumLabels(); i < cnt; ++i) - { - const LabelStruct *label = labelTrack->GetLabel(i); - const double t0 = label->getT0(); - const double t1 = label->getT1(); - CondListAdd(t0, labelTrack); - if (t1 != t0) - { - CondListAdd(t1, labelTrack); - } - } - }, - [&](const WaveTrack *waveTrack) { - for (const auto &clip: waveTrack->GetClips()) - { - if (mClipExclusions) - { - bool skip = false; - for (size_t j = 0, cnt = mClipExclusions->size(); j < cnt; ++j) - { - if ((*mClipExclusions)[j].track == waveTrack && - (*mClipExclusions)[j].clip == clip.get()) - { - skip = true; - break; - } - } - - if (skip) - continue; - } - - CondListAdd(clip->GetStartTime(), waveTrack); - CondListAdd(clip->GetEndTime(), waveTrack); - } - } -#ifdef USE_MIDI - , - [&](const NoteTrack *track) { - CondListAdd(track->GetStartTime(), track); - CondListAdd(track->GetEndTime(), track); - } -#endif - ); + // Adjust and filter the candidate points + for (const auto &candidate : mCandidates) + CondListAdd( candidate.t, candidate.track ); // Sort all by time std::sort(mSnapPoints.begin(), mSnapPoints.end()); diff --git a/src/Snap.h b/src/Snap.h index 5a962c88e..50679d244 100644 --- a/src/Snap.h +++ b/src/Snap.h @@ -77,11 +77,23 @@ struct SnapResults { class SnapManager { public: + SnapManager(const AudacityProject &project, + SnapPointArray candidates, + const ZoomInfo &zoomInfo, + bool noTimeSnap = false, + int pixelTolerance = kPixelTolerance); + SnapManager(const AudacityProject &project, const TrackList &tracks, const ZoomInfo &zoomInfo, bool noTimeSnap = false, - int pixelTolerance = kPixelTolerance, + int pixelTolerance = kPixelTolerance); + + SnapManager(const AudacityProject &project, + const TrackList &tracks, + const ZoomInfo &zoomInfo, + bool noTimeSnap, + int pixelTolerance, const TrackClipArray *clipExclusions = NULL, const TrackArray *trackExclusions = NULL); ~SnapManager(); @@ -112,23 +124,22 @@ private: private: const AudacityProject *mProject; - const TrackList *mTracks; - const TrackClipArray *mClipExclusions; - const TrackArray *mTrackExclusions; const ZoomInfo *mZoomInfo; int mPixelTolerance; bool mNoTimeSnap; - double mEpsilon; + //! Two time points closer than this are considered the same + double mEpsilon{ 1 / 44100.0 }; + SnapPointArray mCandidates; SnapPointArray mSnapPoints; // Info for snap-to-time NumericConverter mConverter; - bool mSnapToTime; + bool mSnapToTime{ false }; - int mSnapTo; - double mRate; - NumericFormatSymbol mFormat; + int mSnapTo{ 0 }; + double mRate{ 0.0 }; + NumericFormatSymbol mFormat{}; }; #endif From dc9eaf6a3a3d54945a8d635b064f961640fb2c17 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 9 Sep 2020 08:09:39 -0400 Subject: [PATCH 4/5] One less delegating ctor of SnapManager, move code to TimeShiftHandle --- src/Snap.cpp | 72 ------------------------------- src/Snap.h | 7 --- src/tracks/ui/TimeShiftHandle.cpp | 70 +++++++++++++++++++++++++++--- 3 files changed, 64 insertions(+), 85 deletions(-) diff --git a/src/Snap.cpp b/src/Snap.cpp index 2753b22a0..123aa4595 100644 --- a/src/Snap.cpp +++ b/src/Snap.cpp @@ -69,65 +69,6 @@ SnapPointArray FindCandidates( const TrackList &tracks ) } return candidates; } - -SnapPointArray FindCandidates( - const TrackList &tracks, - const TrackClipArray *clipExclusions, const TrackArray *trackExclusions ) -{ - // Special case restricted candidates for time shift - SnapPointArray candidates; - auto trackRange = - tracks.Any() - - [&](const Track *pTrack){ - return trackExclusions && - make_iterator_range( *trackExclusions ).contains( pTrack ); - }; - trackRange.Visit( - [&](const LabelTrack *labelTrack) { - for (int i = 0, cnt = labelTrack->GetNumLabels(); i < cnt; ++i) - { - const LabelStruct *label = labelTrack->GetLabel(i); - const double t0 = label->getT0(); - const double t1 = label->getT1(); - candidates.emplace_back(t0, labelTrack); - if (t1 != t0) - candidates.emplace_back(t1, labelTrack); - } - }, - [&](const WaveTrack *waveTrack) { - for (const auto &clip: waveTrack->GetClips()) - { - if (clipExclusions) - { - bool skip = false; - for (size_t j = 0, cnt = clipExclusions->size(); j < cnt; ++j) - { - if ((*clipExclusions)[j].track == waveTrack && - (*clipExclusions)[j].clip == clip.get()) - { - skip = true; - break; - } - } - - if (skip) - continue; - } - - candidates.emplace_back(clip->GetStartTime(), waveTrack); - candidates.emplace_back(clip->GetEndTime(), waveTrack); - } - } -#ifdef USE_MIDI - , - [&](const NoteTrack *track) { - candidates.emplace_back(track->GetStartTime(), track); - candidates.emplace_back(track->GetEndTime(), track); - } -#endif - ); - return candidates; -} } SnapManager::SnapManager(const AudacityProject &project, @@ -141,19 +82,6 @@ SnapManager::SnapManager(const AudacityProject &project, { } -SnapManager::SnapManager(const AudacityProject &project, - const TrackList &tracks, - const ZoomInfo &zoomInfo, - bool noTimeSnap, - int pixelTolerance, - const TrackClipArray *clipExclusions, - const TrackArray *trackExclusions) - : SnapManager{ project, - FindCandidates( tracks, clipExclusions, trackExclusions ), - zoomInfo, noTimeSnap, pixelTolerance } -{ -} - SnapManager::~SnapManager() { } diff --git a/src/Snap.h b/src/Snap.h index 50679d244..5582cdff2 100644 --- a/src/Snap.h +++ b/src/Snap.h @@ -89,13 +89,6 @@ public: bool noTimeSnap = false, int pixelTolerance = kPixelTolerance); - SnapManager(const AudacityProject &project, - const TrackList &tracks, - const ZoomInfo &zoomInfo, - bool noTimeSnap, - int pixelTolerance, - const TrackClipArray *clipExclusions = NULL, - const TrackArray *trackExclusions = NULL); ~SnapManager(); // The track may be NULL. diff --git a/src/tracks/ui/TimeShiftHandle.cpp b/src/tracks/ui/TimeShiftHandle.cpp index 54a039519..acb9d5eb0 100644 --- a/src/tracks/ui/TimeShiftHandle.cpp +++ b/src/tracks/ui/TimeShiftHandle.cpp @@ -350,6 +350,64 @@ void TimeShiftHandle::DoSlideHorizontal DoOffset( state, &capturedTrack, state.hSlideAmount ); } +#include "LabelTrack.h" +namespace { +SnapPointArray FindCandidates( + const TrackList &tracks, + const TrackClipArray &clipExclusions, const TrackArray &trackExclusions ) +{ + // Special case restricted candidates for time shift + SnapPointArray candidates; + auto trackRange = + tracks.Any() + - [&](const Track *pTrack){ + return + make_iterator_range( trackExclusions ).contains( pTrack ); + }; + trackRange.Visit( + [&](const LabelTrack *labelTrack) { + for (const auto &label : labelTrack->GetLabels()) + { + const double t0 = label.getT0(); + const double t1 = label.getT1(); + candidates.emplace_back(t0, labelTrack); + if (t1 != t0) + candidates.emplace_back(t1, labelTrack); + } + }, + [&](const WaveTrack *waveTrack) { + for (const auto &clip: waveTrack->GetClips()) + { + bool skip = false; + for (const auto &exclusion : clipExclusions) + { + if (exclusion.track == waveTrack && + exclusion.clip == clip.get()) + { + skip = true; + break; + } + } + + if (skip) + continue; + + candidates.emplace_back(clip->GetStartTime(), waveTrack); + candidates.emplace_back(clip->GetEndTime(), waveTrack); + } + } +#ifdef USE_MIDI + , + [&](const NoteTrack *track) { + candidates.emplace_back(track->GetStartTime(), track); + candidates.emplace_back(track->GetEndTime(), track); + } +#endif + ); + return candidates; +} +} + UIHandle::Result TimeShiftHandle::Click (const TrackPanelMouseEvent &evt, AudacityProject *pProject) { @@ -415,12 +473,12 @@ UIHandle::Result TimeShiftHandle::Click mRect = rect; mClipMoveState.mMouseClickX = event.m_x; mSnapManager = - std::make_shared(*trackList.GetOwner(), trackList, - viewInfo, - true, // don't snap to time - kPixelTolerance, - &mClipMoveState.capturedClipArray, - &mClipMoveState.trackExclusions); + std::make_shared(*trackList.GetOwner(), + FindCandidates( trackList, + mClipMoveState.capturedClipArray, mClipMoveState.trackExclusions), + viewInfo, + true, // don't snap to time + kPixelTolerance); mClipMoveState.snapLeft = -1; mClipMoveState.snapRight = -1; mSnapPreferRightEdge = From 4653b5ed3d76060a94f6326c70dcec414ff02ea6 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 9 Sep 2020 12:44:46 -0400 Subject: [PATCH 5/5] TrackClip moved to TimeShiftHandle; Snap doesn't use Track subclasses --- src/Snap.cpp | 17 +---------------- src/Snap.h | 22 ---------------------- src/tracks/ui/TimeShiftHandle.cpp | 13 +++++++++++++ src/tracks/ui/TimeShiftHandle.h | 25 +++++++++++++++++++++++-- 4 files changed, 37 insertions(+), 40 deletions(-) diff --git a/src/Snap.cpp b/src/Snap.cpp index 123aa4595..5bb84c0b4 100644 --- a/src/Snap.cpp +++ b/src/Snap.cpp @@ -16,29 +16,14 @@ #include "Project.h" #include "ProjectSettings.h" -#include "LabelTrack.h" -#include "NoteTrack.h" -#include "WaveClip.h" +#include "Track.h" #include "ViewInfo.h" -#include "WaveTrack.h" inline bool operator < (SnapPoint s1, SnapPoint s2) { return s1.t < s2.t; } -TrackClip::TrackClip(Track *t, WaveClip *c) -{ - track = origTrack = t; - dstTrack = NULL; - clip = c; -} - -TrackClip::~TrackClip() -{ - -} - SnapManager::SnapManager(const AudacityProject &project, SnapPointArray candidates, const ZoomInfo &zoomInfo, diff --git a/src/Snap.h b/src/Snap.h index 5582cdff2..5e0e45bc2 100644 --- a/src/Snap.h +++ b/src/Snap.h @@ -21,32 +21,10 @@ class AudacityProject; class Track; -using TrackArray = std::vector< Track* >; -class TrackClipArray; -class WaveClip; -class WaveTrack; class TrackList; class ZoomInfo; class wxDC; -class TrackClip -{ -public: - TrackClip(Track *t, WaveClip *c); - - ~TrackClip(); - - Track *track; - Track *origTrack; - WaveClip *clip; - - // These fields are used only during time-shift dragging - WaveTrack *dstTrack; - std::shared_ptr holder; -}; - -class TrackClipArray : public std::vector < TrackClip > {}; - const int kPixelTolerance = 4; class SnapPoint diff --git a/src/tracks/ui/TimeShiftHandle.cpp b/src/tracks/ui/TimeShiftHandle.cpp index acb9d5eb0..7ae6e2434 100644 --- a/src/tracks/ui/TimeShiftHandle.cpp +++ b/src/tracks/ui/TimeShiftHandle.cpp @@ -21,6 +21,7 @@ Paul Licameli split from TrackPanel.cpp #include "../../ProjectHistory.h" #include "../../ProjectSettings.h" #include "../../RefreshCode.h" +#include "../../Snap.h" #include "../../TrackArtist.h" #include "../../TrackPanelDrawingContext.h" #include "../../TrackPanelMouseEvent.h" @@ -30,6 +31,18 @@ Paul Licameli split from TrackPanel.cpp #include "../../WaveTrack.h" #include "../../../images/Cursors.h" +TrackClip::TrackClip(Track *t, WaveClip *c) +{ + track = origTrack = t; + dstTrack = NULL; + clip = c; +} + +TrackClip::~TrackClip() +{ + +} + TimeShiftHandle::TimeShiftHandle ( const std::shared_ptr &pTrack, bool gripHit ) : mCapturedTrack{ pTrack } diff --git a/src/tracks/ui/TimeShiftHandle.h b/src/tracks/ui/TimeShiftHandle.h index 4cf8e5088..7c3ec0c0a 100644 --- a/src/tracks/ui/TimeShiftHandle.h +++ b/src/tracks/ui/TimeShiftHandle.h @@ -13,10 +13,31 @@ Paul Licameli #include "../../UIHandle.h" -#include "../../Snap.h" - +class SnapManager; +class Track; +using TrackArray = std::vector; +class TrackList; class ViewInfo; class WaveClip; +class WaveTrack; + +class TrackClip +{ +public: + TrackClip(Track *t, WaveClip *c); + + ~TrackClip(); + + Track *track; + Track *origTrack; + WaveClip *clip; + + // These fields are used only during time-shift dragging + WaveTrack *dstTrack; + std::shared_ptr holder; +}; + +using TrackClipArray = std::vector ; struct ClipMoveState { // non-NULL only if click was in a WaveTrack and without Shift key: