Audacity  3.0.3
Classes | Functions
ProjectWindow.h File Reference
#include <memory>
#include "ProjectWindowBase.h"
#include "TrackPanelListener.h"
#include "Prefs.h"
Include dependency graph for ProjectWindow.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

class  ProjectWindow
 A top-level window associated with a project, and handling scrollbars and zooming. More...
 
class  ProjectWindow::PlaybackScroller
 

Functions

void InitProjectWindow (ProjectWindow &window)
 
void GetDefaultWindowRect (wxRect *defRect)
 
void GetNextWindowPlacement (wxRect *nextRect, bool *pMaximized, bool *pIconized)
 

Function Documentation

◆ GetDefaultWindowRect()

void GetDefaultWindowRect ( wxRect *  defRect)

Definition at line 92 of file ProjectWindow.cpp.

93 {
94  *defRect = wxGetClientDisplayRect();
95 
96  int width = 940;
97  int height = 674;
98 
99  //These conditional values assist in improving placement and size
100  //of NEW windows on different platforms.
101 #ifdef __WXGTK__
102  height += 20;
103 #endif
104 
105 #ifdef __WXMSW__
106  height += 40;
107 #endif
108 
109 #ifdef __WXMAC__
110  height += 55;
111 #endif
112 
113  // Use screen size where it is smaller than the values we would like.
114  // Otherwise use the values we would like, and centred.
115  if (width < defRect->width)
116  {
117  defRect->x = (defRect->width - width)/2;
118  defRect->width = width;
119  }
120 
121  if (height < defRect->height)
122  {
123  defRect->y = (defRect->height - height)/2;
124  // Bug 1119 workaround
125  // Small adjustment for very small Mac screens.
126  // If there is only a tiny space at the top
127  // then instead of vertical centre, align to bottom.
128  const int pixelsFormenu = 60;
129  if( defRect->y < pixelsFormenu )
130  defRect->y *=2;
131  defRect->height = height;
132  }
133 }

Referenced by GetNextWindowPlacement(), and ProjectManager::SaveWindowSize().

Here is the caller graph for this function:

◆ GetNextWindowPlacement()

void GetNextWindowPlacement ( wxRect *  nextRect,
bool *  pMaximized,
bool *  pIconized 
)

Definition at line 139 of file ProjectWindow.cpp.

140 {
141  int inc = 25;
142 
143  wxRect defaultRect;
144  GetDefaultWindowRect(&defaultRect);
145 
146  gPrefs->Read(wxT("/Window/Maximized"), pMaximized, false);
147  gPrefs->Read(wxT("/Window/Iconized"), pIconized, false);
148 
149  wxRect windowRect;
150  gPrefs->Read(wxT("/Window/X"), &windowRect.x, defaultRect.x);
151  gPrefs->Read(wxT("/Window/Y"), &windowRect.y, defaultRect.y);
152  gPrefs->Read(wxT("/Window/Width"), &windowRect.width, defaultRect.width);
153  gPrefs->Read(wxT("/Window/Height"), &windowRect.height, defaultRect.height);
154 
155  wxRect normalRect;
156  gPrefs->Read(wxT("/Window/Normal_X"), &normalRect.x, defaultRect.x);
157  gPrefs->Read(wxT("/Window/Normal_Y"), &normalRect.y, defaultRect.y);
158  gPrefs->Read(wxT("/Window/Normal_Width"), &normalRect.width, defaultRect.width);
159  gPrefs->Read(wxT("/Window/Normal_Height"), &normalRect.height, defaultRect.height);
160 
161  // Workaround 2.1.1 and earlier bug on OSX...affects only normalRect, but let's just
162  // validate for all rects and plats
163  if (normalRect.width == 0 || normalRect.height == 0) {
164  normalRect = defaultRect;
165  }
166  if (windowRect.width == 0 || windowRect.height == 0) {
167  windowRect = defaultRect;
168  }
169 
170 
171  wxRect screenRect( wxGetClientDisplayRect());
172 #if defined(__WXMAC__)
173 
174  // On OSX, the top of the window should never be less than the menu height,
175  // so something is amiss if it is
176  if (normalRect.y < screenRect.y) {
177  normalRect = defaultRect;
178  }
179  if (windowRect.y < screenRect.y) {
180  windowRect = defaultRect;
181  }
182 #endif
183 
184  // IF projects empty, THEN it's the first window.
185  // It lands where the config says it should, and can straddle screen.
186  if (AllProjects{}.empty()) {
187  if (*pMaximized || *pIconized) {
188  *nextRect = normalRect;
189  }
190  else {
191  *nextRect = windowRect;
192  }
193  // Resize, for example if one monitor that was on is now off.
194  if (!CornersOnScreen( wxRect(*nextRect).Deflate( 32, 32 ))) {
195  *nextRect = defaultRect;
196  }
197  if (!IsWindowAccessible(nextRect)) {
198  *nextRect = defaultRect;
199  }
200  // Do not trim the first project window down.
201  // All corners are on screen (or almost so), and
202  // the rect may straddle screens.
203  return;
204  }
205 
206 
207  // ELSE a subsequent NEW window. It will NOT straddle screens.
208 
209  // We don't mind being 32 pixels off the screen in any direction.
210  // Make sure initial sizes (pretty much) fit within the display bounds
211  // We used to trim the sizes which could result in ridiculously small windows.
212  // contributing to bug 1243.
213  // Now instead if the window significantly doesn't fit the screen, we use the default
214  // window instead, which we know does.
215  if (ScreenContaining( wxRect(normalRect).Deflate( 32, 32 ))<0) {
216  normalRect = defaultRect;
217  }
218  if (ScreenContaining( wxRect(windowRect).Deflate( 32, 32 ) )<0) {
219  windowRect = defaultRect;
220  }
221 
222  bool validWindowSize = false;
223  ProjectWindow * validProject = NULL;
224  for ( auto iter = AllProjects{}.rbegin(), end = AllProjects{}.rend();
225  iter != end; ++iter
226  ) {
227  auto pProject = *iter;
228  if (!GetProjectFrame( *pProject ).IsIconized()) {
229  validWindowSize = true;
230  validProject = &ProjectWindow::Get( *pProject );
231  break;
232  }
233  }
234  if (validWindowSize) {
235  *nextRect = validProject->GetRect();
236  *pMaximized = validProject->IsMaximized();
237  *pIconized = validProject->IsIconized();
238  // Do not straddle screens.
239  if (ScreenContaining( wxRect(*nextRect).Deflate( 32, 32 ) )<0) {
240  *nextRect = defaultRect;
241  }
242  }
243  else {
244  *nextRect = normalRect;
245  }
246 
247  //Placement depends on the increments
248  nextRect->x += inc;
249  nextRect->y += inc;
250 
251  // defaultrect is a rectangle on the first screen. It's the right fallback to
252  // use most of the time if things are not working out right with sizing.
253  // windowRect is a saved rectangle size.
254  // normalRect seems to be a substitute for windowRect when iconized or maximised.
255 
256  // Windows can say that we are off screen when actually we are not.
257  // On Windows 10 I am seeing miscalculation by about 6 pixels.
258  // To fix this we allow some sloppiness on the edge being counted as off screen.
259  // This matters most when restoring very carefully sized windows that are maximised
260  // in one dimension (height or width) but not both.
261  const int edgeSlop = 10;
262 
263  // Next four lines are getting the rectangle for the screen that contains the
264  // top left corner of nextRect (and defaulting to rect of screen 0 otherwise).
265  wxPoint p = nextRect->GetLeftTop();
266  int scr = std::max( 0, wxDisplay::GetFromPoint( p ));
267  wxDisplay d( scr );
268  screenRect = d.GetClientArea();
269 
270  // Now we (possibly) start trimming our rectangle down.
271  // Have we hit the right side of the screen?
272  wxPoint bottomRight = nextRect->GetBottomRight();
273  if (bottomRight.x > (screenRect.GetRight()+edgeSlop)) {
274  int newWidth = screenRect.GetWidth() - nextRect->GetLeft();
275  if (newWidth < defaultRect.GetWidth()) {
276  nextRect->x = windowRect.x;
277  nextRect->y = windowRect.y;
278  nextRect->width = windowRect.width;
279  }
280  else {
281  nextRect->width = newWidth;
282  }
283  }
284 
285  // Have we hit the bottom of the screen?
286  bottomRight = nextRect->GetBottomRight();
287  if (bottomRight.y > (screenRect.GetBottom()+edgeSlop)) {
288  nextRect->y -= inc;
289  bottomRight = nextRect->GetBottomRight();
290  if (bottomRight.y > (screenRect.GetBottom()+edgeSlop)) {
291  nextRect->SetBottom(screenRect.GetBottom());
292  }
293  }
294 
295  // After all that we could have a window that does not have a visible
296  // top bar. [It is unlikely, but something might have gone wrong]
297  // If so, use the safe fallback size.
298  if (!IsWindowAccessible(nextRect)) {
299  *nextRect = defaultRect;
300  }
301 }

References CornersOnScreen(), AllProjects::empty(), ProjectWindow::Get(), GetDefaultWindowRect(), GetProjectFrame(), gPrefs, ProjectWindow::IsIconized(), IsWindowAccessible(), AllProjects::rbegin(), AllProjects::rend(), and ScreenContaining().

Referenced by AudacityApp::InitPart2(), and ProjectManager::New().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ InitProjectWindow()

void InitProjectWindow ( ProjectWindow window)

Definition at line 360 of file ProjectManager.cpp.

361 {
362  auto &project = window.GetProject();
363 
364 #ifdef EXPERIMENTAL_DA2
365  SetBackgroundColour(theTheme.Colour( clrMedium ));
366 #endif
367  // Note that the first field of the status bar is a dummy, and its width is set
368  // to zero latter in the code. This field is needed for wxWidgets 2.8.12 because
369  // if you move to the menu bar, the first field of the menu bar is cleared, which
370  // is undesirable behaviour.
371  // In addition, the help strings of menu items are by default sent to the first
372  // field. Currently there are no such help strings, but it they were introduced, then
373  // there would need to be an event handler to send them to the appropriate field.
374  auto statusBar = window.CreateStatusBar(4);
375 #if wxUSE_ACCESSIBILITY
376  // so that name can be set on a standard control
377  statusBar->SetAccessible(safenew WindowAccessible(statusBar));
378 #endif
379  statusBar->SetName(wxT("status_line")); // not localized
380 
381  auto &viewInfo = ViewInfo::Get( project );
382 
383  // LLL: Read this!!!
384  //
385  // Until the time (and cpu) required to refresh the track panel is
386  // reduced, leave the following window creations in the order specified.
387  // This will place the refresh of the track panel last, allowing all
388  // the others to get done quickly.
389  //
390  // Near as I can tell, this is only a problem under Windows.
391  //
392 
393 
394  //
395  // Create the ToolDock
396  //
397  ToolManager::Get( project ).CreateWindows();
398  ToolManager::Get( project ).LayoutToolBars();
399 
400  //
401  // Create the horizontal ruler
402  //
403  auto &ruler = AdornedRulerPanel::Get( project );
404 
405  //
406  // Create the TrackPanel and the scrollbars
407  //
408 
409  auto topPanel = window.GetTopPanel();
410 
411  {
412  auto ubs = std::make_unique<wxBoxSizer>(wxVERTICAL);
413  ubs->Add( ToolManager::Get( project ).GetTopDock(), 0, wxEXPAND | wxALIGN_TOP );
414  ubs->Add(&ruler, 0, wxEXPAND);
415  topPanel->SetSizer(ubs.release());
416  }
417 
418  // Ensure that the topdock comes before the ruler in the tab order,
419  // irrespective of the order in which they were created.
420  ToolManager::Get(project).GetTopDock()->MoveBeforeInTabOrder(&ruler);
421 
422  const auto pPage = window.GetMainPage();
423 
424  wxBoxSizer *bs;
425  {
426  auto ubs = std::make_unique<wxBoxSizer>(wxVERTICAL);
427  bs = ubs.get();
428  bs->Add(topPanel, 0, wxEXPAND | wxALIGN_TOP);
429  bs->Add(pPage, 1, wxEXPAND);
430  bs->Add( ToolManager::Get( project ).GetBotDock(), 0, wxEXPAND );
431  window.SetAutoLayout(true);
432  window.SetSizer(ubs.release());
433  }
434  bs->Layout();
435 
436  auto &trackPanel = TrackPanel::Get( project );
437 
438  // LLL: When Audacity starts or becomes active after returning from
439  // another application, the first window that can accept focus
440  // will be given the focus even if we try to SetFocus(). By
441  // making the TrackPanel that first window, we resolve several
442  // keyboard focus problems.
443  pPage->MoveBeforeInTabOrder(topPanel);
444 
445  bs = (wxBoxSizer *)pPage->GetSizer();
446 
447  auto vsBar = &window.GetVerticalScrollBar();
448  auto hsBar = &window.GetHorizontalScrollBar();
449 
450  {
451  // Top horizontal grouping
452  auto hs = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
453 
454  // Track panel
455  hs->Add(&trackPanel, 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP);
456 
457  {
458  // Vertical grouping
459  auto vs = std::make_unique<wxBoxSizer>(wxVERTICAL);
460 
461  // Vertical scroll bar
462  vs->Add(vsBar, 1, wxEXPAND | wxALIGN_TOP);
463  hs->Add(vs.release(), 0, wxEXPAND | wxALIGN_TOP);
464  }
465 
466  bs->Add(hs.release(), 1, wxEXPAND | wxALIGN_LEFT | wxALIGN_TOP);
467  }
468 
469  {
470  // Bottom horizontal grouping
471  auto hs = std::make_unique<wxBoxSizer>(wxHORIZONTAL);
472 
473  // Bottom scrollbar
474  hs->Add(viewInfo.GetLeftOffset() - 1, 0);
475  hs->Add(hsBar, 1, wxALIGN_BOTTOM);
476  hs->Add(vsBar->GetSize().GetWidth(), 0);
477  bs->Add(hs.release(), 0, wxEXPAND | wxALIGN_LEFT);
478  }
479 
480  // Lay it out
481  pPage->SetAutoLayout(true);
482  pPage->Layout();
483 
484 #ifdef EXPERIMENTAL_NOTEBOOK
485  AddPages(this, Factory, pNotebook);
486 #endif
487 
488  auto mainPanel = window.GetMainPanel();
489 
490  mainPanel->Layout();
491 
492  wxASSERT( trackPanel.GetProject() == &project );
493 
494  // MM: Give track panel the focus to ensure keyboard commands work
495  trackPanel.SetFocus();
496 
497  window.FixScrollbars();
498  ruler.SetLeftOffset(viewInfo.GetLeftOffset()); // bevel on AdornedRuler
499 
500  //
501  // Set the Icon
502  //
503 
504  // loads either the XPM or the windows resource, depending on the platform
505 #if !defined(__WXMAC__) && !defined(__WXX11__)
506  {
507 #if defined(__WXMSW__)
508  wxIcon ic{ wxICON(AudacityLogo) };
509 #elif defined(__WXGTK__)
510  wxIcon ic{wxICON(AudacityLogoAlpha)};
511 #else
512  wxIcon ic{};
513  ic.CopyFromBitmap(theTheme.Bitmap(bmpAudacityLogo48x48));
514 #endif
515  window.SetIcon(ic);
516  }
517 #endif
518 
519  window.UpdateStatusWidths();
520  auto msg = XO("Welcome to Audacity version %s")
521  .Format( AUDACITY_VERSION_STRING );
523 
524 #ifdef EXPERIMENTAL_DA2
525  ClearBackground();// For wxGTK.
526 #endif
527 }

References ThemeBase::Bitmap(), ThemeBase::Colour(), ToolManager::CreateWindows(), ProjectWindow::FixScrollbars(), ViewInfo::Get(), AdornedRulerPanel::Get(), ProjectManager::Get(), ToolManager::Get(), TrackPanel::Get(), ProjectWindow::GetHorizontalScrollBar(), ProjectWindow::GetMainPage(), ProjectWindow::GetMainPanel(), ProjectWindowBase::GetProject(), ToolManager::GetTopDock(), ProjectWindow::GetTopPanel(), ProjectWindow::GetVerticalScrollBar(), ToolManager::LayoutToolBars(), mainStatusBarField, anonymous_namespace{TimeTrackVRulerControls.cpp}::ruler(), safenew, ProjectManager::SetStatusText(), theTheme, ProjectWindow::UpdateStatusWidths(), and XO.

Referenced by ProjectManager::New().

Here is the call graph for this function:
Here is the caller graph for this function:
ViewInfo::Get
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:241
ProjectManager::SetStatusText
void SetStatusText(const TranslatableString &text, int number)
Definition: ProjectManager.cpp:1055
ProjectWindow::FixScrollbars
void FixScrollbars()
Definition: ProjectWindow.cpp:1009
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
ProjectWindow::GetTopPanel
wxPanel * GetTopPanel()
Definition: ProjectWindow.h:56
ProjectWindow::GetMainPanel
wxPanel * GetMainPanel()
Definition: ProjectWindow.h:55
ToolManager::Get
static ToolManager & Get(AudacityProject &project)
Definition: ToolManager.cpp:356
ToolManager::CreateWindows
void CreateWindows()
Definition: ToolManager.cpp:437
TrackPanel::Get
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:227
XO
#define XO(s)
Definition: Internat.h:31
ProjectWindow::Get
static ProjectWindow & Get(AudacityProject &project)
Definition: ProjectWindow.cpp:535
anonymous_namespace{TimeTrackVRulerControls.cpp}::ruler
Ruler & ruler()
Definition: TimeTrackVRulerControls.cpp:34
CornersOnScreen
bool CornersOnScreen(wxRect &r)
Definition: ProjectWindow.cpp:59
ThemeBase::Bitmap
wxBitmap & Bitmap(int iIndex)
Definition: Theme.cpp:1209
AllProjects::empty
bool empty() const
Definition: Project.h:46
ProjectWindowBase::GetProject
AudacityProject & GetProject()
Definition: ProjectWindowBase.h:29
AdornedRulerPanel::Get
static AdornedRulerPanel & Get(AudacityProject &project)
Definition: AdornedRulerPanel.cpp:899
ProjectManager::Get
static ProjectManager & Get(AudacityProject &project)
Definition: ProjectManager.cpp:70
AllProjects::rbegin
const_reverse_iterator rbegin() const
Definition: Project.cpp:34
mainStatusBarField
@ mainStatusBarField
Definition: ProjectStatus.h:26
ProjectWindow
A top-level window associated with a project, and handling scrollbars and zooming.
Definition: ProjectWindow.h:32
ToolManager::GetTopDock
ToolDock * GetTopDock()
Definition: ToolManager.cpp:1037
ProjectWindow::GetMainPage
wxWindow * GetMainPage()
Definition: ProjectWindow.h:54
WindowAccessible
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
ToolManager::LayoutToolBars
void LayoutToolBars()
Definition: ToolManager.cpp:1131
GetDefaultWindowRect
void GetDefaultWindowRect(wxRect *defRect)
Definition: ProjectWindow.cpp:92
theTheme
THEME_API Theme theTheme
Definition: Theme.cpp:79
ScreenContaining
int ScreenContaining(wxRect &r)
Definition: ProjectWindow.cpp:44
ProjectWindow::UpdateStatusWidths
void UpdateStatusWidths()
Definition: ProjectWindow.cpp:1231
ProjectWindow::IsIconized
bool IsIconized() const override
Definition: ProjectWindow.cpp:1226
IsWindowAccessible
bool IsWindowAccessible(wxRect *requestedRect)
Definition: ProjectWindow.cpp:66
GetProjectFrame
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 ...
Definition: ProjectWindows.cpp:72
AllProjects
Definition: Project.h:35
ThemeBase::Colour
wxColour & Colour(int iIndex)
Definition: Theme.cpp:1189
safenew
#define safenew
Definition: MemoryX.h:10
ProjectWindow::GetVerticalScrollBar
wxScrollBar & GetVerticalScrollBar()
Definition: ProjectWindow.h:109
AllProjects::rend
const_reverse_iterator rend() const
Definition: Project.cpp:39
ProjectWindow::GetHorizontalScrollBar
wxScrollBar & GetHorizontalScrollBar()
Definition: ProjectWindow.h:110