1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-11 06:07:44 +02:00

Remove some direct dependencies on TrackPanel

This commit is contained in:
Paul Licameli 2019-07-03 14:54:10 -04:00
commit 3af2063fa3
13 changed files with 301 additions and 247 deletions

View File

@ -132,6 +132,11 @@ void AudacityProject::SetFrame( wxFrame *pFrame )
mFrame = pFrame; mFrame = pFrame;
} }
void AudacityProject::SetPanel( wxWindow *pPanel )
{
mPanel = pPanel;
}
wxString AudacityProject::GetProjectName() const wxString AudacityProject::GetProjectName() const
{ {
wxString name = wxFileNameFromPath(mFileName); wxString name = wxFileNameFromPath(mFileName);
@ -159,3 +164,20 @@ AUDACITY_DLL_API const wxFrame &GetProjectFrame( const AudacityProject &project
THROW_INCONSISTENCY_EXCEPTION; THROW_INCONSISTENCY_EXCEPTION;
return *ptr; return *ptr;
} }
AUDACITY_DLL_API wxWindow &GetProjectPanel( AudacityProject &project )
{
auto ptr = project.GetPanel();
if ( !ptr )
THROW_INCONSISTENCY_EXCEPTION;
return *ptr;
}
AUDACITY_DLL_API const wxWindow &GetProjectPanel(
const AudacityProject &project )
{
auto ptr = project.GetPanel();
if ( !ptr )
THROW_INCONSISTENCY_EXCEPTION;
return *ptr;
}

View File

@ -115,6 +115,10 @@ class AUDACITY_DLL_API AudacityProject final
const wxFrame *GetFrame() const { return mFrame; } const wxFrame *GetFrame() const { return mFrame; }
void SetFrame( wxFrame *pFrame ); void SetFrame( wxFrame *pFrame );
wxWindow *GetPanel() { return mPanel; }
const wxWindow *GetPanel() const { return mPanel; }
void SetPanel( wxWindow *pPanel );
wxString GetProjectName() const; wxString GetProjectName() const;
const FilePath &GetFileName() { return mFileName; } const FilePath &GetFileName() { return mFileName; }
@ -136,6 +140,7 @@ class AUDACITY_DLL_API AudacityProject final
private: private:
wxWeakRef< wxFrame > mFrame{}; wxWeakRef< wxFrame > mFrame{};
wxWeakRef< wxWindow > mPanel{};
}; };
///\brief Get the top-level window associated with the project (as a wxFrame ///\brief Get the top-level window associated with the project (as a wxFrame
@ -152,4 +157,10 @@ inline const wxFrame *FindProjectFrame( const AudacityProject *project ) {
return project ? &GetProjectFrame( *project ) : nullptr; return project ? &GetProjectFrame( *project ) : nullptr;
} }
///\brief Get the main sub-window of the project frame that displays track data
// (as a wxWindow only, when you do not need to use the subclass TrackPanel)
AUDACITY_DLL_API wxWindow &GetProjectPanel( AudacityProject &project );
AUDACITY_DLL_API const wxWindow &GetProjectPanel(
const AudacityProject &project );
#endif #endif

View File

@ -49,9 +49,16 @@ Paul Licameli split from AudacityProject.cpp
#include "widgets/AudacityMessageBox.h" #include "widgets/AudacityMessageBox.h"
#include "widgets/FileHistory.h" #include "widgets/FileHistory.h"
#include "widgets/ErrorDialog.h" #include "widgets/ErrorDialog.h"
#include "widgets/WindowAccessible.h"
#include <wx/dataobj.h> #include <wx/dataobj.h>
#include <wx/dnd.h> #include <wx/dnd.h>
#include <wx/scrolbar.h>
#include <wx/sizer.h>
#ifdef __WXGTK__
#include "../images/AudacityLogoAlpha.xpm"
#endif
const int AudacityProjectTimerID = 5200; const int AudacityProjectTimerID = 5200;
@ -347,6 +354,174 @@ private:
#endif #endif
void InitProjectWindow( ProjectWindow &window )
{
auto &project = window.GetProject();
#ifdef EXPERIMENTAL_DA2
SetBackgroundColour(theTheme.Colour( clrMedium ));
#endif
// Note that the first field of the status bar is a dummy, and its width is set
// to zero latter in the code. This field is needed for wxWidgets 2.8.12 because
// if you move to the menu bar, the first field of the menu bar is cleared, which
// is undesirable behaviour.
// In addition, the help strings of menu items are by default sent to the first
// field. Currently there are no such help strings, but it they were introduced, then
// there would need to be an event handler to send them to the appropriate field.
auto statusBar = window.CreateStatusBar(4);
#if wxUSE_ACCESSIBILITY
// so that name can be set on a standard control
statusBar->SetAccessible(safenew WindowAccessible(statusBar));
#endif
statusBar->SetName(wxT("status_line")); // not localized
auto &viewInfo = ViewInfo::Get( project );
// LLL: Read this!!!
//
// Until the time (and cpu) required to refresh the track panel is
// reduced, leave the following window creations in the order specified.
// This will place the refresh of the track panel last, allowing all
// the others to get done quickly.
//
// Near as I can tell, this is only a problem under Windows.
//
//
// Create the ToolDock
//
ToolManager::Get( project ).LayoutToolBars();
//
// Create the horizontal ruler
//
auto &ruler = AdornedRulerPanel::Get( project );
//
// Create the TrackPanel and the scrollbars
//
auto topPanel = window.GetTopPanel();
{
auto ubs = std::make_unique<wxBoxSizer>(wxVERTICAL);
ubs->Add( ToolManager::Get( project ).GetTopDock(), 0, wxEXPAND | wxALIGN_TOP );
ubs->Add(&ruler, 0, wxEXPAND);
topPanel->SetSizer(ubs.release());
}
// Ensure that the topdock comes before the ruler in the tab order,
// irrespective of the order in which they were created.
ToolManager::Get(project).GetTopDock()->MoveBeforeInTabOrder(&ruler);
const auto pPage = window.GetMainPage();
wxBoxSizer *bs;
{
auto ubs = std::make_unique<wxBoxSizer>(wxVERTICAL);
bs = ubs.get();
bs->Add(topPanel, 0, wxEXPAND | wxALIGN_TOP);
bs->Add(pPage, 1, wxEXPAND);
bs->Add( ToolManager::Get( project ).GetBotDock(), 0, wxEXPAND );
window.SetAutoLayout(true);
window.SetSizer(ubs.release());
}
bs->Layout();
auto &trackPanel = TrackPanel::Get( project );
// LLL: When Audacity starts or becomes active after returning from
// another application, the first window that can accept focus
// will be given the focus even if we try to SetFocus(). By
// making the TrackPanel that first window, we resolve several
// keyboard focus problems.
pPage->MoveBeforeInTabOrder(topPanel);
bs = (wxBoxSizer *)pPage->GetSizer();
auto vsBar = &window.GetVerticalScrollBar();
auto hsBar = &window.GetHorizontalScrollBar();
{
// Top horizontal grouping
auto hs = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
// Track panel
hs->Add(&trackPanel, 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP);
{
// Vertical grouping
auto vs = std::make_unique<wxBoxSizer>(wxVERTICAL);
// Vertical scroll bar
vs->Add(vsBar, 1, wxEXPAND | wxALIGN_TOP);
hs->Add(vs.release(), 0, wxEXPAND | wxALIGN_TOP);
}
bs->Add(hs.release(), 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP);
}
{
// Bottom horizontal grouping
auto hs = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
// Bottom scrollbar
hs->Add(viewInfo.GetLeftOffset() - 1, 0);
hs->Add(hsBar, 1, wxALIGN_BOTTOM);
hs->Add(vsBar->GetSize().GetWidth(), 0);
bs->Add(hs.release(), 0, wxEXPAND | wxALIGN_LEFT);
}
// Lay it out
pPage->SetAutoLayout(true);
pPage->Layout();
#ifdef EXPERIMENTAL_NOTEBOOK
AddPages(this, Factory, pNotebook);
#endif
auto mainPanel = window.GetMainPanel();
mainPanel->Layout();
wxASSERT( trackPanel.GetProject() == &project );
// MM: Give track panel the focus to ensure keyboard commands work
trackPanel.SetFocus();
window.FixScrollbars();
ruler.SetLeftOffset(viewInfo.GetLeftOffset()); // bevel on AdornedRuler
//
// Set the Icon
//
// loads either the XPM or the windows resource, depending on the platform
#if !defined(__WXMAC__) && !defined(__WXX11__)
{
#if defined(__WXMSW__)
wxIcon ic{ wxICON(AudacityLogo) };
#elif defined(__WXGTK__)
wxIcon ic{wxICON(AudacityLogoAlpha)};
#else
wxIcon ic{};
ic.CopyFromBitmap(theTheme.Bitmap(bmpAudacityLogo48x48));
#endif
window.SetIcon(ic);
}
#endif
window.UpdateStatusWidths();
wxString msg = wxString::Format(_("Welcome to Audacity version %s"),
AUDACITY_VERSION_STRING);
statusBar->SetStatusText(msg, mainStatusBarField);
#ifdef EXPERIMENTAL_DA2
ClearBackground();// For wxGTK.
#endif
}
AudacityProject *ProjectManager::New() AudacityProject *ProjectManager::New()
{ {
wxRect wndRect; wxRect wndRect;
@ -363,7 +538,7 @@ AudacityProject *ProjectManager::New()
auto &projectHistory = ProjectHistory::Get( project ); auto &projectHistory = ProjectHistory::Get( project );
auto &projectManager = Get( project ); auto &projectManager = Get( project );
auto &window = ProjectWindow::Get( *p ); auto &window = ProjectWindow::Get( *p );
window.Init(); InitProjectWindow( window );
ProjectFileIO::Get( *p ).SetProjectTitle(); ProjectFileIO::Get( *p ).SetProjectTitle();
@ -906,3 +1081,14 @@ int ProjectManager::GetEstimatedRecordingMinsLeftOnDisk(long lCaptureChannels) {
int iRecMins = (int)round(dRecTime / 60.0); int iRecMins = (int)round(dRecTime / 60.0);
return iRecMins; return iRecMins;
} }
/// This was moved here to eliminate dependency of Scrubbing.cpp on
/// TrackPanel, but perhaps a better home should be found for it in future
#include "tracks/ui/Scrubbing.h"
static const AudacityProject::AttachedObjects::RegisteredFactory sOverlayKey{
[]( AudacityProject &parent ){
auto result = std::make_shared< ScrubbingOverlay >( &parent );
TrackPanel::Get( parent ).AddOverlay( result );
return result;
}
};

View File

@ -19,7 +19,6 @@ Paul Licameli split from AudacityProject.cpp
#include "ProjectAudioIO.h" #include "ProjectAudioIO.h"
#include "ProjectStatus.h" #include "ProjectStatus.h"
#include "RefreshCode.h" #include "RefreshCode.h"
#include "TrackPanel.h"
#include "TrackPanelMouseEvent.h" #include "TrackPanelMouseEvent.h"
#include "UndoManager.h" #include "UndoManager.h"
#include "ViewInfo.h" #include "ViewInfo.h"
@ -37,10 +36,6 @@ Paul Licameli split from AudacityProject.cpp
#include <wx/scrolbar.h> #include <wx/scrolbar.h>
#include <wx/sizer.h> #include <wx/sizer.h>
#ifdef __WXGTK__
#include "../images/AudacityLogoAlpha.xpm"
#endif
// Returns the screen containing a rectangle, or -1 if none does. // Returns the screen containing a rectangle, or -1 if none does.
int ScreenContaining( wxRect & r ){ int ScreenContaining( wxRect & r ){
unsigned int n = wxDisplay::GetCount(); unsigned int n = wxDisplay::GetCount();
@ -641,92 +636,15 @@ ProjectWindow::ProjectWindow(wxWindow * parent, wxWindowID id,
mPlaybackScroller = std::make_unique<PlaybackScroller>( &project ); mPlaybackScroller = std::make_unique<PlaybackScroller>( &project );
project.Bind( EVT_UNDO_MODIFIED, &ProjectWindow::OnUndoPushedModified, this ); // PRL: Old comments below. No longer observing the ordering that it
project.Bind( EVT_UNDO_PUSHED, &ProjectWindow::OnUndoPushedModified, this ); // recommends. ProjectWindow::OnActivate puts the focus directly into
project.Bind( EVT_UNDO_OR_REDO, &ProjectWindow::OnUndoRedo, this ); // the TrackPanel, which avoids the problems.
project.Bind( EVT_UNDO_RESET, &ProjectWindow::OnUndoReset, this );
}
void ProjectWindow::Init()
{
auto &project = mProject;
#ifdef EXPERIMENTAL_DA2
SetBackgroundColour(theTheme.Colour( clrMedium ));
#endif
// Note that the first field of the status bar is a dummy, and its width is set
// to zero latter in the code. This field is needed for wxWidgets 2.8.12 because
// if you move to the menu bar, the first field of the menu bar is cleared, which
// is undesirable behaviour.
// In addition, the help strings of menu items are by default sent to the first
// field. Currently there are no such help strings, but it they were introduced, then
// there would need to be an event handler to send them to the appropriate field.
auto statusBar = CreateStatusBar(4);
#if wxUSE_ACCESSIBILITY
// so that name can be set on a standard control
statusBar->SetAccessible(safenew WindowAccessible(statusBar));
#endif
statusBar->SetName(wxT("status_line")); // not localized
auto &viewInfo = ViewInfo::Get( project );
// LLL: Read this!!!
//
// Until the time (and cpu) required to refresh the track panel is
// reduced, leave the following window creations in the order specified.
// This will place the refresh of the track panel last, allowing all
// the others to get done quickly.
//
// Near as I can tell, this is only a problem under Windows.
//
//
// Create the ToolDock
//
ToolManager::Get( project ).LayoutToolBars();
//
// Create the horizontal ruler
//
auto &ruler = AdornedRulerPanel::Get( project );
//
// Create the TrackPanel and the scrollbars
//
{
auto ubs = std::make_unique<wxBoxSizer>(wxVERTICAL);
ubs->Add( ToolManager::Get( project ).GetTopDock(), 0, wxEXPAND | wxALIGN_TOP );
ubs->Add(&ruler, 0, wxEXPAND);
mTopPanel->SetSizer(ubs.release());
}
// Ensure that the topdock comes before the ruler in the tab order,
// irrespective of the order in which they were created.
ToolManager::Get(project).GetTopDock()->MoveBeforeInTabOrder(&ruler);
const auto pPage = GetMainPage();
wxBoxSizer *bs;
{
auto ubs = std::make_unique<wxBoxSizer>(wxVERTICAL);
bs = ubs.get();
bs->Add(mTopPanel, 0, wxEXPAND | wxALIGN_TOP);
bs->Add(pPage, 1, wxEXPAND);
bs->Add( ToolManager::Get( project ).GetBotDock(), 0, wxEXPAND );
SetAutoLayout(true);
SetSizer(ubs.release());
}
bs->Layout();
auto &trackPanel = TrackPanel::Get( project );
// LLL: When Audacity starts or becomes active after returning from // LLL: When Audacity starts or becomes active after returning from
// another application, the first window that can accept focus // another application, the first window that can accept focus
// will be given the focus even if we try to SetFocus(). By // will be given the focus even if we try to SetFocus(). By
// creating the scrollbars after the TrackPanel, we resolve // creating the scrollbars after the TrackPanel, we resolve
// several focus problems. // several focus problems.
mHsbar = safenew ScrollBar(pPage, HSBarID, wxSB_HORIZONTAL); mHsbar = safenew ScrollBar(pPage, HSBarID, wxSB_HORIZONTAL);
mVsbar = safenew ScrollBar(pPage, VSBarID, wxSB_VERTICAL); mVsbar = safenew ScrollBar(pPage, VSBarID, wxSB_VERTICAL);
#if wxUSE_ACCESSIBILITY #if wxUSE_ACCESSIBILITY
@ -737,93 +655,13 @@ void ProjectWindow::Init()
mHsbar->SetLayoutDirection(wxLayout_LeftToRight); mHsbar->SetLayoutDirection(wxLayout_LeftToRight);
mHsbar->SetName(_("Horizontal Scrollbar")); mHsbar->SetName(_("Horizontal Scrollbar"));
mVsbar->SetName(_("Vertical Scrollbar")); mVsbar->SetName(_("Vertical Scrollbar"));
// LLL: When Audacity starts or becomes active after returning from
// another application, the first window that can accept focus
// will be given the focus even if we try to SetFocus(). By
// making the TrackPanel that first window, we resolve several
// keyboard focus problems.
pPage->MoveBeforeInTabOrder(mTopPanel);
bs = (wxBoxSizer *)pPage->GetSizer(); project.Bind( EVT_UNDO_MODIFIED, &ProjectWindow::OnUndoPushedModified, this );
project.Bind( EVT_UNDO_PUSHED, &ProjectWindow::OnUndoPushedModified, this );
{ project.Bind( EVT_UNDO_OR_REDO, &ProjectWindow::OnUndoRedo, this );
// Top horizontal grouping project.Bind( EVT_UNDO_RESET, &ProjectWindow::OnUndoReset, this );
auto hs = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
// Track panel
hs->Add(&trackPanel, 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP);
{
// Vertical grouping
auto vs = std::make_unique<wxBoxSizer>(wxVERTICAL);
// Vertical scroll bar
vs->Add(mVsbar, 1, wxEXPAND | wxALIGN_TOP);
hs->Add(vs.release(), 0, wxEXPAND | wxALIGN_TOP);
}
bs->Add(hs.release(), 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP);
}
{
// Bottom horizontal grouping
auto hs = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
// Bottom scrollbar
hs->Add(viewInfo.GetLeftOffset() - 1, 0);
hs->Add(mHsbar, 1, wxALIGN_BOTTOM);
hs->Add(mVsbar->GetSize().GetWidth(), 0);
bs->Add(hs.release(), 0, wxEXPAND | wxALIGN_LEFT);
}
// Lay it out
pPage->SetAutoLayout(true);
pPage->Layout();
#ifdef EXPERIMENTAL_NOTEBOOK
AddPages(this, Factory, pNotebook);
#endif
mMainPanel->Layout();
wxASSERT( trackPanel.GetProject() == &project );
// MM: Give track panel the focus to ensure keyboard commands work
trackPanel.SetFocus();
FixScrollbars();
ruler.SetLeftOffset(viewInfo.GetLeftOffset()); // bevel on AdornedRuler
//
// Set the Icon
//
// loads either the XPM or the windows resource, depending on the platform
#if !defined(__WXMAC__) && !defined(__WXX11__)
{
#if defined(__WXMSW__)
wxIcon ic{ wxICON(AudacityLogo) };
#elif defined(__WXGTK__)
wxIcon ic{wxICON(AudacityLogoAlpha)};
#else
wxIcon ic{};
ic.CopyFromBitmap(theTheme.Bitmap(bmpAudacityLogo48x48));
#endif
SetIcon(ic);
}
#endif
mIconized = false;
UpdateStatusWidths();
wxString msg = wxString::Format(_("Welcome to Audacity version %s"),
AUDACITY_VERSION_STRING);
statusBar->SetStatusText(msg, mainStatusBarField);
wxTheApp->Bind(EVT_THEME_CHANGE, &ProjectWindow::OnThemeChange, this); wxTheApp->Bind(EVT_THEME_CHANGE, &ProjectWindow::OnThemeChange, this);
#ifdef EXPERIMENTAL_DA2
ClearBackground();// For wxGTK.
#endif
} }
ProjectWindow::~ProjectWindow() ProjectWindow::~ProjectWindow()
@ -871,7 +709,7 @@ void ProjectWindow::RedrawProject(const bool bForceWaveTracks /*= false*/)
auto &project = pThis->mProject ; auto &project = pThis->mProject ;
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::Get( project );
auto &trackPanel = TrackPanel::Get( project ); auto &trackPanel = GetProjectPanel( project );
pThis->FixScrollbars(); pThis->FixScrollbars();
if (bForceWaveTracks) if (bForceWaveTracks)
{ {
@ -935,6 +773,28 @@ const int sbarHjump = 30; //STM: This is how far the thumb jumps when the
#include "AllThemeResources.h" #include "AllThemeResources.h"
#endif #endif
// Make sure selection edge is in view
void ProjectWindow::ScrollIntoView(double pos)
{
auto &trackPanel = GetProjectPanel( mProject );
auto &viewInfo = ViewInfo::Get( mProject );
auto w = viewInfo.GetTracksUsableWidth();
int pixel = viewInfo.TimeToPosition(pos);
if (pixel < 0 || pixel >= w)
{
TP_ScrollWindow
(viewInfo.OffsetTimeByPixels(pos, -(w / 2)));
trackPanel.Refresh(false);
}
}
void ProjectWindow::ScrollIntoView(int x)
{
auto &viewInfo = ViewInfo::Get( mProject );
ScrollIntoView(viewInfo.PositionToTime(x, viewInfo.GetLeftOffset()));
}
/// ///
/// This method handles general left-scrolling, either for drag-scrolling /// This method handles general left-scrolling, either for drag-scrolling
/// or when the scrollbar is clicked to the left of the thumb /// or when the scrollbar is clicked to the left of the thumb
@ -1141,7 +1001,7 @@ void ProjectWindow::FixScrollbars()
{ {
auto &project = mProject; auto &project = mProject;
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::Get( project );
auto &trackPanel = TrackPanel::Get( project ); auto &trackPanel = GetProjectPanel( project );
auto &viewInfo = ViewInfo::Get( project ); auto &viewInfo = ViewInfo::Get( project );
bool refresh = false; bool refresh = false;
@ -1296,7 +1156,7 @@ void ProjectWindow::FixScrollbars()
void ProjectWindow::UpdateLayout() void ProjectWindow::UpdateLayout()
{ {
auto &project = mProject; auto &project = mProject;
auto &trackPanel = TrackPanel::Get( project ); auto &trackPanel = GetProjectPanel( project );
auto &toolManager = ToolManager::Get( project ); auto &toolManager = ToolManager::Get( project );
// 1. Layout panel, to get widths of the docks. // 1. Layout panel, to get widths of the docks.
@ -1503,7 +1363,7 @@ void ProjectWindow::OnScroll(wxScrollEvent & WXUNUSED(event))
void ProjectWindow::DoScroll() void ProjectWindow::DoScroll()
{ {
auto &project = mProject; auto &project = mProject;
auto &trackPanel = TrackPanel::Get( project ); auto &trackPanel = GetProjectPanel( project );
auto &viewInfo = ViewInfo::Get( project ); auto &viewInfo = ViewInfo::Get( project );
const double lowerBound = ScrollingLowerBoundTime(); const double lowerBound = ScrollingLowerBoundTime();
@ -1619,7 +1479,7 @@ void ProjectWindow::OnActivate(wxActivateEvent & event)
auto &toolManager = ToolManager::Get( project ); auto &toolManager = ToolManager::Get( project );
SetActiveProject( &project ); SetActiveProject( &project );
if ( ! toolManager.RestoreFocus() ) if ( ! toolManager.RestoreFocus() )
TrackPanel::Get( project ).SetFocus(); GetProjectPanel( project ).SetFocus();
#ifdef __WXMAC__ #ifdef __WXMAC__
MacShowUndockedToolbars(true); MacShowUndockedToolbars(true);
@ -1644,7 +1504,7 @@ void ProjectWindow::ZoomAfterImport(Track *pTrack)
{ {
auto &project = mProject; auto &project = mProject;
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::Get( project );
auto &trackPanel = TrackPanel::Get( project ); auto &trackPanel = GetProjectPanel( project );
DoZoomFit(); DoZoomFit();
@ -1717,7 +1577,6 @@ void ProjectWindow::SkipEnd(bool shift)
{ {
auto &project = mProject; auto &project = mProject;
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::Get( project );
auto &trackPanel = TrackPanel::Get( project );
auto &viewInfo = ViewInfo::Get( project ); auto &viewInfo = ViewInfo::Get( project );
double len = tracks.GetEndTime(); double len = tracks.GetEndTime();
@ -1726,8 +1585,7 @@ void ProjectWindow::SkipEnd(bool shift)
viewInfo.selectedRegion.setT0(len); viewInfo.selectedRegion.setT0(len);
// Make sure the end of the track is visible // Make sure the end of the track is visible
trackPanel.ScrollIntoView(len); ScrollIntoView(len);
trackPanel.Refresh(false);
} }
void ProjectWindow::TP_DisplaySelection() void ProjectWindow::TP_DisplaySelection()
@ -1796,7 +1654,7 @@ void ProjectWindow::PlaybackScroller::OnTimer(wxCommandEvent &event)
// to the application, so scrub speed control is smoother. // to the application, so scrub speed control is smoother.
// (So I see at least with OS 10.10 and wxWidgets 3.0.2.) // (So I see at least with OS 10.10 and wxWidgets 3.0.2.)
// Is there another way to ensure that than by refreshing? // Is there another way to ensure that than by refreshing?
auto &trackPanel = TrackPanel::Get( *mProject ); auto &trackPanel = GetProjectPanel( *mProject );
trackPanel.Refresh(false); trackPanel.Refresh(false);
} }
else if (mMode != Mode::Off) { else if (mMode != Mode::Off) {
@ -1804,7 +1662,7 @@ void ProjectWindow::PlaybackScroller::OnTimer(wxCommandEvent &event)
// fraction of the window width. // fraction of the window width.
auto &viewInfo = ViewInfo::Get( *mProject ); auto &viewInfo = ViewInfo::Get( *mProject );
auto &trackPanel = TrackPanel::Get( *mProject ); auto &trackPanel = GetProjectPanel( *mProject );
const int posX = viewInfo.TimeToPosition(viewInfo.mRecentStreamTime); const int posX = viewInfo.TimeToPosition(viewInfo.mRecentStreamTime);
auto width = viewInfo.GetTracksUsableWidth(); auto width = viewInfo.GetTracksUsableWidth();
int deltaX; int deltaX;
@ -1832,7 +1690,6 @@ void ProjectWindow::PlaybackScroller::OnTimer(wxCommandEvent &event)
void ProjectWindow::ZoomInByFactor( double ZoomFactor ) void ProjectWindow::ZoomInByFactor( double ZoomFactor )
{ {
auto &project = mProject; auto &project = mProject;
auto &trackPanel = TrackPanel::Get( project );
auto &viewInfo = ViewInfo::Get( project ); auto &viewInfo = ViewInfo::Get( project );
auto gAudioIO = AudioIOBase::Get(); auto gAudioIO = AudioIOBase::Get();
@ -1842,8 +1699,7 @@ void ProjectWindow::ZoomInByFactor( double ZoomFactor )
ProjectAudioIO::Get( project ).GetAudioIOToken()) && ProjectAudioIO::Get( project ).GetAudioIOToken()) &&
!gAudioIO->IsPaused()){ !gAudioIO->IsPaused()){
ZoomBy(ZoomFactor); ZoomBy(ZoomFactor);
trackPanel.ScrollIntoView(gAudioIO->GetStreamTime()); ScrollIntoView(gAudioIO->GetStreamTime());
trackPanel.Refresh(false);
return; return;
} }

View File

@ -22,6 +22,9 @@ class Track;
class wxScrollBar; class wxScrollBar;
class wxPanel; class wxPanel;
class ProjectWindow;
void InitProjectWindow( ProjectWindow &window );
///\brief A top-level window associated with a project, and handling scrollbars ///\brief A top-level window associated with a project, and handling scrollbars
/// and zooming /// and zooming
class ProjectWindow final : public wxFrame class ProjectWindow final : public wxFrame
@ -34,6 +37,7 @@ public:
static ProjectWindow *Find( AudacityProject *pProject ); static ProjectWindow *Find( AudacityProject *pProject );
static const ProjectWindow *Find( const AudacityProject *pProject ); static const ProjectWindow *Find( const AudacityProject *pProject );
AudacityProject &GetProject() { return mProject; } AudacityProject &GetProject() { return mProject; }
const AudacityProject &GetProject() const { return mProject; }
explicit ProjectWindow( explicit ProjectWindow(
wxWindow * parent, wxWindowID id, wxWindow * parent, wxWindowID id,
@ -44,8 +48,6 @@ public:
// Next available ID for sub-windows // Next available ID for sub-windows
int NextWindowID(); int NextWindowID();
void Init();
bool IsActive() override; bool IsActive() override;
bool IsIconized() const override; bool IsIconized() const override;
@ -53,6 +55,7 @@ public:
void SetIsBeingDeleted() { mIsDeleting = true; } void SetIsBeingDeleted() { mIsDeleting = true; }
wxWindow *GetMainPage() { return mMainPage; } wxWindow *GetMainPage() { return mMainPage; }
wxPanel *GetMainPanel() { return mMainPanel; }
wxPanel *GetTopPanel() { return mTopPanel; } wxPanel *GetTopPanel() { return mTopPanel; }
void UpdateStatusWidths(); void UpdateStatusWidths();
@ -101,6 +104,10 @@ public:
// Scrollbars // Scrollbars
wxScrollBar &GetVerticalScrollBar() { return *mVsbar; } wxScrollBar &GetVerticalScrollBar() { return *mVsbar; }
wxScrollBar &GetHorizontalScrollBar() { return *mHsbar; }
void ScrollIntoView(double pos);
void ScrollIntoView(int x);
void OnScrollLeft(); void OnScrollLeft();
void OnScrollRight(); void OnScrollRight();
@ -182,7 +189,7 @@ private:
bool mAutoScrolling{ false }; bool mAutoScrolling{ false };
bool mActive{ true }; bool mActive{ true };
bool mIconized; bool mIconized{ false };
bool mShownOnce{ false }; bool mShownOnce{ false };

View File

@ -205,7 +205,7 @@ AudacityProject::AttachedWindows::RegisteredFactory sKey{
wxASSERT( mainPage ); // to justify safenew wxASSERT( mainPage ); // to justify safenew
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::Get( project );
return safenew TrackPanel(mainPage, auto result = safenew TrackPanel(mainPage,
window.NextWindowID(), window.NextWindowID(),
wxDefaultPosition, wxDefaultPosition,
wxDefaultSize, wxDefaultSize,
@ -213,6 +213,8 @@ AudacityProject::AttachedWindows::RegisteredFactory sKey{
&viewInfo, &viewInfo,
&project, &project,
&ruler); &ruler);
project.SetPanel( result );
return result;
} }
}; };
@ -971,25 +973,6 @@ void TrackPanel::UpdateVRulerSize()
Refresh(false); Refresh(false);
} }
// Make sure selection edge is in view
void TrackPanel::ScrollIntoView(double pos)
{
auto w = mViewInfo->GetTracksUsableWidth();
int pixel = mViewInfo->TimeToPosition(pos);
if (pixel < 0 || pixel >= w)
{
mListener->TP_ScrollWindow
(mViewInfo->OffsetTimeByPixels(pos, -(w / 2)));
Refresh(false);
}
}
void TrackPanel::ScrollIntoView(int x)
{
ScrollIntoView(mViewInfo->PositionToTime(x, mViewInfo->GetLeftOffset()));
}
void TrackPanel::OnTrackMenu(Track *t) void TrackPanel::OnTrackMenu(Track *t)
{ {
CellularPanel::DoContextMenu( t ? &TrackView::Get( *t ) : nullptr ); CellularPanel::DoContextMenu( t ? &TrackView::Get( *t ) : nullptr );

View File

@ -117,9 +117,6 @@ class AUDACITY_DLL_API TrackPanel final
void HandlePageDownKey(); void HandlePageDownKey();
AudacityProject * GetProject() const override; AudacityProject * GetProject() const override;
void ScrollIntoView(double pos);
void ScrollIntoView(int x);
void OnTrackMenu(Track *t = NULL); void OnTrackMenu(Track *t = NULL);
void VerticalScroll( float fracPosition); void VerticalScroll( float fracPosition);

View File

@ -2,6 +2,7 @@
#include "../ProjectHistory.h" #include "../ProjectHistory.h"
#include "../ProjectSettings.h" #include "../ProjectSettings.h"
#include "../TrackPanel.h" #include "../TrackPanel.h"
#include "../ProjectWindow.h"
#include "../UndoManager.h" #include "../UndoManager.h"
#include "../WaveClip.h" #include "../WaveClip.h"
#include "../ViewInfo.h" #include "../ViewInfo.h"
@ -561,6 +562,7 @@ void DoSelectClip(AudacityProject &project, bool next)
{ {
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion; auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
auto &trackPanel = TrackPanel::Get( project ); auto &trackPanel = TrackPanel::Get( project );
auto &window = ProjectWindow::Get( project );
std::vector<FoundClip> results; std::vector<FoundClip> results;
FindClips(project, selectedRegion.t0(), FindClips(project, selectedRegion.t0(),
@ -573,7 +575,7 @@ void DoSelectClip(AudacityProject &project, bool next)
double t1 = results[0].endTime; double t1 = results[0].endTime;
selectedRegion.setTimes(t0, t1); selectedRegion.setTimes(t0, t1);
ProjectHistory::Get( project ).ModifyState(false); ProjectHistory::Get( project ).ModifyState(false);
trackPanel.ScrollIntoView(selectedRegion.t0()); window.ScrollIntoView(selectedRegion.t0());
// create and send message to screen reader // create and send message to screen reader
wxString message; wxString message;
@ -607,6 +609,7 @@ void DoCursorClipBoundary
{ {
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion; auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
auto &trackPanel = TrackPanel::Get( project ); auto &trackPanel = TrackPanel::Get( project );
auto &window = ProjectWindow::Get( project );
std::vector<FoundClipBoundary> results; std::vector<FoundClipBoundary> results;
FindClipBoundaries(project, next ? selectedRegion.t1() : FindClipBoundaries(project, next ? selectedRegion.t1() :
@ -618,7 +621,7 @@ void DoCursorClipBoundary
double time = results[0].time; double time = results[0].time;
selectedRegion.setTimes(time, time); selectedRegion.setTimes(time, time);
ProjectHistory::Get( project ).ModifyState(false); ProjectHistory::Get( project ).ModifyState(false);
trackPanel.ScrollIntoView(selectedRegion.t0()); window.ScrollIntoView(selectedRegion.t0());
wxString message = ClipBoundaryMessage(results); wxString message = ClipBoundaryMessage(results);
trackPanel.MessageForScreenReader(message); trackPanel.MessageForScreenReader(message);
@ -691,6 +694,7 @@ void DoClipLeftOrRight
(AudacityProject &project, bool right, bool keyUp ) (AudacityProject &project, bool right, bool keyUp )
{ {
auto &undoManager = UndoManager::Get( project ); auto &undoManager = UndoManager::Get( project );
auto &window = ProjectWindow::Get( project );
if (keyUp) { if (keyUp) {
undoManager.StopConsolidating(); undoManager.StopConsolidating();
@ -707,7 +711,7 @@ void DoClipLeftOrRight
auto amount = DoClipMove( viewInfo, trackPanel.GetFocusedTrack(), auto amount = DoClipMove( viewInfo, trackPanel.GetFocusedTrack(),
tracks, isSyncLocked, right ); tracks, isSyncLocked, right );
trackPanel.ScrollIntoView(selectedRegion.t0()); window.ScrollIntoView(selectedRegion.t0());
if (amount != 0.0) { if (amount != 0.0) {
wxString message = right? _("Time shifted clips to the right") : wxString message = right? _("Time shifted clips to the right") :

View File

@ -41,7 +41,6 @@ void FinishCopy
bool DoPasteText(AudacityProject &project) bool DoPasteText(AudacityProject &project)
{ {
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::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 );
@ -61,7 +60,7 @@ bool DoPasteText(AudacityProject &project)
// Make sure caret is in view // Make sure caret is in view
int x; int x;
if (view.CalcCursorX( project, &x )) { if (view.CalcCursorX( project, &x )) {
trackPanel.ScrollIntoView(x); window.ScrollIntoView(x);
} }
return true; return true;

View File

@ -273,7 +273,7 @@ void MoveWhenAudioInactive
} }
// Make sure NEW position is in view // Make sure NEW position is in view
trackPanel.ScrollIntoView(viewInfo.selectedRegion.t1()); window.ScrollIntoView(viewInfo.selectedRegion.t1());
return; return;
} }
@ -282,9 +282,9 @@ void SeekWhenAudioInactive
SelectionOperation operation) SelectionOperation operation)
{ {
auto &viewInfo = ViewInfo::Get( project ); auto &viewInfo = ViewInfo::Get( project );
auto &trackPanel = TrackPanel::Get( project );
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::Get( project );
const auto &settings = ProjectSettings::Get( project ); const auto &settings = ProjectSettings::Get( project );
auto &window = ProjectWindow::Get( project );
if( operation == CURSOR_MOVE ) if( operation == CURSOR_MOVE )
{ {
@ -318,9 +318,8 @@ SelectionOperation operation)
else else
viewInfo.selectedRegion.setT1( newT ); viewInfo.selectedRegion.setT1( newT );
// Ensure it is visible, and refresh. // Ensure it is visible
trackPanel.ScrollIntoView(newT); window.ScrollIntoView(newT);
trackPanel.Refresh(false);
} }
// Handle small cursor and play head movements // Handle small cursor and play head movements
@ -381,8 +380,8 @@ void DoCursorMove(
void DoBoundaryMove(AudacityProject &project, int step, SeekInfo &info) void DoBoundaryMove(AudacityProject &project, int step, SeekInfo &info)
{ {
auto &viewInfo = ViewInfo::Get( project ); auto &viewInfo = ViewInfo::Get( project );
auto &trackPanel = TrackPanel::Get( project );
auto &tracks = TrackList::Get( project ); auto &tracks = TrackList::Get( project );
auto &window = ProjectWindow::Get( project );
// step is negative, then is moving left. step positive, moving right. // step is negative, then is moving left. step positive, moving right.
// Move the left/right selection boundary, to expand the selection // Move the left/right selection boundary, to expand the selection
@ -434,9 +433,8 @@ void DoBoundaryMove(AudacityProject &project, int step, SeekInfo &info)
else else
viewInfo.selectedRegion.setT1( newT ); viewInfo.selectedRegion.setT1( newT );
// Ensure it is visible, and refresh. // Ensure it is visible
trackPanel.ScrollIntoView(newT); window.ScrollIntoView(newT);
trackPanel.Refresh(false);
ProjectHistory::Get( project ).ModifyState(false); ProjectHistory::Get( project ).ModifyState(false);
} }
@ -834,31 +832,31 @@ void OnSelContractRight(const CommandContext &context)
void OnCursorSelStart(const CommandContext &context) void OnCursorSelStart(const CommandContext &context)
{ {
auto &project = context.project; auto &project = context.project;
auto &trackPanel = TrackPanel::Get( project );
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion; auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
auto &window = ProjectWindow::Get( project );
selectedRegion.collapseToT0(); selectedRegion.collapseToT0();
ProjectHistory::Get( project ).ModifyState(false); ProjectHistory::Get( project ).ModifyState(false);
trackPanel.ScrollIntoView(selectedRegion.t0()); window.ScrollIntoView(selectedRegion.t0());
} }
void OnCursorSelEnd(const CommandContext &context) void OnCursorSelEnd(const CommandContext &context)
{ {
auto &project = context.project; auto &project = context.project;
auto &trackPanel = TrackPanel::Get( project );
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion; auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
auto &window = ProjectWindow::Get( project );
selectedRegion.collapseToT1(); selectedRegion.collapseToT1();
ProjectHistory::Get( project ).ModifyState(false); ProjectHistory::Get( project ).ModifyState(false);
trackPanel.ScrollIntoView(selectedRegion.t1()); window.ScrollIntoView(selectedRegion.t1());
} }
void OnCursorTrackStart(const CommandContext &context) void OnCursorTrackStart(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 &selectedRegion = ViewInfo::Get( project ).selectedRegion; auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
auto &window = ProjectWindow::Get( project );
double kWayOverToRight = std::numeric_limits<double>::max(); double kWayOverToRight = std::numeric_limits<double>::max();
@ -876,15 +874,15 @@ void OnCursorTrackStart(const CommandContext &context)
selectedRegion.setTimes(minOffset, minOffset); selectedRegion.setTimes(minOffset, minOffset);
ProjectHistory::Get( project ).ModifyState(false); ProjectHistory::Get( project ).ModifyState(false);
trackPanel.ScrollIntoView(selectedRegion.t0()); window.ScrollIntoView(selectedRegion.t0());
} }
void OnCursorTrackEnd(const CommandContext &context) void OnCursorTrackEnd(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 &selectedRegion = ViewInfo::Get( project ).selectedRegion; auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
auto &window = ProjectWindow::Get( project );
double kWayOverToLeft = std::numeric_limits<double>::lowest(); double kWayOverToLeft = std::numeric_limits<double>::lowest();
@ -902,7 +900,7 @@ void OnCursorTrackEnd(const CommandContext &context)
selectedRegion.setTimes(maxEndOffset, maxEndOffset); selectedRegion.setTimes(maxEndOffset, maxEndOffset);
ProjectHistory::Get( project ).ModifyState(false); ProjectHistory::Get( project ).ModifyState(false);
trackPanel.ScrollIntoView(selectedRegion.t1()); window.ScrollIntoView(selectedRegion.t1());
} }
void OnSkipStart(const CommandContext &context) void OnSkipStart(const CommandContext &context)

View File

@ -173,7 +173,7 @@ void DoMoveToLabel(AudacityProject &project, bool next)
} }
else { else {
selectedRegion = label->selectedRegion; selectedRegion = label->selectedRegion;
trackPanel.ScrollIntoView(selectedRegion.t0()); window.ScrollIntoView(selectedRegion.t0());
window.RedrawProject(); window.RedrawProject();
} }

View File

@ -1302,7 +1302,7 @@ unsigned LabelTrackView::KeyDown(
// Make sure caret is in view // Make sure caret is in view
int x; int x;
if (CalcCursorX( *project, &x )) if (CalcCursorX( *project, &x ))
TrackPanel::Get( *project ).ScrollIntoView(x); ProjectWindow::Get( *project ).ScrollIntoView(x);
// If selection modified, refresh // If selection modified, refresh
// Otherwise, refresh track display if the keystroke was handled // Otherwise, refresh track display if the keystroke was handled

View File

@ -25,7 +25,6 @@ Paul Licameli split from TrackPanel.cpp
#include "../../ProjectSettings.h" #include "../../ProjectSettings.h"
#include "../../ProjectStatus.h" #include "../../ProjectStatus.h"
#include "../../Track.h" #include "../../Track.h"
#include "../../TrackPanel.h"
#include "../../ViewInfo.h" #include "../../ViewInfo.h"
#include "../../WaveTrack.h" #include "../../WaveTrack.h"
#include "../../prefs/PlaybackPrefs.h" #include "../../prefs/PlaybackPrefs.h"
@ -597,7 +596,7 @@ void Scrubber::ContinueScrubbingPoll()
gAudioIO->UpdateScrub(speed, mOptions); gAudioIO->UpdateScrub(speed, mOptions);
} else { } else {
const wxMouseState state(::wxGetMouseState()); const wxMouseState state(::wxGetMouseState());
auto &trackPanel = TrackPanel::Get( *mProject ); auto &trackPanel = GetProjectPanel( *mProject );
const wxPoint position = trackPanel.ScreenToClient(state.GetPosition()); const wxPoint position = trackPanel.ScreenToClient(state.GetPosition());
auto &viewInfo = ViewInfo::Get( *mProject ); auto &viewInfo = ViewInfo::Get( *mProject );
#ifdef DRAG_SCRUB #ifdef DRAG_SCRUB
@ -904,14 +903,6 @@ void Scrubber::Forwarder::OnMouse(wxMouseEvent &event)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// class ScrubbingOverlay is responsible for drawing the speed numbers // class ScrubbingOverlay is responsible for drawing the speed numbers
static const AudacityProject::AttachedObjects::RegisteredFactory sOverlayKey{
[]( AudacityProject &parent ){
auto result = std::make_shared< ScrubbingOverlay >( &parent );
TrackPanel::Get( parent ).AddOverlay( result );
return result;
}
};
ScrubbingOverlay::ScrubbingOverlay(AudacityProject *project) ScrubbingOverlay::ScrubbingOverlay(AudacityProject *project)
: mProject(project) : mProject(project)
, mLastScrubRect() , mLastScrubRect()
@ -1003,7 +994,7 @@ void ScrubbingOverlay::OnTimer(wxCommandEvent &event)
mNextScrubRect = wxRect(); mNextScrubRect = wxRect();
} }
else { else {
TrackPanel &trackPanel = TrackPanel::Get( *mProject ); auto &trackPanel = GetProjectPanel( *mProject );
auto &viewInfo = ViewInfo::Get( *mProject ); auto &viewInfo = ViewInfo::Get( *mProject );
int panelWidth, panelHeight; int panelWidth, panelHeight;
trackPanel.GetSize(&panelWidth, &panelHeight); trackPanel.GetSize(&panelWidth, &panelHeight);
@ -1070,7 +1061,7 @@ void Scrubber::DoScrub(bool seek)
const bool wasScrubbing = HasMark() || IsScrubbing(); const bool wasScrubbing = HasMark() || IsScrubbing();
const bool scroll = ShouldScrubPinned(); const bool scroll = ShouldScrubPinned();
if (!wasScrubbing) { if (!wasScrubbing) {
auto &tp = TrackPanel::Get( *mProject ); auto &tp = GetProjectPanel( *mProject );
const auto &viewInfo = ViewInfo::Get( *mProject ); const auto &viewInfo = ViewInfo::Get( *mProject );
wxCoord xx = tp.ScreenToClient(::wxGetMouseState().GetPosition()).x; wxCoord xx = tp.ScreenToClient(::wxGetMouseState().GetPosition()).x;