diff --git a/lib-src/mod-nyq-bench/NyqBench.cpp b/lib-src/mod-nyq-bench/NyqBench.cpp index c837046ec..1e8f5aeea 100755 --- a/lib-src/mod-nyq-bench/NyqBench.cpp +++ b/lib-src/mod-nyq-bench/NyqBench.cpp @@ -187,7 +187,7 @@ extern "C" CommandManager *c = &CommandManager::Get( *p ); wxASSERT(c != NULL); - wxMenuBar * pBar = p->GetMenuBar(); + wxMenuBar * pBar = GetProjectFrame( *p ).GetMenuBar(); wxASSERT(pBar != NULL ); wxMenu * pMenu = pBar->GetMenu( 9 ); // Menu 9 is the Tools Menu. wxASSERT( pMenu != NULL ); diff --git a/src/Project.cpp b/src/Project.cpp index b29a9d4d6..ea529a479 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -7,33 +7,6 @@ Dominic Mazzoni Vaughan Johnson -*******************************************************************//** - -\file Project.cpp -\brief Implements AudacityProject - -*//****************************************************************//** - -\class AudacityProject -\brief AudacityProject provides the main window, with tools and -tracks contained within it. - - In Audacity, the main window you work in is called a project. - AudacityProjects can contain an arbitrary number of tracks of many - different types, but if a project contains just one or two - tracks then it can be saved in standard formats like WAV or AIFF. - This window is the one that contains the menu bar (except on - the Mac). - -\attention The menu functions for AudacityProject, those for creating -the menu bars and acting on clicks, are found in file Menus.cpp - -*//****************************************************************//** - -\class ViewInfo -\brief ViewInfo is used mainly to hold the zooming, selection and -scroll information. It also has some status flags. - *//*******************************************************************/ #include "Audacity.h" // for USE_* macros @@ -556,74 +529,45 @@ enum { NextID, }; -int AudacityProject::NextWindowID() +int ProjectWindow::NextWindowID() { return mNextWindowID++; } -BEGIN_EVENT_TABLE(AudacityProject, wxFrame) - EVT_MENU(wxID_ANY, AudacityProject::OnMenu) - EVT_MOUSE_EVENTS(AudacityProject::OnMouseEvent) - EVT_CLOSE(AudacityProject::OnCloseWindow) - EVT_SIZE(AudacityProject::OnSize) - EVT_SHOW(AudacityProject::OnShow) - EVT_ICONIZE(AudacityProject::OnIconize) - EVT_MOVE(AudacityProject::OnMove) - EVT_ACTIVATE(AudacityProject::OnActivate) - EVT_COMMAND_SCROLL_LINEUP(HSBarID, AudacityProject::OnScrollLeftButton) - EVT_COMMAND_SCROLL_LINEDOWN(HSBarID, AudacityProject::OnScrollRightButton) - EVT_COMMAND_SCROLL(HSBarID, AudacityProject::OnScroll) - EVT_COMMAND_SCROLL(VSBarID, AudacityProject::OnScroll) +BEGIN_EVENT_TABLE(ProjectWindow, wxFrame) + EVT_MENU(wxID_ANY, ProjectWindow::OnMenu) + EVT_MOUSE_EVENTS(ProjectWindow::OnMouseEvent) + EVT_CLOSE(ProjectWindow::OnCloseWindow) + EVT_SIZE(ProjectWindow::OnSize) + EVT_SHOW(ProjectWindow::OnShow) + EVT_ICONIZE(ProjectWindow::OnIconize) + EVT_MOVE(ProjectWindow::OnMove) + EVT_ACTIVATE(ProjectWindow::OnActivate) + EVT_COMMAND_SCROLL_LINEUP(HSBarID, ProjectWindow::OnScrollLeftButton) + EVT_COMMAND_SCROLL_LINEDOWN(HSBarID, ProjectWindow::OnScrollRightButton) + EVT_COMMAND_SCROLL(HSBarID, ProjectWindow::OnScroll) + EVT_COMMAND_SCROLL(VSBarID, ProjectWindow::OnScroll) // Fires for menu with ID #1...first menu defined - EVT_UPDATE_UI(1, AudacityProject::OnUpdateUI) - EVT_ICONIZE(AudacityProject::OnIconize) - EVT_COMMAND(wxID_ANY, EVT_TOOLBAR_UPDATED, AudacityProject::OnToolBarUpdate) + EVT_UPDATE_UI(1, ProjectWindow::OnUpdateUI) + EVT_COMMAND(wxID_ANY, EVT_TOOLBAR_UPDATED, ProjectWindow::OnToolBarUpdate) //mchinen:multithreaded calls - may not be threadsafe with CommandEvent: may have to change. END_EVENT_TABLE() -AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, +ProjectWindow::ProjectWindow(wxWindow * parent, wxWindowID id, const wxPoint & pos, - const wxSize & size) + const wxSize & size, AudacityProject &project) : wxFrame(parent, id, _TS("Audacity"), pos, size) + , mProject{ project } { - auto &project = *this; - auto &window = project; + project.SetFrame( this ); mNextWindowID = NextID; -#ifdef EXPERIMENTAL_DA2 - SetBackgroundColour(theTheme.Colour( clrMedium )); -#endif - // Note that the first field of the status bar is a dummy, and it's 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 - mProjectNo = mProjectCounter++; // Bug 322 - - auto &viewInfo = ViewInfo::Get( *this ); - - mLockPlayRegion = false; - - // 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. - // - + // Two sub-windows need to be made before Init(), + // so that this construcator can complete, and then TrackPanel and + // AdornedRulerPanel can retrieve those windows from this in their + // factory functions // PRL: this panel groups the top tool dock and the ruler into one // tab cycle. @@ -641,19 +585,6 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mTopPanel->SetBackgroundColour(theTheme.Colour( clrMedium )); #endif - // - // Create the ToolDock - // - ToolManager::Get( project ).LayoutToolBars(); - - // - // Create the horizontal ruler - // - auto &ruler = AdornedRulerPanel::Get( project ); - - // - // Create the TrackPanel and the scrollbars - // wxWindow * pPage; #ifdef EXPERIMENTAL_NOTEBOOK @@ -693,6 +624,57 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mMainPage = pPage; + mPlaybackScroller = std::make_unique( &project ); +} + +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(wxVERTICAL); ubs->Add( ToolManager::Get( project ).GetTopDock(), 0, wxEXPAND | wxALIGN_TOP ); @@ -700,6 +682,8 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mTopPanel->SetSizer(ubs.release()); } + const auto pPage = GetMainPage(); + wxBoxSizer *bs; { auto ubs = std::make_unique(wxVERTICAL); @@ -713,8 +697,6 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, bs->Layout(); auto &trackPanel = TrackPanel::Get( project ); - - mPlaybackScroller = std::make_unique(this); // LLL: When Audacity starts or becomes active after returning from // another application, the first window that can accept focus @@ -780,7 +762,7 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mMainPanel->Layout(); - wxASSERT( trackPanel.GetProject()==this); + wxASSERT( trackPanel.GetProject() == &project ); // MM: Give track panel the focus to ensure keyboard commands work trackPanel.SetFocus(); @@ -818,38 +800,103 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, wxString msg = wxString::Format(_("Welcome to Audacity version %s"), AUDACITY_VERSION_STRING); statusBar->SetStatusText(msg, mainStatusBarField); - ControlToolBar::Get( project ).UpdateStatusBar(this); + ControlToolBar::Get( project ).UpdateStatusBar( &project ); - wxTheApp->Bind(EVT_THEME_CHANGE, &AudacityProject::OnThemeChange, this); + wxTheApp->Bind(EVT_THEME_CHANGE, &ProjectWindow::OnThemeChange, this); #ifdef EXPERIMENTAL_DA2 ClearBackground();// For wxGTK. #endif +} +AudacityProject::AudacityProject() +{ + mProjectNo = mProjectCounter++; // Bug 322 AttachedObjects::BuildAll(); // But not for the attached windows. They get built only on demand, such as // from menu items. } AudacityProject::~AudacityProject() +{ +} + +namespace { + +AudacityProject::AttachedWindows::RegisteredFactory sProjectWindowKey{ + []( AudacityProject &parent ) -> wxWeakRef< wxWindow > { + wxRect wndRect; + bool bMaximized = false; + bool bIconized = false; + GetNextWindowPlacement(&wndRect, &bMaximized, &bIconized); + + auto pWindow = safenew ProjectWindow( + nullptr, -1, + wxDefaultPosition, + wxSize(wndRect.width, wndRect.height), + parent + ); + + auto &window = *pWindow; + // wxGTK3 seems to need to require creating the window using default position + // and then manually positioning it. + window.SetPosition(wndRect.GetPosition()); + + if(bMaximized) { + window.Maximize(true); + } + else if (bIconized) { + // if the user close down and iconized state we could start back up and iconized state + // window.Iconize(TRUE); + } + + return pWindow; + } +}; + +} + +ProjectWindow &ProjectWindow::Get( AudacityProject &project ) +{ + return project.AttachedWindows::Get< ProjectWindow >( sProjectWindowKey ); +} + +const ProjectWindow &ProjectWindow::Get( const AudacityProject &project ) +{ + return Get( const_cast< AudacityProject & >( project ) ); +} + +ProjectWindow *ProjectWindow::Find( AudacityProject *pProject ) +{ + return pProject + ? pProject->AttachedWindows::Find< ProjectWindow >( sProjectWindowKey ) + : nullptr; +} + +const ProjectWindow *ProjectWindow::Find( const AudacityProject *pProject ) +{ + return Find( const_cast< AudacityProject * >( pProject ) ); +} + +ProjectWindow::~ProjectWindow() { // Tool manager gives us capture sometimes if(HasCapture()) ReleaseMouse(); } -void AudacityProject::ApplyUpdatedTheme() +void ProjectWindow::ApplyUpdatedTheme() { - auto &project = *this; + auto &project = mProject; auto &trackPanel = TrackPanel::Get( project ); SetBackgroundColour(theTheme.Colour( clrMedium )); ClearBackground();// For wxGTK. trackPanel.ApplyUpdatedTheme(); } -void AudacityProject::RedrawProject(const bool bForceWaveTracks /*= false*/) +void ProjectWindow::RedrawProject(const bool bForceWaveTracks /*= false*/) { - auto &project = *this; + auto &project = mProject ; auto &tracks = TrackList::Get( project ); auto &trackPanel = TrackPanel::Get( project ); FixScrollbars(); @@ -862,18 +909,18 @@ void AudacityProject::RedrawProject(const bool bForceWaveTracks /*= false*/) trackPanel.Refresh(false); } -void AudacityProject::RefreshCursor() +void ProjectWindow::RefreshCursor() { - auto &project = *this; + auto &project = mProject; auto &trackPanel = TrackPanel::Get( project ); trackPanel.HandleCursorForPresentMouseState(); } -void AudacityProject::OnThemeChange(wxCommandEvent& evt) +void ProjectWindow::OnThemeChange(wxCommandEvent& evt) { evt.Skip(); - auto &project = *this; - ProjectWindow::Get( project ).ApplyUpdatedTheme(); + auto &project = mProject; + this->ApplyUpdatedTheme(); auto &toolManager = ToolManager::Get( project ); for( int ii = 0; ii < ToolBarCount; ++ii ) { @@ -896,7 +943,7 @@ wxString AudacityProject::GetProjectName() const return name; } -void AudacityProject::FinishAutoScroll() +void ProjectWindow::FinishAutoScroll() { // Set a flag so we don't have to generate two update events mAutoScrolling = true; @@ -908,14 +955,13 @@ void AudacityProject::FinishAutoScroll() mAutoScrolling = false; } - /// /// This method handles general left-scrolling, either for drag-scrolling /// or when the scrollbar is clicked to the left of the thumb /// -void AudacityProject::OnScrollLeft() +void ProjectWindow::OnScrollLeft() { - auto &project = *this; + auto &project = mProject; auto &viewInfo = ViewInfo::Get( project ); wxInt64 pos = mHsbar->GetThumbPosition(); // move at least one scroll increment @@ -936,9 +982,9 @@ void AudacityProject::OnScrollLeft() /// or when the scrollbar is clicked to the right of the thumb /// -void AudacityProject::OnScrollRight() +void ProjectWindow::OnScrollRight() { - auto &project = *this; + auto &project = mProject; auto &viewInfo = ViewInfo::Get( project ); wxInt64 pos = mHsbar->GetThumbPosition(); // move at least one scroll increment @@ -957,12 +1003,13 @@ void AudacityProject::OnScrollRight() } } + /// /// This handles the event when the left direction button on the scrollbar is depresssed /// -void AudacityProject::OnScrollLeftButton(wxScrollEvent & /*event*/) +void ProjectWindow::OnScrollLeftButton(wxScrollEvent & /*event*/) { - auto &project = *this; + auto &project = mProject; auto &viewInfo = ViewInfo::Get( project ); wxInt64 pos = mHsbar->GetThumbPosition(); // move at least one scroll increment @@ -981,9 +1028,9 @@ void AudacityProject::OnScrollLeftButton(wxScrollEvent & /*event*/) /// /// This handles the event when the right direction button on the scrollbar is depresssed /// -void AudacityProject::OnScrollRightButton(wxScrollEvent & /*event*/) +void ProjectWindow::OnScrollRightButton(wxScrollEvent & /*event*/) { - auto &project = *this; + auto &project = mProject; auto &viewInfo = ViewInfo::Get( project ); wxInt64 pos = mHsbar->GetThumbPosition(); // move at least one scroll increment @@ -1003,9 +1050,9 @@ void AudacityProject::OnScrollRightButton(wxScrollEvent & /*event*/) } -bool AudacityProject::MayScrollBeyondZero() const +bool ProjectWindow::MayScrollBeyondZero() const { - auto &project = *this; + auto &project = mProject; auto &scrubber = Scrubber::Get( project ); auto &viewInfo = ViewInfo::Get( project ); if (viewInfo.bScrollBeyondZero) @@ -1024,9 +1071,9 @@ bool AudacityProject::MayScrollBeyondZero() const return false; } -double AudacityProject::ScrollingLowerBoundTime() const +double ProjectWindow::ScrollingLowerBoundTime() const { - auto &project = *this; + auto &project = mProject; auto &tracks = TrackList::Get( project ); auto &trackPanel = TrackPanel::Get( project ); auto &viewInfo = ViewInfo::Get( project ); @@ -1038,9 +1085,9 @@ double AudacityProject::ScrollingLowerBoundTime() const // PRL: Bug1197: we seem to need to compute all in double, to avoid differing results on Mac // That's why ViewInfo::TimeRangeToPixelWidth was defined, with some regret. -double AudacityProject::PixelWidthBeforeTime(double scrollto) const +double ProjectWindow::PixelWidthBeforeTime(double scrollto) const { - auto &project = *this; + auto &project = mProject; auto &viewInfo = ViewInfo::Get( project ); const double lowerBound = ScrollingLowerBoundTime(); return @@ -1048,9 +1095,9 @@ double AudacityProject::PixelWidthBeforeTime(double scrollto) const viewInfo.TimeRangeToPixelWidth(scrollto - lowerBound); } -void AudacityProject::SetHorizontalThumb(double scrollto) +void ProjectWindow::SetHorizontalThumb(double scrollto) { - auto &project = *this; + auto &project = mProject; auto &viewInfo = ViewInfo::Get( project ); const auto unscaled = PixelWidthBeforeTime(scrollto); const int max = mHsbar->GetRange() - mHsbar->GetThumbSize(); @@ -1071,7 +1118,7 @@ void AudacityProject::SetHorizontalThumb(double scrollto) // This method, like the other methods prefaced with TP, handles TrackPanel // 'callback'. // -void AudacityProject::TP_ScrollWindow(double scrollto) +void ProjectWindow::TP_ScrollWindow(double scrollto) { SetHorizontalThumb(scrollto); @@ -1085,7 +1132,7 @@ void AudacityProject::TP_ScrollWindow(double scrollto) // handler in Track Panel. A positive argument makes the window // scroll down, while a negative argument scrolls up. // -bool AudacityProject::TP_ScrollUpDown(int delta) +bool ProjectWindow::TP_ScrollUpDown(int delta) { int oldPos = mVsbar->GetThumbPosition(); int pos = oldPos + delta; @@ -1111,9 +1158,9 @@ bool AudacityProject::TP_ScrollUpDown(int delta) return false; } -void AudacityProject::FixScrollbars() +void ProjectWindow::FixScrollbars() { - auto &project = *this; + auto &project = mProject; auto &tracks = TrackList::Get( project ); auto &trackPanel = TrackPanel::Get( project ); auto &viewInfo = ViewInfo::Get( project ); @@ -1273,9 +1320,9 @@ void AudacityProject::FixScrollbars() } ); } -void AudacityProject::UpdateLayout() +void ProjectWindow::UpdateLayout() { - auto &project = *this; + auto &project = mProject; auto &trackPanel = TrackPanel::Get( project ); auto &toolManager = ToolManager::Get( project ); @@ -1303,7 +1350,7 @@ void AudacityProject::UpdateLayout() SetSizeHints(250, (mainsz.y - sbpos.y) + tppos.y + 50, 20000, 20000); } -void AudacityProject::HandleResize() +void ProjectWindow::HandleResize() { // Activate events can fire during window teardown, so just // ignore them. @@ -1311,14 +1358,18 @@ void AudacityProject::HandleResize() return; } - auto &project = *this; - FixScrollbars(); UpdateLayout(); } -void AudacityProject::OnIconize(wxIconizeEvent &event) + +bool ProjectWindow::IsIconized() const +{ + return mIconized; +} + +void ProjectWindow::OnIconize(wxIconizeEvent &event) { //JKC: On Iconizing we get called twice. Don't know // why but it does no harm. @@ -1349,14 +1400,14 @@ void AudacityProject::OnIconize(wxIconizeEvent &event) OnShow( Evt ); } -void AudacityProject::OnMove(wxMoveEvent & event) +void ProjectWindow::OnMove(wxMoveEvent & event) { if (!this->IsMaximized() && !this->IsIconized()) SetNormalizedWindowState(this->GetRect()); event.Skip(); } -void AudacityProject::OnSize(wxSizeEvent & event) +void ProjectWindow::OnSize(wxSizeEvent & event) { // (From Debian) // @@ -1374,7 +1425,7 @@ void AudacityProject::OnSize(wxSizeEvent & event) event.Skip(); } -void AudacityProject::OnShow(wxShowEvent & event) +void ProjectWindow::OnShow(wxShowEvent & event) { // Remember that the window has been shown at least once mShownOnce = true; @@ -1414,16 +1465,16 @@ void AudacityProject::OnShow(wxShowEvent & event) /// /// A toolbar has been updated, so handle it like a sizing event. /// -void AudacityProject::OnToolBarUpdate(wxCommandEvent & event) +void ProjectWindow::OnToolBarUpdate(wxCommandEvent & event) { HandleResize(); event.Skip(false); /* No need to propagate any further */ } -void AudacityProject::OnScroll(wxScrollEvent & WXUNUSED(event)) +void ProjectWindow::OnScroll(wxScrollEvent & WXUNUSED(event)) { - auto &project = *this; + auto &project = mProject; auto &viewInfo = ViewInfo::Get( project ); const wxInt64 offset = PixelWidthBeforeTime(0.0); viewInfo.sbarH = @@ -1431,9 +1482,9 @@ void AudacityProject::OnScroll(wxScrollEvent & WXUNUSED(event)) DoScroll(); } -void AudacityProject::DoScroll() +void ProjectWindow::DoScroll() { - auto &project = *this; + auto &project = mProject; auto &trackPanel = TrackPanel::Get( project ); auto &viewInfo = ViewInfo::Get( project ); const double lowerBound = ScrollingLowerBoundTime(); @@ -1471,7 +1522,7 @@ void AudacityProject::DoScroll() } ); } -void AudacityProject::OnMenu(wxCommandEvent & event) +void ProjectWindow::OnMenu(wxCommandEvent & event) { #ifdef __WXMSW__ // Bug 1642: We can arrive here with bogus menu IDs, which we @@ -1486,7 +1537,7 @@ void AudacityProject::OnMenu(wxCommandEvent & event) return; } #endif - auto &project = *this; + auto &project = mProject; auto &commandManager = CommandManager::Get( project ); bool handled = commandManager.HandleMenuID( event.GetId(), MenuManager::Get( project ).GetUpdateFlags( project ), @@ -1500,13 +1551,13 @@ void AudacityProject::OnMenu(wxCommandEvent & event) } } -void AudacityProject::OnUpdateUI(wxUpdateUIEvent & WXUNUSED(event)) +void ProjectWindow::OnUpdateUI(wxUpdateUIEvent & WXUNUSED(event)) { - auto &project = *this; + auto &project = mProject; MenuManager::Get( project ).UpdateMenus( project ); } -void AudacityProject::MacShowUndockedToolbars(bool show) +void ProjectWindow::MacShowUndockedToolbars(bool show) { (void)show;//compiler food #ifdef __WXMAC__ @@ -1524,7 +1575,7 @@ void AudacityProject::MacShowUndockedToolbars(bool show) #endif } -void AudacityProject::OnActivate(wxActivateEvent & event) +void ProjectWindow::OnActivate(wxActivateEvent & event) { // Activate events can fire during window teardown, so just // ignore them. @@ -1532,7 +1583,7 @@ void AudacityProject::OnActivate(wxActivateEvent & event) return; } - auto &project = *this; + auto &project = mProject; mActive = event.GetActive(); @@ -1555,7 +1606,7 @@ void AudacityProject::OnActivate(wxActivateEvent & event) } else { auto &toolManager = ToolManager::Get( project ); - SetActiveProject(this); + SetActiveProject( &project ); if ( ! toolManager.RestoreFocus() ) TrackPanel::Get( project ).SetFocus(); @@ -1566,15 +1617,16 @@ void AudacityProject::OnActivate(wxActivateEvent & event) event.Skip(); } -bool AudacityProject::IsActive() +bool ProjectWindow::IsActive() { return mActive; } -void AudacityProject::OnMouseEvent(wxMouseEvent & event) +void ProjectWindow::OnMouseEvent(wxMouseEvent & event) { + auto &project = mProject; if (event.ButtonDown()) - SetActiveProject(this); + SetActiveProject( &project ); } static void RefreshAllTitles(bool bShowProjectNumbers ) @@ -1587,14 +1639,15 @@ static void RefreshAllTitles(bool bShowProjectNumbers ) } } -TitleRestorer::TitleRestorer(AudacityProject * p ) +TitleRestorer::TitleRestorer(ProjectWindow * pWindow ) { - auto &window = GetProjectFrame( *p ); + auto &window = *pWindow; if( window.IsIconized() ) window.Restore(); window.Raise(); // May help identifying the window on Mac // Construct this projects name and number. + auto p = &pWindow->GetProject(); sProjName = p->GetProjectName(); if (sProjName.empty()){ sProjName = _(""); @@ -1618,12 +1671,12 @@ TitleRestorer::~TitleRestorer() { RefreshAllTitles( false ); } -void AudacityProject::ZoomAfterImport(Track *pTrack) +void ProjectWindow::ZoomAfterImport(Track *pTrack) { - auto &project = *this; + auto &project = mProject; auto &trackPanel = TrackPanel::Get( project ); - ViewActions::DoZoomFit(*this); + ViewActions::DoZoomFit( project ); trackPanel.SetFocus(); RedrawProject(); @@ -1633,9 +1686,9 @@ void AudacityProject::ZoomAfterImport(Track *pTrack) } // Utility function called by other zoom methods -void AudacityProject::Zoom(double level) +void ProjectWindow::Zoom(double level) { - auto &project = *this; + auto &project = mProject; auto &viewInfo = ViewInfo::Get( project ); viewInfo.SetZoom(level); FixScrollbars(); @@ -1652,9 +1705,9 @@ void AudacityProject::Zoom(double level) } // Utility function called by other zoom methods -void AudacityProject::ZoomBy(double multiplier) +void ProjectWindow::ZoomBy(double multiplier) { - auto &project = *this; + auto &project = mProject; auto &viewInfo = ViewInfo::Get( project ); viewInfo.ZoomBy(multiplier); FixScrollbars(); @@ -1668,9 +1721,9 @@ void AudacityProject::ZoomBy(double multiplier) // selection to 0 (holding right edge constant), otherwise it will // move both left and right edge of selection to 0 /////////////////////////////////////////////////////////////////// -void AudacityProject::Rewind(bool shift) +void ProjectWindow::Rewind(bool shift) { - auto &project = *this; + auto &project = mProject; auto &viewInfo = ViewInfo::Get( project ); viewInfo.selectedRegion.setT0(0, false); if (!shift) @@ -1688,9 +1741,9 @@ void AudacityProject::Rewind(bool shift) // selection to the end (holding left edge constant), otherwise it will // move both left and right edge of selection to the end /////////////////////////////////////////////////////////////////// -void AudacityProject::SkipEnd(bool shift) +void ProjectWindow::SkipEnd(bool shift) { - auto &project = *this; + auto &project = mProject; auto &tracks = TrackList::Get( project ); auto &trackPanel = TrackPanel::Get( project ); auto &viewInfo = ViewInfo::Get( project ); @@ -1712,19 +1765,19 @@ void AudacityProject::SetStatus(const wxString &msg) if ( msg != mLastMainStatusMessage ) { mLastMainStatusMessage = msg; wxCommandEvent evt{ EVT_PROJECT_STATUS_UPDATE }; - project.GetEventHandler()->ProcessEvent( evt ); + project.ProcessEvent( evt ); } } -void AudacityProject::TP_DisplaySelection() +void ProjectWindow::TP_DisplaySelection() { - auto &project = *this; + auto &project = mProject; auto &ruler = AdornedRulerPanel::Get(project); auto &viewInfo = ViewInfo::Get( project ); const auto &selectedRegion = viewInfo.selectedRegion; double audioTime; - if (!gAudioIO->IsBusy() && !mLockPlayRegion) + if (!gAudioIO->IsBusy() && project.IsPlayRegionLocked()) ruler.SetPlayRegion( selectedRegion.t0(), selectedRegion.t1() ); else // Cause ruler redraw anyway, because we may be zooming or scrolling @@ -1734,7 +1787,7 @@ void AudacityProject::TP_DisplaySelection() audioTime = gAudioIO->GetStreamTime(); else { double playEnd; - GetPlayRegion(&audioTime, &playEnd); + project.GetPlayRegion(&audioTime, &playEnd); } SelectionBar::Get( project ).SetTimes(selectedRegion.t0(), @@ -1747,24 +1800,24 @@ void AudacityProject::TP_DisplaySelection() // TrackPanel callback method -void AudacityProject::TP_ScrollLeft() +void ProjectWindow::TP_ScrollLeft() { OnScrollLeft(); } // TrackPanel callback method -void AudacityProject::TP_ScrollRight() +void ProjectWindow::TP_ScrollRight() { OnScrollRight(); } // TrackPanel callback method -void AudacityProject::TP_RedrawScrollbars() +void ProjectWindow::TP_RedrawScrollbars() { FixScrollbars(); } -void AudacityProject::TP_HandleResize() +void ProjectWindow::TP_HandleResize() { HandleResize(); } @@ -1777,7 +1830,7 @@ void AudacityProject::GetPlayRegion(double* playRegionStart, playRegionStart, playRegionEnd); } -AudacityProject::PlaybackScroller::PlaybackScroller(AudacityProject *project) +ProjectWindow::PlaybackScroller::PlaybackScroller(AudacityProject *project) : mProject(project) { ViewInfo::Get( *mProject ).Bind(EVT_TRACK_PANEL_TIMER, @@ -1785,7 +1838,7 @@ AudacityProject::PlaybackScroller::PlaybackScroller(AudacityProject *project) this); } -void AudacityProject::PlaybackScroller::OnTimer(wxCommandEvent &event) +void ProjectWindow::PlaybackScroller::OnTimer(wxCommandEvent &event) { // Let other listeners get the notification event.Skip(); @@ -1837,9 +1890,9 @@ void AudacityProject::PlaybackScroller::OnTimer(wxCommandEvent &event) } } -void AudacityProject::ZoomInByFactor( double ZoomFactor ) +void ProjectWindow::ZoomInByFactor( double ZoomFactor ) { - auto &project = *this; + auto &project = mProject; auto &trackPanel = TrackPanel::Get( project ); auto &viewInfo = ViewInfo::Get( project ); @@ -1918,9 +1971,9 @@ void AudacityProject::ZoomInByFactor( double ZoomFactor ) TP_ScrollWindow(newh); } -void AudacityProject::ZoomOutByFactor( double ZoomFactor ) +void ProjectWindow::ZoomOutByFactor( double ZoomFactor ) { - auto &project = *this; + auto &project = mProject; auto &trackPanel = TrackPanel::Get( project ); auto &viewInfo = ViewInfo::Get( project ); @@ -1935,3 +1988,19 @@ void AudacityProject::ZoomOutByFactor( double ZoomFactor ) // newh = (newh > 0) ? newh : 0; TP_ScrollWindow(newh); } + +wxFrame &GetProjectFrame( AudacityProject &project ) +{ + auto ptr = project.GetFrame(); + if ( !ptr ) + THROW_INCONSISTENCY_EXCEPTION; + return *ptr; +} + +const wxFrame &GetProjectFrame( const AudacityProject &project ) +{ + auto ptr = project.GetFrame(); + if ( !ptr ) + THROW_INCONSISTENCY_EXCEPTION; + return *ptr; +} diff --git a/src/Project.h b/src/Project.h index e2f70f0f0..5d439acee 100644 --- a/src/Project.h +++ b/src/Project.h @@ -105,179 +105,35 @@ private: class Track; -// Container of various objects associated with the project, which is -// responsible for destroying them -using AttachedObjects = ClientData::Site< - AudacityProject, ClientData::Base, ClientData::SkipCopying, std::shared_ptr ->; -// Container of pointers to various windows associated with the project, which -// is not responsible for destroying them -- wxWidgets handles that instead -using AttachedWindows = ClientData::Site< - AudacityProject, wxWindow, ClientData::SkipCopying, wxWeakRef ->; - -using ProjectWindow = AudacityProject; -class AUDACITY_DLL_API AudacityProject final : public wxFrame, - public TrackPanelListener - , public AttachedObjects - , public AttachedWindows +class ProjectWindow final : public wxFrame + , public TrackPanelListener { - public: - static ProjectWindow &Get( AudacityProject &project ) { return project; } - static const ProjectWindow &Get( const AudacityProject &project ) { return project; } - static ProjectWindow *Find( AudacityProject *pProject ) { return pProject; } - static const ProjectWindow *Find( const AudacityProject *pProject ) { return pProject; } - AudacityProject &GetProject() { return *this; } - - using AttachedObjects = ::AttachedObjects; - using AttachedWindows = ::AttachedWindows; +public: + static ProjectWindow &Get( AudacityProject &project ); + static const ProjectWindow &Get( const AudacityProject &project ); + static ProjectWindow *Find( AudacityProject *pProject ); + static const ProjectWindow *Find( const AudacityProject *pProject ); + AudacityProject &GetProject() { return mProject; } - AudacityProject(wxWindow * parent, wxWindowID id, - const wxPoint & pos, const wxSize & size); - virtual ~AudacityProject(); + explicit ProjectWindow( + wxWindow * parent, wxWindowID id, + const wxPoint & pos, const wxSize &size, + AudacityProject &project ); + ~ProjectWindow() override; // Next available ID for sub-windows int NextWindowID(); - virtual void ApplyUpdatedTheme(); - - void GetPlayRegion(double* playRegionStart, double *playRegionEnd); - bool IsPlayRegionLocked() { return mLockPlayRegion; } - void SetPlayRegionLocked(bool value) { mLockPlayRegion = value; } - - wxString GetProjectName() const; + void Init(); bool IsActive() override; + bool IsIconized() const override; - using wxFrame::DetachMenuBar; - - void ZoomAfterImport(Track *pTrack); - - const FilePath &GetFileName() { return mFileName; } - void SetFileName( const FilePath &value ) { mFileName = value; } - - wxWindow *GetMainPage() { return mMainPage; } - wxPanel *GetTopPanel() { return mTopPanel; } - - - // Message Handlers - - void OnMenu(wxCommandEvent & event); - void OnUpdateUI(wxUpdateUIEvent & event); - - void MacShowUndockedToolbars(bool show); - void OnActivate(wxActivateEvent & event); - - void OnMouseEvent(wxMouseEvent & event); - void OnIconize(wxIconizeEvent &event); - void OnSize(wxSizeEvent & event); - void OnShow(wxShowEvent & event); - void OnMove(wxMoveEvent & event); - void DoScroll(); - void OnScroll(wxScrollEvent & event); - void OnToolBarUpdate(wxCommandEvent & event); - - void HandleResize(); - void UpdateLayout(); - void ZoomInByFactor( double ZoomFactor ); - void ZoomOutByFactor( double ZoomFactor ); - - // Other commands - - int GetProjectNumber(){ return mProjectNo;}; - void RedrawProject(const bool bForceWaveTracks = false); - void RefreshCursor(); - void Zoom(double level); - void ZoomBy(double multiplier); - void Rewind(bool shift); - void SkipEnd(bool shift); - - - // Scrollbars - - void OnScrollLeft(); - void OnScrollRight(); - - void OnScrollLeftButton(wxScrollEvent & event); - void OnScrollRightButton(wxScrollEvent & event); - - void FinishAutoScroll(); - void FixScrollbars(); - - bool MayScrollBeyondZero() const; - double ScrollingLowerBoundTime() const; - // How many pixels are covered by the period from lowermost scrollable time, to the given time: - // PRL: Bug1197: we seem to need to compute all in double, to avoid differing results on Mac - double PixelWidthBeforeTime(double scrollto) const; - void SetHorizontalThumb(double scrollto); - - // TrackPanel callback methods, overrides of TrackPanelListener - void TP_DisplaySelection() override; - - void TP_RedrawScrollbars() override; - void TP_ScrollLeft() override; - void TP_ScrollRight() override; - void TP_ScrollWindow(double scrollto) override; - bool TP_ScrollUpDown(int delta) override; - void TP_HandleResize() override; - - const wxString &GetStatus() const { return mLastMainStatusMessage; } - void SetStatus(const wxString &msg); - - private: - - void OnThemeChange(wxCommandEvent & evt); - - // The project's name and file info - FilePath mFileName; // Note: extension-less - - static int mProjectCounter;// global counter. - int mProjectNo; // count when this project was created. - - // Window elements - - wxString mLastMainStatusMessage; - - wxPanel *mTopPanel{}; - wxWindow * mMainPage; - wxPanel * mMainPanel; - wxScrollBar *mHsbar; - wxScrollBar *mVsbar; - -public: - wxScrollBar &GetVerticalScrollBar() { return *mVsbar; } - -private: - int mNextWindowID; - - bool mAutoScrolling{ false }; - bool mActive{ true }; - bool mIconized; - - bool mShownOnce{ false }; - - public: - bool mbBusyImporting{ false }; // used to fix bug 584 - int mBatchMode{ 0 };// 0 means not, >0 means in batch mode. - - void SetNormalizedWindowState(wxRect pSizeAndLocation) { mNormalizedWindowState = pSizeAndLocation; } - wxRect GetNormalizedWindowState() const { return mNormalizedWindowState; } - - private: - bool mIsDeleting{ false }; - -public: bool IsBeingDeleted() const { return mIsDeleting; } void SetIsBeingDeleted() { mIsDeleting = true; } -private: - - bool mLockPlayRegion; - - wxRect mNormalizedWindowState; - -public: - bool mbInitializingScrollbar{ false }; + wxWindow *GetMainPage() { return mMainPage; } + wxPanel *GetTopPanel() { return mTopPanel; } class PlaybackScroller final : public wxEvtHandler { @@ -303,20 +159,191 @@ public: AudacityProject *mProject; Mode mMode { Mode::Off }; }; + PlaybackScroller &GetPlaybackScroller() { return *mPlaybackScroller; } + + using wxFrame::DetachMenuBar; + + void SetNormalizedWindowState(wxRect pSizeAndLocation) { mNormalizedWindowState = pSizeAndLocation; } + wxRect GetNormalizedWindowState() const { return mNormalizedWindowState; } + + void RedrawProject(const bool bForceWaveTracks = false); + void RefreshCursor(); + + void Zoom(double level); + void ZoomInByFactor( double ZoomFactor ); + void ZoomOutByFactor( double ZoomFactor ); + void ZoomBy(double multiplier); + void ZoomAfterImport(Track *pTrack); + + void ApplyUpdatedTheme(); + + // Scrollbars + + wxScrollBar &GetVerticalScrollBar() { return *mVsbar; } + + void OnScrollLeft(); + void OnScrollRight(); + + void Rewind(bool shift); + void SkipEnd(bool shift); + + void OnScrollLeftButton(wxScrollEvent & event); + void OnScrollRightButton(wxScrollEvent & event); + + void FinishAutoScroll(); + void FixScrollbars(); + + bool MayScrollBeyondZero() const; + double ScrollingLowerBoundTime() const; + // How many pixels are covered by the period from lowermost scrollable time, to the given time: + // PRL: Bug1197: we seem to need to compute all in double, to avoid differing results on Mac + double PixelWidthBeforeTime(double scrollto) const; + void SetHorizontalThumb(double scrollto); + + // PRL: old and incorrect comment below, these functions are used elsewhere than TrackPanel + // TrackPanel access + wxSize GetTPTracksUsableArea() /* not override */; + void RefreshTPTrack(Track* pTrk, bool refreshbacking = true) /* not override */; + + // TrackPanel callback methods, overrides of TrackPanelListener + void TP_DisplaySelection() override; + + void TP_RedrawScrollbars() override; + void TP_ScrollLeft() override; + void TP_ScrollRight() override; + void TP_ScrollWindow(double scrollto) override; + bool TP_ScrollUpDown(int delta) override; + void TP_HandleResize() override; + + private: + + void OnThemeChange(wxCommandEvent & evt); + + public: + // Message Handlers + + void OnMenu(wxCommandEvent & event); + void OnUpdateUI(wxUpdateUIEvent & event); + + void MacShowUndockedToolbars(bool show); + void OnActivate(wxActivateEvent & event); + + void OnMouseEvent(wxMouseEvent & event); + void OnIconize(wxIconizeEvent &event); + void OnSize(wxSizeEvent & event); + void HandleResize(); + void UpdateLayout(); + void OnShow(wxShowEvent & event); + void OnMove(wxMoveEvent & event); + void DoScroll(); + void OnScroll(wxScrollEvent & event); + void OnToolBarUpdate(wxCommandEvent & event); + + bool mbInitializingScrollbar{ false }; private: - std::unique_ptr mPlaybackScroller; + AudacityProject &mProject; + wxRect mNormalizedWindowState; -public: - PlaybackScroller &GetPlaybackScroller() { return *mPlaybackScroller; } + wxPanel *mTopPanel{}; + wxWindow * mMainPage{}; + wxPanel * mMainPanel{}; + wxScrollBar *mHsbar{}; + wxScrollBar *mVsbar{}; + + int mNextWindowID{}; + + bool mAutoScrolling{ false }; + bool mActive{ true }; + bool mIconized; + bool mShownOnce{ false }; + + + + bool mIsDeleting{ false }; + +private: + + std::unique_ptr mPlaybackScroller; DECLARE_EVENT_TABLE() }; -inline wxFrame &GetProjectFrame( AudacityProject &project ) { return project; } -inline const wxFrame &GetProjectFrame( const AudacityProject &project ) { - return project; -} +// Container of various objects associated with the project, which is +// responsible for destroying them +using AttachedObjects = ClientData::Site< + AudacityProject, ClientData::Base, ClientData::SkipCopying, std::shared_ptr +>; +// Container of pointers to various windows associated with the project, which +// is not responsible for destroying them -- wxWidgets handles that instead +using AttachedWindows = ClientData::Site< + AudacityProject, wxWindow, ClientData::SkipCopying, wxWeakRef +>; + +class AUDACITY_DLL_API AudacityProject final + : public wxEvtHandler + , public AttachedObjects + , public AttachedWindows +{ + public: + using AttachedObjects = ::AttachedObjects; + using AttachedWindows = ::AttachedWindows; + + AudacityProject(); + virtual ~AudacityProject(); + + wxFrame *GetFrame() { return mFrame; } + const wxFrame *GetFrame() const { return mFrame; } + void SetFrame( wxFrame *pFrame ) { mFrame = pFrame; } + + void GetPlayRegion(double* playRegionStart, double *playRegionEnd); + bool IsPlayRegionLocked() { return mLockPlayRegion; } + void SetPlayRegionLocked(bool value) { mLockPlayRegion = value; } + + wxString GetProjectName() const; + + const FilePath &GetFileName() { return mFileName; } + void SetFileName( const FilePath &fileName ) { mFileName = fileName; } + + // Timer Record Auto Save/Export Routines + static int GetOpenProjectCount(); + + + // Message Handlers + + // Other commands + + int GetProjectNumber(){ return mProjectNo;}; + static int CountUnnamed(); + static void RefreshAllTitles(bool bShowProjectNumbers ); + + + const wxString &GetStatus() const { return mLastMainStatusMessage; } + void SetStatus(const wxString &msg); + + private: + + // The project's name and file info + FilePath mFileName; // Note: extension-less + + static int mProjectCounter;// global counter. + int mProjectNo; // count when this project was created. + + public: + bool mbBusyImporting{ false }; // used to fix bug 584 + int mBatchMode{ 0 };// 0 means not, >0 means in batch mode. + + private: + bool mLockPlayRegion{ false }; + + wxString mLastMainStatusMessage; + + wxWeakRef< wxFrame > mFrame{}; +}; + +wxFrame &GetProjectFrame( AudacityProject &project ); +const wxFrame &GetProjectFrame( const AudacityProject &project ); + inline wxFrame *FindProjectFrame( AudacityProject *project ) { return project ? &GetProjectFrame( *project ) : nullptr; } @@ -327,7 +354,7 @@ inline const wxFrame *FindProjectFrame( const AudacityProject *project ) { // TitleRestorer restores project window titles to what they were, in its destructor. class TitleRestorer{ public: - TitleRestorer(AudacityProject * p ); + TitleRestorer(ProjectWindow * pWindow ); ~TitleRestorer(); wxString sProjNumber; wxString sProjName; diff --git a/src/ProjectFileIO.cpp b/src/ProjectFileIO.cpp index 674b8fc5c..018d584fb 100644 --- a/src/ProjectFileIO.cpp +++ b/src/ProjectFileIO.cpp @@ -1106,8 +1106,8 @@ bool ProjectFileIO::SaveAs(const wxString & newFileName, bool bWantSaveCopy /*= bool ProjectFileIO::SaveAs(bool bWantSaveCopy /*= false*/, bool bLossless /*= false*/) { auto &project = mProject; - auto &window = GetProjectFrame( project ); - TitleRestorer Restorer( &project ); // RAII + auto &window = ProjectWindow::Get( project ); + TitleRestorer Restorer( &window ); // RAII bool bHasPath = true; wxFileName filename{ project.GetFileName() }; // Save a copy of the project with 32-bit float tracks. diff --git a/src/ProjectManager.cpp b/src/ProjectManager.cpp index 1afe6b1c9..b0260c058 100644 --- a/src/ProjectManager.cpp +++ b/src/ProjectManager.cpp @@ -361,19 +361,13 @@ AudacityProject *ProjectManager::New() // Create and show a NEW project // Use a non-default deleter in the smart pointer! - auto sp = AllProjects::value_type { - safenew AudacityProject( - nullptr, -1, - wxDefaultPosition, - wxSize(wndRect.width, wndRect.height) - ), - Destroyer< AudacityProject > {} - }; + auto sp = std::make_shared< AudacityProject >(); AllProjects{}.Add( sp ); auto p = sp.get(); auto &project = *p; auto &projectManager = Get( project ); - auto &window = GetProjectFrame( *p ); + auto &window = ProjectWindow::Get( *p ); + window.Init(); MissingAliasFilesDialog::SetShouldShow(true); MenuManager::Get( project ).CreateMenusAndCommands( project ); @@ -457,7 +451,7 @@ bool ProjectManager::SnapSelection() { auto &project = mProject; auto &settings = ProjectSettings::Get( project ); - auto &window = project; + auto &window = ProjectWindow::Get( project ); auto snapTo = settings.GetSnapTo(); if (snapTo != SNAP_OFF) { auto &viewInfo = ViewInfo::Get( project ); @@ -514,7 +508,7 @@ void ProjectManager::AS_SetSnapTo(int snap) { auto &project = mProject; auto &settings = ProjectSettings::Get( project ); - auto &window = project; + auto &window = ProjectWindow::Get( project ); settings.SetSnapTo( snap ); @@ -657,7 +651,7 @@ void ProjectManager::OnCloseWindow(wxCloseEvent & event) const auto &settings = ProjectSettings::Get( project ); auto &projectAudioIO = ProjectAudioIO::Get( project ); auto &tracks = TrackList::Get( project ); - auto &window = project; + auto &window = ProjectWindow::Get( project ); // We are called for the wxEVT_CLOSE_WINDOW, wxEVT_END_SESSION, and // wxEVT_QUERY_END_SESSION, so we have to protect against multiple @@ -1980,7 +1974,7 @@ void ProjectManager::OnTimer(wxTimerEvent& WXUNUSED(event)) void ProjectManager::OnStatusChange( wxCommandEvent & ) { auto &project = mProject; - auto &window = project; + auto &window = GetProjectFrame( project ); const auto &msg = project.GetStatus(); window.GetStatusBar()->SetStatusText(msg, mainStatusBarField); diff --git a/src/ProjectSettings.cpp b/src/ProjectSettings.cpp index 7ad030641..a7a177d67 100644 --- a/src/ProjectSettings.cpp +++ b/src/ProjectSettings.cpp @@ -22,7 +22,7 @@ namespace { { wxCommandEvent e{ EVT_PROJECT_SETTINGS_CHANGE }; e.SetInt( static_cast( code ) ); - project.GetEventHandler()->ProcessEvent( e ); + project.ProcessEvent( e ); } } diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 401b9ebec..d9eb9e75c 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -501,7 +501,7 @@ void TrackPanel::OnTimer(wxTimerEvent& ) // Notify listeners for timer ticks { wxCommandEvent e(EVT_TRACK_PANEL_TIMER); - p->GetEventHandler()->ProcessEvent(e); + p->ProcessEvent(e); } DrawOverlays(false); diff --git a/src/toolbars/ToolManager.h b/src/toolbars/ToolManager.h index 0493bef61..673b76caf 100644 --- a/src/toolbars/ToolManager.h +++ b/src/toolbars/ToolManager.h @@ -34,7 +34,7 @@ class wxTimerEvent; class wxWindow; class AudacityProject; -using ProjectWindow = AudacityProject; +class ProjectWindow; class ToolFrame; //////////////////////////////////////////////////////////// diff --git a/src/tracks/ui/Scrubbing.cpp b/src/tracks/ui/Scrubbing.cpp index 167bac8fa..691c7b695 100644 --- a/src/tracks/ui/Scrubbing.cpp +++ b/src/tracks/ui/Scrubbing.cpp @@ -226,6 +226,7 @@ Scrubber::Scrubber(AudacityProject *project) #endif , mProject(project) + , mWindow( FindProjectFrame( project ) ) , mPoller { std::make_unique(*this) } , mOptions {} @@ -234,7 +235,8 @@ Scrubber::Scrubber(AudacityProject *project) wxTheApp->Bind (wxEVT_ACTIVATE_APP, &Scrubber::OnActivateOrDeactivateApp, this); - mProject->PushEventHandler(&mForwarder); + if (mWindow) + mWindow->PushEventHandler(&mForwarder); } Scrubber::~Scrubber() @@ -244,7 +246,8 @@ Scrubber::~Scrubber() mpThread->Delete(); #endif - mProject->PopEventHandler(); + if ( mWindow ) + mWindow->PopEventHandler(); } namespace { diff --git a/src/tracks/ui/Scrubbing.h b/src/tracks/ui/Scrubbing.h index ae5af2658..bdc8c66c8 100644 --- a/src/tracks/ui/Scrubbing.h +++ b/src/tracks/ui/Scrubbing.h @@ -196,6 +196,7 @@ private: #endif AudacityProject *mProject; + wxWindowRef mWindow; DECLARE_EVENT_TABLE()