Audacity  3.0.3
WaveTrackView.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 WaveTrackView.cpp
6 
7 Paul Licameli split from TrackPanel.cpp
8 
9 **********************************************************************/
10 
11 #include "WaveTrackView.h"
12 
13 #include <unordered_set>
14 
15 #include "CutlineHandle.h"
16 
17 #include <numeric>
18 #include <wx/dc.h>
19 #include <wx/graphics.h>
20 
21 #include "../../../../AColor.h"
22 #include "../../../../WaveClip.h"
23 #include "../../../../WaveTrack.h"
24 
25 #include "../../../../../images/Cursors.h"
26 #include "../../../../AllThemeResources.h"
27 
28 #include "../../../../HitTestResult.h"
29 #include "../../../../ProjectHistory.h"
30 #include "../../../../RefreshCode.h"
31 #include "../../../../TrackArtist.h"
32 #include "../../../../TrackPanelDrawingContext.h"
33 #include "../../../../TrackPanelMouseEvent.h"
34 #include "../../../../ViewInfo.h"
35 #include "../../../../prefs/TracksPrefs.h"
36 
37 #include "../../../ui/TimeShiftHandle.h"
38 #include "../../../ui/ButtonHandle.h"
39 #include "../../../../TrackInfo.h"
40 
41 namespace {
42 
43 using WaveTrackSubViewPtrs = std::vector< std::shared_ptr< WaveTrackSubView > >;
44 
45 // Structure that collects and modifies information on sub-view positions
46 // Written with great generality, allowing any number of sub-views
48 {
49  enum { HotZoneSize = 5 }; // so many pixels at top and bottom of each subview
50 
52  : mwView{
53  std::static_pointer_cast<WaveTrackView>( view.shared_from_this() ) }
54  {
55  mSubViews = view.GetAllSubViews();
56  mOrigPlacements = mNewPlacements = view.SavePlacements();
57  FindPermutation();
58  }
59 
61  {
62  // Find a certain sort of the sub-views
63  auto size = mOrigPlacements.size();
64  wxASSERT( mSubViews.size() == size );
65  mPermutation.resize( size );
66  const auto begin = mPermutation.begin(), end = mPermutation.end();
67  std::iota( begin, end, 0 );
68  static auto invisible = []( const WaveTrackSubViewPlacement &placement ){
69  return placement.index < 0 || placement.fraction <= 0;
70  };
71  const auto comp = [this]( size_t ii, size_t jj ){
72  auto &pi = mOrigPlacements[ii];
73  bool iInvisible = invisible( pi );
74 
75  auto &pj = mOrigPlacements[jj];
76  bool jInvisible = invisible( pj );
77 
78  // Sort the invisibles to the front, rest by index
79  if ( iInvisible != jInvisible )
80  return iInvisible;
81  else if ( !iInvisible )
82  return pi.index < pj.index;
83  else
84  // Minor sort among the invisible views by their type
85  return mSubViews[ii]->SubViewType() < mSubViews[jj]->SubViewType();
86  };
87  std::sort( begin, end, comp );
88  // Find the start of visible sub-views
89  auto first = std::find_if( begin, end, [this](size_t ii){
90  return !invisible( mOrigPlacements[ii] );
91  } );
92  mFirstSubView = first - begin;
93  }
94 
95  size_t NVisible() const
96  { return mPermutation.size() - mFirstSubView; }
97 
98  bool ModifyPermutation( bool top )
99  {
100  bool rotated = false;
101  const auto pBegin = mPermutation.begin(), pEnd = mPermutation.end();
102  auto pFirst = pBegin + mFirstSubView;
103  if ( mFirstSubView > 0 ) {
104  // In case of dragging the top edge of the topmost view, or the
105  // bottom edge of the bottommost, decide which of the invisible
106  // views can become visible, and reassign the sequence.
107  // For definiteness, that choice depends on the subview type numbers;
108  // see the sorting criteria above.
109  --mFirstSubView;
110  --pFirst;
111  if ( top ) {
112  // If you drag down the top, the greatest-numbered invisible
113  // subview type will appear there.
114  mNewPlacements[ *pFirst ].fraction = 0;
115  }
116  else {
117  // If you drag up the bottom, let the least-numbered invisible
118  // subview type appear there.
119  mNewPlacements[ *pBegin ].fraction = 0;
120  std::rotate( pBegin, pBegin + 1, pEnd );
121  rotated = true;
122  }
123  }
124  // Reassign index numbers to all sub-views and 0 fraction to invisibles
125  for ( auto pIter = pBegin; pIter != pFirst; ++pIter ) {
126  auto &placement = mNewPlacements[ *pIter ];
127  placement.index = -1;
128  placement.fraction = 0;
129  }
130  size_t index = 0;
131  for ( auto pIter = pFirst; pIter != pEnd; ++pIter )
132  mNewPlacements[ *pIter ].index = index++;
133  return rotated;
134  }
135 
136  size_t FindIndex( WaveTrackSubView &subView ) const
137  {
138  const auto begin = mPermutation.begin(), end = mPermutation.end();
139  auto iter = std::find_if( begin, end, [&](size_t ii){
140  return mSubViews[ ii ].get() == &subView;
141  } );
142  return iter - begin;
143  }
144 
145  std::pair< size_t, bool >
147  wxCoord yy, wxCoord top, wxCoord height )
148  {
149  const auto index = FindIndex( subView );
150  auto size = mPermutation.size();
151  if ( index < (int)size ) {
152  yy -= top;
153  if ( yy >= 0 && yy < HotZoneSize && index > 0 )
154  return { index, true }; // top hit
155  if ( yy < height && yy >= height - HotZoneSize &&
156  // Have not yet called ModifyPermutation; dragging bottom of
157  // bottommost view allowed only if at least one view is invisible
158  ( index < (int)size - 1 || mFirstSubView > 0 ) )
159  return { index, false }; // bottom hit
160  }
161  return { size, false }; // not hit
162  }
163 
164  std::vector<wxCoord> ComputeHeights( wxCoord totalHeight )
165  {
166  // Compute integer-valued heights
167  float total = 0;
168  for (const auto index : mPermutation ) {
169  const auto &placement = mOrigPlacements[ index ];
170  total += std::max( 0.f, placement.fraction );
171  }
172  float partial = 0;
173  wxCoord lastCoord = 0;
174  std::vector<wxCoord> result;
175  for (const auto index : mPermutation ) {
176  const auto &placement = mOrigPlacements[ index ];
177  auto fraction = std::max( 0.f, placement.fraction );
178  wxCoord coord = ( (partial + fraction ) / total ) * totalHeight;
179  auto height = coord - lastCoord;
180  result.emplace_back( height );
181  mNewPlacements[ index ].fraction = height;
182  lastCoord = coord;
183  partial += fraction;
184  }
185  return result;
186  }
187 
188  void UpdateViews( bool rollback )
189  {
190  auto pView = mwView.lock();
191  if ( pView ) {
192  auto pTrack = static_cast< WaveTrack* >( pView->FindTrack().get() );
193  for ( auto pChannel : TrackList::Channels<WaveTrack>( pTrack ) )
195  rollback ? mOrigPlacements : mNewPlacements );
196  }
197  }
198 
199  std::weak_ptr< WaveTrackView > mwView;
202  // Array mapping ordinal into the placement and subview arrays
203  std::vector< size_t > mPermutation;
204  // index into mPermutation
205  size_t mFirstSubView{};
206 };
207 
209 {
210 public:
211  enum { MinHeight = SubViewAdjuster::HotZoneSize };
212 
213  static UIHandlePtr HitTest( std::weak_ptr<UIHandle> &holder,
214  WaveTrackView &view,
215  WaveTrackSubView &subView,
216  const TrackPanelMouseState &state )
217  {
218  if ( !view.GetMultiView() )
219  return {};
220 
221  SubViewAdjuster adjuster{ view };
222  auto hit = adjuster.HitTest( subView,
223  state.state.GetY(), state.rect.GetTop(), state.rect.GetHeight() );
224  auto index = hit.first;
225 
226  if ( index < adjuster.mPermutation.size() ) {
227  UIHandlePtr result = std::make_shared< SubViewAdjustHandle >(
228  std::move( adjuster ), index, view.GetLastHeight(), hit.second
229  );
230  result = AssignUIHandlePtr( holder, result );
231  return result;
232  }
233  else
234  return {};
235  }
236 
238  SubViewAdjuster &&adjuster, size_t subViewIndex,
239  wxCoord viewHeight, bool top )
240  : mAdjuster{ std::move( adjuster ) }
241  , mMySubView{ subViewIndex }
242  , mViewHeight{ viewHeight }
243  , mTop{ top }
244  {
245  if ( mAdjuster.ModifyPermutation( top ) )
246  --mMySubView;
247  }
248 
250  const TrackPanelMouseEvent &event, AudacityProject *pProject ) override
251  {
252  using namespace RefreshCode;
253  const auto &permutation = mAdjuster.mPermutation;
254  const auto size = permutation.size();
255  if ( mMySubView >= size )
256  return Cancelled;
257 
258  if (event.event.LeftDClick()) {
259  for ( auto &placement : mAdjuster.mNewPlacements ) {
260  if ( placement.index >= 0 )
261  placement.fraction = 1.0f;
262  else
263  placement.fraction = 0.0f;
264  }
265  mAdjuster.UpdateViews( false );
266  ProjectHistory::Get( *pProject ).ModifyState( false );
267 
268  // Do not start a drag
269  return Cancelled | RefreshAll;
270  }
271 
272  const auto &rect = event.rect;
273  const auto height = rect.GetHeight();
274  mOrigHeight = height;
275 
276  mOrigHeights = mAdjuster.ComputeHeights( mViewHeight );
277 
278  // Find the total height of the sub-views that may resize
279  mTotalHeight = 0;
280  auto index = ( mTop ? mAdjuster.mFirstSubView : mMySubView );
281  const auto end = ( mTop ? mMySubView + 1 : permutation.size() );
282  for (; index != end; ++index)
283  mTotalHeight += mOrigHeights[ index ];
284 
285  wxASSERT( height == mOrigHeights[ mMySubView ] );
286 
287  // Compute the maximum and minimum Y coordinates for drag effect
288  if ( mTop ) {
289  mOrigY = rect.GetTop();
290  mYMax = rect.GetBottom();
291  mYMin = mYMax - mTotalHeight + 1;
292  }
293  else {
294  mOrigY = rect.GetBottom();
295  mYMin = rect.GetTop();
296  mYMax = mYMin + mTotalHeight - 1;
297  }
298 
299  return RefreshNone;
300  }
301 
302  Result Drag( const TrackPanelMouseEvent &event, AudacityProject * ) override
303  {
304  using namespace RefreshCode;
305  auto pView = mAdjuster.mwView.lock();
306  if ( !pView )
307  return Cancelled;
308 
309  // Find new height for the dragged sub-view
310  auto newY = std::max( mYMin, std::min( mYMax, event.event.GetY() ) );
311  const auto delta = newY - mOrigY;
312  wxCoord newHeight = mTop
313  ? mOrigHeight - delta
314  : mOrigHeight + delta
315  ;
316  wxASSERT( newHeight >= 0 && newHeight <= mTotalHeight );
317  if ( newHeight < MinHeight )
318  // Snap the dragged sub-view to nothing
319  newHeight = 0;
320 
321  // Reassign height for the dragged sub-view
322  auto &myPlacement =
323  mAdjuster.mNewPlacements[ mAdjuster.mPermutation[ mMySubView ] ];
324  myPlacement.fraction = newHeight;
325 
326  // Grow or shrink other sub-views
327  auto excess = newHeight - mOrigHeight; // maybe negative
328  const auto adjustHeight = [&](size_t ii) {
329  if (excess == 0)
330  return true;
331 
332  const auto oldFraction = mOrigHeights[ ii ];
333 
334  auto index = mAdjuster.mPermutation[ ii ];
335  auto &placement = mAdjuster.mNewPlacements[ index ];
336  auto &fraction = placement.fraction;
337 
338  if (excess > oldFraction) {
339  excess -= oldFraction, fraction = 0;
340  return false;
341  }
342  else {
343  auto newFraction = oldFraction - excess;
344  if ( newFraction < MinHeight ) {
345  // This snaps very short sub-views to nothing
346  myPlacement.fraction += newFraction;
347  fraction = 0;
348  }
349  else
350  fraction = newFraction;
351  return true;
352  }
353  };
354  if ( mTop ) {
355  for ( size_t ii = mMySubView; ii > 0; ) {
356  --ii;
357  if ( adjustHeight( ii ) )
358  break;
359  }
360  }
361  else {
362  for ( size_t ii = mMySubView + 1, size = mAdjuster.mPermutation.size();
363  ii < size; ++ii
364  ) {
365  if ( adjustHeight( ii ) )
366  break;
367  }
368  }
369 
370  // Save adjustment to the track and request a redraw
371  mAdjuster.UpdateViews( false );
372  return RefreshAll;
373  }
374 
376  const TrackPanelMouseState &state, AudacityProject * ) override
377  {
378  static auto resizeCursor =
379  ::MakeCursor(wxCURSOR_ARROW, SubViewsCursorXpm, 16, 16);
380  return {
381  XO(
382 "Click and drag to adjust sizes of sub-views, double-click to split evenly"),
383  &*resizeCursor
384  };
385  }
386 
388  const TrackPanelMouseEvent &event, AudacityProject *pProject,
389  wxWindow *pParent) override
390  {
391  ProjectHistory::Get( *pProject ).ModifyState( false );
393  }
394 
396  {
397  mAdjuster.UpdateViews( true );
399  }
400 
401 private:
402 
404  std::vector<wxCoord> mOrigHeights;
405 
406  // An index into mAdjuster.mPermutation
407  size_t mMySubView{};
408 
409  wxCoord mYMin{}, mYMax{};
410  wxCoord mViewHeight{}; // Total height of all sub-views
411  wxCoord mTotalHeight{}; // Total height of adjusting sub-views only
412  wxCoord mOrigHeight{};
413  wxCoord mOrigY{};
414 
415  // Whether we drag the top or the bottom of the sub-view
416  bool mTop{};
417 };
418 
420 {
421 public:
422  // Make it somewhat wider than the close button
423  enum { HotZoneWidth = 3 * kTrackInfoBtnSize / 2 };
424 
425  static UIHandlePtr HitTest( std::weak_ptr<UIHandle> &holder,
426  WaveTrackView &view, WaveTrackSubView &subView,
427  const TrackPanelMouseState &state )
428  {
429  if ( !view.GetMultiView() )
430  return {};
431 
432  SubViewAdjuster adjuster{ view };
433  if ( adjuster.NVisible() < 2 )
434  return {};
435 
436  auto relX = state.state.GetX() - state.rect.GetLeft();
437  if ( relX >= HotZoneWidth )
438  return {};
439 
440  auto index = adjuster.FindIndex( subView );
441 
442  // Hit on the rearrange cursor only in the top and bottom thirds of
443  // sub-view height, leaving the rest free to hit the selection cursor
444  // first.
445  // And also exclude the top third of the topmost sub-view and bottom
446  // third of bottommost.
447  auto relY = state.state.GetY() - state.rect.GetTop();
448  auto height = state.rect.GetHeight();
449  bool hit =
450  ( ( 3 * relY < height ) && index > 0 ) // top hit
451  ||
452  ( ( 3 * relY > 2 * height ) &&
453  index < adjuster.mPermutation.size() - 1 ) // bottom
454  ;
455  if ( ! hit )
456  return {};
457 
458  UIHandlePtr result = std::make_shared< SubViewRearrangeHandle >(
459  std::move( adjuster ),
460  index, view.GetLastHeight()
461  );
462  result = AssignUIHandlePtr( holder, result );
463  return result;
464  }
465 
467  SubViewAdjuster &&adjuster, size_t subViewIndex,
468  wxCoord viewHeight )
469  : mAdjuster{ std::move( adjuster ) }
470  , mMySubView{ subViewIndex }
471  , mViewHeight{ viewHeight }
472  {
473  }
474 
476  const TrackPanelMouseEvent &event, AudacityProject *pProject ) override
477  {
478  using namespace RefreshCode;
479  const auto &permutation = mAdjuster.mPermutation;
480  const auto size = permutation.size();
481  if ( mMySubView >= size )
482  return Cancelled;
483 
484  mHeights = mAdjuster.ComputeHeights( mViewHeight );
485 
486  // Find y coordinate of first sub-view
487  wxCoord heightAbove = 0;
488  for (auto index = mAdjuster.mFirstSubView;
489  index != mMySubView; ++index)
490  heightAbove += mHeights[ index ];
491  mTopY = event.rect.GetTop() - heightAbove;
492 
493  return RefreshNone;
494  }
495 
496  bool Clicked() const { return !mHeights.empty(); }
497 
498  enum DragChoice_t{ Upward, Downward, Neutral };
499 
501  {
502  // Disregard x coordinate -- so the mouse need not be in any sub-view,
503  // just in the correct range of y coordinates
504  auto yy = event.event.GetY();
505  auto coord = mTopY;
506  size_t ii = mAdjuster.mFirstSubView;
507  if ( yy < mTopY )
508  return ( mMySubView == ii ) ? Neutral : Upward;
509 
510  for ( auto nn = mHeights.size(); ii < nn; ++ii ) {
511  const auto height = mHeights[ ii ];
512  coord += height;
513  if ( yy < coord )
514  break;
515  }
516 
517  if ( ii < mMySubView ) {
518  if ( yy < coord - mHeights[ ii ] + mHeights[ mMySubView ] )
519  return Upward;
520  }
521 
522  if ( ii > mMySubView ) {
523  if( mMySubView < mHeights.size() - 1 &&
524  yy >= coord - mHeights[ mMySubView ] )
525  return Downward;
526  }
527 
528  return Neutral;
529  }
530 
531  Result Drag( const TrackPanelMouseEvent &event, AudacityProject * ) override
532  {
533  using namespace RefreshCode;
534  auto pView = mAdjuster.mwView.lock();
535  if ( !pView )
536  return Cancelled;
537 
538  switch( DragChoice( event ) ) {
539  case Upward:
540  {
541  std::swap( mHeights[ mMySubView ], mHeights[ mMySubView - 1 ] );
542  std::swap(
543  mAdjuster.mNewPlacements[ mMySubView ].index,
544  mAdjuster.mNewPlacements[ mMySubView - 1 ].index
545  );
546  --mMySubView;
547  break;
548  }
549  case Downward:
550  {
551  std::swap( mHeights[ mMySubView ], mHeights[ mMySubView + 1 ] );
552  std::swap(
553  mAdjuster.mNewPlacements[ mMySubView ].index,
554  mAdjuster.mNewPlacements[ mMySubView + 1 ].index
555  );
556  ++mMySubView;
557  break;
558  }
559  default:
560  return RefreshNone;
561  }
562 
563  // Save adjustment to the track and request a redraw
564  mAdjuster.UpdateViews( false );
565  return RefreshAll;
566  }
567 
569  const TrackPanelMouseState &state, AudacityProject * ) override
570  {
571  static auto hoverCursor =
572  ::MakeCursor(wxCURSOR_HAND, RearrangeCursorXpm, 16, 16);
573  static auto clickedCursor =
574  ::MakeCursor(wxCURSOR_HAND, RearrangingCursorXpm, 16, 16);
575  return {
576  XO("Click and drag to rearrange sub-views"),
577  Clicked() ? &*clickedCursor : &*hoverCursor,
578  XO("Rearrange sub-views")
579  };
580  }
581 
583  const TrackPanelMouseEvent &event, AudacityProject *pProject,
584  wxWindow *pParent) override
585  {
586  ProjectHistory::Get( *pProject ).ModifyState( false );
588  }
589 
591  {
592  mAdjuster.UpdateViews( true );
594  }
595 
596 private:
597 
599  std::vector<wxCoord> mHeights;
600  wxCoord mTopY;
601 
602  // An index into mAdjuster.mPermutation
603  size_t mMySubView{};
604 
605  wxCoord mViewHeight{}; // Total height of all sub-views
606 };
607 
609 {
610  static wxRect GetButtonRect( const wxRect &rect )
611  {
612  return {
613  rect.GetLeft(),
614  rect.GetTop(),
617  };
618  }
619 
620 public:
621  static UIHandlePtr HitTest( std::weak_ptr<UIHandle> &holder,
622  WaveTrackView &view, WaveTrackSubView &subView,
623  const TrackPanelMouseState &state )
624  {
625  SubViewAdjuster adjuster{ view };
626  if ( adjuster.NVisible() < 2 )
627  return {};
628 
629  const auto rect = GetButtonRect( state.rect );
630  if ( !rect.Contains( state.state.GetPosition() ) )
631  return {};
632  auto index = adjuster.FindIndex( subView );
633  UIHandlePtr result = std::make_shared<SubViewCloseHandle>(
634  std::move( adjuster ), index, view.FindTrack(), rect );
635  result = AssignUIHandlePtr( holder, result );
636  return result;
637  }
638 
640  SubViewAdjuster &&adjuster, size_t index,
641  const std::shared_ptr<Track> &pTrack, const wxRect &rect )
642  : ButtonHandle{ pTrack, rect }
643  , mAdjuster{ std::move( adjuster ) }
644  , mMySubView{ index }
645  {
646  }
647 
649  const wxMouseEvent &event, AudacityProject *pProject, wxWindow *pParent)
650  override
651  {
652  ProjectHistory::Get( *pProject ).ModifyState( false );
653  auto &myPlacement =
654  mAdjuster.mNewPlacements[ mAdjuster.mPermutation[ mMySubView ] ];
655  myPlacement.fraction = 0;
656  mAdjuster.UpdateViews( false );
658  }
659 
661  const wxMouseState &state, AudacityProject &project) const override
662  {
663  return XO("Close sub-view");
664  }
665 
666  // TrackPanelDrawable implementation
667  void Draw(
668  TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass )
669  override
670  {
671  if ( iPass == TrackArtist::PassMargins ) { // after PassTracks
673  context, GetButtonRect(rect), GetTrack().get(), this );
674  }
675  }
676 
677 private:
679  size_t mMySubView{};
680 };
681 
682 }
683 
684 std::pair<
685  bool, // if true, hit-testing is finished
686  std::vector<UIHandlePtr>
688  const TrackPanelMouseState &state,
689  const AudacityProject *pProject, int currentTool, bool bMultiTool,
690  const std::shared_ptr<WaveTrack> &wt)
691 {
692  auto results = WaveTrackView::DoDetailedHitTest(
693  state, pProject, currentTool, bMultiTool, wt, *this );
694  if ( results.first )
695  return results;
696 
697  auto pWaveTrackView = mwWaveTrackView.lock();
698  if ( pWaveTrackView && !state.state.HasModifiers() ) {
699  if ( auto pHandle = SubViewCloseHandle::HitTest(
700  mCloseHandle,
701  *pWaveTrackView, *this, state ) )
702  results.second.push_back( pHandle );
703  if ( auto pHandle = SubViewAdjustHandle::HitTest(
704  mAdjustHandle,
705  *pWaveTrackView, *this, state ) )
706  results.second.push_back( pHandle );
707  if ( auto pHandle = SubViewRearrangeHandle::HitTest(
708  mRearrangeHandle,
709  *pWaveTrackView, *this, state ) )
710  results.second.push_back( pHandle );
711  }
712  if (auto result = CutlineHandle::HitTest(
713  mCutlineHandle, state.state, state.rect,
714  pProject, wt ))
715  // This overriding test applies in all tools
716  results.second.push_back(result);
717 
718  return results;
719 }
720 
721 
723  TrackPanelDrawingContext &context, const WaveTrack *track,
724  const wxRect &rect )
725 {
726  auto &dc = context.dc;
727  const auto artist = TrackArtist::Get( context );
728 
729  const auto &zoomInfo = *artist->pZoomInfo;
730 
731 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
732  auto target2 = dynamic_cast<CutlineHandle*>(context.target.get());
733 #endif
734  for (const auto loc : track->GetCachedLocations()) {
735  bool highlightLoc = false;
736 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
737  highlightLoc =
738  target2 && target2->GetTrack().get() == track &&
739  target2->GetLocation() == loc;
740 #endif
741  const int xx = zoomInfo.TimeToPosition(loc.pos);
742  if (xx >= 0 && xx < rect.width) {
743  dc.SetPen( highlightLoc ? AColor::uglyPen : *wxGREY_PEN );
744  AColor::Line(dc, (int) (rect.x + xx - 1), rect.y, (int) (rect.x + xx - 1), rect.y + rect.height);
745  if (loc.typ == WaveTrackLocation::locationCutLine) {
746  dc.SetPen( highlightLoc ? AColor::uglyPen : *wxRED_PEN );
747  }
748  else {
749 #ifdef EXPERIMENTAL_DA
750  // JKC Black does not show up enough.
751  dc.SetPen(highlightLoc ? AColor::uglyPen : *wxWHITE_PEN);
752 #else
753  dc.SetPen(highlightLoc ? AColor::uglyPen : *wxBLACK_PEN);
754 #endif
755  }
756  AColor::Line(dc, (int) (rect.x + xx), rect.y, (int) (rect.x + xx), rect.y + rect.height);
757  dc.SetPen( highlightLoc ? AColor::uglyPen : *wxGREY_PEN );
758  AColor::Line(dc, (int) (rect.x + xx + 1), rect.y, (int) (rect.x + xx + 1), rect.y + rect.height);
759  }
760  }
761 }
762 
764 {
765  return static_cast< WaveTrackView& >( TrackView::Get( track ) );
766 }
767 
769 {
770  return Get( const_cast<WaveTrack&>( track ) );
771 }
772 
773 WaveTrackView::WaveTrackView( const std::shared_ptr<Track> &pTrack )
774  : CommonTrackView{ pTrack }
775 {
776 }
777 
779  : CommonTrackView( waveTrackView.FindTrack() )
780 {
781  mwWaveTrackView = std::static_pointer_cast<WaveTrackView>(
782  waveTrackView.shared_from_this() );
783 }
784 
786 {
787 }
788 
789 void WaveTrackView::CopyTo( Track &track ) const
790 {
791  TrackView::CopyTo( track );
792  auto &other = TrackView::Get( track );
793 
794  if ( const auto pOther = dynamic_cast< WaveTrackView* >( &other ) ) {
795  // only these fields are important to preserve in undo/redo history
796  pOther->RestorePlacements( SavePlacements() );
797  pOther->mMultiView = mMultiView;
798  }
799 }
800 
801 std::vector<UIHandlePtr> WaveTrackView::DetailedHitTest
802 (const TrackPanelMouseState &st,
803  const AudacityProject *pProject, int currentTool, bool bMultiTool)
804 {
805  // should not come here any more, delegation to sub-view instead
806  wxASSERT( false );
807  return {};
808 }
809 
810 std::pair< bool, std::vector<UIHandlePtr> >
812 (const TrackPanelMouseState &st,
813  const AudacityProject *pProject, int currentTool, bool bMultiTool,
814  const std::shared_ptr<WaveTrack> &pTrack,
815  CommonTrackView &view)
816 {
817  // common hit-testing for different sub-view types, to help implement their
818  // DetailedHitTest()
819 
820  // This is the only override of Track::DetailedHitTest that still
821  // depends on the state of the Tools toolbar.
822  // If that toolbar were eliminated, this could simplify to a sequence of
823  // hit test routines describable by a table.
824 
825  UIHandlePtr result;
826  std::vector<UIHandlePtr> results;
827 
828  if (bMultiTool && st.state.CmdDown()) {
829  // Ctrl modifier key in multi-tool overrides everything else
830  // (But this does not do the time shift constrained to the vertical only,
831  // which is what happens when you hold Ctrl in the Time Shift tool mode)
833  view.mTimeShiftHandle, pTrack, false);
834  if (result)
835  results.push_back(result);
836  return { true, results };
837  }
838  return { false, results };
839 }
840 
842  -> std::vector< WaveTrackSubView::Type >
843 {
844  BuildSubViews();
845 
846  // Collect the display types of visible views and sort them by position
847  using Pair = std::pair< int, WaveTrackSubView::Type >;
848  std::vector< Pair > pairs;
849  size_t ii = 0;
850  WaveTrackSubViews::ForEach( [&]( const WaveTrackSubView &subView ){
851  auto &placement = mPlacements[ii];
852  if ( placement.fraction > 0 )
853  pairs.emplace_back( placement.index, subView.SubViewType() );
854  ++ii;
855  } );
856  std::sort( pairs.begin(), pairs.end() );
857  std::vector< WaveTrackSubView::Type > results;
858  for ( const auto &pair : pairs )
859  results.push_back( pair.second );
860  return results;
861 }
862 
863 void WaveTrackView::SetDisplay(Display display, bool exclusive)
864 {
865  BuildSubViews();
866  DoSetDisplay( display, exclusive );
867 }
868 
870 {
871  size_t ii = 0;
872  size_t found = 0;
873  if ( WaveTrackSubViews::FindIf( [&]( const WaveTrackSubView &subView ) {
874  if ( subView.SubViewType().id == display ) {
875  found = ii;
876  return true;
877  }
878  ++ii;
879  return false;
880  } ) ) {
881  auto &foundPlacement = mPlacements[found];
882  if ( foundPlacement.fraction > 0.0 ) {
883  // Toggle off
884 
885  if (GetDisplays().size() < 2)
886  // refuse to do it
887  return false;
888 
889  auto index = foundPlacement.index;
890  foundPlacement = { -1, 0.0 };
891  if (index >= 0) {
892  for ( auto &placement : mPlacements ) {
893  if ( placement.index > index )
894  --placement.index;
895  }
896  }
897 
898  return true;
899  }
900  else {
901  // Toggle on
902  float total = 0;
903  int greatest = -1;
904  unsigned nn = 0;
905  for ( const auto &placement : mPlacements ) {
906  if ( placement.fraction > 0.0 && placement.index >= 0 ) {
907  total += placement.fraction;
908  greatest = std::max( greatest, placement.index );
909  ++nn;
910  }
911  }
912  // Turn on the sub-view, putting it lowest, and with average of the
913  // heights of the other sub-views
914  foundPlacement = { greatest + 1, total / nn };
915 
916  return true;
917  }
918  }
919  else
920  // unknown sub-view
921  return false;
922 }
923 
924 // If exclusive, make the chosen view take up all the height. Else,
925 // partition equally, putting the specified view on top.
926 // Be sure the sequence in which the other views appear is determinate.
927 void WaveTrackView::DoSetDisplay(Display display, bool exclusive)
928 {
929  // Some generality here anticipating more than two views.
930  // The order of sub-views in the array is not specified, so make it definite
931  // by sorting by the view type constants.
932  size_t ii = 0;
933  std::vector< std::pair< WaveTrackViewConstants::Display, size_t > > pairs;
934  WaveTrackSubViews::ForEach( [&pairs, &ii]( WaveTrackSubView &subView ){
935  pairs.push_back( { subView.SubViewType().id, ii++ } );
936  } );
937  std::sort( pairs.begin(), pairs.end() );
938 
939  int jj = 1;
940  for ( const auto &pair : pairs ) {
941  auto &placement = mPlacements[ pair.second ];
942  if (pair.first == display) {
943  // 0 for first view
944  placement = { 0, 1.0 };
945  }
946  else if( exclusive )
947  // -1 for not displayed
948  placement = { -1, 0.0 };
949  else
950  // positions other than the first.
951  // (Note that the fractions in the placement don't need to be
952  // denominated to 1. Just make them all equal to get an equal
953  // partitioning of the sub-views.)
954  placement = { jj++, 1.0 };
955  }
956 }
957 
958 auto WaveTrackView::GetSubViews( const wxRect &rect ) -> Refinement
959 {
960  BuildSubViews();
961 
962  // Collect the visible views in the right sequence
963  struct Item {
964  int index; float fraction; std::shared_ptr< TrackView > pView;
965  };
966  std::vector< Item > items;
967  size_t ii = 0;
968  float total = 0;
970  auto &placement = mPlacements[ii];
971  auto index = placement.index;
972  auto fraction = placement.fraction;
973  if ( index >= 0 && fraction > 0.0 )
974  total += fraction,
975  items.push_back( { index, fraction, subView.shared_from_this() } );
976  ++ii;
977  } );
978  std::sort( items.begin(), items.end(), [](const Item &a, const Item &b){
979  return a.index < b.index;
980  } );
981 
982  // Remove views we don't need
983  auto begin = items.begin(), end = items.end(),
984  newEnd = std::remove_if( begin, end,
985  []( const Item &item ){ return !item.pView; } );
986  items.erase( newEnd, end );
987 
988  // Assign coordinates, redenominating to the total height,
989  // storing integer values
990  Refinement results;
991  results.reserve( items.size() );
992  const auto top = rect.GetTop();
993  const auto height = rect.GetHeight();
994  float partial = 0;
995  wxCoord lastCoord = 0;
996  for ( const auto &item : items ) {
997  wxCoord newCoord = top + (partial / total) * height;
998  results.emplace_back( newCoord, item.pView );
999  partial += item.fraction;
1000  }
1001 
1002  // Cache for the use of sub-view dragging
1003  mLastHeight = height;
1004 
1005  return results;
1006 }
1007 
1008 std::vector< std::shared_ptr< WaveTrackSubView > >
1010 {
1011  BuildSubViews();
1012 
1013  std::vector< std::shared_ptr< WaveTrackSubView > > results;
1015  results.push_back( std::static_pointer_cast<WaveTrackSubView>(
1016  subView.shared_from_this() ) );
1017  } );
1018  return results;
1019 }
1020 
1021 void WaveTrackView::DoSetMinimized( bool minimized )
1022 {
1023  BuildSubViews();
1024 
1025  // May come here. Invoke also on sub-views.
1026  TrackView::DoSetMinimized( minimized );
1027  WaveTrackSubViews::ForEach( [minimized](WaveTrackSubView &subView){
1028  subView.DoSetMinimized( minimized );
1029  } );
1030 }
1031 
1033 template<> template<> auto DoGetWaveTrackView::Implementation() -> Function {
1034  return [](WaveTrack &track) {
1035  return std::make_shared<WaveTrackView>( track.SharedPointer() );
1036  };
1037 }
1039 
1040 std::shared_ptr<TrackVRulerControls> WaveTrackView::DoGetVRulerControls()
1041 {
1042  // This should never be called because of delegation to the spectrum or
1043  // waveform sub-view
1044  wxASSERT( false );
1045  return {};
1046 }
1047 
1048 #undef PROFILE_WAVEFORM
1049 #ifdef PROFILE_WAVEFORM
1050 #ifdef __WXMSW__
1051 #include <time.h>
1052 #else
1053 #include <sys/time.h>
1054 #endif
1055 double gWaveformTimeTotal = 0;
1056 int gWaveformTimeCount = 0;
1057 
1058 namespace {
1059  struct Profiler {
1060  Profiler()
1061  {
1062 # ifdef __WXMSW__
1063  _time64(&tv0);
1064 # else
1065  gettimeofday(&tv0, NULL);
1066 # endif
1067  }
1068 
1069  ~Profiler()
1070  {
1071 # ifdef __WXMSW__
1072  _time64(&tv1);
1073  double elapsed = _difftime64(tv1, tv0);
1074 # else
1075  gettimeofday(&tv1, NULL);
1076  double elapsed =
1077  (tv1.tv_sec + tv1.tv_usec*0.000001) -
1078  (tv0.tv_sec + tv0.tv_usec*0.000001);
1079 # endif
1080  gWaveformTimeTotal += elapsed;
1081  gWaveformTimeCount++;
1082  wxPrintf(wxT("Avg waveform drawing time: %f\n"),
1083  gWaveformTimeTotal / gWaveformTimeCount);
1084  }
1085 
1086 # ifdef __WXMSW__
1087  __time64_t tv0, tv1;
1088 #else
1089  struct timeval tv0, tv1;
1090 #endif
1091  };
1092 }
1093 #endif
1094 
1096  (bool spectrum, const WaveTrack *track, const WaveClip *clip, const wxRect &rect,
1097  const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
1098 {
1099  tOffset = clip->GetOffset();
1100  rate = clip->GetRate();
1101 
1102  h = zoomInfo.PositionToTime(0, 0
1103  , true
1104  );
1105  h1 = zoomInfo.PositionToTime(rect.width, 0
1106  , true
1107  );
1108 
1109  double sel0 = selectedRegion.t0(); //left selection bound
1110  double sel1 = selectedRegion.t1(); //right selection bound
1111 
1112  //If the track isn't selected, make the selection empty
1113  if (!track->GetSelected() &&
1114  (spectrum || !track->IsSyncLockSelected())) { // PRL: why was there a difference for spectrum?
1115  sel0 = sel1 = 0.0;
1116  }
1117 
1118  const double trackLen = clip->GetEndTime() - clip->GetStartTime();
1119 
1120  tpre = h - tOffset; // offset corrected time of
1121  // left edge of display
1122  tpost = h1 - tOffset; // offset corrected time of
1123  // right edge of display
1124 
1125  const double sps = 1. / rate; //seconds-per-sample
1126 
1127  // Determine whether we should show individual samples
1128  // or draw circular points as well
1129  averagePixelsPerSample = rect.width / (rate * (h1 - h));
1131 
1132  // Calculate actual selection bounds so that t0 > 0 and t1 < the
1133  // end of the track
1134  t0 = (tpre >= 0.0 ? tpre : 0.0);
1135  t1 = (tpost < trackLen - sps * .99 ? tpost : trackLen - sps * .99);
1136  if (showIndividualSamples) {
1137  // adjustment so that the last circular point doesn't appear
1138  // to be hanging off the end
1139  t1 += 2. / (averagePixelsPerSample * rate);
1140  }
1141 
1142  // Make sure t1 (the right bound) is greater than 0
1143  if (t1 < 0.0) {
1144  t1 = 0.0;
1145  }
1146 
1147  // Make sure t1 is greater than t0
1148  if (t0 > t1) {
1149  t0 = t1;
1150  }
1151 
1152  // Use the WaveTrack method to show what is selected and 'should' be copied, pasted etc.
1153  ssel0 = std::max(sampleCount(0), spectrum
1154  ? sampleCount((sel0 - tOffset) * rate + .99) // PRL: why?
1155  : track->TimeToLongSamples(sel0 - tOffset)
1156  );
1157  ssel1 = std::max(sampleCount(0), spectrum
1158  ? sampleCount((sel1 - tOffset) * rate + .99) // PRL: why?
1159  : track->TimeToLongSamples(sel1 - tOffset)
1160  );
1161 
1162  //trim selection so that it only contains the actual samples
1163  if (ssel0 != ssel1 && ssel1 > (sampleCount)(0.5 + trackLen * rate)) {
1164  ssel1 = sampleCount( 0.5 + trackLen * rate );
1165  }
1166 
1167  // The variable "hiddenMid" will be the rectangle containing the
1168  // actual waveform, as opposed to any blank area before
1169  // or after the track, as it would appear without the fisheye.
1170  hiddenMid = rect;
1171 
1172  // If the left edge of the track is to the right of the left
1173  // edge of the display, then there's some unused area to the
1174  // left of the track. Reduce the "hiddenMid"
1175  hiddenLeftOffset = 0;
1176  if (tpre < 0) {
1177  // Fix Bug #1296 caused by premature conversion to (int).
1178  wxInt64 time64 = zoomInfo.TimeToPosition(tOffset, 0 , true);
1179  if( time64 < 0 )
1180  time64 = 0;
1181  hiddenLeftOffset = (time64 < rect.width) ? (int)time64 : rect.width;
1182 
1184  hiddenMid.width -= hiddenLeftOffset;
1185  }
1186 
1187  // If the right edge of the track is to the left of the right
1188  // edge of the display, then there's some unused area to the right
1189  // of the track. Reduce the "hiddenMid" rect by the
1190  // size of the blank area.
1191  if (tpost > t1) {
1192  wxInt64 time64 = zoomInfo.TimeToPosition(tOffset+t1, 0 , true);
1193  if( time64 < 0 )
1194  time64 = 0;
1195  const int hiddenRightOffset = (time64 < rect.width) ? (int)time64 : rect.width;
1196 
1197  hiddenMid.width = std::max(0, hiddenRightOffset - hiddenLeftOffset);
1198  }
1199  // The variable "mid" will be the rectangle containing the
1200  // actual waveform, as distorted by the fisheye,
1201  // as opposed to any blank area before or after the track.
1202  mid = rect;
1203 
1204  // If the left edge of the track is to the right of the left
1205  // edge of the display, then there's some unused area to the
1206  // left of the track. Reduce the "mid"
1207  leftOffset = 0;
1208  if (tpre < 0) {
1209  wxInt64 time64 = zoomInfo.TimeToPosition(tOffset, 0 , false);
1210  if( time64 < 0 )
1211  time64 = 0;
1212  leftOffset = (time64 < rect.width) ? (int)time64 : rect.width;
1213 
1214  mid.x += leftOffset;
1215  mid.width -= leftOffset;
1216  }
1217 
1218  // If the right edge of the track is to the left of the right
1219  // edge of the display, then there's some unused area to the right
1220  // of the track. Reduce the "mid" rect by the
1221  // size of the blank area.
1222  if (tpost > t1) {
1223  wxInt64 time64 = zoomInfo.TimeToPosition(tOffset+t1, 0 , false);
1224  if( time64 < 0 )
1225  time64 = 0;
1226  const int distortedRightOffset = (time64 < rect.width) ? (int)time64 : rect.width;
1227 
1228  mid.width = std::max(0, distortedRightOffset - leftOffset);
1229  }
1230 }
1231 
1232 void ClipParameters::DrawClipEdges( wxDC &dc, const wxRect &rect ) const
1233 {
1234  // Draw clip edges
1235  dc.SetPen(*wxGREY_PEN);
1236  if (tpre < 0) {
1237  AColor::Line(dc,
1238  mid.x - 1, mid.y,
1239  mid.x - 1, mid.y + rect.height);
1240  }
1241  if (tpost > t1) {
1242  AColor::Line(dc,
1243  mid.x + mid.width, mid.y,
1244  mid.x + mid.width, mid.y + rect.height);
1245  }
1246 }
1247 
1248 void WaveTrackView::Reparent( const std::shared_ptr<Track> &parent )
1249 {
1250  // BuildSubViews(); // not really needed
1251  CommonTrackView::Reparent( parent );
1252  WaveTrackSubViews::ForEach( [&parent](WaveTrackSubView &subView){
1253  subView.Reparent( parent );
1254  } );
1255 }
1256 
1258 {
1259  if ( WaveTrackSubViews::size() == 0) {
1260  // On-demand steps that can't happen in the constructor
1261  auto pThis = const_cast<WaveTrackView*>( this );
1262  pThis->BuildAll();
1263  bool minimized = GetMinimized();
1264  pThis->WaveTrackSubViews::ForEach( [&]( WaveTrackSubView &subView ){
1265  subView.DoSetMinimized( minimized );
1266  } );
1267 
1268  if ( pThis->mPlacements.empty() ) {
1269  pThis->mPlacements.resize( WaveTrackSubViews::size() );
1270 
1271  auto pTrack = pThis->FindTrack();
1272  auto display = TracksPrefs::ViewModeChoice();
1273  bool multi = (display == WaveTrackViewConstants::MultiView);
1274  if ( multi ) {
1275  pThis->SetMultiView( true );
1276  display = WaveTrackSubViewType::Default();
1277  }
1278 
1279  pThis->DoSetDisplay( display, !multi );
1280  }
1281  }
1282 }
1283 
1285  TrackPanelDrawingContext &context,
1286  const wxRect &rect, unsigned iPass )
1287 {
1288  // Should not come here, drawing is now delegated to sub-views
1289  wxASSERT( false );
1290 
1291  CommonTrackView::Draw( context, rect, iPass );
1292 }
ClipParameters::tpost
double tpost
Definition: WaveTrackView.h:171
ProjectHistory::ModifyState
void ModifyState(bool bWantsAutoSave)
Definition: ProjectHistory.cpp:123
TranslatableString
Definition: Types.h:290
WaveTrackView::mPlacements
WaveTrackSubViewPlacements mPlacements
Definition: WaveTrackView.h:148
WaveTrackView::DetailedHitTest
std::vector< UIHandlePtr > DetailedHitTest(const TrackPanelMouseState &state, const AudacityProject *pProject, int currentTool, bool bMultiTool) override
Definition: WaveTrackView.cpp:802
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjuster::FindPermutation
void FindPermutation()
Definition: WaveTrackView.cpp:60
anonymous_namespace{WaveTrackView.cpp}::SubViewCloseHandle::GetButtonRect
static wxRect GetButtonRect(const wxRect &rect)
Definition: WaveTrackView.cpp:610
WaveTrackView::BuildSubViews
void BuildSubViews() const
Definition: WaveTrackView.cpp:1257
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::HitTest
static UIHandlePtr HitTest(std::weak_ptr< UIHandle > &holder, WaveTrackView &view, WaveTrackSubView &subView, const TrackPanelMouseState &state)
Definition: WaveTrackView.cpp:425
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:68
CommonTrackView
Definition: CommonTrackView.h:20
ClientData::Site::ForEach
void ForEach(const Function &function)
Invoke function on each ClientData object that has been created in this.
Definition: ClientData.h:380
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::Clicked
bool Clicked() const
Definition: WaveTrackView.cpp:496
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjustHandle
Definition: WaveTrackView.cpp:209
ClipParameters::DrawClipEdges
void DrawClipEdges(wxDC &dc, const wxRect &rect) const
Definition: WaveTrackView.cpp:1232
WaveTrackSubView::SubViewType
virtual const Type & SubViewType() const =0
ClipParameters::rate
double rate
Definition: WaveTrackView.h:167
WaveTrackView
Definition: WaveTrackView.h:71
WaveTrackView::Draw
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
Definition: WaveTrackView.cpp:1284
RefreshCode::RefreshAll
@ RefreshAll
Definition: RefreshCode.h:26
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjustHandle::Cancel
Result Cancel(AudacityProject *) override
Definition: WaveTrackView.cpp:395
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjuster::mOrigPlacements
WaveTrackSubViewPlacements mOrigPlacements
Definition: WaveTrackView.cpp:201
TrackView::Get
static TrackView & Get(Track &)
Definition: TrackView.cpp:63
RefreshCode::RefreshNone
@ RefreshNone
Definition: RefreshCode.h:21
ClipParameters::averagePixelsPerSample
double averagePixelsPerSample
Definition: WaveTrackView.h:178
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjuster
Definition: WaveTrackView.cpp:48
CutlineHandle
Definition: CutlineHandle.h:22
TrackView::GetMinimized
bool GetMinimized() const
Definition: TrackView.h:49
SelectedRegion::t1
double t1() const
Definition: SelectedRegion.h:95
WaveTrackView::DoSetDisplay
void DoSetDisplay(Display display, bool exclusive=true)
Definition: WaveTrackView.cpp:927
WaveTrackView::GetAllSubViews
std::vector< std::shared_ptr< WaveTrackSubView > > GetAllSubViews()
Definition: WaveTrackView.cpp:1009
Profiler
A simple profiler to measure the average time lengths that a particular task/function takes....
Definition: Profiler.h:40
CommonTrackView::mTimeShiftHandle
std::weak_ptr< TimeShiftHandle > mTimeShiftHandle
Definition: CommonTrackView.h:48
WaveClip::GetOffset
double GetOffset() const
Definition: WaveClip.h:219
WaveTrackView::DoSetMinimized
void DoSetMinimized(bool minimized) override
Definition: WaveTrackView.cpp:1021
ClientData::Site::FindIf
ClientData * FindIf(const Function &function)
Return pointer to first attachment in this that is not null and satisfies a predicate,...
Definition: ClientData.h:412
ZoomInfo
Definition: ZoomInfo.h:47
WaveTrackSubViewType::id
Display id
Definition: WaveTrackViewConstants.h:96
WaveTrackSubViewType::Default
static Display Default()
Return a preferred type.
Definition: WaveTrackViewConstants.cpp:97
CommonTrackPanelCell::FindTrack
std::shared_ptr< Track > FindTrack()
Definition: CommonTrackPanelCell.h:44
anonymous_namespace{WaveTrackView.cpp}::SubViewCloseHandle::SubViewCloseHandle
SubViewCloseHandle(SubViewAdjuster &&adjuster, size_t index, const std::shared_ptr< Track > &pTrack, const wxRect &rect)
Definition: WaveTrackView.cpp:639
TrackPanelDrawingContext
Definition: TrackPanelDrawingContext.h:22
WaveClip::GetRate
int GetRate() const
Definition: WaveClip.h:207
MakeCursor
std::unique_ptr< wxCursor > MakeCursor(int WXUNUSED(CursorId), const char *const pXpm[36], int HotX, int HotY)
Definition: TrackPanel.cpp:177
TrackView::Refinement
std::vector< std::pair< wxCoord, std::shared_ptr< TrackView > > > Refinement
Definition: TrackView.h:73
AColor::Line
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:112
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjuster::FindIndex
size_t FindIndex(WaveTrackSubView &subView) const
Definition: WaveTrackView.cpp:136
WaveTrackSubView::DrawBoldBoundaries
static void DrawBoldBoundaries(TrackPanelDrawingContext &context, const WaveTrack *track, const wxRect &rect)
Definition: WaveTrackView.cpp:722
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::Preview
HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *) override
Definition: WaveTrackView.cpp:568
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjustHandle::Preview
HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *) override
Definition: WaveTrackView.cpp:375
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjuster::UpdateViews
void UpdateViews(bool rollback)
Definition: WaveTrackView.cpp:188
WaveClip::GetEndTime
double GetEndTime() const
Definition: WaveClip.cpp:253
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::mAdjuster
SubViewAdjuster mAdjuster
Definition: WaveTrackView.cpp:598
WaveTrackView::GetSubViews
Refinement GetSubViews(const wxRect &rect) override
Definition: WaveTrackView.cpp:958
anonymous_namespace{WaveTrackView.cpp}::SubViewCloseHandle::Tip
TranslatableString Tip(const wxMouseState &state, AudacityProject &project) const override
Definition: WaveTrackView.cpp:660
XO
#define XO(s)
Definition: Internat.h:32
ProgressResult::Cancelled
@ Cancelled
ClientData::Site::size
size_t size() const
How many attachment pointers are in the Site.
Definition: ClientData.h:251
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle
Definition: WaveTrackView.cpp:420
WaveTrackView::RestorePlacements
void RestorePlacements(const WaveTrackSubViewPlacements &placements)
Definition: WaveTrackView.h:107
WaveTrackView::GetMultiView
bool GetMultiView() const
Definition: WaveTrackView.h:121
ClipParameters::h
double h
Definition: WaveTrackView.h:168
kTrackInfoBtnSize
@ kTrackInfoBtnSize
Definition: ViewInfo.h:111
TrackPanelDrawingContext::dc
wxDC & dc
Definition: TrackPanelDrawingContext.h:23
WaveTrackViewConstants::Display
Display
Definition: WaveTrackViewConstants.h:18
WaveTrackSubView::WaveTrackSubView
WaveTrackSubView(WaveTrackView &waveTrackView)
Definition: WaveTrackView.cpp:778
ClipParameters::hiddenLeftOffset
int hiddenLeftOffset
Definition: WaveTrackView.h:185
WaveTrackView::GetLastHeight
wxCoord GetLastHeight() const
Definition: WaveTrackView.h:119
TrackPanelMouseState::rect
const wxRect & rect
Definition: TrackPanelMouseEvent.h:39
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjuster::NVisible
size_t NVisible() const
Definition: WaveTrackView.cpp:95
Track::IsSyncLockSelected
bool IsSyncLockSelected() const
Definition: Track.cpp:245
ZoomInfo::TimeToPosition
wxInt64 TimeToPosition(double time, wxInt64 origin=0, bool ignoreFisheye=false) const
STM: Converts a project time to screen x position.
Definition: ZoomInfo.cpp:53
WaveTrackSubView
Definition: WaveTrackView.h:25
WaveTrack::GetCachedLocations
const std::vector< Location > & GetCachedLocations() const
Definition: WaveTrack.h:498
ClipParameters::ssel0
sampleCount ssel0
Definition: WaveTrackView.h:181
WaveTrackView::ToggleSubView
bool ToggleSubView(Display id)
Definition: WaveTrackView.cpp:869
WaveTrackSubView::DoDetailedHitTest
std::pair< bool, std::vector< UIHandlePtr > > DoDetailedHitTest(const TrackPanelMouseState &state, const AudacityProject *pProject, int currentTool, bool bMultiTool, const std::shared_ptr< WaveTrack > &wt)
UIHandle
Short-lived drawing and event-handling object associated with a TrackPanelCell.
Definition: UIHandle.h:36
WaveTrackView.h
WaveClip::GetStartTime
double GetStartTime() const
Definition: WaveClip.cpp:247
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjuster::ComputeHeights
std::vector< wxCoord > ComputeHeights(wxCoord totalHeight)
Definition: WaveTrackView.cpp:164
anonymous_namespace{WaveTrackView.cpp}::SubViewCloseHandle::HitTest
static UIHandlePtr HitTest(std::weak_ptr< UIHandle > &holder, WaveTrackView &view, WaveTrackSubView &subView, const TrackPanelMouseState &state)
Definition: WaveTrackView.cpp:621
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjuster::SubViewAdjuster
SubViewAdjuster(WaveTrackView &view)
Definition: WaveTrackView.cpp:51
ClipParameters::hiddenMid
wxRect hiddenMid
Definition: WaveTrackView.h:184
AttachedVirtualFunction::Override::Implementation
static Function Implementation()
A function returning a std::function that must be defined so that the program links.
Definition: LabelTrackControls.cpp:182
TracksPrefs::ViewModeChoice
static WaveTrackViewConstants::Display ViewModeChoice()
Definition: TracksPrefs.cpp:168
registerDoGetWaveTrackView
static DoGetWaveTrackView registerDoGetWaveTrackView
Definition: WaveTrackView.cpp:1038
WaveClip
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:172
CutlineHandle::GetTrack
std::shared_ptr< WaveTrack > GetTrack()
Definition: CutlineHandle.h:44
ClipParameters::showIndividualSamples
bool showIndividualSamples
Definition: WaveTrackView.h:179
TrackArtist::Get
static TrackArtist * Get(TrackPanelDrawingContext &)
Definition: TrackArtist.cpp:75
WaveTrackView::WaveTrackView
WaveTrackView(const WaveTrackView &)=delete
Profiler::Profiler
Profiler()
private constructor - Singleton.
Definition: Profiler.h:56
ButtonHandle
A UIHandle for a TrackPanel button, such as the Mute and Solo buttons.
Definition: ButtonHandle.h:26
ClipParameters::ssel1
sampleCount ssel1
Definition: WaveTrackView.h:182
TrackInfo::DrawCloseButton
void DrawCloseButton(TrackPanelDrawingContext &context, const wxRect &bev, const Track *pTrack, ButtonHandle *target)
Definition: TrackInfo.cpp:267
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjustHandle::mOrigHeights
std::vector< wxCoord > mOrigHeights
Definition: WaveTrackView.cpp:404
WaveTrackView::mMultiView
bool mMultiView
Definition: WaveTrackView.h:151
anonymous_namespace{WaveTrackView.cpp}::SubViewCloseHandle
Definition: WaveTrackView.cpp:609
UIHandle::Result
unsigned Result
Definition: UIHandle.h:39
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjuster::mSubViews
WaveTrackSubViewPtrs mSubViews
Definition: WaveTrackView.cpp:200
CutlineHandle.h
CommonTrackView::HitTest
std::vector< UIHandlePtr > HitTest(const TrackPanelMouseState &, const AudacityProject *pProject) final override
Definition: CommonTrackView.cpp:30
UIHandlePtr
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
WaveTrackView::~WaveTrackView
~WaveTrackView() override
Definition: WaveTrackView.cpp:785
anonymous_namespace{ProjectFileManager.cpp}::Pair
std::pair< const char *, const char * > Pair
Definition: ProjectFileManager.cpp:96
HitTestPreview
Definition: HitTestResult.h:20
anonymous_namespace{WaveTrackView.cpp}::SubViewCloseHandle::mAdjuster
SubViewAdjuster mAdjuster
Definition: WaveTrackView.cpp:678
AColor::uglyPen
static wxPen uglyPen
Definition: AColor.h:130
anonymous_namespace{NoteTrack.cpp}::swap
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
Definition: NoteTrack.cpp:733
WaveTrackSubView::mwWaveTrackView
std::weak_ptr< WaveTrackView > mwWaveTrackView
Definition: WaveTrackView.h:54
WaveTrackSubViewPlacements
std::vector< WaveTrackSubViewPlacement > WaveTrackSubViewPlacements
Definition: WaveTrackView.h:61
TrackView::DoSetMinimized
virtual void DoSetMinimized(bool isMinimized)
Definition: TrackView.cpp:122
WaveTrackView::SavePlacements
const WaveTrackSubViewPlacements & SavePlacements() const
Definition: WaveTrackView.h:105
ClipParameters::tOffset
double tOffset
Definition: WaveTrackView.h:166
WaveTrackSubViewPlacement
Definition: WaveTrackView.h:57
anonymous_namespace{TrackPanel.cpp}::FindTrack
std::shared_ptr< Track > FindTrack(TrackPanelCell *pCell)
Definition: TrackPanel.cpp:525
anonymous_namespace{WaveTrackView.cpp}::SubViewCloseHandle::CommitChanges
Result CommitChanges(const wxMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
Definition: WaveTrackView.cpp:648
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::DragChoice_t
DragChoice_t
Definition: WaveTrackView.cpp:498
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjuster::ModifyPermutation
bool ModifyPermutation(bool top)
Definition: WaveTrackView.cpp:98
ClipParameters::t0
double t0
Definition: WaveTrackView.h:175
WaveTrackView::GetDisplays
std::vector< WaveTrackSubView::Type > GetDisplays() const
Definition: WaveTrackView.cpp:841
Track::GetSelected
bool GetSelected() const
Definition: Track.h:414
ClipParameters::leftOffset
int leftOffset
Definition: WaveTrackView.h:188
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
SelectedRegion::t0
double t0() const
Definition: SelectedRegion.h:94
anonymous_namespace{WaveTrackView.cpp}::WaveTrackSubViewPtrs
std::vector< std::shared_ptr< WaveTrackSubView > > WaveTrackSubViewPtrs
Definition: WaveTrackView.cpp:43
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjustHandle::HitTest
static UIHandlePtr HitTest(std::weak_ptr< UIHandle > &holder, WaveTrackView &view, WaveTrackSubView &subView, const TrackPanelMouseState &state)
Definition: WaveTrackView.cpp:213
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::Release
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
Definition: WaveTrackView.cpp:582
WaveTrack::TimeToLongSamples
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: WaveTrack.cpp:1767
Track
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:238
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::DragChoice
DragChoice_t DragChoice(const TrackPanelMouseEvent &event) const
Definition: WaveTrackView.cpp:500
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::Drag
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *) override
Definition: WaveTrackView.cpp:531
sampleCount
Definition: Types.h:581
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:112
WaveTrackView::Get
static WaveTrackView & Get(WaveTrack &track)
Definition: WaveTrackView.cpp:763
ClientData::Site::BuildAll
void BuildAll()
For each RegisteredFactory, if the corresponding attachment is absent in this, build and store it.
Definition: ClientData.h:441
ClipParameters::h1
double h1
Definition: WaveTrackView.h:170
TrackPanelMouseEvent
Definition: TrackPanelMouseEvent.h:46
ClipParameters::mid
wxRect mid
Definition: WaveTrackView.h:187
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjustHandle::Click
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Definition: WaveTrackView.cpp:249
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::Click
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Definition: WaveTrackView.cpp:475
TrackPanelMouseState
Definition: TrackPanelMouseEvent.h:28
WaveTrackView::DoGetVRulerControls
std::shared_ptr< TrackVRulerControls > DoGetVRulerControls() override
Definition: WaveTrackView.cpp:1040
TrackView::CopyTo
void CopyTo(Track &track) const override
Definition: TrackView.cpp:52
anonymous_namespace{WaveTrackView.cpp}::SubViewCloseHandle::Draw
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
Definition: WaveTrackView.cpp:667
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::Cancel
Result Cancel(AudacityProject *) override
Definition: WaveTrackView.cpp:590
TrackPanelDrawingContext::target
UIHandlePtr target
Definition: TrackPanelDrawingContext.h:24
ClipParameters::t1
double t1
Definition: WaveTrackView.h:176
CommonTrackCell::Reparent
virtual void Reparent(const std::shared_ptr< Track > &parent)
Definition: CommonTrackPanelCell.cpp:64
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjustHandle::mAdjuster
SubViewAdjuster mAdjuster
Definition: WaveTrackView.cpp:403
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::SubViewRearrangeHandle
SubViewRearrangeHandle(SubViewAdjuster &&adjuster, size_t subViewIndex, wxCoord viewHeight)
Definition: WaveTrackView.cpp:466
AttachedVirtualFunction::Override
For defining overrides of the method.
Definition: AttachedVirtualFunction.h:190
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjuster::mPermutation
std::vector< size_t > mPermutation
Definition: WaveTrackView.cpp:203
CutlineHandle::HitTest
static UIHandlePtr HitTest(std::weak_ptr< CutlineHandle > &holder, const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject, const std::shared_ptr< WaveTrack > &pTrack)
Definition: CutlineHandle.cpp:97
ClipParameters::tpre
double tpre
Definition: WaveTrackView.h:169
ClipParameters::ClipParameters
ClipParameters(bool spectrum, const WaveTrack *track, const WaveClip *clip, const wxRect &rect, const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo)
Definition: WaveTrackView.cpp:1096
WaveTrackLocation::locationCutLine
@ locationCutLine
Definition: WaveTrackLocation.h:17
WaveTrackView::Reparent
void Reparent(const std::shared_ptr< Track > &parent) override
Definition: WaveTrackView.cpp:1248
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjustHandle::SubViewAdjustHandle
SubViewAdjustHandle(SubViewAdjuster &&adjuster, size_t subViewIndex, wxCoord viewHeight, bool top)
Definition: WaveTrackView.cpp:237
TrackArtist::PassMargins
@ PassMargins
Definition: TrackArtist.h:61
AssignUIHandlePtr
std::shared_ptr< Subclass > AssignUIHandlePtr(std::weak_ptr< Subclass > &holder, const std::shared_ptr< Subclass > &pNew)
Definition: UIHandle.h:147
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjustHandle::Release
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
Definition: WaveTrackView.cpp:387
RefreshCode
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
WaveTrackView::SetDisplay
void SetDisplay(Display display, bool exclusive=true)
Definition: WaveTrackView.cpp:863
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjuster::HitTest
std::pair< size_t, bool > HitTest(WaveTrackSubView &subView, wxCoord yy, wxCoord top, wxCoord height)
Definition: WaveTrackView.cpp:146
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjuster::mwView
std::weak_ptr< WaveTrackView > mwView
Definition: WaveTrackView.cpp:199
anonymous_namespace{WaveTrackView.cpp}::SubViewAdjustHandle::Drag
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *) override
Definition: WaveTrackView.cpp:302
TimeShiftHandle::HitAnywhere
static UIHandlePtr HitAnywhere(std::weak_ptr< TimeShiftHandle > &holder, const std::shared_ptr< Track > &pTrack, bool gripHit)
Definition: TimeShiftHandle.cpp:65
WaveTrackView::CopyTo
void CopyTo(Track &track) const override
Definition: WaveTrackView.cpp:789
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::mHeights
std::vector< wxCoord > mHeights
Definition: WaveTrackView.cpp:599
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::Upward
@ Upward
Definition: WaveTrackView.cpp:498
WaveTrackViewConstants::MultiView
@ MultiView
"Multi" is special, not really a view type on par with the others.
Definition: WaveTrackViewConstants.h:20
TrackPanelMouseEvent::event
wxMouseEvent & event
Definition: TrackPanelMouseEvent.h:58
WaveTrackView::DoDetailedHitTest
static std::pair< bool, std::vector< UIHandlePtr > > DoDetailedHitTest(const TrackPanelMouseState &state, const AudacityProject *pProject, int currentTool, bool bMultiTool, const std::shared_ptr< WaveTrack > &wt, CommonTrackView &view)
Definition: WaveTrackView.cpp:812
TrackPanelMouseState::state
wxMouseState & state
Definition: TrackPanelMouseEvent.h:38
ProjectHistory::Get
static ProjectHistory & Get(AudacityProject &project)
Definition: ProjectHistory.cpp:26
anonymous_namespace{WaveTrackView.cpp}::SubViewRearrangeHandle::mTopY
wxCoord mTopY
Definition: WaveTrackView.cpp:600
Profiler::~Profiler
virtual ~Profiler()
write to a profile at the end of the test.
Definition: Profiler.cpp:31
ZoomInfo::PositionToTime
double PositionToTime(wxInt64 position, wxInt64 origin=0, bool ignoreFisheye=false) const
Definition: ZoomInfo.cpp:43
SelectedRegion
Defines a selected portion of a project.
Definition: SelectedRegion.h:38
TrackPanelDrawable::Draw
virtual void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass)
Definition: TrackPanelDrawable.cpp:17