Audacity  3.0.3
ProjectWindow.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 ProjectWindow.cpp
6 
7 Paul Licameli split from AudacityProject.cpp
8 
9 **********************************************************************/
10 
11 #include "ProjectWindow.h"
12 
13 
14 
15 #include "ActiveProject.h"
16 #include "AllThemeResources.h"
17 #include "AudioIO.h"
18 #include "Menus.h"
19 #include "Project.h"
20 #include "ProjectAudioIO.h"
21 #include "ProjectWindows.h"
22 #include "ProjectStatus.h"
23 #include "RefreshCode.h"
24 #include "TrackPanelMouseEvent.h"
25 #include "TrackPanelAx.h"
26 #include "UndoManager.h"
27 #include "ViewInfo.h"
28 #include "WaveClip.h"
29 #include "WaveTrack.h"
30 #include "prefs/ThemePrefs.h"
31 #include "prefs/TracksPrefs.h"
32 #include "toolbars/ToolManager.h"
33 #include "tracks/ui/Scrubbing.h"
34 #include "tracks/ui/TrackView.h"
35 #include "widgets/wxPanelWrapper.h"
37 
38 #include <wx/app.h>
39 #include <wx/display.h>
40 #include <wx/scrolbar.h>
41 #include <wx/sizer.h>
42 
43 // Returns the screen containing a rectangle, or -1 if none does.
44 int ScreenContaining( wxRect & r ){
45  unsigned int n = wxDisplay::GetCount();
46  for(unsigned int i = 0;i<n;i++){
47  wxDisplay d(i);
48  wxRect scr = d.GetClientArea();
49  if( scr.Contains( r ) )
50  return (int)i;
51  }
52  return -1;
53 }
54 
55 // true IFF TL and BR corners are on a connected display.
56 // Does not need to check all four. We just need to check that
57 // the window probably is straddling screens in a sensible way.
58 // If the user wants to use mixed landscape and portrait, they can.
59 bool CornersOnScreen( wxRect & r ){
60  if( wxDisplay::GetFromPoint( r.GetTopLeft() ) == wxNOT_FOUND) return false;
61  if( wxDisplay::GetFromPoint( r.GetBottomRight() ) == wxNOT_FOUND) return false;
62  return true;
63 }
64 
65 // true iff we have enough of the top bar to be able to reposition the window.
66 bool IsWindowAccessible(wxRect *requestedRect)
67 {
68  wxDisplay display;
69  wxRect targetTitleRect(requestedRect->GetLeftTop(), requestedRect->GetBottomRight());
70  // Hackery to approximate a window top bar size from a window size.
71  // and exclude the open/close and borders.
72  targetTitleRect.x += 15;
73  targetTitleRect.width -= 100;
74  if (targetTitleRect.width < 165) targetTitleRect.width = 165;
75  targetTitleRect.height = 15;
76  int targetBottom = targetTitleRect.GetBottom();
77  int targetRight = targetTitleRect.GetRight();
78  // This looks like overkill to check each and every pixel in the ranges.
79  // and decide that if any is visible on screen we are OK.
80  for (int i = targetTitleRect.GetLeft(); i < targetRight; i++) {
81  for (int j = targetTitleRect.GetTop(); j < targetBottom; j++) {
82  int monitor = display.GetFromPoint(wxPoint(i, j));
83  if (monitor != wxNOT_FOUND) {
84  return TRUE;
85  }
86  }
87  }
88  return FALSE;
89 }
90 
91 // BG: The default size and position of the first window
92 void GetDefaultWindowRect(wxRect *defRect)
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 }
134 
135 // BG: Calculate where to place the next window (could be the first window)
136 // BG: Does not store X and Y in prefs. This is intentional.
137 //
138 // LL: This should NOT need to be this complicated...FIXME
139 void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized)
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 }
302 
303 namespace {
304 
305 // This wrapper prevents the scrollbars from retaining focus after being
306 // used. Otherwise, the only way back to the track panel is to click it
307 // and that causes your original location to be lost.
308 class ScrollBar final : public wxScrollBar
309 {
310 public:
311  ScrollBar(wxWindow* parent, wxWindowID id, long style)
312  : wxScrollBar(parent, id, wxDefaultPosition, wxDefaultSize, style)
313  {
314  }
315 
316  void OnSetFocus(wxFocusEvent & e)
317  {
318  wxWindow *w = e.GetWindow();
319  if (w != NULL) {
320  w->SetFocus();
321  }
322  }
323 
324  void SetScrollbar(int position, int thumbSize,
325  int range, int pageSize,
326  bool refresh = true) override;
327 
328 private:
329  DECLARE_EVENT_TABLE()
330 };
331 
332 void ScrollBar::SetScrollbar(int position, int thumbSize,
333  int range, int pageSize,
334  bool refresh)
335 {
336  // Mitigate flashing of scrollbars by refreshing only when something really changes.
337 
338  // PRL: This may have been made unnecessary by other fixes for flashing, see
339  // commit ac05b190bee7dd0000bce56edb0e5e26185c972f
340 
341  auto changed =
342  position != GetThumbPosition() ||
343  thumbSize != GetThumbSize() ||
344  range != GetRange() ||
345  pageSize != GetPageSize();
346  if (!changed)
347  return;
348 
349  wxScrollBar::SetScrollbar(position, thumbSize, range, pageSize, refresh);
350 }
351 
352 BEGIN_EVENT_TABLE(ScrollBar, wxScrollBar)
353  EVT_SET_FOCUS(ScrollBar::OnSetFocus)
355 
356 // Common mouse wheel handling in track panel cells, moved here to avoid
357 // compilation dependencies on Track, TrackPanel, and Scrubbing at low levels
358 // which made cycles
359 static struct MouseWheelHandler {
360 
362 {
364 }
365 
366 // Need a bit of memory from one call to the next
367 mutable double mVertScrollRemainder = 0.0;
368 
369 unsigned operator()
370  ( const TrackPanelMouseEvent &evt, AudacityProject *pProject ) const
371 {
372  using namespace RefreshCode;
373 
374  if ( TrackList::Get( *pProject ).empty() )
375  // Scrolling and Zoom in and out commands are disabled when there are no tracks.
376  // This should be disabled too for consistency. Otherwise
377  // you do see changes in the time ruler.
378  return Cancelled;
379 
380  unsigned result = RefreshAll;
381  const wxMouseEvent &event = evt.event;
382  auto &viewInfo = ViewInfo::Get( *pProject );
383  Scrubber &scrubber = Scrubber::Get( *pProject );
384  auto &window = ProjectWindow::Get( *pProject );
385  const auto steps = evt.steps;
386 
387  if (event.ShiftDown()
388  // Don't pan during smooth scrolling. That would conflict with keeping
389  // the play indicator centered.
390  && !scrubber.IsScrollScrubbing()
391  )
392  {
393  // MM: Scroll left/right when used with Shift key down
394  window.TP_ScrollWindow(
395  viewInfo.OffsetTimeByPixels(
396  viewInfo.PositionToTime(0), 50.0 * -steps));
397  }
398  else if (event.CmdDown())
399  {
400 #if 0
401  // JKC: Alternative scroll wheel zooming code
402  // using AudacityProject zooming, which is smarter,
403  // it keeps selections on screen and centred if it can,
404  // also this ensures mousewheel and zoom buttons give same result.
405  double ZoomFactor = pow(2.0, steps);
406  AudacityProject *p = GetProject();
407  if( steps > 0 )
408  // PRL: Track panel refresh may be needed if you reenable this
409  // code, but we don't want this file dependent on TrackPanel.cpp
410  p->ZoomInByFactor( ZoomFactor );
411  else
412  p->ZoomOutByFactor( ZoomFactor );
413 #endif
414  // MM: Zoom in/out when used with Control key down
415  // We're converting pixel positions to times,
416  // counting pixels from the left edge of the track.
417  int trackLeftEdge = viewInfo.GetLeftOffset();
418 
419  // Time corresponding to mouse position
420  wxCoord xx;
421  double center_h;
422  double mouse_h = viewInfo.PositionToTime(event.m_x, trackLeftEdge);
423 
424  // Scrubbing? Expand or contract about the center, ignoring mouse position
425  if (scrubber.IsScrollScrubbing())
426  center_h = viewInfo.h +
427  (viewInfo.GetScreenEndTime() - viewInfo.h) / 2.0;
428  // Zooming out? Focus on mouse.
429  else if( steps <= 0 )
430  center_h = mouse_h;
431  // No Selection? Focus on mouse.
432  else if((viewInfo.selectedRegion.t1() - viewInfo.selectedRegion.t0() ) < 0.00001 )
433  center_h = mouse_h;
434  // Before Selection? Focus on left
435  else if( mouse_h < viewInfo.selectedRegion.t0() )
436  center_h = viewInfo.selectedRegion.t0();
437  // After Selection? Focus on right
438  else if( mouse_h > viewInfo.selectedRegion.t1() )
439  center_h = viewInfo.selectedRegion.t1();
440  // Inside Selection? Focus on mouse
441  else
442  center_h = mouse_h;
443 
444  xx = viewInfo.TimeToPosition(center_h, trackLeftEdge);
445 
446  // Time corresponding to last (most far right) audio.
447  double audioEndTime = TrackList::Get( *pProject ).GetEndTime();
448 
449 // Disabled this code to fix Bug 1923 (tricky to wheel-zoom right of waveform).
450 #if 0
451  // When zooming in empty space, it's easy to 'lose' the waveform.
452  // This prevents it.
453  // IF zooming in
454  if (steps > 0)
455  {
456  // IF mouse is to right of audio
457  if (center_h > audioEndTime)
458  // Zooming brings far right of audio to mouse.
459  center_h = audioEndTime;
460  }
461 #endif
462 
463  wxCoord xTrackEnd = viewInfo.TimeToPosition( audioEndTime );
464  viewInfo.ZoomBy(pow(2.0, steps));
465 
466  double new_center_h = viewInfo.PositionToTime(xx, trackLeftEdge);
467  viewInfo.h += (center_h - new_center_h);
468 
469  // If wave has gone off screen, bring it back.
470  // This means that the end of the track stays where it was.
471  if( viewInfo.h > audioEndTime )
472  viewInfo.h += audioEndTime - viewInfo.PositionToTime( xTrackEnd );
473 
474 
475  result |= FixScrollbars;
476  }
477  else
478  {
479 #ifdef EXPERIMENTAL_SCRUBBING_SCROLL_WHEEL
480  if (scrubber.IsScrubbing()) {
481  scrubber.HandleScrollWheel(steps);
482  evt.event.Skip(false);
483  }
484  else
485 #endif
486  {
487  // MM: Scroll up/down when used without modifier keys
488  double lines = steps * 4 + mVertScrollRemainder;
489  mVertScrollRemainder = lines - floor(lines);
490  lines = floor(lines);
491  auto didSomething = window.TP_ScrollUpDown((int)-lines);
492  if (!didSomething)
493  result |= Cancelled;
494  }
495  }
496 
497  return result;
498 }
499 
501 
502 AttachedWindows::RegisteredFactory sProjectWindowKey{
503  []( AudacityProject &parent ) -> wxWeakRef< wxWindow > {
504  wxRect wndRect;
505  bool bMaximized = false;
506  bool bIconized = false;
507  GetNextWindowPlacement(&wndRect, &bMaximized, &bIconized);
508 
509  auto pWindow = safenew ProjectWindow(
510  nullptr, -1,
511  wxDefaultPosition,
512  wxSize(wndRect.width, wndRect.height),
513  parent
514  );
515 
516  auto &window = *pWindow;
517  // wxGTK3 seems to need to require creating the window using default position
518  // and then manually positioning it.
519  window.SetPosition(wndRect.GetPosition());
520 
521  if(bMaximized) {
522  window.Maximize(true);
523  }
524  else if (bIconized) {
525  // if the user close down and iconized state we could start back up and iconized state
526  // window.Iconize(TRUE);
527  }
528 
529  return pWindow;
530  }
531 };
532 
533 }
534 
536 {
538 }
539 
541 {
542  return Get( const_cast< AudacityProject & >( project ) );
543 }
544 
546 {
547  return pProject
549  : nullptr;
550 }
551 
553 {
554  return Find( const_cast< AudacityProject * >( pProject ) );
555 }
556 
558 {
559  return mNextWindowID++;
560 }
561 
562 enum {
563  FirstID = 1000,
564 
565  // Window controls
566 
569 
571 };
572 
573 //If you want any of these files, ask JKC. They are not
574 //yet checked in to Audacity SVN as of 12-Feb-2010
575 #ifdef EXPERIMENTAL_NOTEBOOK
576  #include "GuiFactory.h"
577  #include "APanel.h"
578 #endif
579 
580 ProjectWindow::ProjectWindow(wxWindow * parent, wxWindowID id,
581  const wxPoint & pos,
582  const wxSize & size, AudacityProject &project)
583  : ProjectWindowBase{ parent, id, pos, size, project }
584 {
585  mNextWindowID = NextID;
586 
587  // Two sub-windows need to be made before Init(),
588  // so that this constructor can complete, and then TrackPanel and
589  // AdornedRulerPanel can retrieve those windows from this in their
590  // factory functions
591 
592  // PRL: this panel groups the top tool dock and the ruler into one
593  // tab cycle.
594  // Must create it with non-default width equal to the main window width,
595  // or else the device toolbar doesn't make initial widths of the choice
596  // controls correct.
597  mTopPanel = safenew wxPanelWrapper {
598  this, wxID_ANY, wxDefaultPosition,
599  wxSize{ this->GetSize().GetWidth(), -1 }
600  };
601  mTopPanel->SetLabel( "Top Panel" );// Not localised
602  mTopPanel->SetLayoutDirection(wxLayout_LeftToRight);
603  mTopPanel->SetAutoLayout(true);
604 #ifdef EXPERIMENTAL_DA2
605  mTopPanel->SetBackgroundColour(theTheme.Colour( clrMedium ));
606 #endif
607 
608  wxWindow * pPage;
609 
610 #ifdef EXPERIMENTAL_NOTEBOOK
611  // We are using a notebook (tabbed panel), so we create the notebook and add pages.
612  GuiFactory Factory;
613  wxNotebook * pNotebook;
614  mMainPanel = Factory.AddPanel(
615  this, wxPoint( left, top ), wxSize( width, height ) );
616  pNotebook = Factory.AddNotebook( mMainPanel );
617  /* i18n-hint: This is an experimental feature where the main panel in
618  Audacity is put on a notebook tab, and this is the name on that tab.
619  Other tabs in that notebook may have instruments, patch panels etc.*/
620  pPage = Factory.AddPage( pNotebook, _("Main Mix"));
621 #else
622  // Not using a notebook, so we place the track panel inside another panel,
623  // this keeps the notebook code and normal code consistent and also
624  // paves the way for adding additional windows inside the track panel.
625  mMainPanel = safenew wxPanelWrapper(this, -1,
626  wxDefaultPosition,
627  wxDefaultSize,
628  wxNO_BORDER);
629  mMainPanel->SetSizer( safenew wxBoxSizer(wxVERTICAL) );
630  mMainPanel->SetLabel("Main Panel");// Not localised.
631  pPage = mMainPanel;
632  // Set the colour here to the track panel background to avoid
633  // flicker when Audacity starts up.
634  // However, that leads to areas next to the horizontal scroller
635  // being painted in background colour and not scroller background
636  // colour, so suppress this for now.
637  //pPage->SetBackgroundColour( theTheme.Colour( clrDark ));
638 #endif
639  pPage->SetLayoutDirection(wxLayout_LeftToRight);
640 
641 #ifdef EXPERIMENTAL_DA2
642  pPage->SetBackgroundColour(theTheme.Colour( clrMedium ));
643 #endif
644 
645  mMainPage = pPage;
646 
647  mPlaybackScroller = std::make_unique<PlaybackScroller>( &project );
648 
649  // PRL: Old comments below. No longer observing the ordering that it
650  // recommends. ProjectWindow::OnActivate puts the focus directly into
651  // the TrackPanel, which avoids the problems.
652  // LLL: When Audacity starts or becomes active after returning from
653  // another application, the first window that can accept focus
654  // will be given the focus even if we try to SetFocus(). By
655  // creating the scrollbars after the TrackPanel, we resolve
656  // several focus problems.
657 
658  mHsbar = safenew ScrollBar(pPage, HSBarID, wxSB_HORIZONTAL);
659  mVsbar = safenew ScrollBar(pPage, VSBarID, wxSB_VERTICAL);
660 #if wxUSE_ACCESSIBILITY
661  // so that name can be set on a standard control
662  mHsbar->SetAccessible(safenew WindowAccessible(mHsbar));
663  mVsbar->SetAccessible(safenew WindowAccessible(mVsbar));
664 #endif
665  mHsbar->SetLayoutDirection(wxLayout_LeftToRight);
666  mHsbar->SetName(_("Horizontal Scrollbar"));
667  mVsbar->SetName(_("Vertical Scrollbar"));
668 
669  project.Bind( EVT_UNDO_MODIFIED, &ProjectWindow::OnUndoPushedModified, this );
670  project.Bind( EVT_UNDO_PUSHED, &ProjectWindow::OnUndoPushedModified, this );
671  project.Bind( EVT_UNDO_OR_REDO, &ProjectWindow::OnUndoRedo, this );
672  project.Bind( EVT_UNDO_RESET, &ProjectWindow::OnUndoReset, this );
673 
674  wxTheApp->Bind(EVT_THEME_CHANGE, &ProjectWindow::OnThemeChange, this);
675 }
676 
678 {
679  // Tool manager gives us capture sometimes
680  if(HasCapture())
681  ReleaseMouse();
682 }
683 
684 BEGIN_EVENT_TABLE(ProjectWindow, wxFrame)
686  EVT_MOUSE_EVENTS(ProjectWindow::OnMouseEvent)
688  EVT_SIZE(ProjectWindow::OnSize)
689  EVT_SHOW(ProjectWindow::OnShow)
690  EVT_ICONIZE(ProjectWindow::OnIconize)
691  EVT_MOVE(ProjectWindow::OnMove)
692  EVT_ACTIVATE(ProjectWindow::OnActivate)
693  EVT_COMMAND_SCROLL_LINEUP(HSBarID, ProjectWindow::OnScrollLeftButton)
694  EVT_COMMAND_SCROLL_LINEDOWN(HSBarID, ProjectWindow::OnScrollRightButton)
695  EVT_COMMAND_SCROLL(HSBarID, ProjectWindow::OnScroll)
696  EVT_COMMAND_SCROLL(VSBarID, ProjectWindow::OnScroll)
697  // Fires for menu with ID #1...first menu defined
698  EVT_UPDATE_UI(1, ProjectWindow::OnUpdateUI)
699  EVT_COMMAND(wxID_ANY, EVT_TOOLBAR_UPDATED, ProjectWindow::OnToolBarUpdate)
700  //mchinen:multithreaded calls - may not be threadsafe with CommandEvent: may have to change.
702 
703 void ProjectWindow::ApplyUpdatedTheme()
704 {
705  auto &project = mProject;
706  SetBackgroundColour(theTheme.Colour( clrMedium ));
707  ClearBackground();// For wxGTK.
708 }
709 
710 void ProjectWindow::RedrawProject(const bool bForceWaveTracks /*= false*/)
711 {
712  auto pThis = wxWeakRef<ProjectWindow>(this);
713  CallAfter( [pThis, bForceWaveTracks]{
714 
715  if (!pThis)
716  return;
717  if (pThis->IsBeingDeleted())
718  return;
719 
720  auto &project = pThis->mProject ;
721  auto &tracks = TrackList::Get( project );
722  auto &trackPanel = GetProjectPanel( project );
723  pThis->FixScrollbars();
724  if (bForceWaveTracks)
725  {
726  for ( auto pWaveTrack : tracks.Any< WaveTrack >() )
727  for (const auto &clip: pWaveTrack->GetClips())
728  clip->MarkChanged();
729  }
730  trackPanel.Refresh(false);
731 
732  });
733 }
734 
735 void ProjectWindow::OnThemeChange(wxCommandEvent& evt)
736 {
737  evt.Skip();
738  auto &project = mProject;
739  this->ApplyUpdatedTheme();
740  auto &toolManager = ToolManager::Get( project );
741  for( int ii = 0; ii < ToolBarCount; ++ii )
742  {
743  ToolBar *pToolBar = toolManager.GetToolBar(ii);
744  if( pToolBar )
745  pToolBar->ReCreateButtons();
746  }
747 }
748 
750 {
751  // Update status bar widths in case of language change
753 }
754 
756 {
757  // Set a flag so we don't have to generate two update events
758  mAutoScrolling = true;
759 
760  // Call our Scroll method which updates our ViewInfo variables
761  // to reflect the positions of the scrollbars
762  DoScroll();
763 
764  mAutoScrolling = false;
765 }
766 
767 #if defined(__WXMAC__)
768 // const int sbarSpaceWidth = 15;
769 // const int sbarControlWidth = 16;
770 // const int sbarExtraLen = 1;
771 const int sbarHjump = 30; //STM: This is how far the thumb jumps when the l/r buttons are pressed, or auto-scrolling occurs -- in pixels
772 #elif defined(__WXMSW__)
773 const int sbarSpaceWidth = 16;
774 const int sbarControlWidth = 16;
775 const int sbarExtraLen = 0;
776 const int sbarHjump = 30; //STM: This is how far the thumb jumps when the l/r buttons are pressed, or auto-scrolling occurs -- in pixels
777 #else // wxGTK, wxMOTIF, wxX11
778 const int sbarSpaceWidth = 15;
779 const int sbarControlWidth = 15;
780 const int sbarExtraLen = 0;
781 const int sbarHjump = 30; //STM: This is how far the thumb jumps when the l/r buttons are pressed, or auto-scrolling occurs -- in pixels
782 #include "AllThemeResources.h"
783 #endif
784 
785 // Make sure selection edge is in view
787 {
788  auto &trackPanel = GetProjectPanel( mProject );
789  auto &viewInfo = ViewInfo::Get( mProject );
790  auto w = viewInfo.GetTracksUsableWidth();
791 
792  int pixel = viewInfo.TimeToPosition(pos);
793  if (pixel < 0 || pixel >= w)
794  {
796  (viewInfo.OffsetTimeByPixels(pos, -(w / 2)));
797  trackPanel.Refresh(false);
798  }
799 }
800 
802 {
803  auto &viewInfo = ViewInfo::Get( mProject );
804  ScrollIntoView(viewInfo.PositionToTime(x, viewInfo.GetLeftOffset()));
805 }
806 
812 {
813  auto &project = mProject;
814  auto &viewInfo = ViewInfo::Get( project );
815  wxInt64 pos = mHsbar->GetThumbPosition();
816  // move at least one scroll increment
817  pos -= wxMax((wxInt64)(sbarHjump * viewInfo.sbarScale), 1);
818  pos = wxMax(pos, 0);
819  viewInfo.sbarH -= sbarHjump;
820  viewInfo.sbarH = std::max(viewInfo.sbarH,
821  -(wxInt64) PixelWidthBeforeTime(0.0));
822 
823 
824  if (pos != mHsbar->GetThumbPosition()) {
825  mHsbar->SetThumbPosition((int)pos);
827  }
828 }
833 
835 {
836  auto &project = mProject;
837  auto &viewInfo = ViewInfo::Get( project );
838  wxInt64 pos = mHsbar->GetThumbPosition();
839  // move at least one scroll increment
840  // use wxInt64 for calculation to prevent temporary overflow
841  pos += wxMax((wxInt64)(sbarHjump * viewInfo.sbarScale), 1);
842  wxInt64 max = mHsbar->GetRange() - mHsbar->GetThumbSize();
843  pos = wxMin(pos, max);
844  viewInfo.sbarH += sbarHjump;
845  viewInfo.sbarH = std::min(viewInfo.sbarH,
846  viewInfo.sbarTotal
847  - (wxInt64) PixelWidthBeforeTime(0.0) - viewInfo.sbarScreen);
848 
849  if (pos != mHsbar->GetThumbPosition()) {
850  mHsbar->SetThumbPosition((int)pos);
852  }
853 }
854 
855 
859 void ProjectWindow::OnScrollLeftButton(wxScrollEvent & /*event*/)
860 {
861  auto &project = mProject;
862  auto &viewInfo = ViewInfo::Get( project );
863  wxInt64 pos = mHsbar->GetThumbPosition();
864  // move at least one scroll increment
865  pos -= wxMax((wxInt64)(sbarHjump * viewInfo.sbarScale), 1);
866  pos = wxMax(pos, 0);
867  viewInfo.sbarH -= sbarHjump;
868  viewInfo.sbarH = std::max(viewInfo.sbarH,
869  - (wxInt64) PixelWidthBeforeTime(0.0));
870 
871  if (pos != mHsbar->GetThumbPosition()) {
872  mHsbar->SetThumbPosition((int)pos);
873  DoScroll();
874  }
875 }
876 
880 void ProjectWindow::OnScrollRightButton(wxScrollEvent & /*event*/)
881 {
882  auto &project = mProject;
883  auto &viewInfo = ViewInfo::Get( project );
884  wxInt64 pos = mHsbar->GetThumbPosition();
885  // move at least one scroll increment
886  // use wxInt64 for calculation to prevent temporary overflow
887  pos += wxMax((wxInt64)(sbarHjump * viewInfo.sbarScale), 1);
888  wxInt64 max = mHsbar->GetRange() - mHsbar->GetThumbSize();
889  pos = wxMin(pos, max);
890  viewInfo.sbarH += sbarHjump;
891  viewInfo.sbarH = std::min(viewInfo.sbarH,
892  viewInfo.sbarTotal
893  - (wxInt64) PixelWidthBeforeTime(0.0) - viewInfo.sbarScreen);
894 
895  if (pos != mHsbar->GetThumbPosition()) {
896  mHsbar->SetThumbPosition((int)pos);
897  DoScroll();
898  }
899 }
900 
901 
903 {
904  auto &project = mProject;
905  auto &scrubber = Scrubber::Get( project );
906  auto &viewInfo = ViewInfo::Get( project );
907  if (viewInfo.bScrollBeyondZero)
908  return true;
909 
910  if (scrubber.HasMark() ||
911  ProjectAudioIO::Get( project ).IsAudioActive()) {
912  if (mPlaybackScroller) {
913  auto mode = mPlaybackScroller->GetMode();
914  if (mode == PlaybackScroller::Mode::Pinned ||
916  return true;
917  }
918  }
919 
920  return false;
921 }
922 
924 {
925  auto &project = mProject;
926  auto &tracks = TrackList::Get( project );
927  auto &viewInfo = ViewInfo::Get( project );
928  if (!MayScrollBeyondZero())
929  return 0;
930  const double screen = viewInfo.GetScreenEndTime() - viewInfo.h;
931  return std::min(tracks.GetStartTime(), -screen);
932 }
933 
934 // PRL: Bug1197: we seem to need to compute all in double, to avoid differing results on Mac
935 // That's why ViewInfo::TimeRangeToPixelWidth was defined, with some regret.
936 double ProjectWindow::PixelWidthBeforeTime(double scrollto) const
937 {
938  auto &project = mProject;
939  auto &viewInfo = ViewInfo::Get( project );
940  const double lowerBound = ScrollingLowerBoundTime();
941  return
942  // Ignoring fisheye is correct here
943  viewInfo.TimeRangeToPixelWidth(scrollto - lowerBound);
944 }
945 
947 {
948  auto &project = mProject;
949  auto &viewInfo = ViewInfo::Get( project );
950  const auto unscaled = PixelWidthBeforeTime(scrollto);
951  const int max = mHsbar->GetRange() - mHsbar->GetThumbSize();
952  const int pos =
953  std::min(max,
954  std::max(0,
955  (int)(floor(0.5 + unscaled * viewInfo.sbarScale))));
956  mHsbar->SetThumbPosition(pos);
957  viewInfo.sbarH = floor(0.5 + unscaled - PixelWidthBeforeTime(0.0));
958  viewInfo.sbarH = std::max(viewInfo.sbarH,
959  - (wxInt64) PixelWidthBeforeTime(0.0));
960  viewInfo.sbarH = std::min(viewInfo.sbarH,
961  viewInfo.sbarTotal
962  - (wxInt64) PixelWidthBeforeTime(0.0) - viewInfo.sbarScreen);
963 }
964 
965 //
966 // This method, like the other methods prefaced with TP, handles TrackPanel
967 // 'callback'.
968 //
969 void ProjectWindow::TP_ScrollWindow(double scrollto)
970 {
971  SetHorizontalThumb(scrollto);
972 
973  // Call our Scroll method which updates our ViewInfo variables
974  // to reflect the positions of the scrollbars
975  DoScroll();
976 }
977 
978 //
979 // Scroll vertically. This is called for example by the mouse wheel
980 // handler in Track Panel. A positive argument makes the window
981 // scroll down, while a negative argument scrolls up.
982 //
984 {
985  int oldPos = mVsbar->GetThumbPosition();
986  int pos = oldPos + delta;
987  int max = mVsbar->GetRange() - mVsbar->GetThumbSize();
988 
989  // Can be negative in case of only one track
990  if (max < 0)
991  max = 0;
992 
993  if (pos > max)
994  pos = max;
995  else if (pos < 0)
996  pos = 0;
997 
998  if (pos != oldPos)
999  {
1000  mVsbar->SetThumbPosition(pos);
1001 
1002  DoScroll();
1003  return true;
1004  }
1005  else
1006  return false;
1007 }
1008 
1010 {
1011  auto &project = mProject;
1012  auto &tracks = TrackList::Get( project );
1013  auto &trackPanel = GetProjectPanel( project );
1014  auto &viewInfo = ViewInfo::Get( project );
1015 
1016  bool refresh = false;
1017  bool rescroll = false;
1018 
1019  int totalHeight = TrackView::GetTotalHeight( tracks ) + 32;
1020 
1021  auto panelWidth = viewInfo.GetTracksUsableWidth();
1022  auto panelHeight = viewInfo.GetHeight();
1023 
1024  // (From Debian...at least I think this is the change corresponding
1025  // to this comment)
1026  //
1027  // (2.) GTK critical warning "IA__gtk_range_set_range: assertion
1028  // 'min < max' failed" because of negative numbers as result of window
1029  // size checking. Added a sanity check that straightens up the numbers
1030  // in edge cases.
1031  if (panelWidth < 0) {
1032  panelWidth = 0;
1033  }
1034  if (panelHeight < 0) {
1035  panelHeight = 0;
1036  }
1037 
1038  auto LastTime = std::numeric_limits<double>::lowest();
1039  for (const Track *track : tracks) {
1040  // Iterate over pending changed tracks if present.
1041  track = track->SubstitutePendingChangedTrack().get();
1042  LastTime = std::max( LastTime, track->GetEndTime() );
1043  }
1044  LastTime =
1045  std::max(LastTime, viewInfo.selectedRegion.t1());
1046 
1047  const double screen =
1048  viewInfo.GetScreenEndTime() - viewInfo.h;
1049  const double halfScreen = screen / 2.0;
1050 
1051  // If we can scroll beyond zero,
1052  // Add 1/2 of a screen of blank space to the end
1053  // and another 1/2 screen before the beginning
1054  // so that any point within the union of the selection and the track duration
1055  // may be scrolled to the midline.
1056  // May add even more to the end, so that you can always scroll the starting time to zero.
1057  const double lowerBound = ScrollingLowerBoundTime();
1058  const double additional = MayScrollBeyondZero()
1059  ? -lowerBound + std::max(halfScreen, screen - LastTime)
1060  : screen / 4.0;
1061 
1062  viewInfo.total = LastTime + additional;
1063 
1064  // Don't remove time from total that's still on the screen
1065  viewInfo.total = std::max(viewInfo.total, viewInfo.h + screen);
1066 
1067  if (viewInfo.h < lowerBound) {
1068  viewInfo.h = lowerBound;
1069  rescroll = true;
1070  }
1071 
1072  viewInfo.sbarTotal = (wxInt64) (viewInfo.GetTotalWidth());
1073  viewInfo.sbarScreen = (wxInt64)(panelWidth);
1074  viewInfo.sbarH = (wxInt64) (viewInfo.GetBeforeScreenWidth());
1075 
1076  // PRL: Can someone else find a more elegant solution to bug 812, than
1077  // introducing this boolean member variable?
1078  // Setting mVSbar earlier, int HandlXMLTag, didn't succeed in restoring
1079  // the vertical scrollbar to its saved position. So defer that till now.
1080  // mbInitializingScrollbar should be true only at the start of the life
1081  // of an AudacityProject reopened from disk.
1082  if (!mbInitializingScrollbar) {
1083  viewInfo.vpos = mVsbar->GetThumbPosition() * viewInfo.scrollStep;
1084  }
1085  mbInitializingScrollbar = false;
1086 
1087  if (viewInfo.vpos >= totalHeight)
1088  viewInfo.vpos = totalHeight - 1;
1089  if (viewInfo.vpos < 0)
1090  viewInfo.vpos = 0;
1091 
1092  bool oldhstate;
1093  bool oldvstate;
1094  bool newhstate =
1095  (viewInfo.GetScreenEndTime() - viewInfo.h) < viewInfo.total;
1096  bool newvstate = panelHeight < totalHeight;
1097 
1098 #ifdef __WXGTK__
1099  oldhstate = mHsbar->IsShown();
1100  oldvstate = mVsbar->IsShown();
1101  mHsbar->Show(newhstate);
1102  mVsbar->Show(panelHeight < totalHeight);
1103 #else
1104  oldhstate = mHsbar->IsEnabled();
1105  oldvstate = mVsbar->IsEnabled();
1106  mHsbar->Enable(newhstate);
1107  mVsbar->Enable(panelHeight < totalHeight);
1108 #endif
1109 
1110  if (panelHeight >= totalHeight && viewInfo.vpos != 0) {
1111  viewInfo.vpos = 0;
1112 
1113  refresh = true;
1114  rescroll = false;
1115  }
1116  if (!newhstate && viewInfo.sbarH != 0) {
1117  viewInfo.sbarH = 0;
1118 
1119  refresh = true;
1120  rescroll = false;
1121  }
1122 
1123  // wxScrollbar only supports int values but we need a greater range, so
1124  // we scale the scrollbar coordinates on demand. We only do this if we
1125  // would exceed the int range, so we can always use the maximum resolution
1126  // available.
1127 
1128  // Don't use the full 2^31 max int range but a bit less, so rounding
1129  // errors in calculations do not overflow max int
1130  wxInt64 maxScrollbarRange = (wxInt64)(2147483647 * 0.999);
1131  if (viewInfo.sbarTotal > maxScrollbarRange)
1132  viewInfo.sbarScale = ((double)maxScrollbarRange) / viewInfo.sbarTotal;
1133  else
1134  viewInfo.sbarScale = 1.0; // use maximum resolution
1135 
1136  {
1137  int scaledSbarH = (int)(viewInfo.sbarH * viewInfo.sbarScale);
1138  int scaledSbarScreen = (int)(viewInfo.sbarScreen * viewInfo.sbarScale);
1139  int scaledSbarTotal = (int)(viewInfo.sbarTotal * viewInfo.sbarScale);
1140  const int offset =
1141  (int)(floor(0.5 + viewInfo.sbarScale * PixelWidthBeforeTime(0.0)));
1142 
1143  mHsbar->SetScrollbar(scaledSbarH + offset, scaledSbarScreen, scaledSbarTotal,
1144  scaledSbarScreen, TRUE);
1145  }
1146 
1147  // Vertical scrollbar
1148  mVsbar->SetScrollbar(viewInfo.vpos / viewInfo.scrollStep,
1149  panelHeight / viewInfo.scrollStep,
1150  totalHeight / viewInfo.scrollStep,
1151  panelHeight / viewInfo.scrollStep, TRUE);
1152 
1153  if (refresh || (rescroll &&
1154  (viewInfo.GetScreenEndTime() - viewInfo.h) < viewInfo.total)) {
1155  trackPanel.Refresh(false);
1156  }
1157 
1158  MenuManager::Get( project ).UpdateMenus();
1159 
1160  if (oldhstate != newhstate || oldvstate != newvstate) {
1161  UpdateLayout();
1162  }
1163 }
1164 
1166 {
1167  auto &project = mProject;
1168  auto &trackPanel = GetProjectPanel( project );
1169  auto &toolManager = ToolManager::Get( project );
1170 
1171  // 1. Layout panel, to get widths of the docks.
1172  Layout();
1173  // 2. Layout toolbars to pack the toolbars correctly in docks which
1174  // are now the correct width.
1175  toolManager.LayoutToolBars();
1176  // 3. Layout panel, to resize docks, in particular reducing the height
1177  // of any empty docks, or increasing the height of docks that need it.
1178  Layout();
1179 
1180  // Bug 2455
1181  // The commented out code below is to calculate a nice minimum size for
1182  // the window. However on Ubuntu when the window is minimised it leads to
1183  // an insanely tall window.
1184  // Using a fixed min size fixes that.
1185  // However there is still something strange when minimised, as once
1186  // UpdateLayout is called once, when minimised, it gets called repeatedly.
1187 #if 0
1188  // Retrieve size of this projects window
1189  wxSize mainsz = GetSize();
1190 
1191  // Retrieve position of the track panel to use as the size of the top
1192  // third of the window
1193  wxPoint tppos = ClientToScreen(trackPanel.GetParent()->GetPosition());
1194 
1195  // Retrieve position of bottom dock to use as the size of the bottom
1196  // third of the window
1197  wxPoint sbpos = ClientToScreen(toolManager.GetBotDock()->GetPosition());
1198 
1199  // The "+ 50" is the minimum height of the TrackPanel
1200  SetMinSize( wxSize(250, (mainsz.y - sbpos.y) + tppos.y + 50));
1201 #endif
1202  SetMinSize( wxSize(250, 250));
1203  SetMaxSize( wxSize(20000, 20000));
1204 }
1205 
1207 {
1208  // Activate events can fire during window teardown, so just
1209  // ignore them.
1210  if (mIsDeleting) {
1211  return;
1212  }
1213 
1214  CallAfter( [this]{
1215 
1216  if (mIsDeleting)
1217  return;
1218 
1219  FixScrollbars();
1220  UpdateLayout();
1221 
1222  });
1223 }
1224 
1225 
1227 {
1228  return mIconized;
1229 }
1230 
1232 {
1233  enum { nWidths = nStatusBarFields + 1 };
1234  int widths[ nWidths ]{ 0 };
1235  widths[ rateStatusBarField ] = 150;
1236  const auto statusBar = GetStatusBar();
1237  const auto &functions = ProjectStatus::GetStatusWidthFunctions();
1238  // Start from 1 not 0
1239  // Specifying a first column always of width 0 was needed for reasons
1240  // I forget now
1241  for ( int ii = 1; ii <= nStatusBarFields; ++ii ) {
1242  int &width = widths[ ii ];
1243  for ( const auto &function : functions ) {
1244  auto results =
1245  function( mProject, static_cast< StatusBarField >( ii ) );
1246  for ( const auto &string : results.first ) {
1247  int w;
1248  statusBar->GetTextExtent(string.Translation(), &w, nullptr);
1249  width = std::max<int>( width, w + results.second );
1250  }
1251  }
1252  }
1253  // The main status field is not fixed width
1254  widths[ mainStatusBarField ] = -1;
1255  statusBar->SetStatusWidths( nWidths, widths );
1256 }
1257 
1259 {
1260  (void)show;//compiler food
1261 #ifdef __WXMAC__
1262  // Save the focus so we can restore it to whatever had it before since
1263  // showing a previously hidden toolbar will cause the focus to be set to
1264  // its frame. If this is not done it will appear that activation events
1265  // aren't being sent to the project window since they are actually being
1266  // delivered to the last tool frame shown.
1267  wxWindow *focused = FindFocus();
1268 
1269  // Find all the floating toolbars, and show or hide them
1270  const auto &children = GetChildren();
1271  for(const auto &child : children) {
1272  if (auto frame = dynamic_cast<ToolFrame*>(child)) {
1273  if (!show) {
1274  frame->Hide();
1275  }
1276  else if (frame->GetBar() &&
1277  frame->GetBar()->IsVisible() ) {
1278  frame->Show();
1279  }
1280  }
1281  }
1282 
1283  // Restore the focus if needed
1284  if (focused) {
1285  focused->SetFocus();
1286  }
1287 #endif
1288 }
1289 
1290 void ProjectWindow::OnIconize(wxIconizeEvent &event)
1291 {
1292  //JKC: On Iconizing we get called twice. Don't know
1293  // why but it does no harm.
1294  // Should we be returning true/false rather than
1295  // void return? I don't know.
1296  mIconized = event.IsIconized();
1297 
1298 #if defined(__WXMAC__)
1299  // Readdresses bug 1431 since a crash could occur when restoring iconized
1300  // floating toolbars due to recursion (bug 2411).
1302  if( !mIconized )
1303  {
1304  Raise();
1305  }
1306 #endif
1307 
1308  // VisibileProjectCount seems to be just a counter for debugging.
1309  // It's not used outside this function.
1310  auto VisibleProjectCount = std::count_if(
1311  AllProjects{}.begin(), AllProjects{}.end(),
1312  []( const AllProjects::value_type &ptr ){
1313  return !GetProjectFrame( *ptr ).IsIconized();
1314  }
1315  );
1316  event.Skip();
1317 
1318  // This step is to fix part of Bug 2040, where the BackingPanel
1319  // size was not restored after we leave Iconized state.
1320 
1321  // Queue up a resize event using OnShow so that we
1322  // refresh the track panel. But skip this, if we're iconized.
1323  if( mIconized )
1324  return;
1325  wxShowEvent Evt;
1326  OnShow( Evt );
1327 }
1328 
1329 void ProjectWindow::OnMove(wxMoveEvent & event)
1330 {
1331  if (!this->IsMaximized() && !this->IsIconized())
1332  SetNormalizedWindowState(this->GetRect());
1333  event.Skip();
1334 }
1335 
1336 void ProjectWindow::OnSize(wxSizeEvent & event)
1337 {
1338  // (From Debian)
1339  //
1340  // (3.) GTK critical warning "IA__gdk_window_get_origin: assertion
1341  // 'GDK_IS_WINDOW (window)' failed": Received events of type wxSizeEvent
1342  // on the main project window cause calls to "ClientToScreen" - which is
1343  // not available until the window is first shown. So the class has to
1344  // keep track of wxShowEvent events and inhibit those actions until the
1345  // window is first shown.
1346  if (mShownOnce) {
1347  HandleResize();
1348  if (!this->IsMaximized() && !this->IsIconized())
1349  SetNormalizedWindowState(this->GetRect());
1350  }
1351  event.Skip();
1352 }
1353 
1354 void ProjectWindow::OnShow(wxShowEvent & event)
1355 {
1356  // Remember that the window has been shown at least once
1357  mShownOnce = true;
1358 
1359  // (From Debian...see also TrackPanel::OnTimer and AudacityTimer::Notify)
1360  //
1361  // Description: Workaround for wxWidgets bug: Reentry in clipboard
1362  // The wxWidgets bug http://trac.wxwidgets.org/ticket/16636 prevents
1363  // us from doing clipboard operations in wxShowEvent and wxTimerEvent
1364  // processing because those event could possibly be processed during
1365  // the (not sufficiently protected) Yield() of a first clipboard
1366  // operation, causing reentry. Audacity had a workaround in place
1367  // for this problem (the class "CaptureEvents"), which however isn't
1368  // applicable with wxWidgets 3.0 because it's based on changing the
1369  // gdk event handler, a change that would be overridden by wxWidgets's
1370  // own gdk event handler change.
1371  // Instead, as a NEW workaround, specifically protect those processings
1372  // of wxShowEvent and wxTimerEvent that try to do clipboard operations
1373  // from being executed within Yield(). This is done by delaying their
1374  // execution by posting pure wxWidgets events - which are never executed
1375  // during Yield().
1376  // Author: Martin Stegh fer <[email protected]>
1377  // Bug-Debian: https://bugs.debian.org/765341
1378 
1379  // the actual creation/showing of the window).
1380  // Post the event instead of calling OnSize(..) directly. This ensures that
1381  // this is a pure wxWidgets event (no GDK event behind it) and that it
1382  // therefore isn't processed within the YieldFor(..) of the clipboard
1383  // operations (workaround for Debian bug #765341).
1384  // QueueEvent() will take ownership of the event
1385  GetEventHandler()->QueueEvent(safenew wxSizeEvent(GetSize()));
1386 
1387  // Further processing by default handlers
1388  event.Skip();
1389 }
1390 
1394 void ProjectWindow::OnToolBarUpdate(wxCommandEvent & event)
1395 {
1396  HandleResize();
1397 
1398  event.Skip(false); /* No need to propagate any further */
1399 }
1400 
1401 void ProjectWindow::OnUndoPushedModified( wxCommandEvent &evt )
1402 {
1403  evt.Skip();
1404  RedrawProject();
1405 }
1406 
1407 void ProjectWindow::OnUndoRedo( wxCommandEvent &evt )
1408 {
1409  evt.Skip();
1410  HandleResize();
1411  RedrawProject();
1412 }
1413 
1414 void ProjectWindow::OnUndoReset( wxCommandEvent &evt )
1415 {
1416  evt.Skip();
1417  HandleResize();
1418  // RedrawProject(); // Should we do this here too?
1419 }
1420 
1421 void ProjectWindow::OnScroll(wxScrollEvent & WXUNUSED(event))
1422 {
1423  auto &project = mProject;
1424  auto &viewInfo = ViewInfo::Get( project );
1425  const wxInt64 offset = PixelWidthBeforeTime(0.0);
1426  viewInfo.sbarH =
1427  (wxInt64)(mHsbar->GetThumbPosition() / viewInfo.sbarScale) - offset;
1428  DoScroll();
1429 
1430 #ifndef __WXMAC__
1431  // Bug2179
1432  // This keeps the time ruler in sync with horizontal scrolling, without
1433  // making an undesirable compilation dependency of this source file on
1434  // the ruler
1435  wxTheApp->ProcessIdle();
1436 #endif
1437 }
1438 
1440 {
1441  auto &project = mProject;
1442  auto &trackPanel = GetProjectPanel( project );
1443  auto &viewInfo = ViewInfo::Get( project );
1444  const double lowerBound = ScrollingLowerBoundTime();
1445 
1446  auto width = viewInfo.GetTracksUsableWidth();
1447  viewInfo.SetBeforeScreenWidth(viewInfo.sbarH, width, lowerBound);
1448 
1449 
1450  if (MayScrollBeyondZero()) {
1451  enum { SCROLL_PIXEL_TOLERANCE = 10 };
1452  if (std::abs(viewInfo.TimeToPosition(0.0, 0
1453  )) < SCROLL_PIXEL_TOLERANCE) {
1454  // Snap the scrollbar to 0
1455  viewInfo.h = 0;
1456  SetHorizontalThumb(0.0);
1457  }
1458  }
1459 
1460  viewInfo.vpos = mVsbar->GetThumbPosition() * viewInfo.scrollStep;
1461 
1462  //mchinen: do not always set this project to be the active one.
1463  //a project may autoscroll while playing in the background
1464  //I think this is okay since OnMouseEvent has one of these.
1465  //SetActiveProject(this);
1466 
1467  if (!mAutoScrolling) {
1468  trackPanel.Refresh(false);
1469  }
1470 }
1471 
1472 void ProjectWindow::OnMenu(wxCommandEvent & event)
1473 {
1474 #ifdef __WXMSW__
1475  // Bug 1642: We can arrive here with bogus menu IDs, which we
1476  // proceed to process. So if bogus, don't.
1477  // The bogus menu IDs are probably generated by controls on the TrackPanel,
1478  // such as the Project Rate.
1479  // 17000 is the magic number at which we start our menu.
1480  // This code would probably NOT be OK on Mac, since we assign
1481  // some specific ID numbers.
1482  if( event.GetId() < 17000){
1483  event.Skip();
1484  return;
1485  }
1486 #endif
1487  auto &project = mProject;
1488  auto &commandManager = CommandManager::Get( project );
1489  bool handled = commandManager.HandleMenuID( GetProject(),
1490  event.GetId(), MenuManager::Get( project ).GetUpdateFlags(),
1491  false);
1492 
1493  if (handled)
1494  event.Skip(false);
1495  else{
1496  event.ResumePropagation( 999 );
1497  event.Skip(true);
1498  }
1499 }
1500 
1501 void ProjectWindow::OnUpdateUI(wxUpdateUIEvent & WXUNUSED(event))
1502 {
1503  auto &project = mProject;
1504  MenuManager::Get( project ).UpdateMenus();
1505 }
1506 
1507 void ProjectWindow::OnActivate(wxActivateEvent & event)
1508 {
1509  // Activate events can fire during window teardown, so just
1510  // ignore them.
1511  if (IsBeingDeleted()) {
1512  return;
1513  }
1514 
1515  auto &project = mProject;
1516 
1517  mActive = event.GetActive();
1518 
1519  // Under Windows, focus can be "lost" when returning to
1520  // Audacity from a different application.
1521  //
1522  // This was observed by minimizing all windows using WINDOWS+M and
1523  // then ALT+TAB to return to Audacity. Focus will be given to the
1524  // project window frame which is not at all useful.
1525  //
1526  // So, we use ToolManager's observation of focus changes in a wxEventFilter.
1527  // Then, when we receive the
1528  // activate event, we restore that focus to the child or the track
1529  // panel if no child had the focus (which probably should never happen).
1530  if (mActive) {
1531  auto &toolManager = ToolManager::Get( project );
1532  SetActiveProject( &project );
1533  if ( ! toolManager.RestoreFocus() )
1534  GetProjectPanel( project ).SetFocus();
1535  }
1536  event.Skip();
1537 }
1538 
1540 {
1541  return mActive;
1542 }
1543 
1544 void ProjectWindow::OnMouseEvent(wxMouseEvent & event)
1545 {
1546  auto &project = mProject;
1547  if (event.ButtonDown())
1548  SetActiveProject( &project );
1549 }
1550 
1552 {
1553  auto &project = mProject;
1554  auto &tracks = TrackList::Get( project );
1555  auto &trackPanel = GetProjectPanel( project );
1556 
1557  DoZoomFit();
1558 
1559  trackPanel.SetFocus();
1560  if (!pTrack)
1561  pTrack = *tracks.Selected().begin();
1562  if (!pTrack)
1563  pTrack = *tracks.Any().begin();
1564  if (pTrack) {
1565  TrackFocus::Get(project).Set(pTrack);
1566  pTrack->EnsureVisible();
1567  }
1568 }
1569 
1570 // Utility function called by other zoom methods
1571 void ProjectWindow::Zoom(double level)
1572 {
1573  auto &project = mProject;
1574  auto &viewInfo = ViewInfo::Get( project );
1575  viewInfo.SetZoom(level);
1576  FixScrollbars();
1577  // See if we can center the selection on screen, and have it actually fit.
1578  // tOnLeft is the amount of time we would need before the selection left edge to center it.
1579  float t0 = viewInfo.selectedRegion.t0();
1580  float t1 = viewInfo.selectedRegion.t1();
1581  float tAvailable = viewInfo.GetScreenEndTime() - viewInfo.h;
1582  float tOnLeft = (tAvailable - t0 + t1)/2.0;
1583  // Bug 1292 (Enh) is effectively a request to do this scrolling of the selection into view.
1584  // If tOnLeft is positive, then we have room for the selection, so scroll to it.
1585  if( tOnLeft >=0 )
1586  TP_ScrollWindow( t0-tOnLeft);
1587 }
1588 
1589 // Utility function called by other zoom methods
1590 void ProjectWindow::ZoomBy(double multiplier)
1591 {
1592  auto &project = mProject;
1593  auto &viewInfo = ViewInfo::Get( project );
1594  viewInfo.ZoomBy(multiplier);
1595  FixScrollbars();
1596 }
1597 
1599 // This method 'rewinds' the track, by setting the cursor to 0 and
1600 // scrolling the window to fit 0 on the left side of it
1601 // (maintaining current zoom).
1602 // If shift is held down, it will extend the left edge of the
1603 // selection to 0 (holding right edge constant), otherwise it will
1604 // move both left and right edge of selection to 0
1606 void ProjectWindow::Rewind(bool shift)
1607 {
1608  auto &project = mProject;
1609  auto &viewInfo = ViewInfo::Get( project );
1610  viewInfo.selectedRegion.setT0(0, false);
1611  if (!shift)
1612  viewInfo.selectedRegion.setT1(0);
1613 
1614  TP_ScrollWindow(0);
1615 }
1616 
1617 
1619 // This method 'fast-forwards' the track, by setting the cursor to
1620 // the end of the samples on the selected track and scrolling the
1621 // window to fit the end on its right side (maintaining current zoom).
1622 // If shift is held down, it will extend the right edge of the
1623 // selection to the end (holding left edge constant), otherwise it will
1624 // move both left and right edge of selection to the end
1626 void ProjectWindow::SkipEnd(bool shift)
1627 {
1628  auto &project = mProject;
1629  auto &tracks = TrackList::Get( project );
1630  auto &viewInfo = ViewInfo::Get( project );
1631  double len = tracks.GetEndTime();
1632 
1633  viewInfo.selectedRegion.setT1(len, false);
1634  if (!shift)
1635  viewInfo.selectedRegion.setT0(len);
1636 
1637  // Make sure the end of the track is visible
1638  ScrollIntoView(len);
1639 }
1640 
1641 // TrackPanel callback method
1643 {
1644  OnScrollLeft();
1645 }
1646 
1647 // TrackPanel callback method
1649 {
1650  OnScrollRight();
1651 }
1652 
1653 // TrackPanel callback method
1655 {
1656  FixScrollbars();
1657 }
1658 
1660 {
1661  HandleResize();
1662 }
1663 
1665 : mProject(project)
1666 {
1667  mProject->Bind(EVT_TRACK_PANEL_TIMER,
1669  this);
1670 }
1671 
1672 void ProjectWindow::PlaybackScroller::OnTimer(wxCommandEvent &event)
1673 {
1674  // Let other listeners get the notification
1675  event.Skip();
1676 
1677  auto gAudioIO = AudioIO::Get();
1678  mRecentStreamTime = gAudioIO->GetStreamTime();
1679 
1680  auto cleanup = finally([&]{
1681  // Propagate the message to other listeners bound to this
1682  this->SafelyProcessEvent( event );
1683  });
1684 
1685  if(!ProjectAudioIO::Get( *mProject ).IsAudioActive())
1686  return;
1687  else if (mMode == Mode::Refresh) {
1688  // PRL: see comments in Scrubbing.cpp for why this is sometimes needed.
1689  // These unnecessary refreshes cause wheel rotation events to be delivered more uniformly
1690  // to the application, so scrub speed control is smoother.
1691  // (So I see at least with OS 10.10 and wxWidgets 3.0.2.)
1692  // Is there another way to ensure that than by refreshing?
1693  auto &trackPanel = GetProjectPanel( *mProject );
1694  trackPanel.Refresh(false);
1695  }
1696  else if (mMode != Mode::Off) {
1697  // Pan the view, so that we put the play indicator at some fixed
1698  // fraction of the window width.
1699 
1700  auto &viewInfo = ViewInfo::Get( *mProject );
1701  auto &trackPanel = GetProjectPanel( *mProject );
1702  const int posX = viewInfo.TimeToPosition(mRecentStreamTime);
1703  auto width = viewInfo.GetTracksUsableWidth();
1704  int deltaX;
1705  switch (mMode)
1706  {
1707  default:
1708  wxASSERT(false);
1709  /* fallthru */
1710  case Mode::Pinned:
1711  deltaX =
1713  break;
1714  case Mode::Right:
1715  deltaX = posX - width; break;
1716  }
1717  viewInfo.h =
1718  viewInfo.OffsetTimeByPixels(viewInfo.h, deltaX, true);
1719  if (!ProjectWindow::Get( *mProject ).MayScrollBeyondZero())
1720  // Can't scroll too far left
1721  viewInfo.h = std::max(0.0, viewInfo.h);
1722  trackPanel.Refresh(false);
1723  }
1724 }
1725 
1726 void ProjectWindow::ZoomInByFactor( double ZoomFactor )
1727 {
1728  auto &project = mProject;
1729  auto &viewInfo = ViewInfo::Get( project );
1730 
1731  auto gAudioIO = AudioIO::Get();
1732  // LLL: Handling positioning differently when audio is
1733  // actively playing. Don't do this if paused.
1734  if (gAudioIO->IsStreamActive(
1735  ProjectAudioIO::Get( project ).GetAudioIOToken()) &&
1736  !gAudioIO->IsPaused()){
1737  ZoomBy(ZoomFactor);
1738  ScrollIntoView(gAudioIO->GetStreamTime());
1739  return;
1740  }
1741 
1742  // DMM: Here's my attempt to get logical zooming behavior
1743  // when there's a selection that's currently at least
1744  // partially on-screen
1745 
1746  const double endTime = viewInfo.GetScreenEndTime();
1747  const double duration = endTime - viewInfo.h;
1748 
1749  bool selectionIsOnscreen =
1750  (viewInfo.selectedRegion.t0() < endTime) &&
1751  (viewInfo.selectedRegion.t1() >= viewInfo.h);
1752 
1753  bool selectionFillsScreen =
1754  (viewInfo.selectedRegion.t0() < viewInfo.h) &&
1755  (viewInfo.selectedRegion.t1() > endTime);
1756 
1757  if (selectionIsOnscreen && !selectionFillsScreen) {
1758  // Start with the center of the selection
1759  double selCenter = (viewInfo.selectedRegion.t0() +
1760  viewInfo.selectedRegion.t1()) / 2;
1761 
1762  // If the selection center is off-screen, pick the
1763  // center of the part that is on-screen.
1764  if (selCenter < viewInfo.h)
1765  selCenter = viewInfo.h +
1766  (viewInfo.selectedRegion.t1() - viewInfo.h) / 2;
1767  if (selCenter > endTime)
1768  selCenter = endTime -
1769  (endTime - viewInfo.selectedRegion.t0()) / 2;
1770 
1771  // Zoom in
1772  ZoomBy(ZoomFactor);
1773  const double newDuration =
1774  viewInfo.GetScreenEndTime() - viewInfo.h;
1775 
1776  // Recenter on selCenter
1777  TP_ScrollWindow(selCenter - newDuration / 2);
1778  return;
1779  }
1780 
1781 
1782  double origLeft = viewInfo.h;
1783  double origWidth = duration;
1784  ZoomBy(ZoomFactor);
1785 
1786  const double newDuration =
1787  viewInfo.GetScreenEndTime() - viewInfo.h;
1788  double newh = origLeft + (origWidth - newDuration) / 2;
1789 
1790  // MM: Commented this out because it was confusing users
1791  /*
1792  // make sure that the *right-hand* end of the selection is
1793  // no further *left* than 1/3 of the way across the screen
1794  if (viewInfo.selectedRegion.t1() < newh + viewInfo.screen / 3)
1795  newh = viewInfo.selectedRegion.t1() - viewInfo.screen / 3;
1796 
1797  // make sure that the *left-hand* end of the selection is
1798  // no further *right* than 2/3 of the way across the screen
1799  if (viewInfo.selectedRegion.t0() > newh + viewInfo.screen * 2 / 3)
1800  newh = viewInfo.selectedRegion.t0() - viewInfo.screen * 2 / 3;
1801  */
1802 
1803  TP_ScrollWindow(newh);
1804 }
1805 
1806 void ProjectWindow::ZoomOutByFactor( double ZoomFactor )
1807 {
1808  auto &project = mProject;
1809  auto &viewInfo = ViewInfo::Get( project );
1810 
1811  //Zoom() may change these, so record original values:
1812  const double origLeft = viewInfo.h;
1813  const double origWidth = viewInfo.GetScreenEndTime() - origLeft;
1814 
1815  ZoomBy(ZoomFactor);
1816  const double newWidth = viewInfo.GetScreenEndTime() - viewInfo.h;
1817 
1818  const double newh = origLeft + (origWidth - newWidth) / 2;
1819  // newh = (newh > 0) ? newh : 0;
1820  TP_ScrollWindow(newh);
1821 }
1822 
1824 {
1825  auto &project = mProject;
1826  auto &tracks = TrackList::Get( project );
1827  auto &viewInfo = ViewInfo::Get( project );
1828 
1829  const double end = tracks.GetEndTime();
1830  const double start = viewInfo.bScrollBeyondZero
1831  ? std::min( tracks.GetStartTime(), 0.0)
1832  : 0;
1833  const double len = end - start;
1834 
1835  if (len <= 0.0)
1836  return viewInfo.GetZoom();
1837 
1838  auto w = viewInfo.GetTracksUsableWidth();
1839  w -= 10;
1840  return w/len;
1841 }
1842 
1844 {
1845  auto &project = mProject;
1846  auto &viewInfo = ViewInfo::Get( project );
1847  auto &tracks = TrackList::Get( project );
1848  auto &window = *this;
1849 
1850  const double start = viewInfo.bScrollBeyondZero
1851  ? std::min(tracks.GetStartTime(), 0.0)
1852  : 0;
1853 
1854  window.Zoom( window.GetZoomOfToFit() );
1855  window.TP_ScrollWindow(start);
1856 }
1857 
1860  []( wxWindow &window ){
1861  auto pProjectWindow = dynamic_cast< ProjectWindow* >( &window );
1862  return pProjectWindow ? pProjectWindow->GetTopPanel() : nullptr;
1863  }
1864  );
size
size_t size
Definition: ffmpeg-2.3.6-single-header.h:412
VSBarID
@ VSBarID
Definition: ProjectWindow.cpp:568
WaveTrack.h
ProjectWindow::DoScroll
void DoScroll()
Definition: ProjectWindow.cpp:1439
RefreshCode::FixScrollbars
@ FixScrollbars
Definition: RefreshCode.h:27
ViewInfo::Get
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:241
monitor
EventMonitor monitor
AllProjects::begin
const_iterator begin() const
Definition: Project.cpp:24
ProjectWindow::TP_RedrawScrollbars
void TP_RedrawScrollbars() override
Definition: ProjectWindow.cpp:1654
sbarControlWidth
const int sbarControlWidth
Definition: ProjectWindow.cpp:779
TrackPanelMouseEvent.h
ProjectAudioIO::GetAudioIOToken
int GetAudioIOToken() const
Definition: ProjectAudioIO.cpp:41
ProjectStatus.h
ToolManager.h
ProjectWindow::Rewind
void Rewind(bool shift)
Definition: ProjectWindow.cpp:1606
Scrubber::Get
static Scrubber & Get(AudacityProject &project)
Definition: Scrubbing.cpp:201
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:69
ProjectWindow::mIconized
bool mIconized
Definition: ProjectWindow.h:191
ToolBarCount
@ ToolBarCount
Definition: ToolBar.h:87
ProjectWindow::OnScroll
void OnScroll(wxScrollEvent &event)
Definition: ProjectWindow.cpp:1421
ProjectWindow::UpdateLayout
void UpdateLayout()
Definition: ProjectWindow.cpp:1165
ProjectWindow::IsBeingDeleted
bool IsBeingDeleted() const
Definition: ProjectWindow.h:51
RefreshCode::RefreshAll
@ RefreshAll
Definition: RefreshCode.h:26
ProjectWindow::PlaybackScroller::mProject
AudacityProject * mProject
Definition: ProjectWindow.h:83
ToolFrame
class ToolFrame
Definition: ToolManager.h:166
ProjectWindow::FixScrollbars
void FixScrollbars()
Definition: ProjectWindow.cpp:1009
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
ClientData::Site::Find
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:333
AllThemeResources.h
TrackView.h
EVT_COMMAND
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
Definition: LabelDialog.cpp:92
ProjectWindow::GetTopPanel
wxPanel * GetTopPanel()
Definition: ProjectWindow.h:56
Project.h
ProjectWindow::OnUpdateUI
void OnUpdateUI(wxUpdateUIEvent &event)
Definition: ProjectWindow.cpp:1501
Track::EnsureVisible
void EnsureVisible(bool modifyState=false)
Definition: Track.cpp:100
wxPanelWrapper
Definition: wxPanelWrapper.h:41
ProjectWindow::OnMove
void OnMove(wxMoveEvent &event)
Definition: ProjectWindow.cpp:1329
wxPanelWrapper::SetLabel
void SetLabel(const TranslatableString &label)
Definition: wxPanelWrapper.cpp:46
ClientData::Site::Get
Subclass & Get(const RegisteredFactory &key)
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
Definition: ClientData.h:309
AllProjects::end
const_iterator end() const
Definition: Project.cpp:29
ProjectWindow::TP_ScrollWindow
void TP_ScrollWindow(double scrollto) override
Definition: ProjectWindow.cpp:969
StatusBarField
StatusBarField
Definition: ProjectStatus.h:24
TracksPrefs.h
ToolManager::Get
static ToolManager & Get(AudacityProject &project)
Definition: ToolManager.cpp:356
ProjectWindow::mHsbar
wxScrollBar * mHsbar
Definition: ProjectWindow.h:184
ProjectWindow::NextWindowID
int NextWindowID()
Definition: ProjectWindow.cpp:557
ProjectWindow::OnShow
void OnShow(wxShowEvent &event)
Definition: ProjectWindow.cpp:1354
anonymous_namespace{ProjectWindow.cpp}::sProjectWindowKey
AttachedWindows::RegisteredFactory sProjectWindowKey
Definition: ProjectWindow.cpp:502
ProjectWindow::mbInitializingScrollbar
bool mbInitializingScrollbar
Definition: ProjectWindow.h:176
TrackPanelAx.h
for
for(int ii=0, nn=names.size();ii< nn;++ii)
Definition: SpectrumVZoomHandle.cpp:276
RefreshCode::Cancelled
@ Cancelled
Definition: RefreshCode.h:23
ProjectWindow::GetZoomOfToFit
double GetZoomOfToFit() const
Definition: ProjectWindow.cpp:1823
wxPanelWrapper.h
sbarHjump
const int sbarHjump
Definition: ProjectWindow.cpp:781
ProjectStatus::GetStatusWidthFunctions
static const StatusWidthFunctions & GetStatusWidthFunctions()
Definition: ProjectStatus.cpp:67
Track::Any
bool Any() const
Definition: Track.cpp:370
ProjectWindow::PixelWidthBeforeTime
double PixelWidthBeforeTime(double scrollto) const
Definition: ProjectWindow.cpp:936
ProjectWindow::Get
static ProjectWindow & Get(AudacityProject &project)
Definition: ProjectWindow.cpp:535
ProjectWindow::ZoomOutByFactor
void ZoomOutByFactor(double ZoomFactor)
Definition: ProjectWindow.cpp:1806
ToolBar::ReCreateButtons
virtual void ReCreateButtons()
Definition: ToolBar.cpp:516
BasicUI::CallAfter
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Definition: BasicUI.cpp:38
ProjectWindowBase::mProject
AudacityProject & mProject
Definition: ProjectWindowBase.h:33
ProjectWindow::OnScrollRight
void OnScrollRight()
Definition: ProjectWindow.cpp:834
ProjectAudioIO::Get
static ProjectAudioIO & Get(AudacityProject &project)
Definition: ProjectAudioIO.cpp:22
FirstID
@ FirstID
Definition: ProjectWindow.cpp:563
Scrubber
Definition: Scrubbing.h:45
sbarSpaceWidth
const int sbarSpaceWidth
Definition: ProjectWindow.cpp:778
ProjectWindow::ZoomBy
void ZoomBy(double multiplier)
Definition: ProjectWindow.cpp:1590
ProjectAudioIO::IsAudioActive
bool IsAudioActive() const
Definition: ProjectAudioIO.cpp:51
CornersOnScreen
bool CornersOnScreen(wxRect &r)
Definition: ProjectWindow.cpp:59
ProjectWindow::MacShowUndockedToolbars
void MacShowUndockedToolbars(bool show)
Definition: ProjectWindow.cpp:1258
AllProjects::empty
bool empty() const
Definition: Project.h:46
ProjectWindowBase::GetProject
AudacityProject & GetProject()
Definition: ProjectWindowBase.h:29
CommonTrackPanelCell::InstallMouseWheelHook
static Hook InstallMouseWheelHook(const Hook &hook)
Definition: CommonTrackPanelCell.cpp:35
TrackList::GetEndTime
double GetEndTime() const
Definition: Track.cpp:1038
ThemePrefs.h
ProjectWindow::ScrollIntoView
void ScrollIntoView(double pos)
Definition: ProjectWindow.cpp:786
ProjectWindow::OnToolBarUpdate
void OnToolBarUpdate(wxCommandEvent &event)
Definition: ProjectWindow.cpp:1394
ProjectWindow::OnScrollRightButton
void OnScrollRightButton(wxScrollEvent &event)
Definition: ProjectWindow.cpp:880
ProjectWindow::~ProjectWindow
~ProjectWindow() override
Definition: ProjectWindow.cpp:677
AllProjects::rbegin
const_reverse_iterator rbegin() const
Definition: Project.cpp:34
ProjectWindow::ApplyUpdatedTheme
void ApplyUpdatedTheme()
Definition: ProjectWindow.cpp:703
ProjectWindow::OnActivate
void OnActivate(wxActivateEvent &event)
Definition: ProjectWindow.cpp:1507
Scrubber::IsScrollScrubbing
bool IsScrollScrubbing() const
Definition: Scrubbing.h:95
ProjectWindow::mIsDeleting
bool mIsDeleting
Definition: ProjectWindow.h:196
mainStatusBarField
@ mainStatusBarField
Definition: ProjectStatus.h:26
NextID
@ NextID
Definition: ProjectWindow.cpp:570
MenuManager::UpdateMenus
void UpdateMenus(bool checkActive=true)
Definition: Menus.cpp:635
ProjectWindow::HandleResize
void HandleResize()
Definition: ProjectWindow.cpp:1206
sbarExtraLen
const int sbarExtraLen
Definition: ProjectWindow.cpp:780
TracksPrefs::GetPinnedHeadPositionPreference
static double GetPinnedHeadPositionPreference()
Definition: TracksPrefs.cpp:406
ProjectWindow::Zoom
void Zoom(double level)
Definition: ProjectWindow.cpp:1571
ProjectWindow::SetHorizontalThumb
void SetHorizontalThumb(double scrollto)
Definition: ProjectWindow.cpp:946
ProjectWindow
A top-level window associated with a project, and handling scrollbars and zooming.
Definition: ProjectWindow.h:32
InstallTopPanelHook
Definition: ProjectWindow.cpp:1858
GetAttachedWindows
AUDACITY_DLL_API AttachedWindows & GetAttachedWindows(AudacityProject &project)
Definition: ProjectWindows.cpp:114
ProjectWindow::PlaybackScroller::Mode::Right
@ Right
anonymous_namespace{ProjectWindow.cpp}::MouseWheelHandler::MouseWheelHandler
MouseWheelHandler()
Definition: ProjectWindow.cpp:361
ToolManager::SetGetTopPanelHook
static GetTopPanelHook SetGetTopPanelHook(const GetTopPanelHook &)
Definition: ToolManager.cpp:342
TrackView::GetTotalHeight
static int GetTotalHeight(const TrackList &list)
Definition: TrackView.cpp:47
rateStatusBarField
@ rateStatusBarField
Definition: ProjectStatus.h:27
EVT_MENU
EVT_MENU(OnSetPlayRegionToSelectionID, AdornedRulerPanel::OnSetPlayRegionToSelection) EVT_COMMAND(OnTogglePinnedStateID
anonymous_namespace{ProjectWindow.cpp}::ScrollBar::ScrollBar
ScrollBar(wxWindow *parent, wxWindowID id, long style)
Definition: ProjectWindow.cpp:311
ProjectWindowBase
A top-level window associated with a project.
Definition: ProjectWindowBase.h:20
Scrubbing.h
HSBarID
@ HSBarID
Definition: ProjectWindow.cpp:567
UndoManager.h
TrackFocus::Get
Track * Get()
Definition: TrackPanelAx.cpp:755
WindowAccessible
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
ProjectWindow::mVsbar
wxScrollBar * mVsbar
Definition: ProjectWindow.h:185
ProjectWindow::UpdatePrefs
void UpdatePrefs() override
Definition: ProjectWindow.cpp:749
installTopPanelHook
static struct InstallTopPanelHook installTopPanelHook
ProjectWindow::OnUndoRedo
void OnUndoRedo(wxCommandEvent &)
Definition: ProjectWindow.cpp:1407
GetDefaultWindowRect
void GetDefaultWindowRect(wxRect *defRect)
Definition: ProjectWindow.cpp:92
ProjectWindow::DoZoomFit
void DoZoomFit()
Definition: ProjectWindow.cpp:1843
ViewInfo.h
anonymous_namespace{ProjectWindow.cpp}::MouseWheelHandler
Definition: ProjectWindow.cpp:359
Menus.h
ProjectWindow::PlaybackScroller::Mode::Pinned
@ Pinned
ProjectWindow::OnIconize
void OnIconize(wxIconizeEvent &event)
Definition: ProjectWindow.cpp:1290
theTheme
THEME_API Theme theTheme
Definition: Theme.cpp:79
ProjectWindows.h
accessors for certain important windows associated with each project
ScreenContaining
int ScreenContaining(wxRect &r)
Definition: ProjectWindow.cpp:44
id
int id
Definition: WaveTrackControls.cpp:577
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
ProjectWindow::UpdateStatusWidths
void UpdateStatusWidths()
Definition: ProjectWindow.cpp:1231
ProjectWindow::ScrollingLowerBoundTime
double ScrollingLowerBoundTime() const
Definition: ProjectWindow.cpp:923
ProjectWindow::OnMenu
void OnMenu(wxCommandEvent &event)
Definition: ProjectWindow.cpp:1472
ProjectWindow::OnMouseEvent
void OnMouseEvent(wxMouseEvent &event)
Definition: ProjectWindow.cpp:1544
ProjectWindow::SetNormalizedWindowState
void SetNormalizedWindowState(wxRect pSizeAndLocation)
Definition: ProjectWindow.h:92
ProjectWindow::SkipEnd
void SkipEnd(bool shift)
Definition: ProjectWindow.cpp:1626
WindowAccessible.h
ProjectWindow::PlaybackScroller::OnTimer
void OnTimer(wxCommandEvent &event)
Definition: ProjectWindow.cpp:1672
ProjectWindow::IsIconized
bool IsIconized() const override
Definition: ProjectWindow.cpp:1226
ProjectWindow::FinishAutoScroll
void FinishAutoScroll()
Definition: ProjectWindow.cpp:755
ProjectWindow::ProjectWindow
ProjectWindow(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, AudacityProject &project)
Definition: ProjectWindow.cpp:580
Scrubber::HandleScrollWheel
void HandleScrollWheel(int steps)
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:506
ProjectWindow::OnUndoReset
void OnUndoReset(wxCommandEvent &)
Definition: ProjectWindow.cpp:1414
ProjectWindow::OnThemeChange
void OnThemeChange(wxCommandEvent &evt)
Definition: ProjectWindow.cpp:735
ProjectWindow::TP_ScrollUpDown
bool TP_ScrollUpDown(int delta) override
Definition: ProjectWindow.cpp:983
IsWindowAccessible
bool IsWindowAccessible(wxRect *requestedRect)
Definition: ProjectWindow.cpp:66
ProjectWindow::ZoomAfterImport
void ZoomAfterImport(Track *pTrack)
Definition: ProjectWindow.cpp:1551
Track
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:239
_
#define _(s)
Definition: Internat.h:75
AudioIO.h
ProjectWindow::OnScrollLeft
void OnScrollLeft()
Definition: ProjectWindow.cpp:811
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
ProjectWindow::ZoomInByFactor
void ZoomInByFactor(double ZoomFactor)
Definition: ProjectWindow.cpp:1726
ProjectWindow::mNextWindowID
int mNextWindowID
Definition: ProjectWindow.h:187
Scrubber::IsScrubbing
bool IsScrubbing() const
SetActiveProject
void SetActiveProject(AudacityProject *project)
Definition: ActiveProject.cpp:29
ProjectWindow::MayScrollBeyondZero
bool MayScrollBeyondZero() const
Definition: ProjectWindow.cpp:902
ProjectWindow::mShownOnce
bool mShownOnce
Definition: ProjectWindow.h:192
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
ProjectWindow::Find
static ProjectWindow * Find(AudacityProject *pProject)
Definition: ProjectWindow.cpp:545
TrackPanelMouseEvent
Definition: TrackPanelMouseEvent.h:46
ProjectWindow::PlaybackScroller::PlaybackScroller
PlaybackScroller(AudacityProject *project)
Definition: ProjectWindow.cpp:1664
MenuManager::Get
static MenuManager & Get(AudacityProject &project)
Definition: Menus.cpp:70
AllProjects
Definition: Project.h:35
ToolBar
Works with ToolManager and ToolDock to provide a dockable window in which buttons can be placed.
Definition: ToolBar.h:98
ActiveProject.h
Handle changing of active project and keep global project pointer.
ProjectWindow::mActive
bool mActive
Definition: ProjectWindow.h:190
ThemeBase::Colour
wxColour & Colour(int iIndex)
Definition: Theme.cpp:1189
GetNextWindowPlacement
void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized)
Definition: ProjectWindow.cpp:139
RefreshCode.h
ProjectWindow::TP_HandleResize
void TP_HandleResize() override
Definition: ProjectWindow.cpp:1659
anonymous_namespace{ProjectWindow.cpp}::sMouseWheelHandler
static struct anonymous_namespace{ProjectWindow.cpp}::MouseWheelHandler sMouseWheelHandler
anonymous_namespace{ProjectWindow.cpp}::ScrollBar::OnSetFocus
void OnSetFocus(wxFocusEvent &e)
Definition: ProjectWindow.cpp:316
ProjectWindow::OnSize
void OnSize(wxSizeEvent &event)
Definition: ProjectWindow.cpp:1336
ProjectWindow.h
ProjectWindow::RedrawProject
void RedrawProject(const bool bForceWaveTracks=false)
Definition: ProjectWindow.cpp:710
GetProjectPanel
AUDACITY_DLL_API wxWindow & GetProjectPanel(AudacityProject &project)
Get the main sub-window of the project frame that displays track data.
Definition: ProjectWindows.cpp:49
CommandManager::Get
static CommandManager & Get(AudacityProject &project)
Definition: CommandManager.cpp:207
AudioIO::Get
static AudioIO * Get()
Definition: AudioIO.cpp:141
ProjectWindow::OnUndoPushedModified
void OnUndoPushedModified(wxCommandEvent &)
Definition: ProjectWindow.cpp:1401
safenew
#define safenew
Definition: MemoryX.h:10
RefreshCode
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
ProjectWindow::TP_ScrollLeft
void TP_ScrollLeft() override
Definition: ProjectWindow.cpp:1642
anonymous_namespace{LogWindow.cpp}::OnCloseWindow
void OnCloseWindow(wxCloseEvent &e)
anonymous_namespace{ProjectWindow.cpp}::ScrollBar
Definition: ProjectWindow.cpp:309
ProjectWindow::OnScrollLeftButton
void OnScrollLeftButton(wxScrollEvent &event)
Definition: ProjectWindow.cpp:859
InstallTopPanelHook::InstallTopPanelHook
InstallTopPanelHook()
Definition: ProjectWindow.cpp:1858
END_EVENT_TABLE
END_EVENT_TABLE()
TrackList::empty
bool empty() const
Definition: Track.cpp:995
ProjectAudioIO.h
MenuManager::GetUpdateFlags
CommandFlag GetUpdateFlags(bool checkActive=false) const
Definition: Menus.cpp:545
AllProjects::value_type
Container::value_type value_type
Definition: Project.h:56
ProjectWindow::IsActive
bool IsActive() override
Definition: ProjectWindow.cpp:1539
nStatusBarFields
@ nStatusBarFields
Definition: ProjectStatus.h:29
AllProjects::rend
const_reverse_iterator rend() const
Definition: Project.cpp:39
ProjectWindow::mAutoScrolling
bool mAutoScrolling
Definition: ProjectWindow.h:189
WaveClip.h
ProjectWindow::mPlaybackScroller
std::unique_ptr< PlaybackScroller > mPlaybackScroller
Definition: ProjectWindow.h:200
ProjectWindow::TP_ScrollRight
void TP_ScrollRight() override
Definition: ProjectWindow.cpp:1648