Audacity 3.2.0
ProjectWindow.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5ProjectWindow.cpp
6
7Paul Licameli split from AudacityProject.cpp
8
9**********************************************************************/
10#include "ProjectWindow.h"
11
12#include "ActiveProject.h"
13#include "AllThemeResources.h"
14#include "AudioIO.h"
16#include "ProjectAudioIO.h"
17#include "ProjectFileIO.h"
18#include "ProjectWindows.h"
19#include "ProjectStatus.h"
20#include "ViewInfo.h"
21#include "WaveClip.h"
22#include "WaveTrack.h"
23#include "CommandManager.h"
24#include "prefs/ThemePrefs.h"
25#include "prefs/TracksPrefs.h"
27#include "tracks/ui/Scrubbing.h"
29#include "wxPanelWrapper.h"
30#include "WindowAccessible.h"
31
32#include "ThemedWrappers.h"
33
34#include <wx/display.h>
35#include <wx/scrolbar.h>
36#include <wx/sizer.h>
37#include <wx/splitter.h>
38#include <wx/wupdlock.h>
39
40#include "TrackPanel.h"
41
42namespace
43{
44#ifdef HAS_AUDIOCOM_UPLOAD
45 constexpr int DEFAULT_WINDOW_WIDTH = 1180;
46#else
47 constexpr int DEFAULT_WINDOW_WIDTH = 1120;
48#endif
49 constexpr int DEFAULT_WINDOW_HEIGHT = 674;
50}
51
52BoolSetting ProjectWindowMaximized{ L"/Window/Maximized", false };
53BoolSetting ProjectWindowIconized{ L"/Window/Iconized", false };
54IntSetting ProjectWindowX{ L"/Window/X", 0 };
55IntSetting ProjectWindowY{ L"/Window/Y", 0 };
58IntSetting ProjectWindowNormalX{ L"/Window/Normal_X", 0 };
59IntSetting ProjectWindowNormalY{ L"/Window/Normal_Y", 0 };
62
63// Returns the screen containing a rectangle, or -1 if none does.
64int ScreenContaining( wxRect & r ){
65 unsigned int n = wxDisplay::GetCount();
66 for(unsigned int i = 0;i<n;i++){
67 wxDisplay d(i);
68 wxRect scr = d.GetClientArea();
69 if( scr.Contains( r ) )
70 return (int)i;
71 }
72 return -1;
73}
74
75// true IFF TL and BR corners are on a connected display.
76// Does not need to check all four. We just need to check that
77// the window probably is straddling screens in a sensible way.
78// If the user wants to use mixed landscape and portrait, they can.
79bool CornersOnScreen( wxRect & r ){
80 if( wxDisplay::GetFromPoint( r.GetTopLeft() ) == wxNOT_FOUND) return false;
81 if( wxDisplay::GetFromPoint( r.GetBottomRight() ) == wxNOT_FOUND) return false;
82 return true;
83}
84
85// true iff we have enough of the top bar to be able to reposition the window.
86bool IsWindowAccessible(wxRect *requestedRect)
87{
88 wxDisplay display;
89 wxRect targetTitleRect(requestedRect->GetLeftTop(), requestedRect->GetBottomRight());
90 // Hackery to approximate a window top bar size from a window size.
91 // and exclude the open/close and borders.
92 targetTitleRect.x += 15;
93 targetTitleRect.width -= 100;
94 if (targetTitleRect.width < 165) targetTitleRect.width = 165;
95 targetTitleRect.height = 15;
96 int targetBottom = targetTitleRect.GetBottom();
97 int targetRight = targetTitleRect.GetRight();
98 // This looks like overkill to check each and every pixel in the ranges.
99 // and decide that if any is visible on screen we are OK.
100 for (int i = targetTitleRect.GetLeft(); i < targetRight; i++) {
101 for (int j = targetTitleRect.GetTop(); j < targetBottom; j++) {
102 int monitor = display.GetFromPoint(wxPoint(i, j));
103 if (monitor != wxNOT_FOUND) {
104 return TRUE;
105 }
106 }
107 }
108 return FALSE;
109}
110
111// BG: The default size and position of the first window
112void GetDefaultWindowRect(wxRect *defRect)
113{
114 *defRect = wxGetClientDisplayRect();
115
116 int width = DEFAULT_WINDOW_WIDTH;
117 int height = DEFAULT_WINDOW_HEIGHT;
118
119 //These conditional values assist in improving placement and size
120 //of NEW windows on different platforms.
121#ifdef __WXGTK__
122 height += 20;
123#endif
124
125#ifdef __WXMSW__
126 height += 40;
127#endif
128
129#ifdef __WXMAC__
130 height += 55;
131#endif
132
133 // Use screen size where it is smaller than the values we would like.
134 // Otherwise use the values we would like, and centred.
135 if (width < defRect->width)
136 {
137 defRect->x = (defRect->width - width)/2;
138 defRect->width = width;
139 }
140
141 if (height < defRect->height)
142 {
143 defRect->y = (defRect->height - height)/2;
144 // Bug 1119 workaround
145 // Small adjustment for very small Mac screens.
146 // If there is only a tiny space at the top
147 // then instead of vertical centre, align to bottom.
148 const int pixelsFormenu = 60;
149 if( defRect->y < pixelsFormenu )
150 defRect->y *=2;
151 defRect->height = height;
152 }
153}
154
155// BG: Calculate where to place the next window (could be the first window)
156// BG: Does not store X and Y in prefs. This is intentional.
157//
158// LL: This should NOT need to be this complicated...FIXME
159void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized)
160{
161 int inc = 25;
162
163 wxRect defaultRect;
164 GetDefaultWindowRect(&defaultRect);
165
166 *pMaximized = ProjectWindowMaximized.Read();
167 *pIconized = ProjectWindowIconized.Read();
168
169 wxRect windowRect;
170 windowRect.x = ProjectWindowX.ReadWithDefault(defaultRect.x);
171 windowRect.y = ProjectWindowY.ReadWithDefault(defaultRect.y);
172 windowRect.width = ProjectWindowWidth.ReadWithDefault(defaultRect.width);
173 windowRect.height = ProjectWindowHeight.ReadWithDefault(defaultRect.height);
174
175 wxRect normalRect;
176 normalRect.x = ProjectWindowNormalX.ReadWithDefault(defaultRect.x);
177 normalRect.y = ProjectWindowNormalY.ReadWithDefault(defaultRect.y);
178 normalRect.width = ProjectWindowNormalWidth.ReadWithDefault(defaultRect.width);
179 normalRect.height = ProjectWindowNormalHeight.ReadWithDefault(defaultRect.height);
180
181 // Workaround 2.1.1 and earlier bug on OSX...affects only normalRect, but let's just
182 // validate for all rects and plats
183 if (normalRect.width == 0 || normalRect.height == 0) {
184 normalRect = defaultRect;
185 }
186 if (windowRect.width == 0 || windowRect.height == 0) {
187 windowRect = defaultRect;
188 }
189
190
191 wxRect screenRect( wxGetClientDisplayRect());
192#if defined(__WXMAC__)
193
194 // On OSX, the top of the window should never be less than the menu height,
195 // so something is amiss if it is
196 if (normalRect.y < screenRect.y) {
197 normalRect = defaultRect;
198 }
199 if (windowRect.y < screenRect.y) {
200 windowRect = defaultRect;
201 }
202#endif
203
204 // IF projects empty, THEN it's the first window.
205 // It lands where the config says it should, and can straddle screen.
206 if (AllProjects{}.empty()) {
207 if (*pMaximized || *pIconized) {
208 *nextRect = normalRect;
209 }
210 else {
211 *nextRect = windowRect;
212 }
213 // Resize, for example if one monitor that was on is now off.
214 if (!CornersOnScreen( wxRect(*nextRect).Deflate( 32, 32 ))) {
215 *nextRect = defaultRect;
216 }
217 if (!IsWindowAccessible(nextRect)) {
218 *nextRect = defaultRect;
219 }
220 // Do not trim the first project window down.
221 // All corners are on screen (or almost so), and
222 // the rect may straddle screens.
223 return;
224 }
225
226
227 // ELSE a subsequent NEW window. It will NOT straddle screens.
228
229 // We don't mind being 32 pixels off the screen in any direction.
230 // Make sure initial sizes (pretty much) fit within the display bounds
231 // We used to trim the sizes which could result in ridiculously small windows.
232 // contributing to bug 1243.
233 // Now instead if the window significantly doesn't fit the screen, we use the default
234 // window instead, which we know does.
235 if (ScreenContaining( wxRect(normalRect).Deflate( 32, 32 ))<0) {
236 normalRect = defaultRect;
237 }
238 if (ScreenContaining( wxRect(windowRect).Deflate( 32, 32 ) )<0) {
239 windowRect = defaultRect;
240 }
241
242 bool validWindowSize = false;
243 ProjectWindow * validProject = NULL;
244 for ( auto iter = AllProjects{}.rbegin(), end = AllProjects{}.rend();
245 iter != end; ++iter
246 ) {
247 auto pProject = *iter;
248 if (!GetProjectFrame( *pProject ).IsIconized()) {
249 validWindowSize = true;
250 validProject = &ProjectWindow::Get( *pProject );
251 break;
252 }
253 }
254 if (validWindowSize) {
255 *nextRect = validProject->GetRect();
256 *pMaximized = validProject->IsMaximized();
257 *pIconized = validProject->IsIconized();
258 // Do not straddle screens.
259 if (ScreenContaining( wxRect(*nextRect).Deflate( 32, 32 ) )<0) {
260 *nextRect = defaultRect;
261 }
262 }
263 else {
264 *nextRect = normalRect;
265 }
266
267 //Placement depends on the increments
268 nextRect->x += inc;
269 nextRect->y += inc;
270
271 // defaultrect is a rectangle on the first screen. It's the right fallback to
272 // use most of the time if things are not working out right with sizing.
273 // windowRect is a saved rectangle size.
274 // normalRect seems to be a substitute for windowRect when iconized or maximised.
275
276 // Windows can say that we are off screen when actually we are not.
277 // On Windows 10 I am seeing miscalculation by about 6 pixels.
278 // To fix this we allow some sloppiness on the edge being counted as off screen.
279 // This matters most when restoring very carefully sized windows that are maximised
280 // in one dimension (height or width) but not both.
281 const int edgeSlop = 10;
282
283 // Next four lines are getting the rectangle for the screen that contains the
284 // top left corner of nextRect (and defaulting to rect of screen 0 otherwise).
285 wxPoint p = nextRect->GetLeftTop();
286 int scr = std::max( 0, wxDisplay::GetFromPoint( p ));
287 wxDisplay d( scr );
288 screenRect = d.GetClientArea();
289
290 // Now we (possibly) start trimming our rectangle down.
291 // Have we hit the right side of the screen?
292 wxPoint bottomRight = nextRect->GetBottomRight();
293 if (bottomRight.x > (screenRect.GetRight()+edgeSlop)) {
294 int newWidth = screenRect.GetWidth() - nextRect->GetLeft();
295 if (newWidth < defaultRect.GetWidth()) {
296 nextRect->x = windowRect.x;
297 nextRect->y = windowRect.y;
298 nextRect->width = windowRect.width;
299 }
300 else {
301 nextRect->width = newWidth;
302 }
303 }
304
305 // Have we hit the bottom of the screen?
306 bottomRight = nextRect->GetBottomRight();
307 if (bottomRight.y > (screenRect.GetBottom()+edgeSlop)) {
308 nextRect->y -= inc;
309 bottomRight = nextRect->GetBottomRight();
310 if (bottomRight.y > (screenRect.GetBottom()+edgeSlop)) {
311 nextRect->SetBottom(screenRect.GetBottom());
312 }
313 }
314
315 // After all that we could have a window that does not have a visible
316 // top bar. [It is unlikely, but something might have gone wrong]
317 // If so, use the safe fallback size.
318 if (!IsWindowAccessible(nextRect)) {
319 *nextRect = defaultRect;
320 }
321}
322
323namespace {
324
325// This wrapper prevents the scrollbars from retaining focus after being
326// used. Otherwise, the only way back to the track panel is to click it
327// and that causes your original location to be lost.
328class ScrollBar final : public wxScrollBar
329{
330public:
331 ScrollBar(wxWindow* parent, wxWindowID id, long style)
332 : wxScrollBar(parent, id, wxDefaultPosition, wxDefaultSize, style)
333 {
334 }
335
336 void OnSetFocus(wxFocusEvent & e)
337 {
338 wxWindow *w = e.GetWindow();
339 if (w != NULL) {
340 w->SetFocus();
341 }
342 }
343
344 void SetScrollbar(int position, int thumbSize,
345 int range, int pageSize,
346 bool refresh = true) override;
347
348private:
349 DECLARE_EVENT_TABLE()
350};
351
352void ScrollBar::SetScrollbar(int position, int thumbSize,
353 int range, int pageSize,
354 bool refresh)
355{
356 // Mitigate flashing of scrollbars by refreshing only when something really changes.
357
358 // PRL: This may have been made unnecessary by other fixes for flashing, see
359 // commit ac05b190bee7dd0000bce56edb0e5e26185c972f
360
361 auto changed =
362 position != GetThumbPosition() ||
363 thumbSize != GetThumbSize() ||
364 range != GetRange() ||
365 pageSize != GetPageSize();
366 if (!changed)
367 return;
368
369 wxScrollBar::SetScrollbar(position, thumbSize, range, pageSize, refresh);
370}
371
372BEGIN_EVENT_TABLE(ScrollBar, wxScrollBar)
373 EVT_SET_FOCUS(ScrollBar::OnSetFocus)
375
377 []( AudacityProject &parent ) -> wxWeakRef< wxWindow > {
378 wxRect wndRect;
379 bool bMaximized = false;
380 bool bIconized = false;
381 GetNextWindowPlacement(&wndRect, &bMaximized, &bIconized);
382
383 auto pWindow = safenew ProjectWindow(
384 nullptr, -1,
385 wxDefaultPosition,
386 wxSize(wndRect.width, wndRect.height),
387 parent
388 );
389
390 auto &window = *pWindow;
391 // wxGTK3 seems to need to require creating the window using default position
392 // and then manually positioning it.
393 window.SetPosition(wndRect.GetPosition());
394
395 if(bMaximized) {
396 window.Maximize(true);
397 }
398 else if (bIconized) {
399 // if the user close down and iconized state we could start back up and iconized state
400 // window.Iconize(TRUE);
401 }
402
403 return pWindow;
404 }
405};
406
407}
408
410{
412}
413
415{
416 return Get( const_cast< AudacityProject & >( project ) );
417}
418
420{
421 return pProject
423 : nullptr;
424}
425
427{
428 return Find( const_cast< AudacityProject * >( pProject ) );
429}
430
432{
433 return mNextWindowID++;
434}
435
436enum {
437 FirstID = 1000,
438
439 // Window controls
440
443
445};
446
447namespace {
451 explicit Adapter(ProjectWindow &window) : mwWindow{ &window } {}
452 ~Adapter() override = default;
453
454 std::pair<int, int> ViewportSize() const override
455 { return mwWindow ? mwWindow->ViewportSize() : std::pair{ 1, 1 }; }
456 bool MayScrollBeyondZero() const override
457 { return mwWindow ? mwWindow->MayScrollBeyondZero() : false; }
458
459 unsigned MinimumTrackHeight() override
460 { return mwWindow ? mwWindow->MinimumTrackHeight() : 0; }
461 bool IsTrackMinimized(const Track &track) override
462 { return mwWindow ? mwWindow->IsTrackMinimized(track) : false; }
463 void SetMinimized(Track &track, bool minimized) override
464 { if (mwWindow) mwWindow->SetMinimized(track, minimized); }
465 int GetTrackHeight(const Track &track) override
466 { return mwWindow ? mwWindow->GetTrackHeight(track) : 0; }
467 void SetChannelHeights(Track &track, unsigned height) override
468 { if (mwWindow) mwWindow->SetChannelHeights(track, height); }
469 int GetTotalHeight(const TrackList &trackList) override
470 { return mwWindow ? mwWindow->GetTotalHeight(trackList) : 0; }
471
472 int GetHorizontalThumbPosition() const override
473 { return mwWindow ? mwWindow->GetHorizontalThumbPosition() : 0; }
474 int GetHorizontalThumbSize() const override
475 { return mwWindow ? mwWindow->GetHorizontalThumbSize() : 0; }
476 int GetHorizontalRange() const override
477 { return mwWindow ? mwWindow->GetHorizontalRange() : 0; }
478 void SetHorizontalThumbPosition(int viewStart) override
479 {
480 if (mwWindow) mwWindow->SetHorizontalThumbPosition(viewStart);
481 }
482 void SetHorizontalScrollbar(int position, int thumbSize,
483 int range, int pageSize, bool refresh) override
484 {
485 if (mwWindow)
486 mwWindow->SetHorizontalScrollbar(
487 position, thumbSize, range, pageSize, refresh);
488 }
489 void ShowHorizontalScrollbar(bool shown) override
490 {
491 if (mwWindow)
492 mwWindow->ShowHorizontalScrollbar(shown);
493 }
494
495 int GetVerticalThumbPosition() const override
496 { return mwWindow ? mwWindow->GetVerticalThumbPosition() : 0; }
497 int GetVerticalThumbSize() const override
498 { return mwWindow ? mwWindow->GetVerticalThumbSize() : 0; }
499 int GetVerticalRange() const override
500 { return mwWindow ? mwWindow->GetVerticalRange() : 0; }
501 void SetVerticalThumbPosition(int viewStart) override
502 {
503 if (mwWindow) mwWindow->SetVerticalThumbPosition(viewStart);
504 }
505 void SetVerticalScrollbar(int position, int thumbSize,
506 int range, int pageSize, bool refresh) override
507 {
508 if (mwWindow)
509 mwWindow->SetVerticalScrollbar(
510 position, thumbSize, range, pageSize, refresh);
511 }
512 void ShowVerticalScrollbar(bool shown) override
513 {
514 if (mwWindow)
515 mwWindow->ShowVerticalScrollbar(shown);
516 }
517 void SetToDefaultSize() override
518 {
519 if (mwWindow)
520 mwWindow->SetToDefaultSize();
521 }
522
523 wxWeakRef<ProjectWindow> mwWindow;
524};
525}
526
527ProjectWindow::ProjectWindow(wxWindow * parent, wxWindowID id,
528 const wxPoint & pos,
529 const wxSize & size, AudacityProject &project
530) : ProjectWindowBase{ parent, id, pos, size, project }
531 , mViewportSubscription{
533 .Subscribe(*this, &ProjectWindow::OnViewportMessage) }
534{
535 Viewport::Get(project).SetCallbacks(std::make_unique<Adapter>(*this));
536
538
539 constexpr auto EffectsPanelMaxWidth { 500 };
540 constexpr auto TrackPanelMinWidth { 250 };
541
542 // Two sub-windows need to be made before Init(),
543 // so that this constructor can complete, and then TrackPanel and
544 // AdornedRulerPanel can retrieve those windows from this in their
545 // factory functions
546
547 // PRL: this panel groups the top tool dock and the ruler into one
548 // tab cycle.
549 // Must create it with non-default width equal to the main window width,
550 // or else the device toolbar doesn't make initial widths of the choice
551 // controls correct.
553 this, wxID_ANY, wxDefaultPosition,
554 wxSize{ this->GetSize().GetWidth(), -1 }
555 };
556 mTopPanel->SetLabel( "Top Panel" );// Not localised
557 mTopPanel->SetLayoutDirection(wxLayout_LeftToRight);
558 mTopPanel->SetAutoLayout(true);
559#ifdef EXPERIMENTAL_DA2
560 mTopPanel->SetBackgroundColour(theTheme.Colour( clrMedium ));
561#endif
562
563 auto container = safenew wxSplitterWindow(this, wxID_ANY,
564 wxDefaultPosition,
565 wxDefaultSize,
566 wxNO_BORDER | wxSP_LIVE_UPDATE | wxSP_THIN_SASH);
567 container->Bind(wxEVT_SPLITTER_DOUBLECLICKED, [](wxSplitterEvent& event){
568 //"The default behaviour is to unsplit the window"
569 event.Veto();//do noting instead
570 });
571 container->Bind(wxEVT_SPLITTER_SASH_POS_CHANGING, [=](wxSplitterEvent& event){
572 if(event.GetSashPosition() > EffectsPanelMaxWidth)
573 //Prevents left panel from expanding further
574 event.SetSashPosition(-1);
575 });
576 mContainerWindow = container;
577
579 wxDefaultPosition,
580 wxDefaultSize,
581 wxNO_BORDER);
582 mTrackListWindow->SetMinSize({TrackPanelMinWidth, -1});
583 mTrackListWindow->SetSizer( safenew wxBoxSizer(wxVERTICAL) );
584 mTrackListWindow->SetLabel("Main Panel");// Not localized.
585 mTrackListWindow->SetLayoutDirection(wxLayout_LeftToRight);
586
588
589#ifdef EXPERIMENTAL_DA2
590 mTrackListWindow->SetBackgroundColour(theTheme.Colour( clrMedium ));
591#endif
592
593 mPlaybackScroller = std::make_unique<PlaybackScroller>( &project );
594
595 // PRL: Old comments below. No longer observing the ordering that it
596 // recommends. ProjectWindow::OnActivate puts the focus directly into
597 // the TrackPanel, which avoids the problems.
598 // LLL: When Audacity starts or becomes active after returning from
599 // another application, the first window that can accept focus
600 // will be given the focus even if we try to SetFocus(). By
601 // creating the scrollbars after the TrackPanel, we resolve
602 // several focus problems.
603
604 mHsbar = safenew ScrollBar(mTrackListWindow, HSBarID, wxSB_HORIZONTAL);
605 mVsbar = safenew ScrollBar(mTrackListWindow, VSBarID, wxSB_VERTICAL);
606#if wxUSE_ACCESSIBILITY
607 // so that name can be set on a standard control
608 mHsbar->SetAccessible(safenew WindowAccessible(mHsbar));
609 mVsbar->SetAccessible(safenew WindowAccessible(mVsbar));
610#endif
611 mHsbar->SetLayoutDirection(wxLayout_LeftToRight);
612 mHsbar->SetName(_("Horizontal Scrollbar"));
613 mVsbar->SetName(_("Vertical Scrollbar"));
614
617
618 // Subscribe to title changes published by ProjectFileIO
621
622 // And also establish my initial consistency with it
624}
625
627{
628 // Tool manager gives us capture sometimes
629 if(HasCapture())
630 ReleaseMouse();
631}
632
633BEGIN_EVENT_TABLE(ProjectWindow, wxFrame)
635 EVT_MOUSE_EVENTS(ProjectWindow::OnMouseEvent)
637 EVT_SIZE(ProjectWindow::OnSize)
638 EVT_SHOW(ProjectWindow::OnShow)
639 EVT_ICONIZE(ProjectWindow::OnIconize)
640 EVT_MOVE(ProjectWindow::OnMove)
641 EVT_ACTIVATE(ProjectWindow::OnActivate)
642 EVT_COMMAND_SCROLL_LINEUP(HSBarID, ProjectWindow::OnScrollLeftButton)
643 EVT_COMMAND_SCROLL_LINEDOWN(HSBarID, ProjectWindow::OnScrollRightButton)
644 EVT_COMMAND_SCROLL(HSBarID, ProjectWindow::OnScroll)
645 EVT_COMMAND_SCROLL(VSBarID, ProjectWindow::OnScroll)
646 // Fires for menu with ID #1...first menu defined
647 EVT_UPDATE_UI(1, ProjectWindow::OnUpdateUI)
648 EVT_COMMAND(wxID_ANY, EVT_TOOLBAR_UPDATED, ProjectWindow::OnToolBarUpdate)
649 //mchinen:multithreaded calls - may not be threadsafe with CommandEvent: may have to change.
651
652void ProjectWindow::ApplyUpdatedTheme()
653{
654 SetBackgroundColour(theTheme.Colour( clrMedium ));
655 ClearBackground();// For wxGTK.
656}
657
659{
660 auto pProject = FindProject();
661 if (!pProject)
662 return;
663 auto &project = *pProject;
664
665 if (message.appearance)
666 return;
667 this->ApplyUpdatedTheme();
668 auto &toolManager = ToolManager::Get( project );
669 toolManager.ForEach([](auto pToolBar){
670 if( pToolBar )
671 pToolBar->ReCreateButtons();
672 });
673}
674
676{
677 // Update status bar widths in case of language change
679}
680
681#include "AllThemeResources.h"
682
684{
685 auto pProject = FindProject();
686 if (!pProject)
687 return;
689}
690
692{
693 auto pProject = FindProject();
694 if (!pProject)
695 return;
697}
698
699std::pair<int, int> ProjectWindow::ViewportSize() const
700{
701 auto pProject = FindProject();
702 if (!pProject)
703 return { 0, 0 };
704 auto &project = *pProject;
705 auto &trackPanel = TrackPanel::Get(project);
706 int width, height;
707 trackPanel.GetSize(&width, &height);
708 return { width, height };
709}
710
712{
713 auto pProject = FindProject();
714 if (!pProject)
715 return false;
716 auto &project = *pProject;
717 auto &scrubber = Scrubber::Get( project );
718 auto &viewInfo = ViewInfo::Get( project );
719 if (viewInfo.bScrollBeyondZero)
720 return true;
721
722 if (scrubber.HasMark() ||
724 if (mPlaybackScroller) {
725 auto mode = mPlaybackScroller->GetMode();
726 if (mode == PlaybackScroller::Mode::Pinned ||
728 return true;
729 }
730 }
731
732 return false;
733}
734
736{
738}
739
741{
742 return ChannelView::Get(*track.GetChannel(0)).GetMinimized();
743}
744
745void ProjectWindow::SetMinimized(Track &track, bool minimized)
746{
747 for (auto pChannel : track.Channels())
748 ChannelView::Get(*pChannel).SetMinimized(minimized);
749}
750
752{
754}
755
757{
758 return ChannelView::GetTotalHeight(trackList);
759}
760
761void ProjectWindow::SetChannelHeights(Track &track, unsigned height)
762{
763 for (auto pChannel : track.Channels())
764 ChannelView::Get(*pChannel).SetExpandedHeight(height);
765}
766
768{
769 return mHsbar->GetThumbPosition();
770}
771
773{
774 return mHsbar->GetThumbSize();
775}
776
778{
779 return mHsbar->GetRange();
780}
781
783{
784 mHsbar->SetThumbPosition(viewStart);
785}
786
787void ProjectWindow::SetHorizontalScrollbar(int position, int thumbSize,
788 int range, int pageSize, bool refresh)
789{
790 mHsbar->SetScrollbar(position, thumbSize, range, pageSize, refresh);
791}
792
794{
795#ifdef __WXGTK__
796 mHsbar->Show(shown);
797#else
798 mHsbar->Enable(shown);
799#endif
800}
801
803{
804 return mVsbar->GetThumbPosition();
805}
806
808{
809 return mVsbar->GetThumbSize();
810}
811
813{
814 return mVsbar->GetRange();
815}
816
818{
819 mVsbar->SetThumbPosition(viewStart);
820}
821
822void ProjectWindow::SetVerticalScrollbar(int position, int thumbSize,
823 int range, int pageSize, bool refresh)
824{
825 mVsbar->SetScrollbar(position, thumbSize, range, pageSize, refresh);
826}
827
829{
830#ifdef __WXGTK__
831 mVsbar->Show(shown);
832#else
833 mVsbar->Enable(shown);
834#endif
835}
836
838{
839 auto pProject = FindProject();
840 if (!pProject)
841 return;
842 auto &project = *pProject;
843 auto &trackPanel = GetProjectPanel( project );
844 auto &toolManager = ToolManager::Get( project );
845
846 // 1. Layout panel, to get widths of the docks.
847 Layout();
848 // 2. Layout toolbars to pack the toolbars correctly in docks which
849 // are now the correct width.
850 toolManager.LayoutToolBars();
851 // 3. Layout panel, to resize docks, in particular reducing the height
852 // of any empty docks, or increasing the height of docks that need it.
853 Layout();
854
855 // Bug 2455
856 // The commented out code below is to calculate a nice minimum size for
857 // the window. However on Ubuntu when the window is minimised it leads to
858 // an insanely tall window.
859 // Using a fixed min size fixes that.
860 // However there is still something strange when minimised, as once
861 // UpdateLayout is called once, when minimised, it gets called repeatedly.
862#if 0
863 // Retrieve size of this projects window
864 wxSize mainsz = GetSize();
865
866 // Retrieve position of the track panel to use as the size of the top
867 // third of the window
868 wxPoint tppos = ClientToScreen(trackPanel.GetParent()->GetPosition());
869
870 // Retrieve position of bottom dock to use as the size of the bottom
871 // third of the window
872 wxPoint sbpos = ClientToScreen(toolManager.GetBotDock()->GetPosition());
873
874 // The "+ 50" is the minimum height of the TrackPanel
875 SetMinSize( wxSize(250, (mainsz.y - sbpos.y) + tppos.y + 50));
876#endif
877 SetMinSize( wxSize(250, 250));
878 SetMaxSize( wxSize(20000, 20000));
879}
880
882{
883 return mIconized;
884}
885
887{
888 return mTrackListWindow;
889}
890
891wxSplitterWindow* ProjectWindow::GetContainerWindow() noexcept
892{
893 return mContainerWindow;
894}
895
896wxPanel* ProjectWindow::GetTopPanel() noexcept
897{
898 return mTopPanel;
899}
900
902{
903 wxRect defaultRect;
904 GetDefaultWindowRect(&defaultRect);
905
906 SetSize(defaultRect.width, defaultRect.height);
907}
908
910{
911 auto pProject = FindProject();
912 if (!pProject)
913 return;
914 auto &project = *pProject;
915 enum { nWidths = nStatusBarFields + 1 };
916 int widths[ nWidths ]{ 0 };
917 widths[ rateStatusBarField ] = 150;
918 const auto statusBar = GetStatusBar();
919 const auto &functions = ProjectStatus::GetStatusWidthFunctions();
920 // Start from 1 not 0
921 // Specifying a first column always of width 0 was needed for reasons
922 // I forget now
923 for ( int ii = 1; ii <= nStatusBarFields; ++ii ) {
924 int &width = widths[ ii ];
925 for ( const auto &function : functions ) {
926 auto results =
927 function( project, static_cast< StatusBarField >( ii ) );
928 for ( const auto &string : results.first ) {
929 int w;
930 statusBar->GetTextExtent(string.Translation(), &w, nullptr);
931 width = std::max<int>( width, w + results.second );
932 }
933 }
934 }
935 // The main status field is not fixed width
936 widths[ mainStatusBarField ] = -1;
937 statusBar->SetStatusWidths( nWidths, widths );
938}
939
941{
942 (void)show;//compiler food
943#ifdef __WXMAC__
944 // Save the focus so we can restore it to whatever had it before since
945 // showing a previously hidden toolbar will cause the focus to be set to
946 // its frame. If this is not done it will appear that activation events
947 // aren't being sent to the project window since they are actually being
948 // delivered to the last tool frame shown.
949 wxWindow *focused = FindFocus();
950
951 // Find all the floating toolbars, and show or hide them
952 const auto &children = GetChildren();
953 for(const auto &child : children) {
954 if (auto frame = dynamic_cast<ToolFrame*>(child)) {
955 if (!show) {
956 frame->Hide();
957 }
958 else if (frame->GetBar() &&
959 frame->GetBar()->IsVisible() ) {
960 frame->Show();
961 }
962 }
963 }
964
965 // Restore the focus if needed
966 if (focused) {
967 focused->SetFocus();
968 }
969#endif
970}
971
972void ProjectWindow::OnIconize(wxIconizeEvent &event)
973{
974 //JKC: On Iconizing we get called twice. Don't know
975 // why but it does no harm.
976 // Should we be returning true/false rather than
977 // void return? I don't know.
978 mIconized = event.IsIconized();
979
980#if defined(__WXMAC__)
981 // Readdresses bug 1431 since a crash could occur when restoring iconized
982 // floating toolbars due to recursion (bug 2411).
984 if( !mIconized )
985 {
986 Raise();
987 }
988#endif
989
990 // VisibileProjectCount seems to be just a counter for debugging.
991 // It's not used outside this function.
992 auto VisibleProjectCount = std::count_if(
994 []( const AllProjects::value_type &ptr ){
995 return !GetProjectFrame( *ptr ).IsIconized();
996 }
997 );
998 event.Skip();
999
1000 // This step is to fix part of Bug 2040, where the BackingPanel
1001 // size was not restored after we leave Iconized state.
1002
1003 // Queue up a resize event using OnShow so that we
1004 // refresh the track panel. But skip this, if we're iconized.
1005 if( mIconized )
1006 return;
1007 wxShowEvent Evt;
1008 OnShow( Evt );
1009}
1010
1011void ProjectWindow::OnMove(wxMoveEvent & event)
1012{
1013 if (!this->IsMaximized() && !this->IsIconized())
1014 SetNormalizedWindowState(this->GetRect());
1015 event.Skip();
1016}
1017
1018void ProjectWindow::OnSize(wxSizeEvent & event)
1019{
1020 // (From Debian)
1021 //
1022 // (3.) GTK critical warning "IA__gdk_window_get_origin: assertion
1023 // 'GDK_IS_WINDOW (window)' failed": Received events of type wxSizeEvent
1024 // on the main project window cause calls to "ClientToScreen" - which is
1025 // not available until the window is first shown. So the class has to
1026 // keep track of wxShowEvent events and inhibit those actions until the
1027 // window is first shown.
1028 if (mShownOnce) {
1029 auto pProject = FindProject();
1030 if (pProject)
1031 Viewport::Get(*pProject).HandleResize();
1032 if (!this->IsMaximized() && !this->IsIconized())
1033 SetNormalizedWindowState(this->GetRect());
1034 }
1035 event.Skip();
1036}
1037
1038void ProjectWindow::OnShow(wxShowEvent & event)
1039{
1040 // Remember that the window has been shown at least once
1041 mShownOnce = true;
1042
1043 // (From Debian...see also TrackPanel::OnTimer and AudacityTimer::Notify)
1044 //
1045 // Description: Workaround for wxWidgets bug: Reentry in clipboard
1046 // The wxWidgets bug http://trac.wxwidgets.org/ticket/16636 prevents
1047 // us from doing clipboard operations in wxShowEvent and wxTimerEvent
1048 // processing because those event could possibly be processed during
1049 // the (not sufficiently protected) Yield() of a first clipboard
1050 // operation, causing reentry. Audacity had a workaround in place
1051 // for this problem (the class "CaptureEvents"), which however isn't
1052 // applicable with wxWidgets 3.0 because it's based on changing the
1053 // gdk event handler, a change that would be overridden by wxWidgets's
1054 // own gdk event handler change.
1055 // Instead, as a NEW workaround, specifically protect those processings
1056 // of wxShowEvent and wxTimerEvent that try to do clipboard operations
1057 // from being executed within Yield(). This is done by delaying their
1058 // execution by posting pure wxWidgets events - which are never executed
1059 // during Yield().
1060 // Author: Martin Stegh fer <[email protected]>
1061 // Bug-Debian: https://bugs.debian.org/765341
1062
1063 // the actual creation/showing of the window).
1064 // Post the event instead of calling OnSize(..) directly. This ensures that
1065 // this is a pure wxWidgets event (no GDK event behind it) and that it
1066 // therefore isn't processed within the YieldFor(..) of the clipboard
1067 // operations (workaround for Debian bug #765341).
1068 // QueueEvent() will take ownership of the event
1069 GetEventHandler()->QueueEvent(safenew wxSizeEvent(GetSize()));
1070
1071 // Further processing by default handlers
1072 event.Skip();
1073}
1074
1078void ProjectWindow::OnToolBarUpdate(wxCommandEvent & event)
1079{
1080 auto pProject = FindProject();
1081 if (pProject)
1082 Viewport::Get(*pProject).HandleResize();
1083 event.Skip(false); /* No need to propagate any further */
1084}
1085
1087{
1089 auto pProject = FindProject();
1090 if (!pProject)
1091 return;
1092 auto &project = *pProject;
1094 if (name != GetTitle()) {
1095 SetTitle(name);
1096 SetName(name); // to make the nvda screen reader read the correct title
1097 }
1098 }
1099}
1100
1101void ProjectWindow::OnScroll(wxScrollEvent &)
1102{
1103 auto pProject = FindProject();
1104 if (!pProject)
1105 return;
1106 Viewport::Get(*pProject).OnScroll();
1107}
1108
1109void ProjectWindow::OnMenu(wxCommandEvent & event)
1110{
1111#ifdef __WXMSW__
1112 // Bug 1642: We can arrive here with bogus menu IDs, which we
1113 // proceed to process. So if bogus, don't.
1114 // The bogus menu IDs are probably generated by controls on the TrackPanel,
1115 // such as the Project Rate.
1116 // 17000 is the magic number at which we start our menu.
1117 // This code would probably NOT be OK on Mac, since we assign
1118 // some specific ID numbers.
1119 if( event.GetId() < 17000){
1120 event.Skip();
1121 return;
1122 }
1123#endif
1124 auto pProject = FindProject();
1125 if (!pProject)
1126 return;
1127 auto &project = *pProject;
1128 auto &commandManager = CommandManager::Get( project );
1129 bool handled = commandManager.HandleMenuID(
1130 event.GetId(), CommandManager::Get( project ).GetUpdateFlags(),
1131 false);
1132
1133 if (handled)
1134 event.Skip(false);
1135 else{
1136 event.ResumePropagation( 999 );
1137 event.Skip(true);
1138 }
1139}
1140
1141void ProjectWindow::OnUpdateUI(wxUpdateUIEvent & WXUNUSED(event))
1142{
1143 auto pProject = FindProject();
1144 if (!pProject)
1145 return;
1146 auto &project = *pProject;
1148}
1149
1150void ProjectWindow::OnActivate(wxActivateEvent & event)
1151{
1152 // Activate events can fire during window teardown, so just
1153 // ignore them.
1154 if (IsBeingDeleted()) {
1155 return;
1156 }
1157
1158 auto pProject = FindProject();
1159 if (!pProject)
1160 return;
1161 auto &project = *pProject;
1162
1163 mActive = event.GetActive();
1164
1165 // Under Windows, focus can be "lost" when returning to
1166 // Audacity from a different application.
1167 //
1168 // This was observed by minimizing all windows using WINDOWS+M and
1169 // then ALT+TAB to return to Audacity. Focus will be given to the
1170 // project window frame which is not at all useful.
1171 //
1172 // So, we use ToolManager's observation of focus changes in a wxEventFilter.
1173 // Then, when we receive the
1174 // activate event, we restore that focus to the child or the track
1175 // panel if no child had the focus (which probably should never happen).
1176 if (mActive) {
1177 auto &toolManager = ToolManager::Get( project );
1179 if ( ! toolManager.RestoreFocus() )
1180 GetProjectPanel( project ).SetFocus();
1181 }
1182 event.Skip();
1183}
1184
1186{
1187 return mActive;
1188}
1189
1190void ProjectWindow::OnMouseEvent(wxMouseEvent & event)
1191{
1192 auto pProject = FindProject();
1193 if (!pProject)
1194 return;
1195 auto &project = *pProject;
1196 if (event.ButtonDown())
1198}
1199
1201: mProject(project)
1202{
1203}
1204
1206{
1207 auto gAudioIO = AudioIO::Get();
1208 mRecentStreamTime = gAudioIO->GetStreamTime();
1209
1210 auto cleanup = finally([&]{
1211 // Propagate the message to other listeners bound to this
1212 this->Publish({});
1213 });
1214
1215 if(!ProjectAudioIO::Get( *mProject ).IsAudioActive())
1216 return;
1217 else if (mMode == Mode::Refresh) {
1218 // PRL: see comments in Scrubbing.cpp for why this is sometimes needed.
1219 // These unnecessary refreshes cause wheel rotation events to be delivered more uniformly
1220 // to the application, so scrub speed control is smoother.
1221 // (So I see at least with OS 10.10 and wxWidgets 3.0.2.)
1222 // Is there another way to ensure that than by refreshing?
1223 auto &trackPanel = GetProjectPanel( *mProject );
1224 trackPanel.Refresh(false);
1225 }
1226 else if (mMode != Mode::Off) {
1227 // Pan the view, so that we put the play indicator at some fixed
1228 // fraction of the window width.
1229
1230 auto &viewInfo = ViewInfo::Get( *mProject );
1231 auto &trackPanel = GetProjectPanel( *mProject );
1232 const int posX = viewInfo.TimeToPosition(mRecentStreamTime);
1233 auto width = viewInfo.GetTracksUsableWidth();
1234 int deltaX;
1235 switch (mMode)
1236 {
1237 default:
1238 wxASSERT(false);
1239 /* fallthru */
1240 case Mode::Pinned:
1241 deltaX =
1243 break;
1244 case Mode::Right:
1245 deltaX = posX - width; break;
1246 }
1247 viewInfo.hpos =
1248 viewInfo.OffsetTimeByPixels(viewInfo.hpos, deltaX, true);
1249 if (!ProjectWindow::Get( *mProject ).MayScrollBeyondZero())
1250 // Can't scroll too far left
1251 viewInfo.hpos = std::max(0.0, viewInfo.hpos);
1252 trackPanel.Refresh(false);
1253 }
1254}
1255
1257{
1258 // Activate events can fire during window teardown, so just
1259 // ignore them.
1260 if (mIsDeleting)
1261 return;
1262 auto pProject = FindProject();
1263 if (!pProject)
1264 return;
1265 auto &project = *pProject;
1266 auto &viewInfo = ViewInfo::Get(project);
1267 auto &trackPanel = GetProjectPanel(project);
1268
1269 auto [rescroll, scrollbarVisibilityChanged, resize] = message;
1270
1271 if (rescroll)
1272 trackPanel.Refresh(false);
1273
1274 // why? Is there a menu item whose availability depends on scroll position
1275 // or zoom level?
1277
1278 if (scrollbarVisibilityChanged || resize)
1279 UpdateLayout();
1280}
1281
1283[]( wxWindow &window ){
1284 auto pProjectWindow = dynamic_cast< ProjectWindow* >( &window );
1285 return pProjectWindow ? pProjectWindow->GetTopPanel() : nullptr;
1286} };
void SetActiveProject(AudacityProject *project)
Handle changing of active project and keep global project pointer.
EVT_MENU(OnSetPlayRegionToSelectionID, AdornedRulerPanel::OnSetPlayRegionToSelection) EVT_COMMAND(OnTogglePinnedStateID
END_EVENT_TABLE()
const TranslatableString name
Definition: Distortion.cpp:76
#define _(s)
Definition: Internat.h:73
EventMonitor monitor
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
Definition: LabelDialog.cpp:89
#define safenew
Definition: MemoryX.h:10
ProjectFileIOMessage
Subscribe to ProjectFileIO to receive messages; always in idle time.
Definition: ProjectFileIO.h:50
@ ProjectTitleChange
A normal occurrence.
StatusBarField
Definition: ProjectStatus.h:24
@ mainStatusBarField
Definition: ProjectStatus.h:26
@ nStatusBarFields
Definition: ProjectStatus.h:29
@ rateStatusBarField
Definition: ProjectStatus.h:27
IntSetting ProjectWindowY
bool CornersOnScreen(wxRect &r)
@ VSBarID
@ HSBarID
@ NextID
@ FirstID
IntSetting ProjectWindowX
void GetDefaultWindowRect(wxRect *defRect)
IntSetting ProjectWindowWidth
BoolSetting ProjectWindowIconized
bool IsWindowAccessible(wxRect *requestedRect)
BoolSetting ProjectWindowMaximized
IntSetting ProjectWindowNormalHeight
IntSetting ProjectWindowHeight
IntSetting ProjectWindowNormalX
void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized)
static ToolManager::TopPanelHook::Scope scope
int ScreenContaining(wxRect &r)
IntSetting ProjectWindowNormalWidth
IntSetting ProjectWindowNormalY
AUDACITY_DLL_API wxWindow & GetProjectPanel(AudacityProject &project)
Get the main sub-window of the project frame that displays track data.
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
AUDACITY_DLL_API AttachedWindows & GetAttachedWindows(AudacityProject &project)
accessors for certain important windows associated with each project
const auto project
THEME_API Theme theTheme
Definition: Theme.cpp:82
int id
const_reverse_iterator rend() const
Definition: Project.cpp:37
const_iterator end() const
Definition: Project.cpp:27
Container::value_type value_type
Definition: Project.h:57
const_iterator begin() const
Definition: Project.cpp:22
const_reverse_iterator rbegin() const
Definition: Project.cpp:32
bool empty() const
Definition: Project.h:47
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
static AudioIO * Get()
Definition: AudioIO.cpp:126
This specialization of Setting for bool adds a Toggle method to negate the saved value.
Definition: Prefs.h:344
IteratorRange< ChannelIterator< ChannelType > > Channels()
Get range of channels with mutative access.
Definition: Channel.h:408
std::shared_ptr< ChannelType > GetChannel(size_t iChannel)
Retrieve a channel, cast to the given type.
Definition: Channel.h:344
static int GetTotalHeight(const TrackList &list)
Definition: ChannelView.cpp:55
static ChannelView & Get(Channel &channel)
bool GetMinimized() const
Definition: ChannelView.h:68
void SetMinimized(bool minimized)
static int GetChannelGroupHeight(const Track *pTrack)
Definition: ChannelView.cpp:32
void SetExpandedHeight(int height)
Subclass * Find(const RegisteredFactory &key)
Get a (bare) pointer to an attachment, or null, down-cast it to Subclass *; will not create on demand...
Definition: ClientData.h:341
Subclass & Get(const RegisteredFactory &key)
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
Definition: ClientData.h:317
static CommandManager & Get(AudacityProject &project)
void UpdateMenus(bool checkActive=true)
CommandFlag GetUpdateFlags(bool quick=false) const
typename GlobalVariable< TopPanelHook, const std::function< wxWindow * >, nullptr, Options... >::Scope Scope
Specialization of Setting for int.
Definition: Prefs.h:354
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
CallbackReturn Publish(const ProjectWindowDestroyedMessage &message)
Send a message to connected callbacks.
Definition: Observer.h:207
bool IsAudioActive() const
static ProjectAudioIO & Get(AudacityProject &project)
const wxString & GetProjectTitle() const
Definition: ProjectFileIO.h:95
static ProjectFileIO & Get(AudacityProject &project)
static const StatusWidthFunctions & GetStatusWidthFunctions()
PlaybackScroller(AudacityProject *project)
A top-level window associated with a project.
std::shared_ptr< AudacityProject > FindProject()
A top-level window associated with a project, and handling scrollbars and zooming.
Definition: ProjectWindow.h:36
void OnToolBarUpdate(wxCommandEvent &event)
wxScrollBar * mHsbar
wxSplitterWindow * mContainerWindow
int GetVerticalThumbSize() const
static ProjectWindow & Get(AudacityProject &project)
int GetTrackHeight(const Track &track)
wxPanel * mTopPanel
void SetMinimized(Track &track, bool minimized)
void ShowHorizontalScrollbar(bool shown)
unsigned MinimumTrackHeight()
void UpdatePrefs() override
void OnActivate(wxActivateEvent &event)
void ApplyUpdatedTheme()
void SetHorizontalThumbPosition(int viewStart)
void OnScrollLeftButton(wxScrollEvent &event)
void OnUpdateUI(wxUpdateUIEvent &event)
bool IsTrackMinimized(const Track &track)
bool IsActive() override
wxPanel * GetTopPanel() noexcept
Top panel contains project-related controls and tools.
int GetVerticalRange() const
void SetVerticalScrollbar(int position, int thumbSize, int range, int pageSize, bool refresh)
int GetVerticalThumbPosition() const
static ProjectWindow * Find(AudacityProject *pProject)
Observer::Subscription mThemeChangeSubscription
wxWindow * GetTrackListWindow() noexcept
Track list window is the parent container for TrackPanel.
void OnMove(wxMoveEvent &event)
wxSplitterWindow * GetContainerWindow() noexcept
Container is a parent window for both effects panel and track list windows.
void SetNormalizedWindowState(wxRect pSizeAndLocation)
void OnViewportMessage(const ViewportMessage &message)
bool MayScrollBeyondZero() const
void OnMouseEvent(wxMouseEvent &event)
void SetVerticalThumbPosition(int viewStart)
~ProjectWindow() override
void SetChannelHeights(Track &track, unsigned height)
bool IsBeingDeleted() const
Definition: ProjectWindow.h:56
void OnScrollRightButton(wxScrollEvent &event)
Observer::Subscription mTitleChangeSubscription
int GetTotalHeight(const TrackList &trackList)
void OnScroll(wxScrollEvent &event)
std::unique_ptr< PlaybackScroller > mPlaybackScroller
void OnSize(wxSizeEvent &event)
void UpdateStatusWidths()
void OnProjectTitleChange(ProjectFileIOMessage)
void ShowVerticalScrollbar(bool shown)
void SetHorizontalScrollbar(int position, int thumbSize, int range, int pageSize, bool refresh)
void OnThemeChange(struct ThemeChangeMessage)
int GetHorizontalThumbSize() const
wxScrollBar * mVsbar
void OnMenu(wxCommandEvent &event)
int GetHorizontalRange() const
bool IsIconized() const override
int GetHorizontalThumbPosition() const
void SetToDefaultSize()
void OnShow(wxShowEvent &event)
std::pair< int, int > ViewportSize() const
wxWindow * mTrackListWindow
ProjectWindow(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, AudacityProject &project)
void OnIconize(wxIconizeEvent &event)
void MacShowUndockedToolbars(bool show)
static Scrubber & Get(AudacityProject &project)
Definition: Scrubbing.cpp:188
bool ReadWithDefault(T *pVar, const T &defaultValue) const
overload of ReadWithDefault returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:211
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:205
wxColour & Colour(int iIndex)
class ToolFrame
Definition: ToolManager.h:189
static ToolManager & Get(AudacityProject &project)
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:122
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:975
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:233
static double GetPinnedHeadPositionPreference()
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
A callback facade hiding GUI toolkit details.
Definition: Viewport.h:22
void OnScrollLeftButton()
Definition: Viewport.cpp:143
void SetCallbacks(std::unique_ptr< ViewportCallbacks > pCallbacks)
Definition: Viewport.cpp:63
void OnScrollRightButton()
Definition: Viewport.cpp:160
void OnScroll()
Definition: Viewport.cpp:411
void HandleResize()
Definition: Viewport.cpp:401
static Viewport & Get(AudacityProject &project)
Definition: Viewport.cpp:32
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
ScrollBar(wxWindow *parent, wxWindowID id, long style)
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:196
std::unique_ptr< WindowPlacement > FindFocus()
Find the window that is accepting keyboard input, if any.
Definition: BasicUI.h:373
AUDACITY_DLL_API unsigned MinimumTrackHeight()
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
void OnCloseWindow(wxCloseEvent &e)
AttachedWindows::RegisteredFactory sProjectWindowKey
std::optional< PreferredSystemAppearance > appearance
Definition: Theme.h:112
bool IsTrackMinimized(const Track &track) override
void SetVerticalScrollbar(int position, int thumbSize, int range, int pageSize, bool refresh) override
void SetHorizontalScrollbar(int position, int thumbSize, int range, int pageSize, bool refresh) override
int GetTrackHeight(const Track &track) override
int GetTotalHeight(const TrackList &trackList) override
void SetVerticalThumbPosition(int viewStart) override
void SetMinimized(Track &track, bool minimized) override
void SetChannelHeights(Track &track, unsigned height) override
void SetHorizontalThumbPosition(int viewStart) override
std::pair< int, int > ViewportSize() const override
Width and height in pixels of proper viewport area (excluding scrollbars)