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