Audacity  3.2.0
TrackPanel.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  TrackPanel.cpp
6 
7  Dominic Mazzoni
8  and lots of other contributors
9 
10  Implements TrackPanel.
11 
12 ********************************************************************//***************************************************************//*****************************************************************//*****************************************************************/
45 
46 
47 #include "TrackPanel.h"
48 #include "TrackPanelConstants.h"
49 
50 #include <wx/setup.h> // for wxUSE_* macros
51 
52 #include "AdornedRulerPanel.h"
54 #include "KeyboardCapture.h"
55 #include "Project.h"
56 #include "ProjectAudioIO.h"
57 #include "ProjectAudioManager.h"
58 #include "ProjectHistory.h"
59 #include "ProjectWindows.h"
60 #include "ProjectSettings.h"
61 #include "ProjectStatus.h"
62 #include "ProjectWindow.h"
63 #include "Theme.h"
64 #include "TrackArt.h"
65 #include "TrackPanelMouseEvent.h"
66 #include "TrackPanelResizeHandle.h"
67 //#define DEBUG_DRAW_TIMING 1
68 
69 #include "UndoManager.h"
70 
71 #include "AColor.h"
72 #include "AllThemeResources.h"
73 #include "AudioIO.h"
74 #include "float_cast.h"
75 
76 #include "Prefs.h"
77 #include "RefreshCode.h"
78 #include "TrackArtist.h"
79 #include "TrackPanelAx.h"
80 #include "TrackPanelResizerCell.h"
81 #include "WaveTrack.h"
82 
84 #include "tracks/ui/TrackView.h"
86 
87 //This loads the appropriate set of cursors, depending on platform.
88 #include "../images/Cursors.h"
89 
90 #include <algorithm>
91 
92 #include <wx/dc.h>
93 #include <wx/dcclient.h>
94 #include <wx/graphics.h>
95 
96 static_assert( kVerticalPadding == kTopMargin + kBottomMargin );
97 static_assert( kTrackInfoBtnSize == kAffordancesAreaHeight, "Drag bar is misaligned with the menu button");
98 
162 // Is the distance between A and B less than D?
163 template < class A, class B, class DIST > bool within(A a, B b, DIST d)
164 {
165  return (a > b - d) && (a < b + d);
166 }
167 
168 BEGIN_EVENT_TABLE(TrackPanel, CellularPanel)
169  EVT_MOUSE_EVENTS(TrackPanel::OnMouseEvent)
170  EVT_KEY_DOWN(TrackPanel::OnKeyDown)
171 
172  EVT_PAINT(TrackPanel::OnPaint)
173 
174  EVT_TIMER(wxID_ANY, TrackPanel::OnTimer)
175 
176  EVT_SIZE(TrackPanel::OnSize)
177 
179 
180 std::unique_ptr<wxCursor> MakeCursor( int WXUNUSED(CursorId), const char * const pXpm[36], int HotX, int HotY )
183 {
184 #define CURSORS_SIZE32
185 #ifdef CURSORS_SIZE32
186  const int HotAdjust =0;
187 #else
188  const int HotAdjust =8;
189 #endif
190 
191  wxImage Image = wxImage(wxBitmap(pXpm).ConvertToImage());
192  Image.SetMaskColour(255,0,0);
193  Image.SetMask();// Enable mask.
194 
195  Image.SetOption( wxIMAGE_OPTION_CUR_HOTSPOT_X, HotX-HotAdjust );
196  Image.SetOption( wxIMAGE_OPTION_CUR_HOTSPOT_Y, HotY-HotAdjust );
197  return std::make_unique<wxCursor>( Image );
198 }
199 
200 
201 namespace{
202 
203 AttachedWindows::RegisteredFactory sKey{
204  []( AudacityProject &project ) -> wxWeakRef< wxWindow > {
205  auto &ruler = AdornedRulerPanel::Get( project );
206  auto &viewInfo = ViewInfo::Get( project );
207  auto &window = ProjectWindow::Get( project );
208  auto mainPage = window.GetMainPage();
209  wxASSERT( mainPage ); // to justify safenew
210 
211  auto &tracks = TrackList::Get( project );
212  auto result = safenew TrackPanel(mainPage,
213  window.NextWindowID(),
214  wxDefaultPosition,
215  wxDefaultSize,
216  tracks.shared_from_this(),
217  &viewInfo,
218  &project,
219  &ruler);
220  SetProjectPanel( project, *result );
221  return result;
222  }
223 };
224 
225 }
226 
228 {
229  return GetAttachedWindows(project).Get< TrackPanel >( sKey );
230 }
231 
233 {
234  return Get( const_cast< AudacityProject & >( project ) );
235 }
236 
238 {
239  auto *pPanel = GetAttachedWindows(project).Find<TrackPanel>( sKey );
240  if (pPanel) {
241  pPanel->wxWindow::Destroy();
242  GetAttachedWindows(project).Assign(sKey, nullptr);
243  }
244 }
245 
246 // Don't warn us about using 'this' in the base member initializer list.
247 #ifndef __WXGTK__ //Get rid if this pragma for gtk
248 #pragma warning( disable: 4355 )
249 #endif
250 TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
251  const wxPoint & pos,
252  const wxSize & size,
253  const std::shared_ptr<TrackList> &tracks,
254  ViewInfo * viewInfo,
255  AudacityProject * project,
257  : CellularPanel(parent, id, pos, size, viewInfo,
258  wxWANTS_CHARS | wxNO_BORDER),
259  mListener( &ProjectWindow::Get( *project ) ),
260  mTracks(tracks),
261  mRuler(ruler),
262  mTrackArtist(nullptr),
263  mRefreshBacking(false)
264 #ifndef __WXGTK__ //Get rid if this pragma for gtk
265 #pragma warning( default: 4355 )
266 #endif
267 {
268  SetLayoutDirection(wxLayout_LeftToRight);
269  SetLabel(XO("Track Panel"));
270  SetName(XO("Track Panel"));
271  SetBackgroundStyle(wxBG_STYLE_PAINT);
272 
273  {
274  auto pAx = std::make_unique <TrackPanelAx>( *project );
275  pAx->SetWindow( this );
276  wxWeakRef< TrackPanel > weakThis{ this };
277  pAx->SetFinder(
278  [weakThis]( const Track &track ) -> wxRect {
279  if (weakThis)
280  return weakThis->FindTrackRect( &track );
281  return {};
282  }
283  );
284  TrackFocus::Get( *GetProject() ).SetAccessible(
285  *this, std::move( pAx ) );
286  }
287 
288  mTrackArtist = std::make_unique<TrackArtist>( this );
289 
290  mTimeCount = 0;
291  mTimer.parent = this;
292  // Timer is started after the window is visible
293  ProjectWindow::Get( *GetProject() ).Bind(wxEVT_IDLE,
294  &TrackPanel::OnIdle, this);
295 
296  // Register for tracklist updates
298  mTracks->Subscribe([this](const TrackListEvent &event){
299  switch (event.mType) {
300  case TrackListEvent::RESIZING:
301  case TrackListEvent::ADDITION:
302  OnTrackListResizing(event); break;
303  case TrackListEvent::DELETION:
304  OnTrackListDeletion(); break;
305  case TrackListEvent::TRACK_REQUEST_VISIBLE:
306  OnEnsureVisible(event); break;
307  default:
308  break;
309  }
310  });
311 
312  auto theProject = GetProject();
313  theProject->Bind(
314  EVT_PROJECT_SETTINGS_CHANGE, &TrackPanel::OnProjectSettingsChange, this);
315  theProject->Bind(
316  EVT_TRACK_FOCUS_CHANGE, &TrackPanel::OnTrackFocusChange, this );
317 
318  theProject->Bind(EVT_UNDO_RESET, &TrackPanel::OnUndoReset, this);
319 
322  UpdatePrefs();
323 }
324 
325 
326 TrackPanel::~TrackPanel()
327 {
328  mTimer.Stop();
329 
330  // This can happen if a label is being edited and the user presses
331  // ALT+F4 or Command+Q
332  if (HasCapture())
333  ReleaseMouse();
334 }
335 
337 {
338  // All vertical rulers must be recalculated since the minimum and maximum
339  // frequencies may have been changed.
340  UpdateVRulers();
341 
342  Refresh();
343 }
344 
348 {
349  //JKC casting away constness here.
350  //Do it in two stages in case 'this' is not a wxWindow.
351  //when the compiler will flag the error.
352  wxWindow const * const pConstWind = this;
353  wxWindow * pWind=(wxWindow*)pConstWind;
354 #ifdef EXPERIMENTAL_NOTEBOOK
355  pWind = pWind->GetParent(); //Page
356  wxASSERT( pWind );
357  pWind = pWind->GetParent(); //Notebook
358  wxASSERT( pWind );
359 #endif
360  pWind = pWind->GetParent(); //MainPanel
361  wxASSERT( pWind );
362  pWind = pWind->GetParent(); //ProjectWindow
363  wxASSERT( pWind );
364  return &static_cast<ProjectWindow*>( pWind )->GetProject();
365 }
366 
367 void TrackPanel::OnSize( wxSizeEvent &evt )
368 {
369  evt.Skip();
370  const auto &size = evt.GetSize();
371  mViewInfo->SetWidth( size.GetWidth() );
372  mViewInfo->SetHeight( size.GetHeight() );
373 }
374 
375 void TrackPanel::OnIdle(wxIdleEvent& event)
376 {
377  event.Skip();
378  // The window must be ready when the timer fires (#1401)
379  if (IsShownOnScreen())
380  {
381  mTimer.Start(std::chrono::milliseconds{kTimerInterval}.count(), FALSE);
382 
383  // Timer is started, we don't need the event anymore
384  GetProjectFrame( *GetProject() ).Unbind(wxEVT_IDLE,
385  &TrackPanel::OnIdle, this);
386  }
387  else
388  {
389  // Get another idle event, wx only guarantees we get one
390  // event after "some other normal events occur"
391  event.RequestMore();
392  }
393 }
394 
396 void TrackPanel::OnTimer(wxTimerEvent& )
397 {
398  mTimeCount++;
399 
400  AudacityProject *const p = GetProject();
401  auto &window = ProjectWindow::Get( *p );
402 
403  auto &projectAudioIO = ProjectAudioIO::Get( *p );
404  auto gAudioIO = AudioIO::Get();
405 
406  // Check whether we were playing or recording, but the stream has stopped.
407  if (projectAudioIO.GetAudioIOToken()>0 && !IsAudioActive())
408  {
409  //the stream may have been started up after this one finished (by some other project)
410  //in that case reset the buttons don't stop the stream
411  auto &projectAudioManager = ProjectAudioManager::Get( *p );
412  projectAudioManager.Stop(!gAudioIO->IsStreamActive());
413  }
414 
415  // Next, check to see if we were playing or recording
416  // audio, but now Audio I/O is completely finished.
417  if (projectAudioIO.GetAudioIOToken()>0 &&
418  !gAudioIO->IsAudioTokenActive(projectAudioIO.GetAudioIOToken()))
419  {
420  projectAudioIO.SetAudioIOToken(0);
421  window.RedrawProject();
422  }
425  }
426 
427  // Notify listeners for timer ticks
428  window.GetPlaybackScroller().OnTimer();
429 
430  DrawOverlays(false);
431  mRuler->DrawOverlays(false);
432 
433  if(IsAudioActive() && gAudioIO->GetNumCaptureChannels()) {
434 
435  // Periodically update the display while recording
436 
437  if ((mTimeCount % 5) == 0) {
438  // Must tell OnPaint() to recreate the backing bitmap
439  // since we've not done a full refresh.
440  mRefreshBacking = true;
441  Refresh( false );
442  }
443  }
444  if(mTimeCount > 1000)
445  mTimeCount = 0;
446 }
447 
448 void TrackPanel::OnProjectSettingsChange( wxCommandEvent &event )
449 {
450  event.Skip();
451  switch ( static_cast<ProjectSettings::EventCode>( event.GetInt() ) ) {
453  Refresh(false);
454  break;
455  default:
456  break;
457  }
458 }
459 
460 void TrackPanel::OnUndoReset( wxCommandEvent &event )
461 {
462  event.Skip();
463  TrackFocus::Get( *GetProject() ).Set( nullptr );
464  Refresh( false );
465 }
466 
469 void TrackPanel::OnPaint(wxPaintEvent & /* event */)
470 {
472 
473 #if DEBUG_DRAW_TIMING
474  wxStopWatch sw;
475 #endif
476 
477  {
478  wxPaintDC dc(this);
479 
480  // Retrieve the damage rectangle
481  wxRect box = GetUpdateRegion().GetBox();
482 
483  // Recreate the backing bitmap if we have a full refresh
484  // (See TrackPanel::Refresh())
485  if (mRefreshBacking || (box == GetRect()))
486  {
487  // Reset (should a mutex be used???)
488  mRefreshBacking = false;
489 
490  // Redraw the backing bitmap
492 
493  // Copy it to the display
494  DisplayBitmap(dc);
495  }
496  else
497  {
498  // Copy full, possibly clipped, damage rectangle
499  RepairBitmap(dc, box.x, box.y, box.width, box.height);
500  }
501 
502  // Done with the clipped DC
503 
504  // Drawing now goes directly to the client area.
505  // DrawOverlays() may need to draw outside the clipped region.
506  // (Used to make a NEW, separate wxClientDC, but that risks flashing
507  // problems on Mac.)
508  dc.DestroyClippingRegion();
509  DrawOverlays(true, &dc);
510  }
511 
512 #if DEBUG_DRAW_TIMING
513  sw.Pause();
514  wxLogDebug(wxT("Total: %ld milliseconds"), sw.Time());
515  wxPrintf(wxT("Total: %ld milliseconds\n"), sw.Time());
516 #endif
517 }
518 
520 {
522 }
523 
524 namespace {
525  std::shared_ptr<Track> FindTrack(TrackPanelCell *pCell )
526  {
527  if (pCell)
528  return static_cast<CommonTrackPanelCell*>( pCell )->FindTrack();
529  return {};
530  }
531 }
532 
534  (TrackPanelCell *pClickedCell, TrackPanelCell *pLatestCell,
535  UIHandle::Result refreshResult)
536 {
537  const auto panel = this;
538  auto pLatestTrack = FindTrack( pLatestCell ).get();
539 
540  // This precaution checks that the track is not only nonnull, but also
541  // really owned by the track list
542  auto pClickedTrack = GetTracks()->Lock(
543  std::weak_ptr<Track>{ FindTrack( pClickedCell ) }
544  ).get();
545 
546  // TODO: make a finer distinction between refreshing the track control area,
547  // and the waveform area. As it is, redraw both whenever you must redraw either.
548 
549  // Copy data from the underlying tracks to the pending tracks that are
550  // really displayed
551  TrackList::Get( *panel->GetProject() ).UpdatePendingTracks();
552 
553  using namespace RefreshCode;
554 
555  if (refreshResult & DestroyedCell) {
556  panel->UpdateViewIfNoTracks();
557  // Beware stale pointer!
558  if (pLatestTrack == pClickedTrack)
559  pLatestTrack = NULL;
560  pClickedTrack = NULL;
561  }
562 
563  if (pClickedTrack && (refreshResult & RefreshCode::UpdateVRuler))
564  panel->UpdateVRuler(pClickedTrack);
565 
566  if (refreshResult & RefreshCode::DrawOverlays) {
567  panel->DrawOverlays(false);
568  mRuler->DrawOverlays(false);
569  }
570 
571  // Refresh all if told to do so, or if told to refresh a track that
572  // is not known.
573  const bool refreshAll =
574  ( (refreshResult & RefreshAll)
575  || ((refreshResult & RefreshCell) && !pClickedTrack)
576  || ((refreshResult & RefreshLatestCell) && !pLatestTrack));
577 
578  if (refreshAll)
579  panel->Refresh(false);
580  else {
581  if (refreshResult & RefreshCell)
582  panel->RefreshTrack(pClickedTrack);
583  if (refreshResult & RefreshLatestCell)
584  panel->RefreshTrack(pLatestTrack);
585  }
586 
587  if (refreshResult & FixScrollbars)
588  panel->MakeParentRedrawScrollbars();
589 
590  if (refreshResult & Resize)
591  panel->GetListener()->TP_HandleResize();
592 
593  if ((refreshResult & RefreshCode::EnsureVisible) && pClickedTrack) {
594  TrackFocus::Get(*GetProject()).Set(pClickedTrack);
595  pClickedTrack->EnsureVisible();
596  }
597 }
598 
600 {
602 }
603 
605 {
607 }
608 
610 {
612  return ProjectAudioIO::Get( *p ).IsAudioActive();
613 }
614 
616 {
617  auto status = st;
618  if (HasEscape())
619  /* i18n-hint Esc is a key on the keyboard */
620  status.Join( XO("(Esc to cancel)"), " " );
621  ProjectStatus::Get( *GetProject() ).Set( status );
622 }
623 
625 {
626  // Full refresh since the label area may need to indicate
627  // newly selected tracks.
628  Refresh(false);
629 
630  // Make sure the ruler follows suit.
632 }
633 
634 // Counts selected tracks, counting stereo tracks as one track.
636 {
637  return GetTracks()->SelectedLeaders().size();
638 }
639 
641 {
642  if (mTracks->empty())
643  {
644  // BG: There are no more tracks on screen
645  //BG: Set zoom to normal
647 
648  //STM: Set selection to 0,0
649  //PRL: and default the rest of the selection information
651 
652  // PRL: Following causes the time ruler to align 0 with left edge.
653  // Bug 972
654  mViewInfo->h = 0;
655 
657  //STM: Clear message if all tracks are removed
659  }
660 }
661 
662 // The tracks positions within the list have changed, so update the vertical
663 // ruler size for the track that triggered the event.
665 {
666  auto t = e.mpTrack.lock();
667  // A deleted track can trigger the event. In which case do nothing here.
668  // A deleted track can have a valid pointer but no owner, bug 2060
669  if( t && t->HasOwner() )
670  UpdateVRuler(t.get());
671 
672  // fix for bug 2477
674 }
675 
676 // Tracks have been removed from the list.
678 {
679  // copy shared_ptr for safety, as in HandleClick
680  auto handle = Target();
681  if (handle) {
682  handle->OnProjectChange(GetProject());
683  }
684 
685  // If the focused track disappeared but there are still other tracks,
686  // this reassigns focus.
687  TrackFocus( *GetProject() ).Get();
688 
690 }
691 
692 void TrackPanel::OnKeyDown(wxKeyEvent & event)
693 {
694  switch (event.GetKeyCode())
695  {
696  // Allow PageUp and PageDown keys to
697  //scroll the Track Panel left and right
698  case WXK_PAGEUP:
699  HandlePageUpKey();
700  return;
701 
702  case WXK_PAGEDOWN:
704  return;
705 
706  default:
707  // fall through to base class handler
708  event.Skip();
709  }
710 }
711 
712 void TrackPanel::OnMouseEvent(wxMouseEvent & event)
713 {
714  if (event.LeftDown()) {
715  // wxTimers seem to be a little unreliable, so this
716  // "primes" it to make sure it keeps going for a while...
717 
718  // When this timer fires, we call TrackPanel::OnTimer and
719  // possibly update the screen for offscreen scrolling.
720  mTimer.Stop();
721  mTimer.Start(std::chrono::milliseconds{kTimerInterval}.count(), FALSE);
722  }
723 
724 
725  if (event.ButtonUp()) {
726  //EnsureVisible should be called after processing the up-click.
727  this->CallAfter( [this, event]{
728  const auto foundCell = FindCell(event.m_x, event.m_y);
729  const auto t = FindTrack( foundCell.pCell.get() );
730  if ( t ) {
731  TrackFocus::Get(*GetProject()).Set(t.get());
732  t->EnsureVisible();
733  }
734  } );
735  }
736 
737  // Must also fall through to base class handler
738  event.Skip();
739 }
740 
742 {
743  return mViewInfo->PositionToTime(
745 }
746 
747 void TrackPanel::RefreshTrack(Track *trk, bool refreshbacking)
748 {
749  if (!trk)
750  return;
751 
752  // Always move to the first channel of the group, and use only
753  // the sum of channel heights, not the height of any channel alone!
754  trk = *GetTracks()->FindLeader(trk);
755  auto &view = TrackView::Get( *trk );
756  auto height =
758 
759  // Set rectangle top according to the scrolling position, `vpos`
760  // Subtract the inset (above) and shadow (below) from the height of the
761  // rectangle, but not the border
762  // This matters because some separators do paint over the border
763  const auto top =
764  -mViewInfo->vpos + view.GetCumulativeHeightBefore() + kTopInset;
765  height -= (kTopInset + kShadowThickness);
766 
767  // Width also subtracts insets (left and right) plus shadow (right)
768  const auto left = kLeftInset;
769  const auto width = GetRect().GetWidth()
771 
772  wxRect rect(left, top, width, height);
773 
774  if( refreshbacking )
775  mRefreshBacking = true;
776 
777  Refresh( false, &rect );
778 }
779 
780 
785 void TrackPanel::Refresh(bool eraseBackground /* = TRUE */,
786  const wxRect *rect /* = NULL */)
787 {
788  // Tell OnPaint() to refresh the backing bitmap.
789  //
790  // Originally I had the check within the OnPaint() routine and it
791  // was working fine. That was until I found that, even though a full
792  // refresh was requested, Windows only set the onscreen portion of a
793  // window as damaged.
794  //
795  // So, if any part of the trackpanel was off the screen, full refreshes
796  // didn't work and the display got corrupted.
797  if( !rect || ( *rect == GetRect() ) )
798  {
799  mRefreshBacking = true;
800  }
801  wxWindow::Refresh(eraseBackground, rect);
802 
804 }
805 
807 {
808  if (evt.type == AudioIOEvent::MONITOR)
809  return;
810  // Some hit tests want to change their cursor to and from the ban symbol
812 }
813 
815 
819 void TrackPanel::DrawTracks(wxDC * dc)
820 {
821  wxRegion region = GetUpdateRegion();
822 
823  const wxRect clip = GetRect();
824 
826  mTrackArtist->pSelectedRegion = &sr;
827  mTrackArtist->pZoomInfo = mViewInfo;
828  TrackPanelDrawingContext context {
829  *dc, Target(), mLastMouseState, mTrackArtist.get()
830  };
831 
832  // Don't draw a bottom margin here.
833 
834  const auto &settings = ProjectSettings::Get( *GetProject() );
835  bool bMultiToolDown =
836  (ToolCodes::multiTool == settings.GetTool());
837  bool envelopeFlag =
838  bMultiToolDown || (ToolCodes::envelopeTool == settings.GetTool());
839  bool bigPointsFlag =
840  bMultiToolDown || (ToolCodes::drawTool == settings.GetTool());
841  bool sliderFlag = bMultiToolDown;
842  bool brushFlag = false;
843 #ifdef EXPERIMENTAL_BRUSH_TOOL
844  brushFlag = (ToolCodes::brushTool == settings.GetTool());
845 #endif
846 
847  const bool hasSolo = GetTracks()->Any< PlayableTrack >()
848  .any_of( []( const PlayableTrack *pt ) {
849  pt = static_cast< const PlayableTrack * >(
850  pt->SubstitutePendingChangedTrack().get() );
851  return (pt && pt->GetSolo());
852  } );
853 
854  mTrackArtist->drawEnvelope = envelopeFlag;
855  mTrackArtist->bigPoints = bigPointsFlag;
856  mTrackArtist->drawSliders = sliderFlag;
857  mTrackArtist->onBrushTool = brushFlag;
858  mTrackArtist->hasSolo = hasSolo;
859 
860  this->CellularPanel::Draw( context, TrackArtist::NPasses );
861 }
862 
864 (const std::shared_ptr< CommonTrackPanelCell > &pCell)
865 {
866  mpBackground = pCell;
867 }
868 
869 std::shared_ptr< CommonTrackPanelCell > TrackPanel::GetBackgroundCell()
870 {
871  return mpBackground;
872 }
873 
874 namespace {
875 std::vector<int> FindAdjustedChannelHeights( Track &t )
876 {
877  auto channels = TrackList::Channels(&t);
878  wxASSERT(!channels.empty());
879 
880  // Collect heights, and count affordances
881  int nAffordances = 0;
882  int totalHeight = 0;
883  std::vector<int> oldHeights;
884  for (auto channel : channels) {
885  auto &view = TrackView::Get( *channel );
886  const auto height = view.GetHeight();
887  totalHeight += height;
888  oldHeights.push_back( height );
889  if (view.GetAffordanceControls())
890  ++nAffordances;
891  }
892 
893  // Allocate results
894  auto nChannels = static_cast<int>(oldHeights.size());
895  std::vector<int> results;
896  results.reserve(nChannels);
897 
898  // Now reallocate the channel heights for the presence of affordances
899  // and separators
900  auto availableHeight = totalHeight
901  - nAffordances * kAffordancesAreaHeight
902  - (nChannels - 1) * kChannelSeparatorThickness
904  int cumulativeOldHeight = 0;
905  int cumulativeNewHeight = 0;
906  for (const auto &oldHeight : oldHeights) {
907  // Preserve the porportions among the stored heights
908  cumulativeOldHeight += oldHeight;
909  const auto newHeight =
910  cumulativeOldHeight * availableHeight / totalHeight
911  - cumulativeNewHeight;
912  cumulativeNewHeight += newHeight;
913  results.push_back(newHeight);
914  }
915 
916  return results;
917 }
918 }
919 
921 {
922  for (auto t : GetTracks()->Any< WaveTrack >())
924 
926 }
927 
929 {
930  if (t)
932 
934 }
935 
937 {
938  wxASSERT(t);
939  if (!t)
940  return;
941 
942  auto heights = FindAdjustedChannelHeights(*t);
943 
944  wxRect rect(mViewInfo->GetVRulerOffset(),
945  0,
947  0);
948 
949  auto pHeight = heights.begin();
950  for (auto channel : TrackList::Channels(t)) {
951  auto &view = TrackView::Get( *channel );
952  const auto height = *pHeight++;
953  rect.SetHeight( height );
954  const auto subViews = view.GetSubViews( rect );
955  if (subViews.empty())
956  continue;
957 
958  auto iter = subViews.begin(), end = subViews.end(), next = iter;
959  auto yy = iter->first;
960  wxSize vRulerSize{ 0, 0 };
961  for ( ; iter != end; iter = next ) {
962  ++next;
963  auto nextY = ( next == end )
964  ? height
965  : next->first;
966  rect.SetHeight( nextY - yy );
967  // This causes ruler size in the track to be reassigned:
968  TrackVRulerControls::Get( *iter->second ).UpdateRuler( rect );
969  // But we want to know the maximum width and height over all sub-views:
970  vRulerSize.IncTo( {t->vrulerSize.first, t->vrulerSize.second} );
971  yy = nextY;
972  }
973  t->vrulerSize = {vRulerSize.x, vRulerSize.y};
974  }
975 }
976 
978 {
979  auto trackRange = GetTracks()->Any();
980  if (trackRange) {
981  wxSize s { 0, 0 };
982  for (auto t : trackRange)
983  s.IncTo({t->vrulerSize.first, t->vrulerSize.second});
984 
985  if (mViewInfo->GetVRulerWidth() != s.GetWidth()) {
986  mViewInfo->SetVRulerWidth( s.GetWidth() );
988  mViewInfo->GetLeftOffset()); // bevel on AdornedRuler
989  mRuler->Refresh();
990  }
991  }
992  Refresh(false);
993 }
994 
996 {
997  CellularPanel::DoContextMenu( t ? &TrackView::Get( *t ) : nullptr );
998 }
999 
1000 // Tracks have been removed from the list.
1002 {
1003  bool modifyState = e.mExtra;
1004 
1005  auto pTrack = e.mpTrack.lock();
1006  auto t = pTrack.get();
1007 
1008  int trackTop = 0;
1009  int trackHeight =0;
1010 
1011  for (auto it : GetTracks()->Leaders()) {
1012  trackTop += trackHeight;
1013 
1014  auto channels = TrackList::Channels(it);
1015  trackHeight = channels.sum( TrackView::GetTrackHeight );
1016 
1017  //We have found the track we want to ensure is visible.
1018  if (channels.contains(t)) {
1019 
1020  //Get the size of the trackpanel.
1021  int width, height;
1022  GetSize(&width, &height);
1023 
1024  if (trackTop < mViewInfo->vpos) {
1025  height = mViewInfo->vpos - trackTop + mViewInfo->scrollStep;
1026  height /= mViewInfo->scrollStep;
1027  mListener->TP_ScrollUpDown(-height);
1028  }
1029  else if (trackTop + trackHeight > mViewInfo->vpos + height) {
1030  height = (trackTop + trackHeight) - (mViewInfo->vpos + height);
1031  height = (height + mViewInfo->scrollStep + 1) / mViewInfo->scrollStep;
1032  mListener->TP_ScrollUpDown(height);
1033  }
1034 
1035  break;
1036  }
1037  }
1038  Refresh(false);
1039 
1040  if ( modifyState )
1042 }
1043 
1044 // 0.0 scrolls to top
1045 // 1.0 scrolls to bottom.
1046 void TrackPanel::VerticalScroll( float fracPosition){
1047 
1048  int trackTop = 0;
1049  int trackHeight = 0;
1050 
1051  auto tracks = GetTracks();
1052 
1053  auto range = tracks->Leaders();
1054  if (!range.empty()) {
1055  trackHeight = TrackView::GetChannelGroupHeight( *range.rbegin() );
1056  --range.second;
1057  }
1058  trackTop = range.sum( TrackView::GetChannelGroupHeight );
1059 
1060  int delta;
1061 
1062  //Get the size of the trackpanel.
1063  int width, height;
1064  GetSize(&width, &height);
1065 
1066  delta = (fracPosition * (trackTop + trackHeight - height)) - mViewInfo->vpos + mViewInfo->scrollStep;
1067  //wxLogDebug( "Scroll down by %i pixels", delta );
1068  delta /= mViewInfo->scrollStep;
1069  mListener->TP_ScrollUpDown(delta);
1070  Refresh(false);
1071 }
1072 
1073 
1074 namespace {
1075  // Drawing constants
1076  // DisplaceX and MarginX are large enough to avoid overwriting <- symbol
1077  // See TrackArt::DrawNegativeOffsetTrackArrows
1078  enum : int {
1079  // Displacement of the rectangle from upper left corner
1081  // Size of margins about the text extent that determine the rectangle size
1082  MarginX = 8, MarginY = 2,
1083  // Derived constants
1085  };
1086 
1088  wxDC &dc, const Track *t, wxCoord *pW, wxCoord *pH )
1089 {
1090  wxFont labelFont(12, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1091  dc.SetFont(labelFont);
1092  dc.GetTextExtent( t->GetName(), pW, pH );
1093 }
1094 
1096  int leftOffset,
1097  const wxRect &trackRect, wxCoord textWidth, wxCoord textHeight )
1098 {
1099  return {
1100  leftOffset + DisplaceX,
1101  trackRect.y + DisplaceY,
1102  textWidth + MarginsX,
1103  textHeight + MarginsY
1104  };
1105 }
1106 
1107 // Draws the track name on the track, if it is needed.
1109  int leftOffset,
1110  TrackPanelDrawingContext &context, const Track * t, const wxRect & rect )
1111 {
1112  if( !TrackArtist::Get( context )->mbShowTrackNameInTrack )
1113  return;
1114  auto name = t->GetName();
1115  if( name.IsEmpty())
1116  return;
1117  if( !t->IsLeader())
1118  return;
1119  auto &dc = context.dc;
1120  wxBrush Brush;
1121  wxCoord textWidth, textHeight;
1122  GetTrackNameExtent( dc, t, &textWidth, &textHeight );
1123 
1124  // Logic for name background translucency (aka 'shields')
1125  // Tracks less than kOpaqueHeight high will have opaque shields.
1126  // Tracks more than kTranslucentHeight will have maximum translucency for shields.
1127  const int kOpaqueHeight = 44;
1128  const int kTranslucentHeight = 124;
1129 
1130  // PRL: to do: reexamine this strange use of TrackView::GetHeight,
1131  // ultimately to compute an opacity
1132  int h = TrackView::Get( *t ).GetHeight();
1133 
1134  // f codes the opacity as a number between 0.0 and 1.0
1135  float f = wxClip((h-kOpaqueHeight)/(float)(kTranslucentHeight-kOpaqueHeight),0.0,1.0);
1136  // kOpaque is the shield's alpha for tracks that are not tall
1137  // kTranslucent is the shield's alpha for tracks that are tall.
1138  const int kOpaque = 255;
1139  const int kTranslucent = 140;
1140  // 0.0 maps to full opacity, 1.0 maps to full translucency.
1141  int opacity = 255 - (255-140)*f;
1142 
1143  const auto nameRect =
1144  GetTrackNameRect( leftOffset, rect, textWidth, textHeight );
1145 
1146 #ifdef __WXMAC__
1147  // Mac dc is a graphics dc already.
1148  AColor::UseThemeColour( &dc, clrTrackInfoSelected, clrTrackPanelText, opacity );
1149  dc.DrawRoundedRectangle( nameRect, 8.0 );
1150 #else
1151  // This little dance with wxImage in order to draw to a graphic dc
1152  // which we can then paste as a translucent bitmap onto the real dc.
1153  enum : int {
1154  SecondMarginX = 1, SecondMarginY = 1,
1155  SecondMarginsX = 2 * SecondMarginX, SecondMarginsY = 2 * SecondMarginY,
1156  };
1157  wxImage image(
1158  textWidth + MarginsX + SecondMarginsX,
1159  textHeight + MarginsY + SecondMarginsY );
1160  image.InitAlpha();
1161  unsigned char *alpha=image.GetAlpha();
1162  memset(alpha, wxIMAGE_ALPHA_TRANSPARENT, image.GetWidth()*image.GetHeight());
1163 
1164  {
1165  std::unique_ptr< wxGraphicsContext >
1166  pGc{ wxGraphicsContext::Create(image) };
1167  auto &gc = *pGc;
1168  // This is to a gc, not a dc.
1169  AColor::UseThemeColour( &gc, clrTrackInfoSelected, clrTrackPanelText, opacity );
1170  // Draw at 1,1, not at 0,0 to avoid clipping of the antialiasing.
1171  gc.DrawRoundedRectangle(
1172  SecondMarginX, SecondMarginY,
1173  textWidth + MarginsX, textHeight + MarginsY, 8.0 );
1174  // destructor of gc updates the wxImage.
1175  }
1176  wxBitmap bitmap( image );
1177  dc.DrawBitmap( bitmap,
1178  nameRect.x - SecondMarginX, nameRect.y - SecondMarginY );
1179 #endif
1180  dc.SetTextForeground(theTheme.Colour( clrTrackPanelText ));
1181  dc.DrawText(t->GetName(),
1182  nameRect.x + MarginX,
1183  nameRect.y + MarginY);
1184 }
1185 
1186 /*
1187 
1188  The following classes define the subdivision of the area of the TrackPanel
1189  into cells with differing responses to mouse, keyboard, and scroll wheel
1190  events.
1191 
1192  The classes defining the less inclusive areas are earlier, while those
1193  defining ever larger hierarchical groupings of cells are later.
1194 
1195  To describe that subdivision again, informally, and top-down:
1196 
1197  Firstly subtract margin areas, on the left and right, that do not interact.
1198 
1199  Secondly subtract a noninterative margin above the first track, and an area
1200  below all tracks that causes deselection of all tracks if you click it.
1201  (One or both of those areas might be vertically scrolled off-screen, though.)
1202  Divide what remains into areas corresponding to the several tracks.
1203 
1204  Thirdly, for each track, subtract an area below, which you can click and drag
1205  to resize the track vertically.
1206 
1207  Fourthly, subtract an area at the left, which contains the track controls,
1208  such as the menu and delete and minimize buttons, and others appropriate
1209  to the track subtype.
1210 
1211  Fifthly, divide what remains into the vertically stacked channels, if there
1212  are more than one, alternating with separators, which can be clicked to
1213  resize the channel views.
1214 
1215  Sixthly, divide each channel into one or more vertically stacked sub-views.
1216 
1217  Lastly, split the area for each sub-view into a vertical ruler, and an area
1218  that displays the channel's own contents.
1219 
1220 */
1221 
1223  std::vector< UIHandlePtr > HitTest(
1224  const TrackPanelMouseState &, const AudacityProject *) override
1225  { return {}; }
1226  virtual std::shared_ptr< Track > DoFindTrack() override { return {}; }
1227  static std::shared_ptr<EmptyCell> Instance()
1228  {
1229  static auto instance = std::make_shared< EmptyCell >();
1230  return instance;
1231  }
1232 
1233  // TrackPanelDrawable implementation
1234  void Draw(
1235  TrackPanelDrawingContext &context,
1236  const wxRect &rect, unsigned iPass ) override
1237  {
1238  if ( iPass == TrackArtist::PassMargins ) {
1239  // Draw a margin area of TrackPanel
1240  auto dc = &context.dc;
1241 
1242  AColor::TrackPanelBackground( dc, false );
1243  dc->DrawRectangle( rect );
1244  }
1245  }
1246 };
1247 
1248 // A vertical ruler left of a channel
1251  const std::shared_ptr< TrackView > &pView, wxCoord leftOffset )
1252  : mpView{ pView }, mLeftOffset{ leftOffset } {}
1253  Subdivision Children( const wxRect &rect ) override
1254  {
1255  return { Axis::X, Refinement{
1256  { rect.GetLeft(),
1257  TrackVRulerControls::Get( *mpView ).shared_from_this() },
1258  { mLeftOffset, mpView }
1259  } };
1260  }
1261  std::shared_ptr< TrackView > mpView;
1262  wxCoord mLeftOffset;
1263 };
1264 
1265 // One or more sub-views of one channel, stacked vertically, each containing
1266 // a vertical ruler and a channel
1269  const std::shared_ptr<Track> &pTrack,
1270  TrackView::Refinement refinement, wxCoord leftOffset )
1271  : mpTrack{ pTrack }
1272  , mRefinement{ std::move( refinement ) }
1273  , mLeftOffset{ leftOffset } {}
1274  Subdivision Children( const wxRect &rect ) override
1275  {
1276  Refinement refinement;
1277  auto y1 = rect.GetTop();
1278  for ( const auto &subView : mRefinement ) {
1279  y1 = std::max( y1, subView.first );
1280  refinement.emplace_back( y1,
1281  std::make_shared< VRulerAndChannel >(
1282  subView.second, mLeftOffset ) );
1283  }
1284  return { Axis::Y, std::move( refinement ) };
1285  }
1286 
1287  // TrackPanelDrawable implementation
1288  void Draw(
1289  TrackPanelDrawingContext &context,
1290  const wxRect &rect, unsigned iPass ) override
1291  {
1292  // This overpaints the track area, but sometimes too the stereo channel
1293  // separator, so draw at least later than that
1294  if ( iPass == TrackArtist::PassBorders ) {
1295  DrawTrackName( mLeftOffset,
1296  context, mpTrack->SubstitutePendingChangedTrack().get(), rect );
1297  }
1298  if ( iPass == TrackArtist::PassControls ) {
1299  if (mRefinement.size() > 1) {
1300  // Draw lines separating sub-views
1301  auto &dc = context.dc;
1302  AColor::CursorColor( &dc );
1303  auto iter = mRefinement.begin() + 1, end = mRefinement.end();
1304  for ( ; iter != end; ++iter ) {
1305  auto yy = iter->first;
1306  AColor::Line( dc, mLeftOffset, yy, rect.GetRight(), yy );
1307  }
1308  }
1309  }
1310  }
1311 
1312  wxRect DrawingArea(
1313  TrackPanelDrawingContext &context,
1314  const wxRect &rect, const wxRect &panelRect, unsigned iPass ) override
1315  {
1316  auto result = rect;
1317  if ( iPass == TrackArtist::PassBorders ) {
1318  if ( true ) {
1319  wxCoord textWidth, textHeight;
1320  GetTrackNameExtent( context.dc, mpTrack.get(),
1321  &textWidth, &textHeight );
1322  result =
1323  GetTrackNameRect( mLeftOffset, rect, textWidth, textHeight );
1324  }
1325  }
1326  return result;
1327  }
1328 
1329  std::shared_ptr< Track > mpTrack;
1331  wxCoord mLeftOffset;
1332 };
1333 
1334 //Simply fills area using specified brush and outlines borders
1336 {
1337  //Required to keep selection behaviour similar to others
1338  std::shared_ptr<Track> mTrack;
1340 public:
1341  explicit EmptyPanelRect(const std::shared_ptr<Track>& track, int fillBrushName)
1342  : mTrack(track), mFillBrushName(fillBrushName)
1343  {
1344  }
1345 
1347 
1349  const wxRect& rect, unsigned iPass) override
1350  {
1351  if (iPass == TrackArtist::PassBackground)
1352  {
1353  context.dc.SetPen(*wxTRANSPARENT_PEN);
1354  AColor::UseThemeColour(&context.dc, mFillBrushName);
1355  context.dc.DrawRectangle(rect);
1356  wxRect bevel(rect.x, rect.y, rect.width - 1, rect.height - 1);
1357  AColor::BevelTrackInfo(context.dc, true, bevel, false);
1358  }
1359  }
1360 
1361  std::shared_ptr<Track> DoFindTrack() override
1362  {
1363  return mTrack;
1364  }
1365 
1366  std::vector<UIHandlePtr> HitTest(const TrackPanelMouseState& state,
1367  const AudacityProject* pProject) override
1368  {
1369  return {};
1370  }
1371 };
1372 
1373 //Simply place children one after another horizontally, without any specific logic
1375 
1377 
1379  : mRefinement(std::move(refinement))
1380  {
1381  }
1382 
1383  Subdivision Children(const wxRect& /*rect*/) override
1384  {
1385  return { Axis::X, mRefinement };
1386  }
1387 
1388 };
1389 
1390 
1391 // optional affordance areas, and n channels with vertical rulers,
1392 // alternating with n - 1 resizers;
1393 // each channel-ruler pair might be divided into multiple views
1395  ChannelGroup( const std::shared_ptr< Track > &pTrack, wxCoord leftOffset )
1396  : mpTrack{ pTrack }, mLeftOffset{ leftOffset } {}
1397  Subdivision Children( const wxRect &rect_ ) override
1398  {
1399  auto rect = rect_;
1400  Refinement refinement;
1401 
1402  const auto channels = TrackList::Channels( mpTrack.get() );
1403  const auto pLast = *channels.rbegin();
1404  wxCoord yy = rect.GetTop();
1405  auto heights = FindAdjustedChannelHeights(*mpTrack);
1406  auto pHeight = heights.begin();
1407  for ( auto channel : channels )
1408  {
1409  auto &view = TrackView::Get( *channel );
1410  if (auto affordance = view.GetAffordanceControls())
1411  {
1412  auto panelRect = std::make_shared<EmptyPanelRect>(
1413  channel->shared_from_this(),
1414  channel->GetSelected() ? clrTrackInfoSelected : clrTrackInfo);
1415  Refinement hgroup {
1416  std::make_pair(rect.GetLeft() + 1, panelRect),
1417  std::make_pair(mLeftOffset, affordance)
1418  };
1419  refinement.emplace_back(yy, std::make_shared<HorizontalGroup>(hgroup));
1420  yy += kAffordancesAreaHeight;
1421  }
1422 
1423  auto height = *pHeight++;
1424  rect.SetTop( yy );
1425  rect.SetHeight( height - kChannelSeparatorThickness );
1426  refinement.emplace_back( yy,
1427  std::make_shared< VRulersAndChannels >(
1428  channel->shared_from_this(),
1429  TrackView::Get( *channel ).GetSubViews( rect ),
1430  mLeftOffset ) );
1431  if ( channel != pLast ) {
1432  yy += height;
1433  refinement.emplace_back(
1435  TrackPanelResizerCell::Get( *channel ).shared_from_this() );
1436  }
1437  }
1438 
1439  return { Axis::Y, std::move( refinement ) };
1440  }
1441 
1442  void Draw(TrackPanelDrawingContext& context, const wxRect& rect, unsigned iPass) override
1443  {
1444  TrackPanelGroup::Draw(context, rect, iPass);
1445  if (iPass == TrackArtist::PassFocus && mpTrack->IsSelected())
1446  {
1447  const auto channels = TrackList::Channels(mpTrack.get());
1448  const auto pLast = *channels.rbegin();
1449  wxCoord yy = rect.GetTop();
1450  auto heights = FindAdjustedChannelHeights(*mpTrack);
1451  auto pHeight = heights.begin();
1452  for (auto channel : channels)
1453  {
1454  auto& view = TrackView::Get(*channel);
1455  auto height = *pHeight++;
1456  if (auto affordance = view.GetAffordanceControls())
1457  {
1458  height += kAffordancesAreaHeight;
1459  }
1460  auto trackRect = wxRect(
1461  mLeftOffset,
1462  yy,
1463  rect.GetRight() - mLeftOffset,
1464  height - kChannelSeparatorThickness);
1465  TrackArt::DrawCursor(context, trackRect, mpTrack.get());
1466  yy += height;
1467  }
1468  }
1469  }
1470 
1471  std::shared_ptr< Track > mpTrack;
1472  wxCoord mLeftOffset;
1473 };
1474 
1475 // A track control panel, left of n vertical rulers and n channels
1476 // alternating with n - 1 resizers
1479  const std::shared_ptr< Track > &pTrack, wxCoord leftOffset )
1480  : mpTrack{ pTrack }, mLeftOffset{ leftOffset } {}
1481  Subdivision Children( const wxRect &rect ) override
1482  { return { Axis::X, Refinement{
1483  { rect.GetLeft(),
1484  TrackControls::Get( *mpTrack ).shared_from_this() },
1485  { rect.GetLeft() + kTrackInfoWidth,
1486  std::make_shared< ChannelGroup >( mpTrack, mLeftOffset ) }
1487  } }; }
1488 
1489  // TrackPanelDrawable implementation
1491  const wxRect &rect, unsigned iPass ) override
1492  {
1493  if ( iPass == TrackArtist::PassBorders ) {
1494  auto &dc = context.dc;
1495  dc.SetBrush(*wxTRANSPARENT_BRUSH);
1496  dc.SetPen(*wxBLACK_PEN);
1497 
1498  // border
1499  dc.DrawRectangle(
1500  rect.x, rect.y,
1501  rect.width - kShadowThickness, rect.height - kShadowThickness
1502  );
1503 
1504  // shadow
1505  // Stroke lines along bottom and right, which are slightly short at
1506  // bottom-left and top-right
1507  const auto right = rect.GetRight();
1508  const auto bottom = rect.GetBottom();
1509 
1510  // bottom
1511  AColor::Line(dc, rect.x + 2, bottom, right, bottom);
1512  // right
1513  AColor::Line(dc, right, rect.y + 2, right, bottom);
1514  }
1515  if ( iPass == TrackArtist::PassFocus ) {
1516  // Sometimes highlight is not drawn on backing bitmap. I thought
1517  // it was because FindFocus did not return the TrackPanel on Mac, but
1518  // when I removed that test, yielding this condition:
1519  // if (GetFocusedTrack() != NULL) {
1520  // the highlight was reportedly drawn even when something else
1521  // was the focus and no highlight should be drawn. -RBD
1522  const auto artist = TrackArtist::Get( context );
1523  auto &trackPanel = *artist->parent;
1524  auto &trackFocus = TrackFocus::Get( *trackPanel.GetProject() );
1525  if (trackFocus.Get() == mpTrack.get() &&
1526  wxWindow::FindFocus() == &trackPanel ) {
1528  wxRect theRect = rect;
1529  auto &dc = context.dc;
1530  dc.SetBrush(*wxTRANSPARENT_BRUSH);
1531 
1532  AColor::TrackFocusPen( &dc, 2 );
1533  dc.DrawRectangle(theRect);
1534  theRect.Deflate(1);
1535 
1536  AColor::TrackFocusPen( &dc, 1 );
1537  dc.DrawRectangle(theRect);
1538  theRect.Deflate(1);
1539 
1540  AColor::TrackFocusPen( &dc, 0 );
1541  dc.DrawRectangle(theRect);
1542  }
1543  }
1544  }
1545 
1546  wxRect DrawingArea(
1548  const wxRect &rect, const wxRect &, unsigned iPass ) override
1549  {
1550  if ( iPass == TrackArtist::PassBorders )
1551  return {
1552  rect.x - kBorderThickness,
1553  rect.y - kBorderThickness,
1554  rect.width + 2 * kBorderThickness + kShadowThickness,
1555  rect.height + 2 * kBorderThickness + kShadowThickness
1556  };
1557  else if ( iPass == TrackArtist::PassFocus ) {
1558  constexpr auto extra = kBorderThickness + 3;
1559  return {
1560  rect.x - extra,
1561  rect.y - extra,
1562  rect.width + 2 * extra + kShadowThickness,
1563  rect.height + 2 * extra + kShadowThickness
1564  };
1565  }
1566  else
1567  return rect;
1568  }
1569 
1570  std::shared_ptr< Track > mpTrack;
1571  wxCoord mLeftOffset;
1572 };
1573 
1574 // Stacks a label and a single or multi-channel track on a resizer below,
1575 // which is associated with the last channel
1578  const std::shared_ptr< Track > &pTrack, wxCoord leftOffset )
1579  : mpTrack{ pTrack }, mLeftOffset{ leftOffset } {}
1580  Subdivision Children( const wxRect &rect ) override
1581  { return { Axis::Y, Refinement{
1582  { rect.GetTop(),
1583  std::make_shared< LabeledChannelGroup >( mpTrack, mLeftOffset ) },
1584  { rect.GetTop() + rect.GetHeight() - kTrackSeparatorThickness,
1586  **TrackList::Channels( mpTrack.get() ).rbegin() ).shared_from_this()
1587  }
1588  } }; }
1589  std::shared_ptr< Track > mpTrack;
1590  wxCoord mLeftOffset;
1591 };
1592 
1593 // Stacks a dead area at top, the tracks, and the click-to-deselect area below
1594 struct Subgroup final : TrackPanelGroup {
1595  explicit Subgroup( TrackPanel &panel ) : mPanel{ panel } {}
1596  Subdivision Children( const wxRect &rect ) override
1597  {
1598  const auto &viewInfo = *mPanel.GetViewInfo();
1599  wxCoord yy = -viewInfo.vpos;
1600  Refinement refinement;
1601 
1602  auto &tracks = *mPanel.GetTracks();
1603  if ( tracks.Any() )
1604  refinement.emplace_back( yy, EmptyCell::Instance() ),
1605  yy += kTopMargin;
1606 
1607  for ( const auto leader : tracks.Leaders() ) {
1608  wxCoord height = 0;
1609  for ( auto channel : TrackList::Channels( leader ) ) {
1610  auto &view = TrackView::Get( *channel );
1611  height += view.GetHeight();
1612  }
1613  refinement.emplace_back( yy,
1614  std::make_shared< ResizingChannelGroup >(
1615  leader->SharedPointer(), viewInfo.GetLeftOffset() )
1616  );
1617  yy += height;
1618  }
1619 
1620  refinement.emplace_back( std::max( 0, yy ), mPanel.GetBackgroundCell() );
1621 
1622  return { Axis::Y, std::move( refinement ) };
1623  }
1625 };
1626 
1627 // Main group shaves off the left and right margins
1628 struct MainGroup final : TrackPanelGroup {
1629  explicit MainGroup( TrackPanel &panel ) : mPanel{ panel } {}
1630  Subdivision Children( const wxRect &rect ) override
1631  { return { Axis::X, Refinement{
1632  { 0, EmptyCell::Instance() },
1633  { kLeftMargin, std::make_shared< Subgroup >( mPanel ) },
1634  { rect.GetRight() + 1 - kRightMargin, EmptyCell::Instance() }
1635  } }; }
1637 };
1638 
1639 }
1640 
1641 std::shared_ptr<TrackPanelNode> TrackPanel::Root()
1642 {
1643  // Root and other subgroup objects are throwaways.
1644  // They might instead be cached to avoid repeated allocation.
1645  // That cache would need invalidation when there is addition, deletion, or
1646  // permutation of tracks, or change of width of the vertical rulers.
1647  return std::make_shared< MainGroup >( *this );
1648 }
1649 
1650 // This finds the rectangle of a given track (including all channels),
1651 // either that of the label 'adornment' or the track itself
1652 // The given track is assumed to be the first channel
1653 wxRect TrackPanel::FindTrackRect( const Track * target )
1654 {
1655  auto leader = *GetTracks()->FindLeader( target );
1656  if (!leader) {
1657  return {};
1658  }
1659 
1660  return CellularPanel::FindRect( [&] ( TrackPanelNode &node ) {
1661  if (auto pGroup = dynamic_cast<const LabeledChannelGroup*>( &node ))
1662  return pGroup->mpTrack.get() == leader;
1663  return false;
1664  } );
1665 }
1666 
1667 wxRect TrackPanel::FindFocusedTrackRect( const Track * target )
1668 {
1669  auto rect = FindTrackRect(target);
1670  if (rect != wxRect{}) {
1671  // Enlarge horizontally.
1672  // PRL: perhaps it's one pixel too much each side, including some gray
1673  // beyond the yellow?
1674  rect.x = 0;
1675  GetClientSize(&rect.width, nullptr);
1676 
1677  // Enlarge vertically, enough to enclose the yellow focus border pixels
1678  // The the outermost ring of gray pixels is included on three sides
1679  // but not the top (should that be fixed?)
1680 
1681  // (Note that TrackPanel paints its focus over the "top margin" of the
1682  // rectangle allotted to the track, according to TrackView::GetY() and
1683  // TrackView::GetHeight(), but also over the margin of the next track.)
1684 
1685  rect.height += kBottomMargin;
1686  int dy = kTopMargin - 1;
1687  rect.Inflate( 0, dy );
1688 
1689  // Note that this rectangle does not coincide with any one of
1690  // the nodes in the subdivision.
1691  }
1692  return rect;
1693 }
1694 
1695 std::vector<wxRect> TrackPanel::FindRulerRects( const Track *target )
1696 {
1697  std::vector<wxRect> results;
1698  if (target)
1699  VisitCells( [&]( const wxRect &rect, TrackPanelCell &visited ) {
1700  if (auto pRuler = dynamic_cast<const TrackVRulerControls*>(&visited);
1701  pRuler && pRuler->FindTrack().get() == target)
1702  results.push_back(rect);
1703  } );
1704  return results;
1705 }
1706 
1708 {
1709  auto pTrack = TrackFocus::Get( *GetProject() ).Get();
1710  return pTrack ? &TrackView::Get( *pTrack ) : GetBackgroundCell().get();
1711 }
1712 
1714 {
1715  // This may have a side-effect of assigning a focus if there was none
1716  auto& trackFocus = TrackFocus::Get(*GetProject());
1717  trackFocus.Set(trackFocus.Get());
1719 }
1720 
1721 void TrackPanel::OnTrackFocusChange( wxCommandEvent &event )
1722 {
1723  event.Skip();
1724  auto cell = GetFocusedCell();
1725 
1726  if (cell) {
1727  Refresh( false );
1728  }
1729 }
size
size_t size
Definition: ffmpeg-2.3.6-single-header.h:412
kTimerInterval
constexpr auto kTimerInterval
Definition: TimerRecordDialog.cpp:89
WaveTrack.h
ZoomInfo::vpos
int vpos
Definition: ZoomInfo.h:58
anonymous_namespace{TrackPanel.cpp}::ChannelGroup::ChannelGroup
ChannelGroup(const std::shared_ptr< Track > &pTrack, wxCoord leftOffset)
Definition: TrackPanel.cpp:1395
ProjectHistory::ModifyState
void ModifyState(bool bWantsAutoSave)
Definition: ProjectHistory.cpp:124
kLeftInset
@ kLeftInset
Definition: ZoomInfo.h:31
anonymous_namespace{TrackPanel.cpp}::MarginsY
@ MarginsY
Definition: TrackPanel.cpp:1084
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
RefreshCode::DrawOverlays
@ DrawOverlays
Definition: RefreshCode.h:32
RefreshCode::FixScrollbars
@ FixScrollbars
Definition: RefreshCode.h:27
ViewInfo::Get
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
anonymous_namespace{TrackPanel.cpp}::EmptyCell::Draw
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
Definition: TrackPanel.cpp:1234
AColor::UseThemeColour
static void UseThemeColour(wxDC *dc, int iBrush, int iPen=-1, int alpha=255)
Definition: AColor.cpp:280
TrackPanel::GetTracks
const TrackList * GetTracks() const
Definition: TrackPanel.h:168
TrackPanel::UpdateVRulerSize
void UpdateVRulerSize()
Definition: TrackPanel.cpp:977
TrackPanelGroup::Refinement
std::vector< Child > Refinement
Definition: TrackPanelCell.h:64
TrackPanelMouseEvent.h
TrackPanelGroup::Subdivision
std::pair< Axis, Refinement > Subdivision
Definition: TrackPanelCell.h:65
AColor::TrackPanelBackground
static void TrackPanelBackground(wxDC *dc, bool selected)
Definition: AColor.cpp:362
AdornedRulerPanel::Refresh
void Refresh(bool eraseBackground=true, const wxRect *rect=(const wxRect *) NULL) override
Definition: AdornedRulerPanel.cpp:1318
TrackPanel::DrawTracks
void DrawTracks(wxDC *dc)
Definition: TrackPanel.cpp:819
ProjectStatus.h
CellularPanel::HandleCursorForPresentMouseState
void HandleCursorForPresentMouseState(bool doHit=true)
Definition: CellularPanel.cpp:254
AColor::CursorColor
static void CursorColor(wxDC *dc)
Definition: AColor.cpp:371
TrackPanel::TrackPanel
TrackPanel(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, const std::shared_ptr< TrackList > &tracks, ViewInfo *viewInfo, AudacityProject *project, AdornedRulerPanel *ruler)
Definition: TrackPanel.cpp:250
AdornedRulerPanel
This is an Audacity Specific ruler panel which additionally has border, selection markers,...
Definition: AdornedRulerPanel.h:29
PlayableTrack::GetSolo
bool GetSolo() const
Definition: Track.h:884
ProjectAudioManager::Get
static ProjectAudioManager & Get(AudacityProject &project)
Definition: ProjectAudioManager.cpp:55
anonymous_namespace{TrackPanel.cpp}::EmptyPanelRect::HitTest
std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &state, const AudacityProject *pProject) override
Definition: TrackPanel.cpp:1366
anonymous_namespace{TrackPanel.cpp}::HorizontalGroup::HorizontalGroup
HorizontalGroup(Refinement refinement)
Definition: TrackPanel.cpp:1378
TrackVRulerControls.h
TrackPanelListener::TP_RedrawScrollbars
virtual void TP_RedrawScrollbars()=0
anonymous_namespace{TrackPanel.cpp}::LabeledChannelGroup
Definition: TrackPanel.cpp:1477
ToolCodes::drawTool
@ drawTool
Definition: ProjectSettings.h:42
TrackPanel::FindFocusedTrackRect
wxRect FindFocusedTrackRect(const Track *target)
Definition: TrackPanel.cpp:1667
RefreshCode::RefreshAll
@ RefreshAll
Definition: RefreshCode.h:26
ZoomInfo::GetVRulerOffset
int GetVRulerOffset() const
Definition: ZoomInfo.h:100
TrackArtist::NPasses
@ NPasses
Definition: TrackArtist.h:53
TrackView::Get
static TrackView & Get(Track &)
Definition: TrackView.cpp:69
TrackPanel::UpdateVRuler
void UpdateVRuler(Track *t)
Definition: TrackPanel.cpp:928
TrackArtist.h
BackedPanel::DisplayBitmap
void DisplayBitmap(wxDC &dc)
Definition: BackedPanel.cpp:65
BackedPanel::RepairBitmap
void RepairBitmap(wxDC &dc, wxCoord x, wxCoord y, wxCoord width, wxCoord height)
Definition: BackedPanel.cpp:60
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
TrackFocus
Definition: TrackPanelAx.h:161
AllThemeResources.h
anonymous_namespace{TrackPanel.cpp}::VRulersAndChannels::mRefinement
TrackView::Refinement mRefinement
Definition: TrackPanel.cpp:1330
TrackView.h
anonymous_namespace{TrackPanel.cpp}::Subgroup::Subgroup
Subgroup(TrackPanel &panel)
Definition: TrackPanel.cpp:1595
TrackList::Lock
std::shared_ptr< Subclass > Lock(const std::weak_ptr< Subclass > &wTrack)
Definition: Track.h:1541
Track::GetName
wxString GetName() const
Definition: Track.h:423
ZoomInfo::GetDefaultZoom
static double GetDefaultZoom()
Definition: ZoomInfo.h:123
Project.h
TrackPanel::OnIdle
void OnIdle(wxIdleEvent &event)
Definition: TrackPanel.cpp:375
Track::EnsureVisible
void EnsureVisible(bool modifyState=false)
Definition: Track.cpp:95
wxPanelWrapper::SetLabel
void SetLabel(const TranslatableString &label)
Definition: wxPanelWrapper.cpp:46
TrackPanelListener::TP_ScrollWindow
virtual void TP_ScrollWindow(double scrollto)=0
CellularPanel::mViewInfo
ViewInfo * mViewInfo
Definition: CellularPanel.h:162
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
TrackControls::Get
static TrackControls & Get(Track &track)
Definition: TrackControls.cpp:31
anonymous_namespace{TrackPanel.cpp}::ResizingChannelGroup::mLeftOffset
wxCoord mLeftOffset
Definition: TrackPanel.cpp:1590
TrackArtist::PassBorders
@ PassBorders
Definition: TrackArtist.h:46
KeyboardCapture.h
CommonTrackPanelCell::FindTrack
std::shared_ptr< Track > FindTrack()
Definition: CommonTrackPanelCell.h:47
TrackPanelDrawingContext
Definition: TrackPanelDrawingContext.h:22
TrackList::Channels
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1483
MakeCursor
std::unique_ptr< wxCursor > MakeCursor(int WXUNUSED(CursorId), const char *const pXpm[36], int HotX, int HotY)
Definition: TrackPanel.cpp:182
TrackView::Refinement
std::vector< std::pair< wxCoord, std::shared_ptr< TrackView > > > Refinement
Definition: TrackView.h:104
AColor::Line
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:109
TrackPanel.h
ViewInfo
Definition: ViewInfo.h:188
kBorderThickness
@ kBorderThickness
Definition: ZoomInfo.h:28
anonymous_namespace{TrackPanel.cpp}::DisplaceX
@ DisplaceX
Definition: TrackPanel.cpp:1080
anonymous_namespace{TrackPanel.cpp}::LabeledChannelGroup::Draw
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
Definition: TrackPanel.cpp:1490
TrackPanelAx.h
AColor::TrackFocusPen
static void TrackFocusPen(wxDC *dc, int level)
Definition: AColor.cpp:389
kShadowThickness
@ kShadowThickness
Definition: ZoomInfo.h:29
TrackPanel::Get
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:227
TrackView::GetTrackHeight
static int GetTrackHeight(const Track *pTrack)
Definition: TrackView.cpp:29
XO
#define XO(s)
Definition: Internat.h:31
TrackPanel::mAudioIOScubscription
Observer::Subscription mAudioIOScubscription
Definition: TrackPanel.h:188
TrackPanel::OnKeyDown
void OnKeyDown(wxKeyEvent &event)
Definition: TrackPanel.cpp:692
ProjectSettings::Get
static ProjectSettings & Get(AudacityProject &project)
Definition: ProjectSettings.cpp:45
TrackPanel::FindTrackRect
wxRect FindTrackRect(const Track *target)
Definition: TrackPanel.cpp:1653
anonymous_namespace{TrackPanel.cpp}::ChannelGroup::Draw
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
Definition: TrackPanel.cpp:1442
TrackPanel::GetMostRecentXPos
double GetMostRecentXPos()
Definition: TrackPanel.cpp:741
TrackPanel::AudacityTimer::parent
TrackPanel * parent
Definition: TrackPanel.h:211
anonymous_namespace{TrackPanel.cpp}::Subgroup
Definition: TrackPanel.cpp:1594
kTrackInfoBtnSize
@ kTrackInfoBtnSize
Definition: ViewInfo.h:95
TrackPanelDrawingContext::dc
wxDC & dc
Definition: TrackPanelDrawingContext.h:23
ZoomInfo::SetVRulerWidth
void SetVRulerWidth(int width)
Definition: ZoomInfo.h:99
kRightInset
@ kRightInset
Definition: ZoomInfo.h:32
ProjectSettings.h
ProjectWindow::Get
static ProjectWindow & Get(AudacityProject &project)
Definition: ProjectWindow.cpp:525
ZoomInfo::GetVRulerWidth
int GetVRulerWidth() const
Definition: ZoomInfo.h:98
CellularPanel::FindRect
wxRect FindRect(const TrackPanelCell &cell)
Definition: CellularPanel.cpp:1171
anonymous_namespace{TrackPanel.cpp}::MarginX
@ MarginX
Definition: TrackPanel.cpp:1082
BasicUI::CallAfter
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Definition: BasicUI.cpp:38
anonymous_namespace{TrackPanel.cpp}::HorizontalGroup::Children
Subdivision Children(const wxRect &) override
Definition: TrackPanel.cpp:1383
AColor::BevelTrackInfo
static void BevelTrackInfo(wxDC &dc, bool up, const wxRect &r, bool highlight=false)
Definition: AColor.cpp:248
ProjectAudioManager.h
ProjectAudioIO::Get
static ProjectAudioIO & Get(AudacityProject &project)
Definition: ProjectAudioIO.cpp:24
TrackPanel::UpdateViewIfNoTracks
void UpdateViewIfNoTracks()
Definition: TrackPanel.cpp:640
TrackPanel::MakeParentRedrawScrollbars
void MakeParentRedrawScrollbars()
Definition: TrackPanel.cpp:519
TrackPanel::OnMouseEvent
void OnMouseEvent(wxMouseEvent &event)
Definition: TrackPanel.cpp:712
anonymous_namespace{TrackPanel.cpp}::VRulerAndChannel
Definition: TrackPanel.cpp:1249
anonymous_namespace{TimeTrackVRulerControls.cpp}::ruler
Ruler & ruler()
Definition: TimeTrackVRulerControls.cpp:34
TrackPanel
The TrackPanel class coordinates updates and operations on the main part of the screen which contains...
Definition: TrackPanel.h:65
kBottomMargin
@ kBottomMargin
Definition: TrackPanelConstants.h:22
TrackArt.h
TrackList::SelectedLeaders
auto SelectedLeaders() -> TrackIterRange< TrackType >
Definition: Track.h:1430
anonymous_namespace{TrackPanel.cpp}::HorizontalGroup
Definition: TrackPanel.cpp:1374
anonymous_namespace{TrackPanel.cpp}::LabeledChannelGroup::mpTrack
std::shared_ptr< Track > mpTrack
Definition: TrackPanel.cpp:1570
RefreshCode::EnsureVisible
@ EnsureVisible
Definition: RefreshCode.h:31
ProjectAudioIO::IsAudioActive
bool IsAudioActive() const
Definition: ProjectAudioIO.cpp:53
TrackPanel::ProcessUIHandleResult
void ProcessUIHandleResult(TrackPanelCell *pClickedTrack, TrackPanelCell *pLatestCell, unsigned refreshResult) override
Definition: TrackPanel.cpp:534
TrackPanelListener::TP_ScrollUpDown
virtual bool TP_ScrollUpDown(int delta)=0
anonymous_namespace{TrackPanel.cpp}::EmptyPanelRect::mFillBrushName
int mFillBrushName
Definition: TrackPanel.cpp:1339
anonymous_namespace{TrackPanel.cpp}::EmptyCell::DoFindTrack
virtual std::shared_ptr< Track > DoFindTrack() override
Definition: TrackPanel.cpp:1226
anonymous_namespace{TrackPanel.cpp}::LabeledChannelGroup::LabeledChannelGroup
LabeledChannelGroup(const std::shared_ptr< Track > &pTrack, wxCoord leftOffset)
Definition: TrackPanel.cpp:1478
anonymous_namespace{TrackPanel.cpp}::EmptyPanelRect::Draw
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
Definition: TrackPanel.cpp:1348
TrackPanel::OnTrackListResizing
void OnTrackListResizing(const TrackListEvent &event)
Definition: TrackPanel.cpp:664
anonymous_namespace{TrackPanel.cpp}::EmptyCell::HitTest
std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &, const AudacityProject *) override
Definition: TrackPanel.cpp:1223
TrackPanel::GetSelectedTrackCount
size_t GetSelectedTrackCount() const
Definition: TrackPanel.cpp:635
TrackPanel::GetProject
AudacityProject * GetProject() const override
Definition: TrackPanel.cpp:347
anonymous_namespace{TrackPanel.cpp}::EmptyPanelRect::DoFindTrack
std::shared_ptr< Track > DoFindTrack() override
Definition: TrackPanel.cpp:1361
ZoomInfo::GetLeftOffset
int GetLeftOffset() const
Definition: ZoomInfo.h:103
anonymous_namespace{TrackPanel.cpp}::VRulersAndChannels::DrawingArea
wxRect DrawingArea(TrackPanelDrawingContext &context, const wxRect &rect, const wxRect &panelRect, unsigned iPass) override
Definition: TrackPanel.cpp:1312
TrackPanel::UpdatePrefs
void UpdatePrefs() override
Definition: TrackPanel.cpp:336
anonymous_namespace{TrackPanel.cpp}::MainGroup::MainGroup
MainGroup(TrackPanel &panel)
Definition: TrackPanel.cpp:1629
anonymous_namespace{TrackPanel.cpp}::FindAdjustedChannelHeights
std::vector< int > FindAdjustedChannelHeights(Track &t)
Definition: TrackPanel.cpp:875
ViewInfo::scrollStep
int scrollStep
Definition: ViewInfo.h:233
TrackPanel::UpdateSelectionDisplay
void UpdateSelectionDisplay()
Definition: TrackPanel.cpp:624
ClientData::Site::Assign
void Assign(const RegisteredFactory &key, ReplacementPointer &&replacement)
Reassign Site's pointer to ClientData.
Definition: ClientData.h:355
Track::vrulerSize
std::pair< int, int > vrulerSize
Definition: Track.h:365
TrackVRulerControls
Definition: TrackVRulerControls.h:25
ProjectSettings::EventCode
EventCode
Definition: ProjectSettings.h:66
anonymous_namespace{TrackPanel.cpp}::LabeledChannelGroup::Children
Subdivision Children(const wxRect &rect) override
Definition: TrackPanel.cpp:1481
TrackPanel::GetFocusedCell
TrackPanelCell * GetFocusedCell() override
Definition: TrackPanel.cpp:1707
BackedPanel::GetBackingDCForRepaint
wxDC & GetBackingDCForRepaint()
Definition: BackedPanel.cpp:35
ProjectSettings::ChangedSyncLock
@ ChangedSyncLock
Definition: ProjectSettings.h:67
AdornedRulerPanel::Get
static AdornedRulerPanel & Get(AudacityProject &project)
Definition: AdornedRulerPanel.cpp:1233
TrackPanelNode
The TrackPanel is built up of nodes, subtrees of the CellularPanel's area Common base class for Track...
Definition: TrackPanelCell.h:39
TrackList::FindLeader
TrackIter< Track > FindLeader(Track *pTrack)
Definition: Track.cpp:518
ProjectStatus::Set
void Set(const TranslatableString &msg, StatusBarField field=mainStatusBarField)
Definition: ProjectStatus.cpp:63
Track::SubstitutePendingChangedTrack
std::shared_ptr< Track > SubstitutePendingChangedTrack()
Definition: Track.cpp:1055
anonymous_namespace{TrackPanel.cpp}::EmptyCell
Definition: TrackPanel.cpp:1222
A
#define A(N)
Definition: ToChars.cpp:62
ViewInfo::selectedRegion
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:215
TrackArtist::Get
static TrackArtist * Get(TrackPanelDrawingContext &)
Definition: TrackArtist.cpp:69
CommonTrackPanelCell.h
TrackPanel::OnTrackListDeletion
void OnTrackListDeletion()
Definition: TrackPanel.cpp:677
CellularPanel::MostRecentXCoord
wxCoord MostRecentXCoord() const
Definition: CellularPanel.cpp:1209
TrackFocus::Get
static TrackFocus & Get(AudacityProject &project)
Definition: TrackPanelAx.cpp:741
TrackPanel::OnProjectSettingsChange
void OnProjectSettingsChange(wxCommandEvent &event)
Definition: TrackPanel.cpp:448
ToolCodes::multiTool
@ multiTool
Definition: ProjectSettings.h:44
CellularPanel::HasEscape
bool HasEscape()
Definition: CellularPanel.cpp:445
TrackListEvent
Notification of changes in individual tracks of TrackList, or of TrackList's composition.
Definition: Track.h:1240
anonymous_namespace{TrackPanel.cpp}::EmptyCell::Instance
static std::shared_ptr< EmptyCell > Instance()
Definition: TrackPanel.cpp:1227
TrackPanel::OnSize
void OnSize(wxSizeEvent &)
Definition: TrackPanel.cpp:367
ZoomInfo::SetZoom
void SetZoom(double pixelsPerSecond)
Definition: ZoomInfo.cpp:86
BasicUI::Get
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:26
anonymous_namespace{TrackPanel.cpp}::DisplaceY
@ DisplaceY
Definition: TrackPanel.cpp:1080
TrackPanel::mLastDrawnSelectedRegion
SelectedRegion mLastDrawnSelectedRegion
Definition: TrackPanel.h:221
TrackPanelListener::TP_HandleResize
virtual void TP_HandleResize()=0
ProjectWindow
A top-level window associated with a project, and handling scrollbars and zooming.
Definition: ProjectWindow.h:33
anonymous_namespace{TrackPanel.cpp}::EmptyPanelRect::mTrack
std::shared_ptr< Track > mTrack
Definition: TrackPanel.cpp:1338
anonymous_namespace{TrackPanel.cpp}::EmptyPanelRect::EmptyPanelRect
EmptyPanelRect(const std::shared_ptr< Track > &track, int fillBrushName)
Definition: TrackPanel.cpp:1341
anonymous_namespace{TrackPanel.cpp}::MainGroup
Definition: TrackPanel.cpp:1628
GetAttachedWindows
AUDACITY_DLL_API AttachedWindows & GetAttachedWindows(AudacityProject &project)
Definition: ProjectWindows.cpp:114
UIHandle::Result
unsigned Result
Definition: UIHandle.h:38
Theme.h
kVerticalPadding
@ kVerticalPadding
Definition: ViewInfo.h:91
AdornedRulerPanel::DrawSelection
void DrawSelection()
Definition: AdornedRulerPanel.cpp:2456
anonymous_namespace{TrackPanel.cpp}::ResizingChannelGroup::ResizingChannelGroup
ResizingChannelGroup(const std::shared_ptr< Track > &pTrack, wxCoord leftOffset)
Definition: TrackPanel.cpp:1577
kTopMargin
@ kTopMargin
Definition: TrackPanelConstants.h:21
TrackListEvent::mpTrack
const std::weak_ptr< Track > mpTrack
Definition: Track.h:1276
KeyboardCapture::Capture
void Capture(wxWindow *handler)
Definition: KeyboardCapture.cpp:60
TrackVRulerControls::Get
static TrackVRulerControls & Get(TrackView &)
Definition: TrackVRulerControls.cpp:36
name
const TranslatableString name
Definition: Distortion.cpp:98
RefreshCode::Resize
@ Resize
Definition: RefreshCode.h:28
TrackPanelCell
Definition: TrackPanelCell.h:74
ZoomInfo::GetScreenEndTime
double GetScreenEndTime() const
Definition: ZoomInfo.h:114
TrackControls.h
TrackArtist::PassControls
@ PassControls
Definition: TrackArtist.h:47
TrackPanel::SetBackgroundCell
void SetBackgroundCell(const std::shared_ptr< CommonTrackPanelCell > &pCell)
Definition: TrackPanel.cpp:864
AdornedRulerPanel::SetLeftOffset
void SetLeftOffset(int offset)
Definition: AdornedRulerPanel.cpp:2575
anonymous_namespace{TrackPanel.cpp}::VRulersAndChannels::mpTrack
std::shared_ptr< Track > mpTrack
Definition: TrackPanel.cpp:1329
CellularPanel::Target
UIHandlePtr Target()
Definition: CellularPanel.cpp:1200
UndoManager.h
TrackPanel::OnEnsureVisible
void OnEnsureVisible(const TrackListEvent &event)
Definition: TrackPanel.cpp:1001
TrackFocus::Get
Track * Get()
Definition: TrackPanelAx.cpp:760
RefreshCode::UpdateVRuler
@ UpdateVRuler
Definition: RefreshCode.h:30
TrackPanel::OnTimer
void OnTimer(wxTimerEvent &event)
AS: This gets called on our wx timer events.
Definition: TrackPanel.cpp:396
TrackPanel::SetFocusedCell
void SetFocusedCell() override
Definition: TrackPanel.cpp:1713
TrackPanel::mTimer
TrackPanel::AudacityTimer mTimer
TrackPanel::GetBackgroundCell
std::shared_ptr< CommonTrackPanelCell > GetBackgroundCell()
Definition: TrackPanel.cpp:869
RefreshCode::RefreshCell
@ RefreshCell
Definition: RefreshCode.h:24
TrackPanel::mRuler
AdornedRulerPanel * mRuler
Definition: TrackPanel.h:194
TrackPanel::mTrackListScubscription
Observer::Subscription mTrackListScubscription
Definition: TrackPanel.h:187
TrackPanelGroup
Definition: TrackPanelCell.h:47
anonymous_namespace{TrackPanel.cpp}::VRulerAndChannel::mpView
std::shared_ptr< TrackView > mpView
Definition: TrackPanel.cpp:1261
TrackPanel::Root
std::shared_ptr< TrackPanelNode > Root() override
Definition: TrackPanel.cpp:1641
anonymous_namespace{TrackPanel.cpp}::FindTrack
std::shared_ptr< Track > FindTrack(TrackPanelCell *pCell)
Definition: TrackPanel.cpp:525
TrackVRulerControls::UpdateRuler
virtual void UpdateRuler(const wxRect &rect)=0
PlayableTrack
AudioTrack subclass that can also be audibly replayed by the program.
Definition: Track.h:875
RefreshCode::RefreshLatestCell
@ RefreshLatestCell
Definition: RefreshCode.h:25
anonymous_namespace{TrackPanel.cpp}::VRulerAndChannel::VRulerAndChannel
VRulerAndChannel(const std::shared_ptr< TrackView > &pView, wxCoord leftOffset)
Definition: TrackPanel.cpp:1250
theTheme
THEME_API Theme theTheme
Definition: Theme.cpp:82
anonymous_namespace{TrackPanel.cpp}::VRulerAndChannel::Children
Subdivision Children(const wxRect &rect) override
Definition: TrackPanel.cpp:1253
TrackPanel::OnPaint
void OnPaint(wxPaintEvent &event)
Definition: TrackPanel.cpp:469
ProjectWindows.h
accessors for certain important windows associated with each project
anonymous_namespace{TrackPanel.cpp}::MarginsX
@ MarginsX
Definition: TrackPanel.cpp:1084
TrackPanel::HandlePageUpKey
void HandlePageUpKey()
Definition: TrackPanel.cpp:599
TrackList::UpdatePendingTracks
void UpdatePendingTracks()
Definition: Track.cpp:930
CellularPanel::Draw
void Draw(TrackPanelDrawingContext &context, unsigned nPasses)
Definition: CellularPanel.cpp:1232
anonymous_namespace{TrackPanel.cpp}::GetTrackNameExtent
void GetTrackNameExtent(wxDC &dc, const Track *t, wxCoord *pW, wxCoord *pH)
Definition: TrackPanel.cpp:1087
RefreshCode::DestroyedCell
@ DestroyedCell
Definition: RefreshCode.h:34
anonymous_namespace{TrackPanel.cpp}::VRulerAndChannel::mLeftOffset
wxCoord mLeftOffset
Definition: TrackPanel.cpp:1262
TrackListEvent::mExtra
const int mExtra
Definition: Track.h:1277
anonymous_namespace{TrackPanel.cpp}::VRulersAndChannels::mLeftOffset
wxCoord mLeftOffset
Definition: TrackPanel.cpp:1331
TrackArt::DrawCursor
AUDACITY_DLL_API void DrawCursor(TrackPanelDrawingContext &context, const wxRect &rect, const Track *track)
Definition: TrackArt.cpp:488
id
int id
Definition: WaveTrackControls.cpp:577
TrackPanel::mListener
TrackPanelListener * mListener
Definition: TrackPanel.h:190
TrackPanelDrawingContext.h
TrackPanel::UpdateVRulers
void UpdateVRulers()
Definition: TrackPanel.cpp:920
TrackPanel::UpdateStatusMessage
void UpdateStatusMessage(const TranslatableString &status) override
Definition: TrackPanel.cpp:615
wxPanelWrapper::SetName
void SetName()
Definition: wxPanelWrapper.cpp:61
anonymous_namespace{TrackPanel.cpp}::DrawTrackName
void DrawTrackName(int leftOffset, TrackPanelDrawingContext &context, const Track *t, const wxRect &rect)
Definition: TrackPanel.cpp:1108
anonymous_namespace{TrackPanel.cpp}::sKey
AttachedWindows::RegisteredFactory sKey
Definition: TrackPanel.cpp:203
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:377
Track
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:224
Track::IsLeader
bool IsLeader() const
Definition: Track.cpp:298
ToolCodes::envelopeTool
@ envelopeTool
Definition: ProjectSettings.h:41
anonymous_namespace{TrackPanel.cpp}::Subgroup::Children
Subdivision Children(const wxRect &rect) override
Definition: TrackPanel.cpp:1596
TrackPanelResizeHandle.h
anonymous_namespace{TrackPanel.cpp}::MainGroup::mPanel
TrackPanel & mPanel
Definition: TrackPanel.cpp:1636
kTrackSeparatorThickness
@ kTrackSeparatorThickness
Definition: TrackPanelConstants.h:23
AudioIO.h
anonymous_namespace{TrackPanel.cpp}::ChannelGroup
Definition: TrackPanel.cpp:1394
ProjectStatus::Get
static ProjectStatus & Get(AudacityProject &project)
Definition: ProjectStatus.cpp:21
anonymous_namespace{TrackPanel.cpp}::ChannelGroup::mpTrack
std::shared_ptr< Track > mpTrack
Definition: TrackPanel.cpp:1471
kTopInset
@ kTopInset
Definition: TrackPanelConstants.h:20
TrackPanel::Refresh
void Refresh(bool eraseBackground=true, const wxRect *rect=(const wxRect *) NULL) override
Definition: TrackPanel.cpp:785
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
kAffordancesAreaHeight
@ kAffordancesAreaHeight
Definition: TrackPanelConstants.h:19
TrackPanel::mRefreshBacking
bool mRefreshBacking
Definition: TrackPanel.h:216
anonymous_namespace{TrackPanel.cpp}::VRulersAndChannels
Definition: TrackPanel.cpp:1267
CellularPanel
Formerly part of TrackPanel, this abstract base class has no special knowledge of Track objects and i...
Definition: CellularPanel.h:34
TrackView::GetSubViews
virtual Refinement GetSubViews(const wxRect &rect)
Definition: TrackView.cpp:131
anonymous_namespace{TrackPanel.cpp}::VRulersAndChannels::Children
Subdivision Children(const wxRect &rect) override
Definition: TrackPanel.cpp:1274
anonymous_namespace{TrackPanel.cpp}::MainGroup::Children
Subdivision Children(const wxRect &rect) override
Definition: TrackPanel.cpp:1630
TrackPanel::mTrackArtist
std::unique_ptr< TrackArtist > mTrackArtist
Definition: TrackPanel.h:196
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
AdornedRulerPanel.h
SetProjectPanel
AUDACITY_DLL_API void SetProjectPanel(AudacityProject &project, wxWindow &panel)
Definition: ProjectWindows.cpp:66
anonymous_namespace{TrackPanel.cpp}::VRulersAndChannels::VRulersAndChannels
VRulersAndChannels(const std::shared_ptr< Track > &pTrack, TrackView::Refinement refinement, wxCoord leftOffset)
Definition: TrackPanel.cpp:1268
AudioIOEvent::type
enum AudioIOEvent::Type type
TrackPanelMouseState
Definition: TrackPanelMouseEvent.h:28
ProjectHistory.h
TrackPanel::OnTrackMenu
void OnTrackMenu(Track *t=NULL)
Definition: TrackPanel.cpp:995
CellularPanel::mLastMouseState
wxMouseState mLastMouseState
Definition: CellularPanel.h:165
CellularPanel::VisitCells
void VisitCells(const SimpleCellVisitor &visitor)
Definition: CellularPanel.cpp:1061
ViewInfo::SetHeight
void SetHeight(int height)
Definition: ViewInfo.h:198
anonymous_namespace{TrackPanel.cpp}::MarginY
@ MarginY
Definition: TrackPanel.cpp:1082
RefreshCode.h
kRightMargin
@ kRightMargin
Definition: ZoomInfo.h:34
OverlayPanel::DrawOverlays
void DrawOverlays(bool repaint_all, wxDC *pDC=nullptr)
Definition: OverlayPanel.cpp:43
anonymous_namespace{TrackPanel.cpp}::HorizontalGroup::mRefinement
Refinement mRefinement
Definition: TrackPanel.cpp:1376
TrackPanel::OnTrackFocusChange
void OnTrackFocusChange(wxCommandEvent &event)
Definition: TrackPanel.cpp:1721
CellularPanel::DoContextMenu
void DoContextMenu(TrackPanelCell *pCell=nullptr)
Definition: CellularPanel.cpp:967
TrackView::GetChannelGroupHeight
static int GetChannelGroupHeight(const Track *pTrack)
Definition: TrackView.cpp:34
anonymous_namespace{TrackPanel.cpp}::ResizingChannelGroup
Definition: TrackPanel.cpp:1576
TrackListEvent::mType
const Type mType
Definition: Track.h:1275
Prefs.h
kChannelSeparatorThickness
@ kChannelSeparatorThickness
Definition: TrackPanelConstants.h:24
AudioIOEvent
Definition: AudioIO.h:59
AudioIOEvent::MONITOR
@ MONITOR
Definition: AudioIO.h:64
anonymous_namespace{TrackPanel.cpp}::GetTrackNameRect
wxRect GetTrackNameRect(int leftOffset, const wxRect &trackRect, wxCoord textWidth, wxCoord textHeight)
Definition: TrackPanel.cpp:1095
ProjectWindow.h
TrackPanel::mTracks
std::shared_ptr< TrackList > mTracks
Definition: TrackPanel.h:192
TrackArtist::PassMargins
@ PassMargins
Definition: TrackArtist.h:45
anonymous_namespace{TrackPanel.cpp}::ChannelGroup::mLeftOffset
wxCoord mLeftOffset
Definition: TrackPanel.cpp:1472
TrackList::Any
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1379
anonymous_namespace{TrackPanel.cpp}::VRulersAndChannels::Draw
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
Definition: TrackPanel.cpp:1288
anonymous_namespace{TrackPanel.cpp}::Subgroup::mPanel
TrackPanel & mPanel
Definition: TrackPanel.cpp:1624
anonymous_namespace{TrackPanel.cpp}::EmptyPanelRect
Definition: TrackPanel.cpp:1336
CommonTrackPanelCell
Definition: CommonTrackPanelCell.h:31
TranslatableString::Join
TranslatableString & Join(TranslatableString arg, const wxString &separator={}) &
Append another translatable string.
Definition: TranslatableString.cpp:124
TrackPanel::OnUndoReset
void OnUndoReset(wxCommandEvent &event)
Definition: TrackPanel.cpp:460
TrackPanel::OnAudioIO
void OnAudioIO(AudioIOEvent)
Definition: TrackPanel.cpp:806
AudioIO::Get
static AudioIO * Get()
Definition: AudioIO.cpp:140
TrackPanelConstants.h
ThemeBase::Colour
wxColour & Colour(int iIndex)
safenew
#define safenew
Definition: MemoryX.h:10
settings
static Settings & settings()
Definition: TrackInfo.cpp:87
RefreshCode
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
TrackArtist::PassBackground
@ PassBackground
Definition: TrackArtist.h:49
float_cast.h
AColor.h
kTrackInfoWidth
@ kTrackInfoWidth
Definition: ZoomInfo.h:36
within
bool within(A a, B b, DIST d)
Definition: TrackPanel.cpp:163
TrackPanel::HandlePageDownKey
void HandlePageDownKey()
Definition: TrackPanel.cpp:604
TrackPanelResizerCell.h
END_EVENT_TABLE
END_EVENT_TABLE()
CellularPanel::FindCell
FoundCell FindCell(int mouseX, int mouseY)
Definition: CellularPanel.cpp:1132
ProjectAudioIO.h
TrackPanel::Destroy
static void Destroy(AudacityProject &project)
Definition: TrackPanel.cpp:237
TrackPanel::mTimeCount
int mTimeCount
Definition: TrackPanel.h:214
Observer::Publisher::Subscribe
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
TrackPanel::RefreshTrack
void RefreshTrack(Track *trk, bool refreshbacking=true)
Definition: TrackPanel.cpp:747
TrackPanel::VerticalScroll
void VerticalScroll(float fracPosition)
Definition: TrackPanel.cpp:1046
ProjectHistory::Get
static ProjectHistory & Get(AudacityProject &project)
Definition: ProjectHistory.cpp:26
TrackArtist::PassFocus
@ PassFocus
Definition: TrackArtist.h:50
TrackPanelResizerCell::Get
static TrackPanelResizerCell & Get(Track &track)
Definition: TrackPanelResizerCell.cpp:114
ZoomInfo::h
double h
Definition: ZoomInfo.h:60
TrackPanel::FindRulerRects
std::vector< wxRect > FindRulerRects(const Track *target)
Definition: TrackPanel.cpp:1695
kLeftMargin
@ kLeftMargin
Definition: ZoomInfo.h:33
TrackPanel::IsAudioActive
bool IsAudioActive()
Definition: TrackPanel.cpp:609
ZoomInfo::PositionToTime
double PositionToTime(wxInt64 position, wxInt64 origin=0, bool ignoreFisheye=false) const
Definition: ZoomInfo.cpp:41
anonymous_namespace{TrackPanel.cpp}::LabeledChannelGroup::DrawingArea
wxRect DrawingArea(TrackPanelDrawingContext &, const wxRect &rect, const wxRect &, unsigned iPass) override
Definition: TrackPanel.cpp:1546
TrackView::GetHeight
int GetHeight() const
Definition: TrackView.cpp:164
anonymous_namespace{TrackPanel.cpp}::ResizingChannelGroup::Children
Subdivision Children(const wxRect &rect) override
Definition: TrackPanel.cpp:1580
anonymous_namespace{TrackPanel.cpp}::EmptyPanelRect::~EmptyPanelRect
~EmptyPanelRect()
Definition: TrackPanel.cpp:1346
anonymous_namespace{TrackPanel.cpp}::ChannelGroup::Children
Subdivision Children(const wxRect &rect_) override
Definition: TrackPanel.cpp:1397
TrackPanel::UpdateTrackVRuler
void UpdateTrackVRuler(Track *t)
Definition: TrackPanel.cpp:936
SelectedRegion
Defines a selected portion of a project.
Definition: SelectedRegion.h:38
ZoomInfo::SetWidth
void SetWidth(int width)
Definition: ZoomInfo.h:96
TrackPanel::mpBackground
std::shared_ptr< CommonTrackPanelCell > mpBackground
Definition: TrackPanel.h:225
anonymous_namespace{TrackPanel.cpp}::ResizingChannelGroup::mpTrack
std::shared_ptr< Track > mpTrack
Definition: TrackPanel.cpp:1589
anonymous_namespace{TrackPanel.cpp}::LabeledChannelGroup::mLeftOffset
wxCoord mLeftOffset
Definition: TrackPanel.cpp:1571
TrackPanelDrawable::Draw
virtual void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass)
Definition: TrackPanelDrawable.cpp:17