diff --git a/src/ProjectWindow.cpp b/src/ProjectWindow.cpp index 809372143..a0e7b4bc7 100644 --- a/src/ProjectWindow.cpp +++ b/src/ProjectWindow.cpp @@ -1604,6 +1604,7 @@ void ProjectWindow::OnMouseEvent(wxMouseEvent & event) void ProjectWindow::ZoomAfterImport(Track *pTrack) { auto &project = mProject; + auto &tracks = TrackList::Get( project ); auto &trackPanel = TrackPanel::Get( project ); DoZoomFit(); @@ -1611,8 +1612,11 @@ void ProjectWindow::ZoomAfterImport(Track *pTrack) trackPanel.SetFocus(); RedrawProject(); if (!pTrack) - pTrack = trackPanel.GetFirstSelectedTrack(); - trackPanel.EnsureVisible(pTrack); + pTrack = *tracks.Selected().begin(); + if (!pTrack) + pTrack = *tracks.Any().begin(); + if (pTrack) + pTrack->EnsureVisible(); } // Utility function called by other zoom methods diff --git a/src/Track.cpp b/src/Track.cpp index 9a4d50cd3..aca0103ed 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -101,6 +101,13 @@ void Track::SetSelected(bool s) } } +void Track::EnsureVisible( bool modifyState ) +{ + auto pList = mList.lock(); + if (pList) + pList->EnsureVisibleEvent( SharedPointer(), modifyState ); +} + void Track::Merge(const Track &orig) { mSelected = orig.mSelected; @@ -475,6 +482,7 @@ std::pair TrackList::FindSyncLockGroup(Track *pMember) const // wxDEFINE_EVENT(EVT_TRACKLIST_TRACK_DATA_CHANGE, TrackListEvent); wxDEFINE_EVENT(EVT_TRACKLIST_SELECTION_CHANGE, TrackListEvent); +wxDEFINE_EVENT(EVT_TRACKLIST_TRACK_REQUEST_VISIBLE, TrackListEvent); wxDEFINE_EVENT(EVT_TRACKLIST_PERMUTED, TrackListEvent); wxDEFINE_EVENT(EVT_TRACKLIST_RESIZING, TrackListEvent); wxDEFINE_EVENT(EVT_TRACKLIST_ADDITION, TrackListEvent); @@ -579,6 +587,16 @@ void TrackList::DataEvent( const std::shared_ptr &pTrack, int code ) safenew TrackListEvent{ EVT_TRACKLIST_TRACK_DATA_CHANGE, pTrack, code } ); } +void TrackList::EnsureVisibleEvent( + const std::shared_ptr &pTrack, bool modifyState ) +{ + auto pEvent = std::make_unique( + EVT_TRACKLIST_TRACK_REQUEST_VISIBLE, pTrack, 0 ); + pEvent->SetInt( modifyState ? 1 : 0 ); + // wxWidgets will own the event object + QueueEvent( pEvent.release() ); +} + void TrackList::PermutationEvent(TrackNodePointer node) { // wxWidgets will own the event object diff --git a/src/Track.h b/src/Track.h index d850a983a..5a1757a2d 100644 --- a/src/Track.h +++ b/src/Track.h @@ -336,6 +336,10 @@ private: void SetSelected(bool s); + // The argument tells whether the last undo history state should be + // updated for the appearance change + void EnsureVisible( bool modifyState = false ); + public: virtual ChannelType GetChannel() const { return mChannel;} @@ -1091,6 +1095,10 @@ wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, EVT_TRACKLIST_TRACK_DATA_CHANGE, TrackListEvent); +// Posted when a track needs to be scrolled into view. +wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, + EVT_TRACKLIST_TRACK_REQUEST_VISIBLE, TrackListEvent); + // Posted when tracks are reordered but otherwise unchanged. // mpTrack points to the moved track that is earliest in the New ordering. wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, @@ -1491,6 +1499,8 @@ private: void SelectionEvent( const std::shared_ptr &pTrack ); void PermutationEvent(TrackNodePointer node); void DataEvent( const std::shared_ptr &pTrack, int code ); + void EnsureVisibleEvent( + const std::shared_ptr &pTrack, bool modifyState ); void DeletionEvent(TrackNodePointer node = {}); void AdditionEvent(TrackNodePointer node); void ResizingEvent(TrackNodePointer node); diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 914cfa25b..80e1d4ea2 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -296,6 +296,9 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id, mTracks->Bind(EVT_TRACKLIST_DELETION, &TrackPanel::OnTrackListDeletion, this); + mTracks->Bind(EVT_TRACKLIST_TRACK_REQUEST_VISIBLE, + &TrackPanel::OnEnsureVisible, + this); auto theProject = GetProject(); theProject->Bind(EVT_ODTASK_UPDATE, &TrackPanel::OnODTask, this); @@ -656,7 +659,7 @@ void TrackPanel::ProcessUIHandleResult } if ((refreshResult & RefreshCode::EnsureVisible) && pClickedTrack) - panel->EnsureVisible(pClickedTrack); + pClickedTrack->EnsureVisible(); } void TrackPanel::HandlePageUpKey() @@ -812,7 +815,7 @@ void TrackPanel::OnMouseEvent(wxMouseEvent & event) const auto foundCell = FindCell(event.m_x, event.m_y); const auto t = FindTrack( foundCell.pCell.get() ); if ( t ) - EnsureVisible(t.get()); + t->EnsureVisible(); } ); } @@ -1304,18 +1307,15 @@ void TrackPanel::OnTrackMenu(Track *t) CellularPanel::DoContextMenu( &TrackView::Get( *t ) ); } -Track * TrackPanel::GetFirstSelectedTrack() +// Tracks have been removed from the list. +void TrackPanel::OnEnsureVisible(TrackListEvent & e) { - auto t = *GetTracks()->Selected().begin(); - if (t) - return t; - else - //if nothing is selected, return the first track - return *GetTracks()->Any().begin(); -} + e.Skip(); + bool modifyState = e.GetInt(); + + auto pTrack = e.mpTrack.lock(); + auto t = pTrack.get(); -void TrackPanel::EnsureVisible(Track * t) -{ SetFocusedTrack(t); int trackTop = 0; @@ -1349,6 +1349,9 @@ void TrackPanel::EnsureVisible(Track * t) } } Refresh(false); + + if ( modifyState ) + ProjectHistory::Get( *GetProject() ).ModifyState( false ); } // 0.0 scrolls to top diff --git a/src/TrackPanel.h b/src/TrackPanel.h index ca7f446de..57c6c061e 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -91,6 +91,7 @@ class AUDACITY_DLL_API TrackPanel final void OnTrackListResizing(TrackListEvent & event); void OnTrackListDeletion(wxEvent & event); + void OnEnsureVisible(TrackListEvent & event); void UpdateViewIfNoTracks(); // Call this to update mViewInfo, etc, after track(s) removal, before Refresh(). double GetMostRecentXPos(); @@ -126,9 +127,7 @@ class AUDACITY_DLL_API TrackPanel final void ScrollIntoView(int x); void OnTrackMenu(Track *t = NULL); - Track * GetFirstSelectedTrack(); - void EnsureVisible(Track * t); void VerticalScroll( float fracPosition); TrackPanelCell *GetFocusedCell() override; diff --git a/src/TrackPanelAx.cpp b/src/TrackPanelAx.cpp index 8d5391c3a..d1e8f125a 100644 --- a/src/TrackPanelAx.cpp +++ b/src/TrackPanelAx.cpp @@ -704,8 +704,7 @@ wxAccStatus TrackPanelAx::Select(int childId, wxAccSelectionFlags selectFlags) Track* t = FindTrack(childId).get(); if (t) { mTrackPanel->SetFocusedTrack(t); - mTrackPanel->EnsureVisible(t); - mTrackPanel->MakeParentModifyState(false); + t->EnsureVisible( true ); } } else diff --git a/src/TrackUtilities.cpp b/src/TrackUtilities.cpp index ca2f239af..bd1600a91 100644 --- a/src/TrackUtilities.cpp +++ b/src/TrackUtilities.cpp @@ -50,7 +50,7 @@ void DoRemoveTracks( AudacityProject &project ) // If we actually have something left, then make sure it's seen if (f) - trackPanel.EnsureVisible(f); + f->EnsureVisible(); ProjectHistory::Get( project ) .PushState(_("Removed audio track(s)"), _("Remove Track")); diff --git a/src/effects/EffectManager.cpp b/src/effects/EffectManager.cpp index e0012420d..a3567d60c 100644 --- a/src/effects/EffectManager.cpp +++ b/src/effects/EffectManager.cpp @@ -219,9 +219,13 @@ void EffectManager::UnregisterEffect(const PluginID & ID) if( tracks.size() > nTracksOriginally ){ // 0.0 is min scroll position, 1.0 is max scroll position. trackPanel.VerticalScroll( 1.0 ); - } else { - trackPanel.EnsureVisible(trackPanel.GetFirstSelectedTrack()); - trackPanel.Refresh(false); + } + else { + auto pTrack = *tracks.Selected().begin(); + if (!pTrack) + pTrack = *tracks.Any().begin(); + if (pTrack) + pTrack->EnsureVisible(); } return true; diff --git a/src/menus/EditMenus.cpp b/src/menus/EditMenus.cpp index 79b1865aa..97fdbae80 100644 --- a/src/menus/EditMenus.cpp +++ b/src/menus/EditMenus.cpp @@ -80,7 +80,6 @@ bool DoPasteNothingSelected(AudacityProject &project) { auto &tracks = TrackList::Get( project ); auto &trackFactory = TrackFactory::Get( project ); - auto &trackPanel = TrackPanel::Get( project ); auto &selectedRegion = ViewInfo::Get( project ).selectedRegion; auto &window = ProjectWindow::Get( project ); @@ -161,7 +160,7 @@ bool DoPasteNothingSelected(AudacityProject &project) window.RedrawProject(); if (pFirstNewTrack) - trackPanel.EnsureVisible(pFirstNewTrack); + pFirstNewTrack->EnsureVisible(); return true; } @@ -178,6 +177,7 @@ struct Handler : CommandHandlerObject { void OnUndo(const CommandContext &context) { auto &project = context.project; + auto &tracks = TrackList::Get( project ); auto &trackPanel = TrackPanel::Get( project ); auto &undoManager = UndoManager::Get( project ); auto &window = ProjectWindow::Get( project ); @@ -196,11 +196,17 @@ void OnUndo(const CommandContext &context) [&]( const UndoState &state ){ ProjectHistory::Get( project ).PopState( state ); } ); - trackPanel.EnsureVisible(trackPanel.GetFirstSelectedTrack()); + auto t = *tracks.Selected().begin(); + if (!t) + t = *tracks.Any().begin(); + if (t) + t->EnsureVisible(); } + void OnRedo(const CommandContext &context) { auto &project = context.project; + auto &tracks = TrackList::Get( project ); auto &trackPanel = TrackPanel::Get( project ); auto &undoManager = UndoManager::Get( project ); auto &window = ProjectWindow::Get( project ); @@ -218,7 +224,11 @@ void OnRedo(const CommandContext &context) [&]( const UndoState &state ){ ProjectHistory::Get( project ).PopState( state ); } ); - trackPanel.EnsureVisible(trackPanel.GetFirstSelectedTrack()); + auto t = *tracks.Selected().begin(); + if (!t) + t = *tracks.Any().begin(); + if (t) + t->EnsureVisible(); } void OnCut(const CommandContext &context) @@ -374,7 +384,6 @@ void OnPaste(const CommandContext &context) { auto &project = context.project; auto &tracks = TrackList::Get( project ); - auto &trackPanel = TrackPanel::Get( project ); auto &trackFactory = TrackFactory::Get( project ); auto &selectedRegion = ViewInfo::Get( project ).selectedRegion; const auto &settings = ProjectSettings::Get( project ); @@ -633,7 +642,7 @@ void OnPaste(const CommandContext &context) window.RedrawProject(); if (ff) - trackPanel.EnsureVisible(ff); + ff->EnsureVisible(); } } diff --git a/src/menus/LabelMenus.cpp b/src/menus/LabelMenus.cpp index b5942f266..4fb29dba4 100644 --- a/src/menus/LabelMenus.cpp +++ b/src/menus/LabelMenus.cpp @@ -78,7 +78,7 @@ int DoAddLabel( window.RedrawProject(); if (!useDialog) { - trackPanel.EnsureVisible(lt); + lt->EnsureVisible(); } trackPanel.SetFocus(); @@ -336,7 +336,7 @@ void OnPasteNewLabel(const CommandContext &context) // plt should point to the last label track pasted to -- ensure it's visible // and set focus if (plt) { - trackPanel.EnsureVisible(plt); + plt->EnsureVisible(); trackPanel.SetFocus(); } diff --git a/src/menus/NavigationMenus.cpp b/src/menus/NavigationMenus.cpp index c9c66705c..c668b4dad 100644 --- a/src/menus/NavigationMenus.cpp +++ b/src/menus/NavigationMenus.cpp @@ -96,8 +96,8 @@ void DoPrevTrack( { t = *tracks.Any().rbegin(); trackPanel.SetFocusedTrack( t ); - trackPanel.EnsureVisible( t ); - projectHistory.ModifyState(false); + if (t) + t->EnsureVisible( true ); return; } @@ -116,7 +116,7 @@ void DoPrevTrack( p = *tracks.Any().rbegin(); else { - trackPanel.EnsureVisible( t ); + t->EnsureVisible(); return; } } @@ -128,8 +128,8 @@ void DoPrevTrack( selectionState.SelectTrack ( *t, false, false ); trackPanel.SetFocusedTrack( p ); // move focus to next track up - trackPanel.EnsureVisible( p ); - projectHistory.ModifyState(false); + if (p) + p->EnsureVisible( true ); return; } if( tSelected && !pSelected ) @@ -137,8 +137,8 @@ void DoPrevTrack( selectionState.SelectTrack ( *p, true, false ); trackPanel.SetFocusedTrack( p ); // move focus to next track up - trackPanel.EnsureVisible( p ); - projectHistory.ModifyState(false); + if (p) + p->EnsureVisible( true ); return; } if( !tSelected && pSelected ) @@ -146,8 +146,8 @@ void DoPrevTrack( selectionState.SelectTrack ( *p, false, false ); trackPanel.SetFocusedTrack( p ); // move focus to next track up - trackPanel.EnsureVisible( p ); - projectHistory.ModifyState(false); + if (p) + p->EnsureVisible( true ); return; } if( !tSelected && !pSelected ) @@ -155,8 +155,8 @@ void DoPrevTrack( selectionState.SelectTrack ( *t, true, false ); trackPanel.SetFocusedTrack( p ); // move focus to next track up - trackPanel.EnsureVisible( p ); - projectHistory.ModifyState(false); + if (p) + p->EnsureVisible( true ); return; } } @@ -171,21 +171,20 @@ void DoPrevTrack( auto range = tracks.Leaders(); p = * range.rbegin(); // null if range is empty trackPanel.SetFocusedTrack( p ); // Wrap to the last track - trackPanel.EnsureVisible( p ); - projectHistory.ModifyState(false); + if (p) + p->EnsureVisible( true ); return; } else { - trackPanel.EnsureVisible( t ); + t->EnsureVisible(); return; } } else { trackPanel.SetFocusedTrack( p ); // move focus to next track up - trackPanel.EnsureVisible( p ); - projectHistory.ModifyState(false); + p->EnsureVisible( true ); return; } } @@ -207,8 +206,8 @@ void DoNextTrack( { t = *tracks.Any().begin(); trackPanel.SetFocusedTrack( t ); - trackPanel.EnsureVisible( t ); - projectHistory.ModifyState(false); + if (t) + t->EnsureVisible( true ); return; } @@ -222,7 +221,7 @@ void DoNextTrack( n = *tracks.Any().begin(); else { - trackPanel.EnsureVisible( t ); + t->EnsureVisible(); return; } } @@ -233,8 +232,8 @@ void DoNextTrack( selectionState.SelectTrack ( *t, false, false ); trackPanel.SetFocusedTrack( n ); // move focus to next track down - trackPanel.EnsureVisible( n ); - projectHistory.ModifyState(false); + if (n) + n->EnsureVisible( true ); return; } if( tSelected && !nSelected ) @@ -242,8 +241,8 @@ void DoNextTrack( selectionState.SelectTrack ( *n, true, false ); trackPanel.SetFocusedTrack( n ); // move focus to next track down - trackPanel.EnsureVisible( n ); - projectHistory.ModifyState(false); + if (n) + n->EnsureVisible( true ); return; } if( !tSelected && nSelected ) @@ -251,8 +250,8 @@ void DoNextTrack( selectionState.SelectTrack ( *n, false, false ); trackPanel.SetFocusedTrack( n ); // move focus to next track down - trackPanel.EnsureVisible( n ); - projectHistory.ModifyState(false); + if (n) + n->EnsureVisible( true ); return; } if( !tSelected && !nSelected ) @@ -260,8 +259,8 @@ void DoNextTrack( selectionState.SelectTrack ( *t, true, false ); trackPanel.SetFocusedTrack( n ); // move focus to next track down - trackPanel.EnsureVisible( n ); - projectHistory.ModifyState(false); + if (n) + n->EnsureVisible( true ); return; } } @@ -275,21 +274,20 @@ void DoNextTrack( { n = *tracks.Any().begin(); trackPanel.SetFocusedTrack( n ); // Wrap to the first track - trackPanel.EnsureVisible( n ); - projectHistory.ModifyState(false); + if (n) + n->EnsureVisible( true ); return; } else { - trackPanel.EnsureVisible( t ); + t->EnsureVisible(); return; } } else { trackPanel.SetFocusedTrack( n ); // move focus to next track down - trackPanel.EnsureVisible( n ); - projectHistory.ModifyState(false); + n->EnsureVisible( true ); return; } } @@ -472,11 +470,9 @@ void OnFirstTrack(const CommandContext &context) auto f = *tracks.Any().begin(); if (t != f) - { trackPanel.SetFocusedTrack(f); - ProjectHistory::Get( project ).ModifyState(false); - } - trackPanel.EnsureVisible(f); + if (f) + f->EnsureVisible( t != f ); } void OnLastTrack(const CommandContext &context) @@ -491,11 +487,9 @@ void OnLastTrack(const CommandContext &context) auto l = *tracks.Any().rbegin(); if (t != l) - { trackPanel.SetFocusedTrack(l); - ProjectHistory::Get( project ).ModifyState(false); - } - trackPanel.EnsureVisible(l); + if (l) + l->EnsureVisible( t != l ); } void OnShiftUp(const CommandContext &context) @@ -524,8 +518,7 @@ void OnToggle(const CommandContext &context) selectionState.SelectTrack ( *t, !t->GetSelected(), true ); - trackPanel.EnsureVisible( t ); - ProjectHistory::Get( project ).ModifyState(false); + t->EnsureVisible( true ); trackPanel.GetAx().Updated(); diff --git a/src/menus/TrackMenus.cpp b/src/menus/TrackMenus.cpp index ffe61516b..e1cd080c0 100644 --- a/src/menus/TrackMenus.cpp +++ b/src/menus/TrackMenus.cpp @@ -114,7 +114,7 @@ void DoMixAndRender trackPanel.SetFocus(); trackPanel.SetFocusedTrack(pNewLeft); - trackPanel.EnsureVisible(pNewLeft); + pNewLeft->EnsureVisible(); window.RedrawProject(); } } @@ -577,7 +577,6 @@ void OnNewWaveTrack(const CommandContext &context) const auto &settings = ProjectSettings::Get( project ); auto &tracks = TrackList::Get( project ); auto &trackFactory = TrackFactory::Get( project ); - auto &trackPanel = TrackPanel::Get( project ); auto &window = ProjectWindow::Get( project ); auto defaultFormat = settings.GetDefaultFormat(); @@ -592,7 +591,7 @@ void OnNewWaveTrack(const CommandContext &context) .PushState(_("Created new audio track"), _("New Track")); window.RedrawProject(); - trackPanel.EnsureVisible(t); + t->EnsureVisible(); } void OnNewStereoTrack(const CommandContext &context) @@ -601,7 +600,6 @@ void OnNewStereoTrack(const CommandContext &context) const auto &settings = ProjectSettings::Get( project ); auto &tracks = TrackList::Get( project ); auto &trackFactory = TrackFactory::Get( project ); - auto &trackPanel = TrackPanel::Get( project ); auto &window = ProjectWindow::Get( project ); auto defaultFormat = settings.GetDefaultFormat(); @@ -621,7 +619,7 @@ void OnNewStereoTrack(const CommandContext &context) .PushState(_("Created new stereo audio track"), _("New Track")); window.RedrawProject(); - trackPanel.EnsureVisible(left); + left->EnsureVisible(); } void OnNewLabelTrack(const CommandContext &context) @@ -629,7 +627,6 @@ void OnNewLabelTrack(const CommandContext &context) auto &project = context.project; auto &tracks = TrackList::Get( project ); auto &trackFactory = TrackFactory::Get( project ); - auto &trackPanel = TrackPanel::Get( project ); auto &window = ProjectWindow::Get( project ); auto t = tracks.Add( trackFactory.NewLabelTrack() ); @@ -642,7 +639,7 @@ void OnNewLabelTrack(const CommandContext &context) .PushState(_("Created new label track"), _("New Track")); window.RedrawProject(); - trackPanel.EnsureVisible(t); + t->EnsureVisible(); } void OnNewTimeTrack(const CommandContext &context) @@ -650,7 +647,6 @@ void OnNewTimeTrack(const CommandContext &context) auto &project = context.project; auto &tracks = TrackList::Get( project ); auto &trackFactory = TrackFactory::Get( project ); - auto &trackPanel = TrackPanel::Get( project ); auto &window = ProjectWindow::Get( project ); if ( *tracks.Any().begin() ) { @@ -668,7 +664,7 @@ void OnNewTimeTrack(const CommandContext &context) .PushState(_("Created new time track"), _("New Track")); window.RedrawProject(); - trackPanel.EnsureVisible(t); + t->EnsureVisible(); } void OnStereoToMono(const CommandContext &context)