1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-26 09:28:07 +02:00

TrackPanelAx.cpp freed from cycles leaving 24 in largest s.c.c.

This commit is contained in:
Paul Licameli 2019-06-25 11:23:43 -04:00
commit dc870cf2c5
14 changed files with 200 additions and 120 deletions

View File

@ -1604,6 +1604,7 @@ void ProjectWindow::OnMouseEvent(wxMouseEvent & event)
void ProjectWindow::ZoomAfterImport(Track *pTrack) void ProjectWindow::ZoomAfterImport(Track *pTrack)
{ {
auto &project = mProject; auto &project = mProject;
auto &tracks = TrackList::Get( project );
auto &trackPanel = TrackPanel::Get( project ); auto &trackPanel = TrackPanel::Get( project );
DoZoomFit(); DoZoomFit();
@ -1611,8 +1612,11 @@ void ProjectWindow::ZoomAfterImport(Track *pTrack)
trackPanel.SetFocus(); trackPanel.SetFocus();
RedrawProject(); RedrawProject();
if (!pTrack) if (!pTrack)
pTrack = trackPanel.GetFirstSelectedTrack(); pTrack = *tracks.Selected().begin();
trackPanel.EnsureVisible(pTrack); if (!pTrack)
pTrack = *tracks.Any().begin();
if (pTrack)
pTrack->EnsureVisible();
} }
// Utility function called by other zoom methods // Utility function called by other zoom methods

View File

@ -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) void Track::Merge(const Track &orig)
{ {
mSelected = orig.mSelected; mSelected = orig.mSelected;
@ -475,6 +482,7 @@ std::pair<Track *, Track *> TrackList::FindSyncLockGroup(Track *pMember) const
// //
wxDEFINE_EVENT(EVT_TRACKLIST_TRACK_DATA_CHANGE, TrackListEvent); wxDEFINE_EVENT(EVT_TRACKLIST_TRACK_DATA_CHANGE, TrackListEvent);
wxDEFINE_EVENT(EVT_TRACKLIST_SELECTION_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_PERMUTED, TrackListEvent);
wxDEFINE_EVENT(EVT_TRACKLIST_RESIZING, TrackListEvent); wxDEFINE_EVENT(EVT_TRACKLIST_RESIZING, TrackListEvent);
wxDEFINE_EVENT(EVT_TRACKLIST_ADDITION, TrackListEvent); wxDEFINE_EVENT(EVT_TRACKLIST_ADDITION, TrackListEvent);
@ -579,6 +587,16 @@ void TrackList::DataEvent( const std::shared_ptr<Track> &pTrack, int code )
safenew TrackListEvent{ EVT_TRACKLIST_TRACK_DATA_CHANGE, pTrack, code } ); safenew TrackListEvent{ EVT_TRACKLIST_TRACK_DATA_CHANGE, pTrack, code } );
} }
void TrackList::EnsureVisibleEvent(
const std::shared_ptr<Track> &pTrack, bool modifyState )
{
auto pEvent = std::make_unique<TrackListEvent>(
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) void TrackList::PermutationEvent(TrackNodePointer node)
{ {
// wxWidgets will own the event object // wxWidgets will own the event object

View File

@ -336,6 +336,10 @@ private:
void SetSelected(bool s); 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: public:
virtual ChannelType GetChannel() const { return mChannel;} virtual ChannelType GetChannel() const { return mChannel;}
@ -1091,6 +1095,10 @@ wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API,
wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API,
EVT_TRACKLIST_TRACK_DATA_CHANGE, TrackListEvent); 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. // Posted when tracks are reordered but otherwise unchanged.
// mpTrack points to the moved track that is earliest in the New ordering. // mpTrack points to the moved track that is earliest in the New ordering.
wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API, wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API,
@ -1491,6 +1499,8 @@ private:
void SelectionEvent( const std::shared_ptr<Track> &pTrack ); void SelectionEvent( const std::shared_ptr<Track> &pTrack );
void PermutationEvent(TrackNodePointer node); void PermutationEvent(TrackNodePointer node);
void DataEvent( const std::shared_ptr<Track> &pTrack, int code ); void DataEvent( const std::shared_ptr<Track> &pTrack, int code );
void EnsureVisibleEvent(
const std::shared_ptr<Track> &pTrack, bool modifyState );
void DeletionEvent(TrackNodePointer node = {}); void DeletionEvent(TrackNodePointer node = {});
void AdditionEvent(TrackNodePointer node); void AdditionEvent(TrackNodePointer node);
void ResizingEvent(TrackNodePointer node); void ResizingEvent(TrackNodePointer node);

View File

@ -266,7 +266,16 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
SetBackgroundStyle(wxBG_STYLE_PAINT); SetBackgroundStyle(wxBG_STYLE_PAINT);
{ {
auto pAx = std::make_unique <TrackPanelAx>( this ); auto pAx = std::make_unique <TrackPanelAx>( *project );
pAx->SetWindow( this );
wxWeakRef< TrackPanel > weakThis{ this };
pAx->SetFinder(
[weakThis]( const Track &track ) -> wxRect {
if (weakThis)
return weakThis->FindTrackRect( &track );
return {};
}
);
#if wxUSE_ACCESSIBILITY #if wxUSE_ACCESSIBILITY
// wxWidgets owns the accessible object // wxWidgets owns the accessible object
SetAccessible(mAx = pAx.release()); SetAccessible(mAx = pAx.release());
@ -296,12 +305,17 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
mTracks->Bind(EVT_TRACKLIST_DELETION, mTracks->Bind(EVT_TRACKLIST_DELETION,
&TrackPanel::OnTrackListDeletion, &TrackPanel::OnTrackListDeletion,
this); this);
mTracks->Bind(EVT_TRACKLIST_TRACK_REQUEST_VISIBLE,
&TrackPanel::OnEnsureVisible,
this);
auto theProject = GetProject(); auto theProject = GetProject();
theProject->Bind(EVT_ODTASK_UPDATE, &TrackPanel::OnODTask, this); theProject->Bind(EVT_ODTASK_UPDATE, &TrackPanel::OnODTask, this);
theProject->Bind(EVT_ODTASK_COMPLETE, &TrackPanel::OnODTask, this); theProject->Bind(EVT_ODTASK_COMPLETE, &TrackPanel::OnODTask, this);
theProject->Bind( theProject->Bind(
EVT_PROJECT_SETTINGS_CHANGE, &TrackPanel::OnProjectSettingsChange, this); EVT_PROJECT_SETTINGS_CHANGE, &TrackPanel::OnProjectSettingsChange, this);
theProject->Bind(
EVT_TRACK_FOCUS_CHANGE, &TrackPanel::OnTrackFocusChange, this );
theProject->Bind(EVT_UNDO_RESET, &TrackPanel::OnUndoReset, this); theProject->Bind(EVT_UNDO_RESET, &TrackPanel::OnUndoReset, this);
@ -656,7 +670,7 @@ void TrackPanel::ProcessUIHandleResult
} }
if ((refreshResult & RefreshCode::EnsureVisible) && pClickedTrack) if ((refreshResult & RefreshCode::EnsureVisible) && pClickedTrack)
panel->EnsureVisible(pClickedTrack); pClickedTrack->EnsureVisible();
} }
void TrackPanel::HandlePageUpKey() void TrackPanel::HandlePageUpKey()
@ -703,12 +717,6 @@ void TrackPanel::UpdateAccessibility()
mAx->Updated(); mAx->Updated();
} }
// Counts tracks, counting stereo tracks as one track.
size_t TrackPanel::GetTrackCount() const
{
return GetTracks()->Leaders().size();
}
// Counts selected tracks, counting stereo tracks as one track. // Counts selected tracks, counting stereo tracks as one track.
size_t TrackPanel::GetSelectedTrackCount() const size_t TrackPanel::GetSelectedTrackCount() const
{ {
@ -812,7 +820,7 @@ void TrackPanel::OnMouseEvent(wxMouseEvent & event)
const auto foundCell = FindCell(event.m_x, event.m_y); const auto foundCell = FindCell(event.m_x, event.m_y);
const auto t = FindTrack( foundCell.pCell.get() ); const auto t = FindTrack( foundCell.pCell.get() );
if ( t ) if ( t )
EnsureVisible(t.get()); t->EnsureVisible();
} ); } );
} }
@ -1304,18 +1312,15 @@ void TrackPanel::OnTrackMenu(Track *t)
CellularPanel::DoContextMenu( &TrackView::Get( *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(); e.Skip();
if (t) bool modifyState = e.GetInt();
return t;
else auto pTrack = e.mpTrack.lock();
//if nothing is selected, return the first track auto t = pTrack.get();
return *GetTracks()->Any().begin();
}
void TrackPanel::EnsureVisible(Track * t)
{
SetFocusedTrack(t); SetFocusedTrack(t);
int trackTop = 0; int trackTop = 0;
@ -1349,6 +1354,9 @@ void TrackPanel::EnsureVisible(Track * t)
} }
} }
Refresh(false); Refresh(false);
if ( modifyState )
ProjectHistory::Get( *GetProject() ).ModifyState( false );
} }
// 0.0 scrolls to top // 0.0 scrolls to top
@ -1667,7 +1675,14 @@ void TrackPanel::SetFocusedTrack( Track *t )
// Make sure we always have the first linked track of a stereo track // Make sure we always have the first linked track of a stereo track
t = *GetTracks()->FindLeader(t); t = *GetTracks()->FindLeader(t);
auto cell = mAx->SetFocus( Track::SharedPointer( t ) ).get(); // This will cause callback to the handler function, defined next
mAx->SetFocus( Track::SharedPointer( t ) );
}
void TrackPanel::OnTrackFocusChange( wxCommandEvent &event )
{
event.Skip();
auto cell = mAx->GetFocus().get();
if (cell) { if (cell) {
KeyboardCapture::Capture(this); KeyboardCapture::Capture(this);

View File

@ -91,6 +91,7 @@ class AUDACITY_DLL_API TrackPanel final
void OnTrackListResizing(TrackListEvent & event); void OnTrackListResizing(TrackListEvent & event);
void OnTrackListDeletion(wxEvent & event); void OnTrackListDeletion(wxEvent & event);
void OnEnsureVisible(TrackListEvent & event);
void UpdateViewIfNoTracks(); // Call this to update mViewInfo, etc, after track(s) removal, before Refresh(). void UpdateViewIfNoTracks(); // Call this to update mViewInfo, etc, after track(s) removal, before Refresh().
double GetMostRecentXPos(); double GetMostRecentXPos();
@ -99,6 +100,7 @@ class AUDACITY_DLL_API TrackPanel final
void OnTimer(wxTimerEvent& event); void OnTimer(wxTimerEvent& event);
void OnODTask(wxCommandEvent &event); void OnODTask(wxCommandEvent &event);
void OnProjectSettingsChange(wxCommandEvent &event); void OnProjectSettingsChange(wxCommandEvent &event);
void OnTrackFocusChange( wxCommandEvent &event );
int GetLeftOffset() const { return GetLabelWidth() + 1;} int GetLeftOffset() const { return GetLabelWidth() + 1;}
@ -126,9 +128,7 @@ class AUDACITY_DLL_API TrackPanel final
void ScrollIntoView(int x); void ScrollIntoView(int x);
void OnTrackMenu(Track *t = NULL); void OnTrackMenu(Track *t = NULL);
Track * GetFirstSelectedTrack();
void EnsureVisible(Track * t);
void VerticalScroll( float fracPosition); void VerticalScroll( float fracPosition);
TrackPanelCell *GetFocusedCell() override; TrackPanelCell *GetFocusedCell() override;
@ -149,7 +149,6 @@ class AUDACITY_DLL_API TrackPanel final
bool IsAudioActive(); bool IsAudioActive();
public: public:
size_t GetTrackCount() const;
size_t GetSelectedTrackCount() const; size_t GetSelectedTrackCount() const;
protected: protected:

View File

@ -30,16 +30,20 @@
#include <wx/intl.h> #include <wx/intl.h>
#include "Project.h"
#include "Track.h" #include "Track.h"
#include "TrackPanel.h"
TrackPanelAx::TrackPanelAx( wxWindow *window )
wxDEFINE_EVENT(EVT_TRACK_FOCUS_CHANGE, wxCommandEvent);
TrackPanelAx::TrackPanelAx( AudacityProject &project )
:
#if wxUSE_ACCESSIBILITY #if wxUSE_ACCESSIBILITY
:WindowAccessible( window ) WindowAccessible( nullptr ) // window pointer must be set after construction
,
#endif #endif
mProject{ project }
{ {
mTrackPanel = wxDynamicCast( window, TrackPanel );
mTrackName = true; mTrackName = true;
mMessageCount = 0; mMessageCount = 0;
mNumFocusedTrack = 0; mNumFocusedTrack = 0;
@ -49,6 +53,11 @@ TrackPanelAx::~TrackPanelAx()
{ {
} }
TrackList &TrackPanelAx::GetTracks()
{
return TrackList::Get( mProject );
}
// Returns currently focused track // Returns currently focused track
// if that track no longer exists, if there is a track at // if that track no longer exists, if there is a track at
// the same position, use that, else if there is a first // the same position, use that, else if there is a first
@ -65,7 +74,7 @@ std::shared_ptr<Track> TrackPanelAx::GetFocus()
} }
if (!focusedTrack) { if (!focusedTrack) {
focusedTrack = focusedTrack =
Track::SharedPointer( *mTrackPanel->GetTracks()->Any().first ); Track::SharedPointer( *GetTracks().Any().first );
// only call SetFocus if the focus has changed to avoid // only call SetFocus if the focus has changed to avoid
// unnecessary focus events // unnecessary focus events
if (focusedTrack) if (focusedTrack)
@ -93,25 +102,28 @@ std::shared_ptr<Track> TrackPanelAx::SetFocus( std::shared_ptr<Track> track )
if( focusedTrack && !focusedTrack->GetSelected() ) if( focusedTrack && !focusedTrack->GetSelected() )
{ {
NotifyEvent( wxACC_EVENT_OBJECT_SELECTIONREMOVE, NotifyEvent( wxACC_EVENT_OBJECT_SELECTIONREMOVE,
mTrackPanel, GetWindow(),
wxOBJID_CLIENT, wxOBJID_CLIENT,
TrackNum( focusedTrack ) ); TrackNum( focusedTrack ) );
} }
#endif #endif
if( !track ) if( !track )
track = Track::SharedPointer( *mTrackPanel->GetTracks()->Any().begin() ); track = Track::SharedPointer( *GetTracks().Any().begin() );
mFocusedTrack = track; if ( mFocusedTrack.lock() != track ) {
mFocusedTrack = track;
mProject.QueueEvent( safenew wxCommandEvent{ EVT_TRACK_FOCUS_CHANGE } );
}
mNumFocusedTrack = TrackNum(track); mNumFocusedTrack = TrackNum(track);
#if wxUSE_ACCESSIBILITY #if wxUSE_ACCESSIBILITY
if( track ) if( track )
{ {
if (mTrackPanel == wxWindow::FindFocus()) if (GetWindow() == wxWindow::FindFocus())
{ {
NotifyEvent( wxACC_EVENT_OBJECT_FOCUS, NotifyEvent( wxACC_EVENT_OBJECT_FOCUS,
mTrackPanel, GetWindow(),
wxOBJID_CLIENT, wxOBJID_CLIENT,
mNumFocusedTrack ); mNumFocusedTrack );
} }
@ -119,7 +131,7 @@ std::shared_ptr<Track> TrackPanelAx::SetFocus( std::shared_ptr<Track> track )
if( track->GetSelected() ) if( track->GetSelected() )
{ {
NotifyEvent( wxACC_EVENT_OBJECT_SELECTION, NotifyEvent( wxACC_EVENT_OBJECT_SELECTION,
mTrackPanel, GetWindow(),
wxOBJID_CLIENT, wxOBJID_CLIENT,
mNumFocusedTrack ); mNumFocusedTrack );
} }
@ -127,7 +139,7 @@ std::shared_ptr<Track> TrackPanelAx::SetFocus( std::shared_ptr<Track> track )
else else
{ {
NotifyEvent(wxACC_EVENT_OBJECT_FOCUS, NotifyEvent(wxACC_EVENT_OBJECT_FOCUS,
mTrackPanel, GetWindow(),
wxOBJID_CLIENT, wxOBJID_CLIENT,
wxACC_SELF); wxACC_SELF);
} }
@ -146,7 +158,7 @@ bool TrackPanelAx::IsFocused( const Track *track )
// Remap track pointer if there are oustanding pending updates // Remap track pointer if there are oustanding pending updates
auto origTrack = auto origTrack =
mTrackPanel->GetTracks()->FindById( track->GetId() ); GetTracks().FindById( track->GetId() );
if (origTrack) if (origTrack)
track = origTrack; track = origTrack;
@ -161,7 +173,7 @@ int TrackPanelAx::TrackNum( const std::shared_ptr<Track> &target )
// found // found
int ndx = 0; int ndx = 0;
for ( auto t : mTrackPanel->GetTracks()->Leaders() ) for ( auto t : GetTracks().Leaders() )
{ {
ndx++; ndx++;
if( t == target.get() ) if( t == target.get() )
@ -177,7 +189,7 @@ std::shared_ptr<Track> TrackPanelAx::FindTrack( int num )
{ {
int ndx = 0; int ndx = 0;
for ( auto t : mTrackPanel->GetTracks()->Leaders() ) for ( auto t : GetTracks().Leaders() )
{ {
ndx++; ndx++;
if( ndx == num ) if( ndx == num )
@ -196,12 +208,12 @@ void TrackPanelAx::Updated()
// The object_focus event is only needed by Window-Eyes // The object_focus event is only needed by Window-Eyes
// and can be removed when we cease to support this screen reader. // and can be removed when we cease to support this screen reader.
NotifyEvent(wxACC_EVENT_OBJECT_FOCUS, NotifyEvent(wxACC_EVENT_OBJECT_FOCUS,
mTrackPanel, GetWindow(),
wxOBJID_CLIENT, wxOBJID_CLIENT,
TrackNum(t)); TrackNum(t));
NotifyEvent(wxACC_EVENT_OBJECT_NAMECHANGE, NotifyEvent(wxACC_EVENT_OBJECT_NAMECHANGE,
mTrackPanel, GetWindow(),
wxOBJID_CLIENT, wxOBJID_CLIENT,
TrackNum(t)); TrackNum(t));
#endif #endif
@ -210,7 +222,7 @@ void TrackPanelAx::Updated()
void TrackPanelAx::MessageForScreenReader(const wxString& message) void TrackPanelAx::MessageForScreenReader(const wxString& message)
{ {
#if wxUSE_ACCESSIBILITY #if wxUSE_ACCESSIBILITY
if (mTrackPanel == wxWindow::FindFocus()) if (GetWindow() == wxWindow::FindFocus())
{ {
auto t = GetFocus(); auto t = GetFocus();
int childId = t ? TrackNum(t) : 0; int childId = t ? TrackNum(t) : 0;
@ -225,7 +237,7 @@ void TrackPanelAx::MessageForScreenReader(const wxString& message)
mTrackName = false; mTrackName = false;
NotifyEvent(wxACC_EVENT_OBJECT_NAMECHANGE, NotifyEvent(wxACC_EVENT_OBJECT_NAMECHANGE,
mTrackPanel, GetWindow(),
wxOBJID_CLIENT, wxOBJID_CLIENT,
childId); childId);
} }
@ -254,7 +266,7 @@ wxAccStatus TrackPanelAx::GetChild( int childId, wxAccessible** child )
// Gets the number of children. // Gets the number of children.
wxAccStatus TrackPanelAx::GetChildCount( int* childCount ) wxAccStatus TrackPanelAx::GetChildCount( int* childCount )
{ {
*childCount = mTrackPanel->GetTrackCount(); *childCount = GetTracks().Leaders().size();
return wxACC_OK; return wxACC_OK;
} }
@ -304,7 +316,7 @@ wxAccStatus TrackPanelAx::GetLocation( wxRect& rect, int elementId )
if( elementId == wxACC_SELF ) if( elementId == wxACC_SELF )
{ {
rect = mTrackPanel->GetRect(); rect = GetWindow()->GetRect();
} }
else else
{ {
@ -315,7 +327,7 @@ wxAccStatus TrackPanelAx::GetLocation( wxRect& rect, int elementId )
return wxACC_FAIL; return wxACC_FAIL;
} }
rect = mTrackPanel->FindTrackRect( t.get() ); rect = mFinder ? mFinder( *t ) : wxRect{};
// Inflate the screen reader's rectangle so it overpaints Audacity's own // Inflate the screen reader's rectangle so it overpaints Audacity's own
// yellow focus rectangle. // yellow focus rectangle.
#ifdef __WXMAC__ #ifdef __WXMAC__
@ -326,7 +338,7 @@ wxAccStatus TrackPanelAx::GetLocation( wxRect& rect, int elementId )
rect.Inflate(dx, dx); rect.Inflate(dx, dx);
} }
rect.SetPosition( mTrackPanel->GetParent()->ClientToScreen( rect.GetPosition() ) ); rect.SetPosition( GetWindow()->GetParent()->ClientToScreen( rect.GetPosition() ) );
return wxACC_OK; return wxACC_OK;
} }
@ -593,7 +605,7 @@ wxAccStatus TrackPanelAx::GetFocus( int *childId, wxAccessible **child )
{ {
#if defined(__WXMSW__) #if defined(__WXMSW__)
if (mTrackPanel == wxWindow::FindFocus()) if (GetWindow() == wxWindow::FindFocus())
{ {
auto focusedTrack = mFocusedTrack.lock(); auto focusedTrack = mFocusedTrack.lock();
if (focusedTrack) if (focusedTrack)
@ -703,9 +715,8 @@ wxAccStatus TrackPanelAx::Select(int childId, wxAccSelectionFlags selectFlags)
Track* t = FindTrack(childId).get(); Track* t = FindTrack(childId).get();
if (t) { if (t) {
mTrackPanel->SetFocusedTrack(t); SetFocus( t->SharedPointer() );
mTrackPanel->EnsureVisible(t); t->EnsureVisible();
mTrackPanel->MakeParentModifyState(false);
} }
} }
else else

View File

@ -11,8 +11,10 @@
#ifndef __AUDACITY_TRACK_PANEL_ACCESSIBILITY__ #ifndef __AUDACITY_TRACK_PANEL_ACCESSIBILITY__
#define __AUDACITY_TRACK_PANEL_ACCESSIBILITY__ #define __AUDACITY_TRACK_PANEL_ACCESSIBILITY__
#include <functional>
#include <memory> #include <memory>
#include <wx/event.h> // to declare custom event types
#include <wx/setup.h> // for wxUSE_* macros #include <wx/setup.h> // for wxUSE_* macros
#include <wx/string.h> // member variable #include <wx/string.h> // member variable
@ -21,9 +23,15 @@
#include "widgets/WindowAccessible.h" // to inherit #include "widgets/WindowAccessible.h" // to inherit
#endif #endif
class wxRect;
class AudacityProject;
class Track; class Track;
class TrackPanel; class TrackList;
// An event sent to the project
wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API,
EVT_TRACK_FOCUS_CHANGE, wxCommandEvent);
class TrackPanelAx final class TrackPanelAx final
#if wxUSE_ACCESSIBILITY #if wxUSE_ACCESSIBILITY
@ -31,9 +39,12 @@ class TrackPanelAx final
#endif #endif
{ {
public: public:
TrackPanelAx(wxWindow * window); TrackPanelAx(AudacityProject &project);
virtual ~ TrackPanelAx(); virtual ~ TrackPanelAx();
using RectangleFinder = std::function< wxRect( Track& ) >;
void SetFinder( const RectangleFinder &finder ) { mFinder = finder; }
// Returns currently focused track or first one if none focused // Returns currently focused track or first one if none focused
std::shared_ptr<Track> GetFocus(); std::shared_ptr<Track> GetFocus();
@ -114,14 +125,24 @@ public:
// Modify focus or selection // Modify focus or selection
wxAccStatus Select(int childId, wxAccSelectionFlags selectFlags) override; wxAccStatus Select(int childId, wxAccSelectionFlags selectFlags) override;
#else
wxWindow *GetWindow() const { return mWindow; }
void SetWindow( wxWindow *window ) { mWindow = window; }
#endif #endif
private: private:
TrackList &GetTracks();
int TrackNum( const std::shared_ptr<Track> &track ); int TrackNum( const std::shared_ptr<Track> &track );
std::shared_ptr<Track> FindTrack( int num ); std::shared_ptr<Track> FindTrack( int num );
TrackPanel *mTrackPanel; AudacityProject &mProject;
#if !wxUSE_ACCESSIBILITY
wxWindow *mWindow{};
#endif
RectangleFinder mFinder;
std::weak_ptr<Track> mFocusedTrack; std::weak_ptr<Track> mFocusedTrack;
int mNumFocusedTrack; int mNumFocusedTrack;

View File

@ -50,7 +50,7 @@ void DoRemoveTracks( AudacityProject &project )
// If we actually have something left, then make sure it's seen // If we actually have something left, then make sure it's seen
if (f) if (f)
trackPanel.EnsureVisible(f); f->EnsureVisible();
ProjectHistory::Get( project ) ProjectHistory::Get( project )
.PushState(_("Removed audio track(s)"), _("Remove Track")); .PushState(_("Removed audio track(s)"), _("Remove Track"));

View File

@ -219,9 +219,13 @@ void EffectManager::UnregisterEffect(const PluginID & ID)
if( tracks.size() > nTracksOriginally ){ if( tracks.size() > nTracksOriginally ){
// 0.0 is min scroll position, 1.0 is max scroll position. // 0.0 is min scroll position, 1.0 is max scroll position.
trackPanel.VerticalScroll( 1.0 ); trackPanel.VerticalScroll( 1.0 );
} else { }
trackPanel.EnsureVisible(trackPanel.GetFirstSelectedTrack()); else {
trackPanel.Refresh(false); auto pTrack = *tracks.Selected().begin();
if (!pTrack)
pTrack = *tracks.Any().begin();
if (pTrack)
pTrack->EnsureVisible();
} }
return true; return true;

View File

@ -80,7 +80,6 @@ bool DoPasteNothingSelected(AudacityProject &project)
{ {
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::Get( project );
auto &trackFactory = TrackFactory::Get( project ); auto &trackFactory = TrackFactory::Get( project );
auto &trackPanel = TrackPanel::Get( project );
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion; auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
auto &window = ProjectWindow::Get( project ); auto &window = ProjectWindow::Get( project );
@ -161,7 +160,7 @@ bool DoPasteNothingSelected(AudacityProject &project)
window.RedrawProject(); window.RedrawProject();
if (pFirstNewTrack) if (pFirstNewTrack)
trackPanel.EnsureVisible(pFirstNewTrack); pFirstNewTrack->EnsureVisible();
return true; return true;
} }
@ -178,6 +177,7 @@ struct Handler : CommandHandlerObject {
void OnUndo(const CommandContext &context) void OnUndo(const CommandContext &context)
{ {
auto &project = context.project; auto &project = context.project;
auto &tracks = TrackList::Get( project );
auto &trackPanel = TrackPanel::Get( project ); auto &trackPanel = TrackPanel::Get( project );
auto &undoManager = UndoManager::Get( project ); auto &undoManager = UndoManager::Get( project );
auto &window = ProjectWindow::Get( project ); auto &window = ProjectWindow::Get( project );
@ -196,11 +196,17 @@ void OnUndo(const CommandContext &context)
[&]( const UndoState &state ){ [&]( const UndoState &state ){
ProjectHistory::Get( project ).PopState( 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) void OnRedo(const CommandContext &context)
{ {
auto &project = context.project; auto &project = context.project;
auto &tracks = TrackList::Get( project );
auto &trackPanel = TrackPanel::Get( project ); auto &trackPanel = TrackPanel::Get( project );
auto &undoManager = UndoManager::Get( project ); auto &undoManager = UndoManager::Get( project );
auto &window = ProjectWindow::Get( project ); auto &window = ProjectWindow::Get( project );
@ -218,7 +224,11 @@ void OnRedo(const CommandContext &context)
[&]( const UndoState &state ){ [&]( const UndoState &state ){
ProjectHistory::Get( project ).PopState( 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) void OnCut(const CommandContext &context)
@ -374,7 +384,6 @@ void OnPaste(const CommandContext &context)
{ {
auto &project = context.project; auto &project = context.project;
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::Get( project );
auto &trackPanel = TrackPanel::Get( project );
auto &trackFactory = TrackFactory::Get( project ); auto &trackFactory = TrackFactory::Get( project );
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion; auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
const auto &settings = ProjectSettings::Get( project ); const auto &settings = ProjectSettings::Get( project );
@ -633,7 +642,7 @@ void OnPaste(const CommandContext &context)
window.RedrawProject(); window.RedrawProject();
if (ff) if (ff)
trackPanel.EnsureVisible(ff); ff->EnsureVisible();
} }
} }

View File

@ -78,7 +78,7 @@ int DoAddLabel(
window.RedrawProject(); window.RedrawProject();
if (!useDialog) { if (!useDialog) {
trackPanel.EnsureVisible(lt); lt->EnsureVisible();
} }
trackPanel.SetFocus(); 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 // plt should point to the last label track pasted to -- ensure it's visible
// and set focus // and set focus
if (plt) { if (plt) {
trackPanel.EnsureVisible(plt); plt->EnsureVisible();
trackPanel.SetFocus(); trackPanel.SetFocus();
} }

View File

@ -96,8 +96,8 @@ void DoPrevTrack(
{ {
t = *tracks.Any().rbegin(); t = *tracks.Any().rbegin();
trackPanel.SetFocusedTrack( t ); trackPanel.SetFocusedTrack( t );
trackPanel.EnsureVisible( t ); if (t)
projectHistory.ModifyState(false); t->EnsureVisible( true );
return; return;
} }
@ -116,7 +116,7 @@ void DoPrevTrack(
p = *tracks.Any().rbegin(); p = *tracks.Any().rbegin();
else else
{ {
trackPanel.EnsureVisible( t ); t->EnsureVisible();
return; return;
} }
} }
@ -128,8 +128,8 @@ void DoPrevTrack(
selectionState.SelectTrack selectionState.SelectTrack
( *t, false, false ); ( *t, false, false );
trackPanel.SetFocusedTrack( p ); // move focus to next track up trackPanel.SetFocusedTrack( p ); // move focus to next track up
trackPanel.EnsureVisible( p ); if (p)
projectHistory.ModifyState(false); p->EnsureVisible( true );
return; return;
} }
if( tSelected && !pSelected ) if( tSelected && !pSelected )
@ -137,8 +137,8 @@ void DoPrevTrack(
selectionState.SelectTrack selectionState.SelectTrack
( *p, true, false ); ( *p, true, false );
trackPanel.SetFocusedTrack( p ); // move focus to next track up trackPanel.SetFocusedTrack( p ); // move focus to next track up
trackPanel.EnsureVisible( p ); if (p)
projectHistory.ModifyState(false); p->EnsureVisible( true );
return; return;
} }
if( !tSelected && pSelected ) if( !tSelected && pSelected )
@ -146,8 +146,8 @@ void DoPrevTrack(
selectionState.SelectTrack selectionState.SelectTrack
( *p, false, false ); ( *p, false, false );
trackPanel.SetFocusedTrack( p ); // move focus to next track up trackPanel.SetFocusedTrack( p ); // move focus to next track up
trackPanel.EnsureVisible( p ); if (p)
projectHistory.ModifyState(false); p->EnsureVisible( true );
return; return;
} }
if( !tSelected && !pSelected ) if( !tSelected && !pSelected )
@ -155,8 +155,8 @@ void DoPrevTrack(
selectionState.SelectTrack selectionState.SelectTrack
( *t, true, false ); ( *t, true, false );
trackPanel.SetFocusedTrack( p ); // move focus to next track up trackPanel.SetFocusedTrack( p ); // move focus to next track up
trackPanel.EnsureVisible( p ); if (p)
projectHistory.ModifyState(false); p->EnsureVisible( true );
return; return;
} }
} }
@ -171,21 +171,20 @@ void DoPrevTrack(
auto range = tracks.Leaders(); auto range = tracks.Leaders();
p = * range.rbegin(); // null if range is empty p = * range.rbegin(); // null if range is empty
trackPanel.SetFocusedTrack( p ); // Wrap to the last track trackPanel.SetFocusedTrack( p ); // Wrap to the last track
trackPanel.EnsureVisible( p ); if (p)
projectHistory.ModifyState(false); p->EnsureVisible( true );
return; return;
} }
else else
{ {
trackPanel.EnsureVisible( t ); t->EnsureVisible();
return; return;
} }
} }
else else
{ {
trackPanel.SetFocusedTrack( p ); // move focus to next track up trackPanel.SetFocusedTrack( p ); // move focus to next track up
trackPanel.EnsureVisible( p ); p->EnsureVisible( true );
projectHistory.ModifyState(false);
return; return;
} }
} }
@ -207,8 +206,8 @@ void DoNextTrack(
{ {
t = *tracks.Any().begin(); t = *tracks.Any().begin();
trackPanel.SetFocusedTrack( t ); trackPanel.SetFocusedTrack( t );
trackPanel.EnsureVisible( t ); if (t)
projectHistory.ModifyState(false); t->EnsureVisible( true );
return; return;
} }
@ -222,7 +221,7 @@ void DoNextTrack(
n = *tracks.Any().begin(); n = *tracks.Any().begin();
else else
{ {
trackPanel.EnsureVisible( t ); t->EnsureVisible();
return; return;
} }
} }
@ -233,8 +232,8 @@ void DoNextTrack(
selectionState.SelectTrack selectionState.SelectTrack
( *t, false, false ); ( *t, false, false );
trackPanel.SetFocusedTrack( n ); // move focus to next track down trackPanel.SetFocusedTrack( n ); // move focus to next track down
trackPanel.EnsureVisible( n ); if (n)
projectHistory.ModifyState(false); n->EnsureVisible( true );
return; return;
} }
if( tSelected && !nSelected ) if( tSelected && !nSelected )
@ -242,8 +241,8 @@ void DoNextTrack(
selectionState.SelectTrack selectionState.SelectTrack
( *n, true, false ); ( *n, true, false );
trackPanel.SetFocusedTrack( n ); // move focus to next track down trackPanel.SetFocusedTrack( n ); // move focus to next track down
trackPanel.EnsureVisible( n ); if (n)
projectHistory.ModifyState(false); n->EnsureVisible( true );
return; return;
} }
if( !tSelected && nSelected ) if( !tSelected && nSelected )
@ -251,8 +250,8 @@ void DoNextTrack(
selectionState.SelectTrack selectionState.SelectTrack
( *n, false, false ); ( *n, false, false );
trackPanel.SetFocusedTrack( n ); // move focus to next track down trackPanel.SetFocusedTrack( n ); // move focus to next track down
trackPanel.EnsureVisible( n ); if (n)
projectHistory.ModifyState(false); n->EnsureVisible( true );
return; return;
} }
if( !tSelected && !nSelected ) if( !tSelected && !nSelected )
@ -260,8 +259,8 @@ void DoNextTrack(
selectionState.SelectTrack selectionState.SelectTrack
( *t, true, false ); ( *t, true, false );
trackPanel.SetFocusedTrack( n ); // move focus to next track down trackPanel.SetFocusedTrack( n ); // move focus to next track down
trackPanel.EnsureVisible( n ); if (n)
projectHistory.ModifyState(false); n->EnsureVisible( true );
return; return;
} }
} }
@ -275,21 +274,20 @@ void DoNextTrack(
{ {
n = *tracks.Any().begin(); n = *tracks.Any().begin();
trackPanel.SetFocusedTrack( n ); // Wrap to the first track trackPanel.SetFocusedTrack( n ); // Wrap to the first track
trackPanel.EnsureVisible( n ); if (n)
projectHistory.ModifyState(false); n->EnsureVisible( true );
return; return;
} }
else else
{ {
trackPanel.EnsureVisible( t ); t->EnsureVisible();
return; return;
} }
} }
else else
{ {
trackPanel.SetFocusedTrack( n ); // move focus to next track down trackPanel.SetFocusedTrack( n ); // move focus to next track down
trackPanel.EnsureVisible( n ); n->EnsureVisible( true );
projectHistory.ModifyState(false);
return; return;
} }
} }
@ -472,11 +470,9 @@ void OnFirstTrack(const CommandContext &context)
auto f = *tracks.Any().begin(); auto f = *tracks.Any().begin();
if (t != f) if (t != f)
{
trackPanel.SetFocusedTrack(f); trackPanel.SetFocusedTrack(f);
ProjectHistory::Get( project ).ModifyState(false); if (f)
} f->EnsureVisible( t != f );
trackPanel.EnsureVisible(f);
} }
void OnLastTrack(const CommandContext &context) void OnLastTrack(const CommandContext &context)
@ -491,11 +487,9 @@ void OnLastTrack(const CommandContext &context)
auto l = *tracks.Any().rbegin(); auto l = *tracks.Any().rbegin();
if (t != l) if (t != l)
{
trackPanel.SetFocusedTrack(l); trackPanel.SetFocusedTrack(l);
ProjectHistory::Get( project ).ModifyState(false); if (l)
} l->EnsureVisible( t != l );
trackPanel.EnsureVisible(l);
} }
void OnShiftUp(const CommandContext &context) void OnShiftUp(const CommandContext &context)
@ -524,8 +518,7 @@ void OnToggle(const CommandContext &context)
selectionState.SelectTrack selectionState.SelectTrack
( *t, !t->GetSelected(), true ); ( *t, !t->GetSelected(), true );
trackPanel.EnsureVisible( t ); t->EnsureVisible( true );
ProjectHistory::Get( project ).ModifyState(false);
trackPanel.GetAx().Updated(); trackPanel.GetAx().Updated();

View File

@ -114,7 +114,7 @@ void DoMixAndRender
trackPanel.SetFocus(); trackPanel.SetFocus();
trackPanel.SetFocusedTrack(pNewLeft); trackPanel.SetFocusedTrack(pNewLeft);
trackPanel.EnsureVisible(pNewLeft); pNewLeft->EnsureVisible();
window.RedrawProject(); window.RedrawProject();
} }
} }
@ -577,7 +577,6 @@ void OnNewWaveTrack(const CommandContext &context)
const auto &settings = ProjectSettings::Get( project ); const auto &settings = ProjectSettings::Get( project );
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::Get( project );
auto &trackFactory = TrackFactory::Get( project ); auto &trackFactory = TrackFactory::Get( project );
auto &trackPanel = TrackPanel::Get( project );
auto &window = ProjectWindow::Get( project ); auto &window = ProjectWindow::Get( project );
auto defaultFormat = settings.GetDefaultFormat(); auto defaultFormat = settings.GetDefaultFormat();
@ -592,7 +591,7 @@ void OnNewWaveTrack(const CommandContext &context)
.PushState(_("Created new audio track"), _("New Track")); .PushState(_("Created new audio track"), _("New Track"));
window.RedrawProject(); window.RedrawProject();
trackPanel.EnsureVisible(t); t->EnsureVisible();
} }
void OnNewStereoTrack(const CommandContext &context) void OnNewStereoTrack(const CommandContext &context)
@ -601,7 +600,6 @@ void OnNewStereoTrack(const CommandContext &context)
const auto &settings = ProjectSettings::Get( project ); const auto &settings = ProjectSettings::Get( project );
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::Get( project );
auto &trackFactory = TrackFactory::Get( project ); auto &trackFactory = TrackFactory::Get( project );
auto &trackPanel = TrackPanel::Get( project );
auto &window = ProjectWindow::Get( project ); auto &window = ProjectWindow::Get( project );
auto defaultFormat = settings.GetDefaultFormat(); auto defaultFormat = settings.GetDefaultFormat();
@ -621,7 +619,7 @@ void OnNewStereoTrack(const CommandContext &context)
.PushState(_("Created new stereo audio track"), _("New Track")); .PushState(_("Created new stereo audio track"), _("New Track"));
window.RedrawProject(); window.RedrawProject();
trackPanel.EnsureVisible(left); left->EnsureVisible();
} }
void OnNewLabelTrack(const CommandContext &context) void OnNewLabelTrack(const CommandContext &context)
@ -629,7 +627,6 @@ void OnNewLabelTrack(const CommandContext &context)
auto &project = context.project; auto &project = context.project;
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::Get( project );
auto &trackFactory = TrackFactory::Get( project ); auto &trackFactory = TrackFactory::Get( project );
auto &trackPanel = TrackPanel::Get( project );
auto &window = ProjectWindow::Get( project ); auto &window = ProjectWindow::Get( project );
auto t = tracks.Add( trackFactory.NewLabelTrack() ); auto t = tracks.Add( trackFactory.NewLabelTrack() );
@ -642,7 +639,7 @@ void OnNewLabelTrack(const CommandContext &context)
.PushState(_("Created new label track"), _("New Track")); .PushState(_("Created new label track"), _("New Track"));
window.RedrawProject(); window.RedrawProject();
trackPanel.EnsureVisible(t); t->EnsureVisible();
} }
void OnNewTimeTrack(const CommandContext &context) void OnNewTimeTrack(const CommandContext &context)
@ -650,7 +647,6 @@ void OnNewTimeTrack(const CommandContext &context)
auto &project = context.project; auto &project = context.project;
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::Get( project );
auto &trackFactory = TrackFactory::Get( project ); auto &trackFactory = TrackFactory::Get( project );
auto &trackPanel = TrackPanel::Get( project );
auto &window = ProjectWindow::Get( project ); auto &window = ProjectWindow::Get( project );
if ( *tracks.Any<TimeTrack>().begin() ) { if ( *tracks.Any<TimeTrack>().begin() ) {
@ -668,7 +664,7 @@ void OnNewTimeTrack(const CommandContext &context)
.PushState(_("Created new time track"), _("New Track")); .PushState(_("Created new time track"), _("New Track"));
window.RedrawProject(); window.RedrawProject();
trackPanel.EnsureVisible(t); t->EnsureVisible();
} }
void OnStereoToMono(const CommandContext &context) void OnStereoToMono(const CommandContext &context)

View File

@ -145,7 +145,7 @@ UIHandle::Result TrackSelectHandle::Drag
HitTestPreview TrackSelectHandle::Preview HitTestPreview TrackSelectHandle::Preview
(const TrackPanelMouseState &, const AudacityProject *project) (const TrackPanelMouseState &, const AudacityProject *project)
{ {
const auto trackCount = TrackPanel::Get( *project ).GetTrackCount(); const auto trackCount = TrackList::Get( *project ).Leaders().size();
auto message = Message(trackCount); auto message = Message(trackCount);
if (mClicked) { if (mClicked) {
static auto disabledCursor = static auto disabledCursor =