diff --git a/src/tracks/playabletrack/wavetrack/ui/SpectrumView.cpp b/src/tracks/playabletrack/wavetrack/ui/SpectrumView.cpp index 6447255df..03352137f 100644 --- a/src/tracks/playabletrack/wavetrack/ui/SpectrumView.cpp +++ b/src/tracks/playabletrack/wavetrack/ui/SpectrumView.cpp @@ -31,6 +31,11 @@ Paul Licameli split from WaveTrackView.cpp SpectrumView::~SpectrumView() = default; +bool SpectrumView::IsSpectral() const +{ + return true; +} + std::vector SpectrumView::DetailedHitTest( const TrackPanelMouseState &state, const AudacityProject *pProject, int currentTool, bool bMultiTool ) diff --git a/src/tracks/playabletrack/wavetrack/ui/SpectrumView.h b/src/tracks/playabletrack/wavetrack/ui/SpectrumView.h index 06f98131b..5fc9c49d1 100644 --- a/src/tracks/playabletrack/wavetrack/ui/SpectrumView.h +++ b/src/tracks/playabletrack/wavetrack/ui/SpectrumView.h @@ -28,6 +28,7 @@ public: std::shared_ptr DoGetVRulerControls() override; + bool IsSpectral() const override; private: // TrackPanelDrawable implementation diff --git a/src/tracks/ui/CommonTrackView.cpp b/src/tracks/ui/CommonTrackView.cpp index e998e21a4..a8fd75d0f 100644 --- a/src/tracks/ui/CommonTrackView.cpp +++ b/src/tracks/ui/CommonTrackView.cpp @@ -73,7 +73,7 @@ std::vector CommonTrackView::HitTest // Finally, default of all is adjustment of the selection box. if ( isMultiTool || currentTool == selectTool ) { result = SelectHandle::HitTest( - mSelectHandle, st, pProject, FindTrack() ); + mSelectHandle, st, pProject, shared_from_this() ); if (result) results.push_back(result); } diff --git a/src/tracks/ui/SelectHandle.cpp b/src/tracks/ui/SelectHandle.cpp index 45799485b..69ef49370 100644 --- a/src/tracks/ui/SelectHandle.cpp +++ b/src/tracks/ui/SelectHandle.cpp @@ -128,13 +128,16 @@ namespace } // This returns true if we're a spectral editing track. - inline bool isSpectralSelectionTrack(const Track *pTrack) { - return pTrack && pTrack->TypeSwitch< bool >( [&](const WaveTrack *wt) { - const SpectrogramSettings &settings = wt->GetSpectrogramSettings(); - const int display = wt->GetDisplay(); - return (display == WaveTrackViewConstants::Spectrum) && - settings.SpectralSelectionEnabled(); - }); + inline bool isSpectralSelectionView(const TrackView *pTrackView) { + return + pTrackView && + pTrackView->IsSpectral() && + pTrackView->FindTrack() && + pTrackView->FindTrack()->TypeSwitch< bool >( + [&](const WaveTrack *wt) { + const SpectrogramSettings &settings = wt->GetSpectrogramSettings(); + return settings.SpectralSelectionEnabled(); + }); } enum SelectionBoundary { @@ -187,7 +190,7 @@ namespace SelectionBoundary ChooseBoundary (const ViewInfo &viewInfo, - wxCoord xx, wxCoord yy, const Track *pTrack, const wxRect &rect, + wxCoord xx, wxCoord yy, const TrackView *pTrackView, const wxRect &rect, bool mayDragWidth, bool onlyWithinSnapDistance, double *pPinValue = NULL) { @@ -220,9 +223,11 @@ namespace // within the time boundaries if (!viewInfo.selectedRegion.isPoint() && t0 <= selend && selend < t1 && - isSpectralSelectionTrack(pTrack)) { + isSpectralSelectionView(pTrackView)) { // Spectral selection track is always wave - const WaveTrack *const wt = static_cast(pTrack); + auto pTrack = pTrackView->FindTrack(); + const WaveTrack *const wt = + static_cast(pTrack.get()); const wxInt64 bottomSel = (f0 >= 0) ? FrequencyToPosition(wt, f0, rect.y, rect.height) : rect.y + rect.height; @@ -374,7 +379,7 @@ namespace UIHandlePtr SelectHandle::HitTest (std::weak_ptr &holder, const TrackPanelMouseState &st, const AudacityProject *pProject, - const std::shared_ptr &pTrack) + const std::shared_ptr &pTrackView) { // This handle is a little special because there may be some state to // preserve during movement before the click. @@ -393,13 +398,14 @@ UIHandlePtr SelectHandle::HitTest const auto &viewInfo = ViewInfo::Get( *pProject ); auto result = std::make_shared( - pTrack, oldUseSnap, TrackList::Get( *pProject ), st, viewInfo ); + pTrackView, oldUseSnap, TrackList::Get( *pProject ), st, viewInfo ); result = AssignUIHandlePtr(holder, result); //Make sure we are within the selected track // Adjusting the selection edges can be turned off in // the preferences... + auto pTrack = pTrackView->FindTrack(); if (!pTrack->GetSelected() || !viewInfo.bAdjustSelectionEdges) { return result; @@ -438,16 +444,17 @@ UIHandle::Result SelectHandle::NeedChangeHighlight } SelectHandle::SelectHandle -( const std::shared_ptr &pTrack, bool useSnap, +( const std::shared_ptr &pTrackView, bool useSnap, const TrackList &trackList, const TrackPanelMouseState &st, const ViewInfo &viewInfo ) - : mpTrack{ pTrack } + : mpView{ pTrackView } , mSnapManager{ std::make_shared(&trackList, &viewInfo) } { const wxMouseState &state = st.state; mRect = st.rect; auto time = std::max(0.0, viewInfo.PositionToTime(state.m_x, mRect.x)); + auto pTrack = pTrackView->FindTrack(); mSnapStart = mSnapManager->Snap(pTrack.get(), time, false); if (mSnapStart.snappedPoint) mSnapStart.outCoord += mRect.x; @@ -531,8 +538,12 @@ UIHandle::Result SelectHandle::Click using namespace RefreshCode; + const auto pView = mpView.lock(); + if ( !pView ) + return Cancelled; + wxMouseEvent &event = evt.event; - const auto sTrack = TrackList::Get( *pProject ).Lock(mpTrack); + const auto sTrack = TrackList::Get( *pProject ).Lock( FindTrack() ); const auto pTrack = sTrack.get(); auto &trackPanel = TrackPanel::Get( *pProject ); auto &viewInfo = ViewInfo::Get( *pProject ); @@ -620,7 +631,8 @@ UIHandle::Result SelectHandle::Click double value; // Shift-click, choose closest boundary SelectionBoundary boundary = - ChooseBoundary(viewInfo, xx, event.m_y, pTrack, mRect, false, false, &value); + ChooseBoundary(viewInfo, xx, event.m_y, + pView.get(), mRect, false, false, &value); mSelectionBoundary = boundary; switch (boundary) { case SBLeft: @@ -686,7 +698,7 @@ UIHandle::Result SelectHandle::Click if (viewInfo.bAdjustSelectionEdges) { #ifdef EXPERIMENTAL_SPECTRAL_EDITING if (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER && - isSpectralSelectionTrack(pTrack)) { + isSpectralSelectionView(pView.get())) { // This code is no longer reachable, but it had a place in the // spectral selection prototype. It used to be that you could be // in a center-frequency-snapping mode that was not a mouse drag @@ -714,7 +726,8 @@ UIHandle::Result SelectHandle::Click // Not shift-down, choose boundary only within snapping double value; SelectionBoundary boundary = - ChooseBoundary(viewInfo, xx, event.m_y, pTrack, mRect, true, true, &value); + ChooseBoundary(viewInfo, xx, event.m_y, + pView.get(), mRect, true, true, &value); mSelectionBoundary = boundary; switch (boundary) { case SBNone: @@ -766,7 +779,8 @@ UIHandle::Result SelectHandle::Click // If we didn't move a selection boundary, start a NEW selection selectionState.SelectNone( trackList ); #ifdef EXPERIMENTAL_SPECTRAL_EDITING - StartFreqSelection (viewInfo, event.m_y, mRect.y, mRect.height, pTrack); + StartFreqSelection (viewInfo, event.m_y, mRect.y, mRect.height, + pView.get()); #endif StartSelection(pProject); selectionState.SelectTrack( *pTrack, true, true ); @@ -791,6 +805,10 @@ UIHandle::Result SelectHandle::Drag { using namespace RefreshCode; + const auto pView = mpView.lock(); + if ( !pView ) + return Cancelled; + auto &viewInfo = ViewInfo::Get( *pProject ); const wxMouseEvent &event = evt.event; @@ -814,7 +832,7 @@ UIHandle::Result SelectHandle::Drag } // Also fuhggeddaboudit if not in a track. - auto pTrack = TrackList::Get( *pProject ).Lock(mpTrack); + auto pTrack = TrackList::Get( *pProject ).Lock( FindTrack() ); if (!pTrack) return RefreshNone; @@ -850,7 +868,7 @@ UIHandle::Result SelectHandle::Drag if (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER && !viewInfo.selectedRegion.isPoint()) MoveSnappingFreqSelection - (pProject, viewInfo, y, mRect.y, mRect.height, pTrack.get()); + (pProject, viewInfo, y, mRect.y, mRect.height, pView.get()); else #endif if ( TrackList::Get( *pProject ).Lock(mFreqSelTrack) == pTrack ) @@ -883,7 +901,11 @@ HitTestPreview SelectHandle::Preview // Moved out of snapping; revert to un-escaped state mUseSnap = true; - auto pTrack = mpTrack.lock(); + const auto pView = mpView.lock(); + if ( !pView ) + return {}; + + auto pTrack = FindTrack().lock(); if (!pTrack) return {}; @@ -937,7 +959,8 @@ HitTestPreview SelectHandle::Preview // choose boundaries only in snapping tolerance, // and may choose center. SelectionBoundary boundary = - ChooseBoundary(viewInfo, xx, state.m_y, pTrack.get(), rect, !bModifierDown, !bModifierDown); + ChooseBoundary(viewInfo, xx, state.m_y, + pView.get(), rect, !bModifierDown, !bModifierDown); SetTipAndCursorForBoundary(boundary, !bShiftDown, tip, pCursor); } @@ -949,7 +972,7 @@ HitTestPreview SelectHandle::Preview // and drag width. #ifdef EXPERIMENTAL_SPECTRAL_EDITING if ((mFreqSelMode == FREQ_SEL_SNAPPING_CENTER) && - isSpectralSelectionTrack(pTrack)) { + isSpectralSelectionView(pView)) { // Not shift-down, but center frequency snapping toggle is on tip = _("Click and drag to set frequency bandwidth."); pCursor = &*envelopeCursor; @@ -966,7 +989,8 @@ HitTestPreview SelectHandle::Preview const bool bCtrlDown = state.ControlDown(); const bool bModifierDown = bShiftDown || bCtrlDown; SelectionBoundary boundary = ChooseBoundary( - viewInfo, xx, state.m_y, pTrack.get(), rect, !bModifierDown, !bModifierDown); + viewInfo, xx, state.m_y, + pView.get(), rect, !bModifierDown, !bModifierDown); SetTipAndCursorForBoundary(boundary, !bShiftDown, tip, pCursor); } @@ -1034,6 +1058,15 @@ wxRect SelectHandle::DrawingArea( return rect; } +std::weak_ptr SelectHandle::FindTrack() +{ + auto pView = mpView.lock(); + if (!pView) + return {}; + else + return pView->FindTrack(); +} + void SelectHandle::Connect(AudacityProject *pProject) { mTimerHandler = std::make_shared( this, pProject ); @@ -1113,7 +1146,7 @@ void SelectHandle::TimerHandler::OnTimer(wxCommandEvent &event) } } - auto pTrack = mParent->mpTrack.lock(); // TrackList::Lock() ? + auto pTrack = mParent->FindTrack().lock(); // TrackList::Lock() ? if (mParent->mAutoScrolling && pTrack) { // AS: To keep the selection working properly as we scroll, // we fake a mouse event (remember, this method is called @@ -1164,7 +1197,7 @@ void SelectHandle::AdjustSelection auto pTrack = Track::SharedPointer( track ); if (!pTrack) - pTrack = TrackList::Get( *pProject ).Lock(mpTrack); + pTrack = TrackList::Get( *pProject ).Lock( FindTrack() ); if (pTrack && mSnapManager.get()) { bool rightEdge = (selend > mSelStart); @@ -1216,15 +1249,15 @@ void SelectHandle::AssignSelection void SelectHandle::StartFreqSelection(ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge, - int trackHeight, Track *pTrack) + int trackHeight, TrackView *pTrackView) { mFreqSelTrack.reset(); mFreqSelMode = FREQ_SEL_INVALID; mFreqSelPin = SelectedRegion::UndefinedFrequency; - if (isSpectralSelectionTrack(pTrack)) { + if (isSpectralSelectionView(pTrackView)) { // Spectral selection track is always wave - auto shTrack = pTrack->SharedPointer(); + auto shTrack = pTrackView->FindTrack()->SharedPointer(); mFreqSelTrack = shTrack; mFreqSelMode = FREQ_SEL_FREE; mFreqSelPin = @@ -1386,11 +1419,12 @@ void SelectHandle::StartSnappingFreqSelection void SelectHandle::MoveSnappingFreqSelection (AudacityProject *pProject, ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge, - int trackHeight, Track *pTrack) + int trackHeight, TrackView *pTrackView) { + auto pTrack = pTrackView->FindTrack().get(); if (pTrack && pTrack->GetSelected() && - isSpectralSelectionTrack(pTrack)) { + isSpectralSelectionView(pTrackView)) { // Spectral selection track is always wave WaveTrack *const wt = static_cast(pTrack); // PRL: diff --git a/src/tracks/ui/SelectHandle.h b/src/tracks/ui/SelectHandle.h index 39ef26c81..0ef6a82be 100644 --- a/src/tracks/ui/SelectHandle.h +++ b/src/tracks/ui/SelectHandle.h @@ -21,6 +21,7 @@ class SelectionStateChanger; class SnapManager; class SpectrumAnalyst; class Track; +class TrackView; class TrackList; class ViewInfo; class WaveTrack; @@ -32,7 +33,7 @@ class SelectHandle : public UIHandle public: explicit SelectHandle - (const std::shared_ptr &pTrack, bool useSnap, + (const std::shared_ptr &pTrackView, bool useSnap, const TrackList &trackList, const TrackPanelMouseState &st, const ViewInfo &viewInfo); @@ -41,7 +42,7 @@ public: static UIHandlePtr HitTest (std::weak_ptr &holder, const TrackPanelMouseState &state, const AudacityProject *pProject, - const std::shared_ptr &pTrack); + const std::shared_ptr &pTrackView); SelectHandle &operator=(const SelectHandle&) = default; @@ -78,6 +79,8 @@ public: const SelectHandle &newState); private: + std::weak_ptr FindTrack(); + void Connect(AudacityProject *pProject); void StartSelection(AudacityProject *pProject); @@ -89,7 +92,7 @@ private: void StartFreqSelection (ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge, - int trackHeight, Track *pTrack); + int trackHeight, TrackView *pTrackView); void AdjustFreqSelection (const WaveTrack *wt, ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge, @@ -104,7 +107,7 @@ private: void MoveSnappingFreqSelection (AudacityProject *pProject, ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge, - int trackHeight, Track *pTrack); + int trackHeight, TrackView *pTrackView); public: // This is needed to implement a command assignable to keystrokes static void SnapCenterOnce @@ -124,7 +127,7 @@ private: // (const ViewInfo &viewInfo, double hintFrequency, bool logF); - std::weak_ptr mpTrack; + std::weak_ptr mpView; wxRect mRect{}; SelectedRegion mInitialSelection{}; diff --git a/src/tracks/ui/TrackView.cpp b/src/tracks/ui/TrackView.cpp index e0feffa05..08e47c718 100644 --- a/src/tracks/ui/TrackView.cpp +++ b/src/tracks/ui/TrackView.cpp @@ -114,6 +114,11 @@ auto TrackView::GetSubViews( const wxRect &rect ) -> Refinement return { { rect.GetTop(), shared_from_this() } }; } +bool TrackView::IsSpectral() const +{ + return false; +} + void TrackView::DoSetMinimized(bool isMinimized) { mMinimized = isMinimized; diff --git a/src/tracks/ui/TrackView.h b/src/tracks/ui/TrackView.h index 04ca9c86c..4037b5705 100644 --- a/src/tracks/ui/TrackView.h +++ b/src/tracks/ui/TrackView.h @@ -73,6 +73,9 @@ public: > >; virtual Refinement GetSubViews( const wxRect &rect ); + // default is false + virtual bool IsSpectral() const; + virtual void DoSetMinimized( bool isMinimized ); protected: