Audacity  3.2.0
SelectHandle.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 SelectHandle.cpp
6 
7 Paul Licameli split from TrackPanel.cpp
8 
9 **********************************************************************/
10 
11 
12 #include "SelectHandle.h"
13 
14 #include "Scrubbing.h"
15 #include "TrackView.h"
16 
17 #include "AColor.h"
18 #include "../../SpectrumAnalyst.h"
19 #include "../../LabelTrack.h"
20 #include "NumberScale.h"
21 #include "Project.h"
22 #include "../../ProjectAudioIO.h"
23 #include "../../ProjectHistory.h"
24 #include "../../ProjectSettings.h"
25 #include "../../ProjectWindow.h"
26 #include "../../RefreshCode.h"
27 #include "../../SelectUtilities.h"
28 #include "../../SelectionState.h"
29 #include "../../TrackArtist.h"
30 #include "../../TrackPanelAx.h"
31 #include "../../TrackPanel.h"
32 #include "../../TrackPanelDrawingContext.h"
33 #include "../../TrackPanelMouseEvent.h"
34 #include "ViewInfo.h"
35 #include "../../WaveClip.h"
36 #include "../../WaveTrack.h"
37 #include "../../prefs/SpectrogramSettings.h"
38 #include "../../../images/Cursors.h"
39 
40 // Only for definition of SonifyBeginModifyState:
41 //#include "../../NoteTrack.h"
42 
43 enum {
44  //This constant determines the size of the horizontal region (in pixels) around
45  //the right and left selection bounds that can be used for horizontal selection adjusting
46  //(or, vertical distance around top and bottom bounds in spectrograms,
47  // for vertical selection adjusting)
49 
50  // Seems 4 is too small to work at the top. Why?
52 };
53 
54 // #define SPECTRAL_EDITING_ESC_KEY
55 
57 {
58  return mSelectionStateChanger.get() != NULL;
59 }
60 
61 namespace
62 {
64  wxInt64 FrequencyToPosition(const WaveTrack *wt,
65  double frequency,
66  wxInt64 trackTopEdge,
67  int trackHeight)
68  {
70  float minFreq, maxFreq;
71  wt->GetSpectrumBounds(&minFreq, &maxFreq);
72  const NumberScale numberScale(settings.GetScale(minFreq, maxFreq));
73  const float p = numberScale.ValueToPosition(frequency);
74  return trackTopEdge + wxInt64((1.0 - p) * trackHeight);
75  }
76 
79  double PositionToFrequency(const WaveTrack *wt,
80  bool maySnap,
81  wxInt64 mouseYCoordinate,
82  wxInt64 trackTopEdge,
83  int trackHeight)
84  {
85  const double rate = wt->GetRate();
86 
87  // Handle snapping
88  if (maySnap &&
89  mouseYCoordinate - trackTopEdge < FREQ_SNAP_DISTANCE)
90  return rate;
91  if (maySnap &&
92  trackTopEdge + trackHeight - mouseYCoordinate < FREQ_SNAP_DISTANCE)
93  return -1;
94 
96  float minFreq, maxFreq;
97  wt->GetSpectrumBounds(&minFreq, &maxFreq);
98  const NumberScale numberScale(settings.GetScale(minFreq, maxFreq));
99  const double p = double(mouseYCoordinate - trackTopEdge) / trackHeight;
100  return numberScale.PositionToValue(1.0 - p);
101  }
102 
103  template<typename T>
104  inline void SetIfNotNull(T * pValue, const T Value)
105  {
106  if (pValue == NULL)
107  return;
108  *pValue = Value;
109  }
110 
111  // This returns true if we're a spectral editing track.
112  inline bool isSpectralSelectionView(const TrackView *pTrackView) {
113  return
114  pTrackView &&
115  pTrackView->IsSpectral() &&
116  pTrackView->FindTrack() &&
117  pTrackView->FindTrack()->TypeSwitch< bool >(
118  [&](const WaveTrack *wt) {
119  const SpectrogramSettings &settings = wt->GetSpectrogramSettings();
120  return settings.SpectralSelectionEnabled();
121  });
122  }
123 
127 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
128  SBBottom, SBTop, SBCenter, SBWidth,
129 #endif
130  };
131 
133  (
134  const double t0, const double t1,
135  const ViewInfo &viewInfo,
136  double selend, bool onlyWithinSnapDistance,
137  wxInt64 *pPixelDist, double *pPinValue)
138  {
139  const wxInt64 posS = viewInfo.TimeToPosition(selend);
140  const wxInt64 pos0 = viewInfo.TimeToPosition(t0);
141  wxInt64 pixelDist = std::abs(posS - pos0);
142  bool chooseLeft = true;
143 
144  if (t1<=t0)
145  // Special case when selection is a point, and thus left
146  // and right distances are the same
147  chooseLeft = (selend < t0);
148  else {
149  const wxInt64 pos1 = viewInfo.TimeToPosition(t1);
150  const wxInt64 rightDist = std::abs(posS - pos1);
151  if (rightDist < pixelDist)
152  chooseLeft = false, pixelDist = rightDist;
153  }
154 
155  SetIfNotNull(pPixelDist, pixelDist);
156 
157  if (onlyWithinSnapDistance &&
158  pixelDist >= SELECTION_RESIZE_REGION) {
159  SetIfNotNull(pPinValue, -1.0);
160  return SBNone;
161  }
162  else if (chooseLeft) {
163  SetIfNotNull(pPinValue, t1);
164  return SBLeft;
165  }
166  else {
167  SetIfNotNull(pPinValue, t0);
168  return SBRight;
169  }
170  }
171 
173  (const ViewInfo &viewInfo,
174  wxCoord xx, wxCoord yy, const TrackView *pTrackView, const wxRect &rect,
175  bool mayDragWidth, bool onlyWithinSnapDistance,
176  double *pPinValue = NULL)
177  {
178  // Choose one of four boundaries to adjust, or the center frequency.
179  // May choose frequencies only if in a spectrogram view and
180  // within the time boundaries.
181  // May choose no boundary if onlyWithinSnapDistance is true.
182  // Otherwise choose the eligible boundary nearest the mouse click.
183  const double selend = viewInfo.PositionToTime(xx, rect.x);
184  wxInt64 pixelDist = 0;
185  const double t0 = viewInfo.selectedRegion.t0();
186  const double t1 = viewInfo.selectedRegion.t1();
187 
188  SelectionBoundary boundary =
189  ChooseTimeBoundary(t0,t1,viewInfo, selend, onlyWithinSnapDistance,
190  &pixelDist, pPinValue);
191 
192 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
193  //const double t0 = viewInfo.selectedRegion.t0();
194  //const double t1 = viewInfo.selectedRegion.t1();
195  const double f0 = viewInfo.selectedRegion.f0();
196  const double f1 = viewInfo.selectedRegion.f1();
197  const double fc = viewInfo.selectedRegion.fc();
198  double ratio = 0;
199 
200  bool chooseTime = true;
201  bool chooseBottom = true;
202  bool chooseCenter = false;
203  // Consider adjustment of frequencies only if mouse is
204  // within the time boundaries
205  if (!viewInfo.selectedRegion.isPoint() &&
206  t0 <= selend && selend < t1 &&
207  isSpectralSelectionView(pTrackView)) {
208  // Spectral selection track is always wave
209  auto pTrack = pTrackView->FindTrack();
210  const WaveTrack *const wt =
211  static_cast<const WaveTrack*>(pTrack.get());
212  const wxInt64 bottomSel = (f0 >= 0)
213  ? FrequencyToPosition(wt, f0, rect.y, rect.height)
214  : rect.y + rect.height;
215  const wxInt64 topSel = (f1 >= 0)
216  ? FrequencyToPosition(wt, f1, rect.y, rect.height)
217  : rect.y;
218  wxInt64 signedBottomDist = (int)(yy - bottomSel);
219  wxInt64 verticalDist = std::abs(signedBottomDist);
220  if (bottomSel == topSel)
221  // Top and bottom are too close to resolve on screen
222  chooseBottom = (signedBottomDist >= 0);
223  else {
224  const wxInt64 topDist = std::abs((int)(yy - topSel));
225  if (topDist < verticalDist)
226  chooseBottom = false, verticalDist = topDist;
227  }
228  if (fc > 0
229 #ifdef SPECTRAL_EDITING_ESC_KEY
230  && mayDragWidth
231 #endif
232  ) {
233  const wxInt64 centerSel =
234  FrequencyToPosition(wt, fc, rect.y, rect.height);
235  const wxInt64 centerDist = abs((int)(yy - centerSel));
236  if (centerDist < verticalDist)
237  chooseCenter = true, verticalDist = centerDist,
238  ratio = f1 / fc;
239  }
240  if (verticalDist >= 0 &&
241  verticalDist < pixelDist) {
242  pixelDist = verticalDist;
243  chooseTime = false;
244  }
245  }
246 
247  if (!chooseTime) {
248  // PRL: Seems I need a larger tolerance to make snapping work
249  // at top of track, not sure why
250  if (onlyWithinSnapDistance &&
251  pixelDist >= FREQ_SNAP_DISTANCE) {
252  SetIfNotNull(pPinValue, -1.0);
253  return SBNone;
254  }
255  else if (chooseCenter) {
256  SetIfNotNull(pPinValue, ratio);
257  return SBCenter;
258  }
259  else if (mayDragWidth && fc > 0) {
260  SetIfNotNull(pPinValue, fc);
261  return SBWidth;
262  }
263  else if (chooseBottom) {
264  SetIfNotNull(pPinValue, f1);
265  return SBBottom;
266  }
267  else {
268  SetIfNotNull(pPinValue, f0);
269  return SBTop;
270  }
271  }
272  else
273 #endif
274  {
275  return boundary;
276  }
277  }
278 
279  wxCursor *SelectCursor()
280  {
281  static auto selectCursor =
282  ::MakeCursor(wxCURSOR_IBEAM, IBeamCursorXpm, 17, 16);
283  return &*selectCursor;
284  }
285 
286  wxCursor *EnvelopeCursor()
287  {
288  // This one doubles as the center frequency cursor for spectral selection:
289  static auto envelopeCursor =
290  ::MakeCursor(wxCURSOR_ARROW, EnvCursorXpm, 16, 16);
291  return &*envelopeCursor;
292  }
293 
295  (SelectionBoundary boundary, bool frequencySnapping,
296  TranslatableString &tip, wxCursor *&pCursor)
297  {
298  static wxCursor adjustLeftSelectionCursor{ wxCURSOR_POINT_LEFT };
299  static wxCursor adjustRightSelectionCursor{ wxCURSOR_POINT_RIGHT };
300 
301  static auto bottomFrequencyCursor =
302  ::MakeCursor(wxCURSOR_ARROW, BottomFrequencyCursorXpm, 16, 16);
303  static auto topFrequencyCursor =
304  ::MakeCursor(wxCURSOR_ARROW, TopFrequencyCursorXpm, 16, 16);
305  static auto bandWidthCursor =
306  ::MakeCursor(wxCURSOR_ARROW, BandWidthCursorXpm, 16, 16);
307 
308  switch (boundary) {
309  case SBNone:
310  pCursor = SelectCursor();
311  break;
312  case SBLeft:
313  tip = XO("Click and drag to move left selection boundary.");
314  pCursor = &adjustLeftSelectionCursor;
315  break;
316  case SBRight:
317  tip = XO("Click and drag to move right selection boundary.");
318  pCursor = &adjustRightSelectionCursor;
319  break;
320 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
321  case SBBottom:
322  tip = XO("Click and drag to move bottom selection frequency.");
323  pCursor = &*bottomFrequencyCursor;
324  break;
325  case SBTop:
326  tip = XO("Click and drag to move top selection frequency.");
327  pCursor = &*topFrequencyCursor;
328  break;
329  case SBCenter:
330  {
331 #ifndef SPECTRAL_EDITING_ESC_KEY
332  tip =
333  frequencySnapping ?
334  XO("Click and drag to move center selection frequency to a spectral peak.") :
335  XO("Click and drag to move center selection frequency.");
336 
337 #else
338  shiftDown;
339 
340  tip =
341  XO("Click and drag to move center selection frequency.");
342 
343 #endif
344 
345  pCursor = EnvelopeCursor();
346  }
347  break;
348  case SBWidth:
349  tip = XO("Click and drag to adjust frequency bandwidth.");
350  pCursor = &*bandWidthCursor;
351  break;
352 #endif
353  default:
354  wxASSERT(false);
355  } // switch
356  // Falls through the switch if there was no boundary found.
357  }
358 }
359 
361 (std::weak_ptr<SelectHandle> &holder,
362  const TrackPanelMouseState &st, const AudacityProject *pProject,
363  const std::shared_ptr<TrackView> &pTrackView)
364 {
365  // This handle is a little special because there may be some state to
366  // preserve during movement before the click.
367  auto old = holder.lock();
368  bool oldUseSnap = true;
369  if (old) {
370  // It should not have started listening to timer events
371  if( old->mTimerHandler ) {
372  wxASSERT(false);
373  // Handle this eventuality anyway, don't leave a dangling back-pointer
374  // in the attached event handler.
375  old->mTimerHandler.reset();
376  }
377  oldUseSnap = old->mUseSnap;
378  }
379 
380  const auto &viewInfo = ViewInfo::Get( *pProject );
381  auto result = std::make_shared<SelectHandle>(
382  pTrackView, oldUseSnap, TrackList::Get( *pProject ), st, viewInfo );
383 
384  result = AssignUIHandlePtr(holder, result);
385 
386  //Make sure we are within the selected track
387  // Adjusting the selection edges can be turned off in
388  // the preferences...
389  auto pTrack = pTrackView->FindTrack();
390  if (!pTrack->GetSelected() || !viewInfo.bAdjustSelectionEdges)
391  {
392  return result;
393  }
394 
395  {
396  const wxRect &rect = st.rect;
397  wxInt64 leftSel = viewInfo.TimeToPosition(viewInfo.selectedRegion.t0(), rect.x);
398  wxInt64 rightSel = viewInfo.TimeToPosition(viewInfo.selectedRegion.t1(), rect.x);
399  // Something is wrong if right edge comes before left edge
400  wxASSERT(!(rightSel < leftSel));
401  static_cast<void>(leftSel); // Suppress unused variable warnings if not in debug-mode
402  static_cast<void>(rightSel);
403  }
404 
405  return result;
406 }
407 
409 (const SelectHandle &oldState, const SelectHandle &newState)
410 {
411  auto useSnap = oldState.mUseSnap;
412  // This is guaranteed when constructing the NEW handle:
413  wxASSERT( useSnap == newState.mUseSnap );
414  if (!useSnap)
415  return 0;
416 
417  auto &oldSnapState = oldState.mSnapStart;
418  auto &newSnapState = newState.mSnapStart;
419  if ( oldSnapState.Snapped() == newSnapState.Snapped() &&
420  (!oldSnapState.Snapped() ||
421  oldSnapState.outCoord == newSnapState.outCoord) )
422  return 0;
423 
425 }
426 
428 ( const std::shared_ptr<TrackView> &pTrackView, bool useSnap,
429  const TrackList &trackList,
430  const TrackPanelMouseState &st, const ViewInfo &viewInfo )
431  : mpView{ pTrackView }
432  // Selection dragging can snap to play region boundaries
433  , mSnapManager{ std::make_shared<SnapManager>(
434  *trackList.GetOwner(), trackList, viewInfo, SnapPointArray{
435  SnapPoint{ viewInfo.playRegion.GetLastActiveStart() },
436  SnapPoint{ viewInfo.playRegion.GetLastActiveEnd() },
437  } ) }
438 {
439  const wxMouseState &state = st.state;
440  mRect = st.rect;
441 
442  auto time = std::max(0.0, viewInfo.PositionToTime(state.m_x, mRect.x));
443  auto pTrack = pTrackView->FindTrack();
444  mSnapStart = mSnapManager->Snap(pTrack.get(), time, false);
445  if (mSnapStart.snappedPoint)
446  mSnapStart.outCoord += mRect.x;
447  else
448  mSnapStart.outCoord = -1;
449 
450  mUseSnap = useSnap;
451 }
452 
454 {
455 }
456 
457 namespace {
458  // Is the distance between A and B less than D?
459  template < class A, class B, class DIST > bool within(A a, B b, DIST d)
460  {
461  return (a > b - d) && (a < b + d);
462  }
463 
464  inline double findMaxRatio(double center, double rate)
465  {
466  const double minFrequency = 1.0;
467  const double maxFrequency = (rate / 2.0);
468  const double frequency =
469  std::min(maxFrequency,
470  std::max(minFrequency, center));
471  return
472  std::min(frequency / minFrequency, maxFrequency / frequency);
473  }
474 }
475 
477 {
478  SetUseSnap(true, project);
479 }
480 
482 {
483  mUseSnap = use;
484 
485  bool hasSnap = HasSnap();
486  if (hasSnap)
487  // Repaint to turn the snap lines on or off
489 
490  if (IsClicked()) {
491  // Readjust the moving selection end
493  ViewInfo::Get( *project ),
495  nullptr);
496  }
497 }
498 
500 {
501  return
502  (IsClicked() ? mSnapEnd : mSnapStart).snappedPoint;
503 }
504 
506 {
507  return HasSnap() && mUseSnap;
508 }
509 
511 {
512  if (SelectHandle::HasEscape(project)) {
513  SetUseSnap(false, project);
514  return true;
515  }
516  return false;
517 }
518 
520 (const TrackPanelMouseEvent &evt, AudacityProject *pProject)
521 {
524 
525  using namespace RefreshCode;
526 
527  const auto pView = mpView.lock();
528  if ( !pView )
529  return Cancelled;
530 
531  wxMouseEvent &event = evt.event;
532  const auto sTrack = TrackList::Get( *pProject ).Lock( FindTrack() );
533  const auto pTrack = sTrack.get();
534  auto &trackPanel = TrackPanel::Get( *pProject );
535  auto &viewInfo = ViewInfo::Get( *pProject );
536 
537  mMostRecentX = event.m_x;
538  mMostRecentY = event.m_y;
539 
540  bool selectChange = (
541  event.LeftDown() &&
542  event.ControlDown() &&
543  pTrack->TypeSwitch<bool>( [&](LabelTrack *){
544  // We should reach this, only in default of other hits on glyphs or
545  // text boxes.
546  bool bShift = event.ShiftDown();
547  bool unsafe = ProjectAudioIO::Get( *pProject ).IsAudioActive();
549  *pProject, pTrack, bShift, true, !unsafe);
550  return true;
551  } )
552  );
553  if ( selectChange )
554  // Do not start a drag
555  return RefreshAll | Cancelled;
556 
557  auto &selectionState = SelectionState::Get( *pProject );
558  const auto &settings = ProjectSettings::Get( *pProject );
559  if (event.LeftDClick() && !event.ShiftDown()) {
560  auto &trackList = TrackList::Get( *pProject );
561 
562  // Deselect all other tracks and select this one.
563  selectionState.SelectNone( trackList );
564 
565  selectionState.SelectTrack( *pTrack, true, true );
566 
567  // Default behavior: select whole track
569  ( viewInfo, *pTrack, settings.IsSyncLocked() );
570 
571  // Special case: if we're over a clip in a WaveTrack,
572  // select just that clip
573  pTrack->TypeSwitch( [&] ( WaveTrack *wt ) {
574  auto time = viewInfo.PositionToTime(event.m_x, mRect.x);
575  WaveClip *const selectedClip = wt->GetClipAtTime(time);
576  if (selectedClip) {
577  viewInfo.selectedRegion.setTimes(
578  selectedClip->GetPlayStartTime(), selectedClip->GetPlayEndTime());
579  }
580  } );
581 
582  ProjectHistory::Get( *pProject ).ModifyState(false);
583 
584  // Do not start a drag
585  return RefreshAll | Cancelled;
586  }
587  else if (!event.LeftDown())
588  return Cancelled;
589 
590  mInitialSelection = viewInfo.selectedRegion;
591 
592  auto &trackList = TrackList::Get( *pProject );
594  std::make_shared< SelectionStateChanger >( selectionState, trackList );
595 
596  mSelectionBoundary = 0;
597 
598  bool bShiftDown = event.ShiftDown();
599  bool bCtrlDown = event.ControlDown();
600 
602  auto xx = viewInfo.TimeToPosition(mSelStart, mRect.x);
603 
604  // I. Shift-click adjusts an existing selection
605  if (bShiftDown || bCtrlDown) {
606  if (bShiftDown)
607  selectionState.ChangeSelectionOnShiftClick( trackList, *pTrack );
608  if( bCtrlDown ){
609  //Commented out bIsSelected toggles, as in Track Control Panel.
610  //bool bIsSelected = pTrack->GetSelected();
611  //Actual bIsSelected will always add.
612  bool bIsSelected = false;
613  // Don't toggle away the last selected track.
614  if( !bIsSelected || trackPanel.GetSelectedTrackCount() > 1 )
615  selectionState.SelectTrack( *pTrack, !bIsSelected, true );
616  }
617 
618  double value;
619  // Shift-click, choose closest boundary
620  SelectionBoundary boundary =
621  ChooseBoundary(viewInfo, xx, event.m_y,
622  pView.get(), mRect, false, false, &value);
623  mSelectionBoundary = boundary;
624  switch (boundary) {
625  case SBLeft:
626  case SBRight:
627  {
628 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
629  // If drag starts, change time selection only
630  // (also exit frequency snapping)
631  mFreqSelMode = FREQ_SEL_INVALID;
632 #endif
633  mSelStartValid = true;
634  mSelStart = value;
636  AdjustSelection(pProject, viewInfo, event.m_x, mRect.x, pTrack);
637  break;
638  }
639 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
640  case SBBottom:
641  case SBTop:
642  {
643  mFreqSelTrack = pTrack->SharedPointer<const WaveTrack>();
644  mFreqSelPin = value;
645  mFreqSelMode =
646  (boundary == SBBottom)
648 
649  // Drag frequency only, not time:
650  mSelStartValid = false;
652  static_cast<WaveTrack*>(pTrack),
653  viewInfo, event.m_y, mRect.y, mRect.height);
654  break;
655  }
656  case SBCenter:
657  {
658  const auto wt = static_cast<const WaveTrack*>(pTrack);
659  HandleCenterFrequencyClick(viewInfo, true, wt, value);
660  break;
661  }
662 #endif
663  default:
664  wxASSERT(false);
665  };
666 
667  // For persistence of the selection change:
668  ProjectHistory::Get( *pProject ).ModifyState(false);
669 
670  // Get timer events so we can auto-scroll
671  Connect(pProject);
672 
673  // Full refresh since the label area may need to indicate
674  // newly selected tracks.
675  return RefreshAll;
676  }
677 
678  // II. Unmodified click starts a NEW selection
679 
680  //Make sure you are within the selected track
681  bool startNewSelection = true;
682  if (pTrack && pTrack->GetSelected()) {
683  // Adjusting selection edges can be turned off in the
684  // preferences now
685  if (viewInfo.bAdjustSelectionEdges) {
686 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
687  if (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER &&
688  isSpectralSelectionView(pView.get())) {
689  // This code is no longer reachable, but it had a place in the
690  // spectral selection prototype. It used to be that you could be
691  // in a center-frequency-snapping mode that was not a mouse drag
692  // but responded to mouse movements. Click exited that and dragged
693  // width instead. PRL.
694 
695  // Ignore whether we are inside the time selection.
696  // Exit center-snapping, start dragging the width.
697  mFreqSelMode = FREQ_SEL_PINNED_CENTER;
698  mFreqSelTrack = pTrack->SharedPointer<const WaveTrack>();
699  mFreqSelPin = viewInfo.selectedRegion.fc();
700  // Do not adjust time boundaries
701  mSelStartValid = false;
703  static_cast<WaveTrack*>(pTrack),
704  viewInfo, event.m_y, mRect.y, mRect.height);
705  // For persistence of the selection change:
706  ProjectHistory::Get( *pProject ).ModifyState(false);
707  mSelectionBoundary = SBWidth;
708  return RefreshNone;
709  }
710  else
711 #endif
712  {
713  // Not shift-down, choose boundary only within snapping
714  double value;
715  SelectionBoundary boundary =
716  ChooseBoundary(viewInfo, xx, event.m_y,
717  pView.get(), mRect, true, true, &value);
718  mSelectionBoundary = boundary;
719  switch (boundary) {
720  case SBNone:
721  // startNewSelection remains true
722  break;
723  case SBLeft:
724  case SBRight:
725  startNewSelection = false;
726 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
727  // Disable frequency selection
728  mFreqSelMode = FREQ_SEL_INVALID;
729 #endif
730  mSelStartValid = true;
731  mSelStart = value;
733  break;
734 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
735  case SBBottom:
736  case SBTop:
737  case SBWidth:
738  startNewSelection = false;
739  // Disable time selection
740  mSelStartValid = false;
741  mFreqSelTrack = pTrack->SharedPointer<const WaveTrack>();
742  mFreqSelPin = value;
743  mFreqSelMode =
744  (boundary == SBWidth) ? FREQ_SEL_PINNED_CENTER :
745  (boundary == SBBottom) ? FREQ_SEL_BOTTOM_FREE :
747  break;
748  case SBCenter:
749  {
750  const auto wt = static_cast<const WaveTrack*>(pTrack);
751  HandleCenterFrequencyClick(viewInfo, false, wt, value);
752  startNewSelection = false;
753  break;
754  }
755 #endif
756  default:
757  wxASSERT(false);
758  }
759  }
760  } // bAdjustSelectionEdges
761  }
762 
763  // III. Common case for starting a NEW selection
764 
765  if (startNewSelection) {
766  // If we didn't move a selection boundary, start a NEW selection
767  selectionState.SelectNone( trackList );
768 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
769  StartFreqSelection (viewInfo, event.m_y, mRect.y, mRect.height,
770  pView.get());
771 #endif
772  StartSelection(pProject);
773  selectionState.SelectTrack( *pTrack, true, true );
774  TrackFocus::Get( *pProject ).Set(pTrack);
775 
776  Connect(pProject);
777  return RefreshAll;
778  }
779  else {
780  Connect(pProject);
781  return RefreshAll;
782  }
783 }
784 
786 (const TrackPanelMouseEvent &evt, AudacityProject *pProject)
787 {
788  using namespace RefreshCode;
789 
790  const auto pView = mpView.lock();
791  if ( !pView )
792  return Cancelled;
793 
794  auto &viewInfo = ViewInfo::Get( *pProject );
795  const wxMouseEvent &event = evt.event;
796 
797  int x = mAutoScrolling ? mMostRecentX : event.m_x;
798  int y = mAutoScrolling ? mMostRecentY : event.m_y;
799  mMostRecentX = x;
800  mMostRecentY = y;
801 
805 
806  // Fuhggeddaboudit if we're not dragging and not autoscrolling.
807  if (!event.Dragging() && !mAutoScrolling)
808  return RefreshNone;
809 
810  if (event.CmdDown()) {
811  // Ctrl-drag has no meaning, fuhggeddaboudit
812  // JKC YES it has meaning.
813  //return RefreshNone;
814  }
815 
816  // Also fuhggeddaboudit if not in a track.
817  auto pTrack = TrackList::Get( *pProject ).Lock( FindTrack() );
818  if (!pTrack)
819  return RefreshNone;
820 
821  // JKC: Logic to prevent a selection smaller than 5 pixels to
822  // prevent accidental dragging when selecting.
823  // (if user really wants a tiny selection, they should zoom in).
824  // Can someone make this value of '5' configurable in
825  // preferences?
826  enum { minimumSizedSelection = 5 }; //measured in pixels
827 
828  // Might be dragging frequency bounds only, test
829  if (mSelStartValid) {
830  wxInt64 SelStart = viewInfo.TimeToPosition(mSelStart, mRect.x); //cvt time to pixels.
831  // Abandon this drag if selecting < 5 pixels.
832  if (wxLongLong(SelStart - x).Abs() < minimumSizedSelection)
833  return RefreshNone;
834  }
835 
836  if (evt.pCell) {
837  if ( auto clickedTrack =
838  static_cast<CommonTrackPanelCell*>(evt.pCell.get())->FindTrack() ) {
839  // Handle which tracks are selected
840  Track *sTrack = pTrack.get();
841  Track *eTrack = clickedTrack.get();
842  auto &trackList = TrackList::Get( *pProject );
843  if ( sTrack && eTrack && !event.ControlDown() ) {
844  auto &selectionState = SelectionState::Get( *pProject );
845  selectionState.SelectRangeOfTracks( trackList, *sTrack, *eTrack );
846  }
847 
848  #ifdef EXPERIMENTAL_SPECTRAL_EDITING
849  #ifndef SPECTRAL_EDITING_ESC_KEY
850  if (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER &&
851  !viewInfo.selectedRegion.isPoint())
853  (pProject, viewInfo, y, mRect.y, mRect.height, pView.get());
854  else
855  #endif
856  if ( TrackList::Get( *pProject ).Lock(mFreqSelTrack) == pTrack )
858  static_cast<WaveTrack*>(pTrack.get()),
859  viewInfo, y, mRect.y, mRect.height);
860  #endif
861 
862  AdjustSelection(pProject, viewInfo, x, mRect.x, clickedTrack.get());
863  }
864  }
865 
866  return RefreshNone
867 
868  // If scrubbing does not use the helper poller thread, then
869  // don't refresh at every mouse event, because it slows down seek-scrub.
870  // Instead, let OnTimer do it, which is often enough.
871  // And even if scrubbing does use the thread, then skipping refresh does not
872  // bring that advantage, but it is probably still a good idea anyway.
873 
874  // | UpdateSelection
875 
876  ;
877 }
878 
880 (const TrackPanelMouseState &st, AudacityProject *pProject)
881 {
882  if (!HasSnap() && !mUseSnap)
883  // Moved out of snapping; revert to un-escaped state
884  mUseSnap = true;
885 
886  const auto pView = mpView.lock();
887  if ( !pView )
888  return {};
889 
890  auto pTrack = FindTrack().lock();
891  if (!pTrack)
892  return {};
893 
894  TranslatableString tip;
895  wxCursor *pCursor = SelectCursor();
896  if ( IsClicked() )
897  // Use same cursor as at the click
900  (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER),
901  tip, pCursor);
902  else {
903  // Choose one of many cursors for mouse-over
904 
905  auto &viewInfo = ViewInfo::Get( *pProject );
906 
907  auto &state = st.state;
909  auto xx = viewInfo.TimeToPosition(time, mRect.x);
910 
911  const bool bMultiToolMode =
913 
914  //In Multi-tool mode, give multitool prompt if no-special-hit.
915  if (bMultiToolMode) {
916  // Look up the current key binding for Preferences.
917  // (Don't assume it's the default!)
918  auto keyStr =
919  CommandManager::Get( *pProject ).GetKeyFromName(wxT("Preferences"))
920  .Display( true );
921  if (keyStr.empty())
922  // No keyboard preference defined for opening Preferences dialog
923  /* i18n-hint: These are the names of a menu and a command in that menu */
924  keyStr = _("Edit, Preferences...");
925 
926  /* i18n-hint: %s is usually replaced by "Ctrl+P" for Windows/Linux, "Command+," for Mac */
927  tip = XO("Multi-Tool Mode: %s for Mouse and Keyboard Preferences.")
928  .Format( keyStr );
929  // Later in this function we may point to some other string instead.
930  if (!pTrack->GetSelected() ||
931  !viewInfo.bAdjustSelectionEdges)
932  ;
933  else {
934  const wxRect &rect = st.rect;
935  const bool bShiftDown = state.ShiftDown();
936  const bool bCtrlDown = state.ControlDown();
937  const bool bModifierDown = bShiftDown || bCtrlDown;
938 
939  // If not shift-down and not snapping center, then
940  // choose boundaries only in snapping tolerance,
941  // and may choose center.
942  SelectionBoundary boundary =
943  ChooseBoundary(viewInfo, xx, state.m_y,
944  pView.get(), rect, !bModifierDown, !bModifierDown);
945 
946  SetTipAndCursorForBoundary(boundary, !bShiftDown, tip, pCursor);
947  }
948  }
949 
950 #if 0
951  // This is a vestige of an idea in the prototype version.
952  // Center would snap without mouse button down, click would pin the center
953  // and drag width.
954 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
955  if ((mFreqSelMode == FREQ_SEL_SNAPPING_CENTER) &&
956  isSpectralSelectionView(pView)) {
957  // Not shift-down, but center frequency snapping toggle is on
958  tip = XO("Click and drag to set frequency bandwidth.");
959  pCursor = &*envelopeCursor;
960  return {};
961  }
962 #endif
963 #endif
964 
965  if (!pTrack->GetSelected() || !viewInfo.bAdjustSelectionEdges)
966  ;
967  else {
968  const wxRect &rect = st.rect;
969  const bool bShiftDown = state.ShiftDown();
970  const bool bCtrlDown = state.ControlDown();
971  const bool bModifierDown = bShiftDown || bCtrlDown;
973  viewInfo, xx, state.m_y,
974  pView.get(), rect, !bModifierDown, !bModifierDown);
975  SetTipAndCursorForBoundary(boundary, !bShiftDown, tip, pCursor);
976  }
977  }
978  if (tip.empty()) {
979  tip = XO("Click and drag to select audio");
980  }
981  if (HasEscape(pProject) && mUseSnap) {
982  tip.Join(
983 /* i18n-hint: "Snapping" means automatic alignment of selection edges to any nearby label or clip boundaries */
984  XO("(snapping)"), wxT(" ")
985  );
986  }
987  return { tip, pCursor };
988 }
989 
991 (const TrackPanelMouseEvent &, AudacityProject *pProject,
992  wxWindow *)
993 {
994  using namespace RefreshCode;
995  ProjectHistory::Get( *pProject ).ModifyState(false);
996  mFrequencySnapper.reset();
997  mSnapManager.reset();
999  mSelectionStateChanger->Commit();
1000  mSelectionStateChanger.reset();
1001  }
1002 
1003  if (mUseSnap && (mSnapStart.outCoord != -1 || mSnapEnd.outCoord != -1))
1004  return RefreshAll;
1005  else
1006  return RefreshNone;
1007 }
1008 
1010 {
1011  mSelectionStateChanger.reset();
1013 
1014  return RefreshCode::RefreshAll;
1015 }
1016 
1018  TrackPanelDrawingContext &context,
1019  const wxRect &rect, unsigned iPass )
1020 {
1021  if ( iPass == TrackArtist::PassSnapping ) {
1022  auto &dc = context.dc;
1023  // Draw snap guidelines if we have any
1024  if ( mSnapManager ) {
1025  auto coord1 = (mUseSnap || IsClicked()) ? mSnapStart.outCoord : -1;
1026  auto coord2 = (!mUseSnap || !IsClicked()) ? -1 : mSnapEnd.outCoord;
1027  mSnapManager->Draw( &dc, coord1, coord2 );
1028  }
1029  }
1030 }
1031 
1034  const wxRect &rect, const wxRect &panelRect, unsigned iPass )
1035 {
1036  if ( iPass == TrackArtist::PassSnapping )
1037  return MaximizeHeight( rect, panelRect );
1038  else
1039  return rect;
1040 }
1041 
1042 std::weak_ptr<Track> SelectHandle::FindTrack()
1043 {
1044  auto pView = mpView.lock();
1045  if (!pView)
1046  return {};
1047  else
1048  return pView->FindTrack();
1049 }
1050 
1052 {
1053  mTimerHandler = std::make_shared<TimerHandler>( this, pProject );
1054 }
1055 
1057 {
1058 public:
1060  : mParent{ pParent }
1061  , mConnectedProject{ pProject }
1062  {
1063  if (mConnectedProject)
1066  }
1067 
1068  // Receives timer event notifications, to implement auto-scroll
1069  void OnTimer(Observer::Message);
1070 
1071 private:
1075 };
1076 
1078 {
1079  // AS: If the user is dragging the mouse and there is a track that
1080  // has captured the mouse, then scroll the screen, as necessary.
1081 
1083 
1084  // DM: If we're "autoscrolling" (which means that we're scrolling
1085  // because the user dragged from inside to outside the window,
1086  // not because the user clicked in the scroll bar), then
1087  // the selection code needs to be handled slightly differently.
1088  // We set this flag ("mAutoScrolling") to tell the selecting
1089  // code that we didn't get here as a result of a mouse event,
1090  // and therefore it should ignore the event,
1091  // and instead use the last known mouse position. Setting
1092  // this flag also causes the Mac to redraw immediately rather
1093  // than waiting for the next update event; this makes scrolling
1094  // smoother on MacOS 9.
1095 
1096  const auto project = mConnectedProject;
1097  const auto &trackPanel = TrackPanel::Get( *project );
1098  auto &window = ProjectWindow::Get( *project );
1099  if (mParent->mMostRecentX >= mParent->mRect.x + mParent->mRect.width) {
1100  mParent->mAutoScrolling = true;
1101  window.TP_ScrollRight();
1102  }
1103  else if (mParent->mMostRecentX < mParent->mRect.x) {
1104  mParent->mAutoScrolling = true;
1105  window.TP_ScrollLeft();
1106  }
1107  else {
1108  // Bug1387: enable autoscroll during drag, if the pointer is at either
1109  // extreme x coordinate of the screen, even if that is still within the
1110  // track area.
1111 
1112  int xx = mParent->mMostRecentX, yy = 0;
1113  trackPanel.ClientToScreen(&xx, &yy);
1114  if (xx == 0) {
1115  mParent->mAutoScrolling = true;
1116  window.TP_ScrollLeft();
1117  }
1118  else {
1119  int width, height;
1120  ::wxDisplaySize(&width, &height);
1121  if (xx == width - 1) {
1122  mParent->mAutoScrolling = true;
1123  window.TP_ScrollRight();
1124  }
1125  }
1126  }
1127 
1128  auto pTrack = mParent->FindTrack().lock(); // TrackList::Lock() ?
1129  if (mParent->mAutoScrolling && pTrack) {
1130  // AS: To keep the selection working properly as we scroll,
1131  // we fake a mouse event (remember, this method is called
1132  // from a timer tick).
1133 
1134  // AS: For some reason, GCC won't let us pass this directly.
1135  wxMouseEvent evt(wxEVT_MOTION);
1136  const auto size = trackPanel.GetSize();
1137  mParent->Drag(
1139  evt, mParent->mRect, size,
1140  TrackView::Get( *pTrack ).shared_from_this() },
1141  project
1142  );
1143  mParent->mAutoScrolling = false;
1144  TrackPanel::Get( *mConnectedProject ).Refresh(false);
1145  }
1146 }
1147 
1150 {
1151  auto &viewInfo = ViewInfo::Get( *pProject );
1152  mSelStartValid = true;
1153 
1154  viewInfo.selectedRegion.setTimes(mSelStart, mSelStart);
1155 
1156  // PRL: commented out the Sonify stuff with the TrackPanel refactor.
1157  // It was no-op anyway.
1158  //SonifyBeginModifyState();
1159  ProjectHistory::Get( *pProject ).ModifyState(false);
1160  //SonifyEndModifyState();
1161 }
1162 
1165 (AudacityProject *pProject,
1166  ViewInfo &viewInfo, int mouseXCoordinate, int trackLeftEdge,
1167  Track *track)
1168 {
1169  if (!mSelStartValid)
1170  // Must be dragging frequency bounds only.
1171  return;
1172 
1173  double selend =
1174  std::max(0.0, viewInfo.PositionToTime(mouseXCoordinate, trackLeftEdge));
1175  double origSelend = selend;
1176 
1177  auto pTrack = Track::SharedPointer( track );
1178  if (!pTrack)
1179  pTrack = TrackList::Get( *pProject ).Lock( FindTrack() );
1180 
1181  if (pTrack && mSnapManager.get()) {
1182  bool rightEdge = (selend > mSelStart);
1183  mSnapEnd = mSnapManager->Snap(pTrack.get(), selend, rightEdge);
1184  if (mSnapEnd.Snapped()) {
1185  if (mUseSnap)
1186  selend = mSnapEnd.outTime;
1187  if (mSnapEnd.snappedPoint)
1188  mSnapEnd.outCoord += trackLeftEdge;
1189  }
1190  if (!mSnapEnd.snappedPoint)
1191  mSnapEnd.outCoord = -1;
1192 
1193  // Check if selection endpoints are too close together to snap (unless
1194  // using snap-to-time -- then we always accept the snap results)
1195  if (mSnapStart.outCoord >= 0 &&
1196  mSnapEnd.outCoord >= 0 &&
1197  std::abs(mSnapStart.outCoord - mSnapEnd.outCoord) < 3) {
1198  if(!mSnapEnd.snappedTime)
1199  selend = origSelend;
1200  mSnapEnd.outCoord = -1;
1201  }
1202  }
1203  AssignSelection(viewInfo, selend, pTrack.get());
1204 }
1205 
1207 (ViewInfo &viewInfo, double selend, Track *pTrack)
1208 {
1209  double sel0, sel1;
1210  if (mSelStart < selend) {
1211  sel0 = mSelStart;
1212  sel1 = selend;
1213  }
1214  else {
1215  sel1 = mSelStart;
1216  sel0 = selend;
1217  }
1218 
1219  viewInfo.selectedRegion.setTimes(sel0, sel1);
1220 }
1221 
1223  int mouseYCoordinate, int trackTopEdge,
1224  int trackHeight, TrackView *pTrackView)
1225 {
1226  mFreqSelTrack.reset();
1227  mFreqSelMode = FREQ_SEL_INVALID;
1229 
1230  if (isSpectralSelectionView(pTrackView)) {
1231  // Spectral selection track is always wave
1232  auto shTrack = pTrackView->FindTrack()->SharedPointer<const WaveTrack>();
1233  mFreqSelTrack = shTrack;
1234  mFreqSelMode = FREQ_SEL_FREE;
1235  mFreqSelPin =
1236  PositionToFrequency(shTrack.get(), false, mouseYCoordinate,
1237  trackTopEdge, trackHeight);
1239  }
1240 }
1241 
1243  const WaveTrack *wt, ViewInfo &viewInfo,
1244  int mouseYCoordinate, int trackTopEdge,
1245  int trackHeight)
1246 {
1247  if (mFreqSelMode == FREQ_SEL_INVALID ||
1248  mFreqSelMode == FREQ_SEL_SNAPPING_CENTER)
1249  return;
1250 
1251  // Extension happens only when dragging in the same track in which we
1252  // started, and that is of a spectrogram display type.
1253 
1254  const double rate = wt->GetRate();
1255  const double frequency =
1256  PositionToFrequency(wt, true, mouseYCoordinate,
1257  trackTopEdge, trackHeight);
1258 
1259  // Dragging center?
1260  if (mFreqSelMode == FREQ_SEL_DRAG_CENTER) {
1261  if (frequency == rate || frequency < 1.0)
1262  // snapped to top or bottom
1263  viewInfo.selectedRegion.setFrequencies(
1266  else {
1267  // mFreqSelPin holds the ratio of top to center
1268  const double maxRatio = findMaxRatio(frequency, rate);
1269  const double ratio = std::min(maxRatio, mFreqSelPin);
1270  viewInfo.selectedRegion.setFrequencies(
1271  frequency / ratio, frequency * ratio);
1272  }
1273  }
1274  else if (mFreqSelMode == FREQ_SEL_PINNED_CENTER) {
1275  if (mFreqSelPin >= 0) {
1276  // Change both upper and lower edges leaving centre where it is.
1277  if (frequency == rate || frequency < 1.0)
1278  // snapped to top or bottom
1279  viewInfo.selectedRegion.setFrequencies(
1282  else {
1283  // Given center and mouse position, find ratio of the larger to the
1284  // smaller, limit that to the frequency scale bounds, and adjust
1285  // top and bottom accordingly.
1286  const double maxRatio = findMaxRatio(mFreqSelPin, rate);
1287  double ratio = frequency / mFreqSelPin;
1288  if (ratio < 1.0)
1289  ratio = 1.0 / ratio;
1290  ratio = std::min(maxRatio, ratio);
1291  viewInfo.selectedRegion.setFrequencies(
1292  mFreqSelPin / ratio, mFreqSelPin * ratio);
1293  }
1294  }
1295  }
1296  else {
1297  // Dragging of upper or lower.
1298  const bool bottomDefined =
1299  !(mFreqSelMode == FREQ_SEL_TOP_FREE && mFreqSelPin < 0);
1300  const bool topDefined =
1301  !(mFreqSelMode == FREQ_SEL_BOTTOM_FREE && mFreqSelPin < 0);
1302  if (!bottomDefined || (topDefined && mFreqSelPin < frequency)) {
1303  // Adjust top
1304  if (frequency == rate)
1305  // snapped high; upper frequency is undefined
1307  else
1308  viewInfo.selectedRegion.setF1(std::max(1.0, frequency));
1309 
1310  viewInfo.selectedRegion.setF0(mFreqSelPin);
1311  }
1312  else {
1313  // Adjust bottom
1314  if (frequency < 1.0)
1315  // snapped low; lower frequency is undefined
1317  else
1318  viewInfo.selectedRegion.setF0(std::min(rate / 2.0, frequency));
1319 
1320  viewInfo.selectedRegion.setF1(mFreqSelPin);
1321  }
1322  }
1323 }
1324 
1326 (const ViewInfo &viewInfo, bool shiftDown, const WaveTrack *pTrack, double value)
1327 {
1328  if (shiftDown) {
1329  // Disable time selection
1330  mSelStartValid = false;
1331  mFreqSelTrack = pTrack->SharedPointer<const WaveTrack>();
1332  mFreqSelPin = value;
1333  mFreqSelMode = FREQ_SEL_DRAG_CENTER;
1334  }
1335  else {
1336 #ifndef SPECTRAL_EDITING_ESC_KEY
1337  // Start center snapping
1338  // Turn center snapping on (the only way to do this)
1339  mFreqSelMode = FREQ_SEL_SNAPPING_CENTER;
1340  // Disable time selection
1341  mSelStartValid = false;
1342  mFrequencySnapper = std::make_shared<SpectrumAnalyst>();
1343  StartSnappingFreqSelection(*mFrequencySnapper, viewInfo, pTrack);
1344 #endif
1345  }
1346 }
1347 
1349  (SpectrumAnalyst &analyst,
1350  const ViewInfo &viewInfo, const WaveTrack *pTrack)
1351 {
1352  static const size_t minLength = 8;
1353 
1354  const double rate = pTrack->GetRate();
1355 
1356  // Grab samples, just for this track, at these times
1357  std::vector<float> frequencySnappingData;
1358  const auto start =
1359  pTrack->TimeToLongSamples(viewInfo.selectedRegion.t0());
1360  const auto end =
1361  pTrack->TimeToLongSamples(viewInfo.selectedRegion.t1());
1362  const auto length =
1363  std::min(frequencySnappingData.max_size(),
1364  limitSampleBufferSize(10485760, // as in FreqWindow.cpp
1365  end - start));
1366  const auto effectiveLength = std::max(minLength, length);
1367  frequencySnappingData.resize(effectiveLength, 0.0f);
1368  pTrack->GetFloats(
1369  &frequencySnappingData[0],
1370  start, length, fillZero,
1371  // Don't try to cope with exceptions, just read zeroes instead.
1372  false);
1373 
1374  // Use same settings as are now used for spectrogram display,
1375  // except, shrink the window as needed so we get some answers
1376 
1378  auto windowSize = settings.GetFFTLength();
1379 
1380  while(windowSize > effectiveLength)
1381  windowSize >>= 1;
1382  const int windowType = settings.windowType;
1383 
1384  analyst.Calculate(
1385  SpectrumAnalyst::Spectrum, windowType, windowSize, rate,
1386  &frequencySnappingData[0], length);
1387 
1388  // We can now throw away the sample data but we keep the spectrum.
1389 }
1390 
1392  (AudacityProject *pProject, ViewInfo &viewInfo, int mouseYCoordinate,
1393  int trackTopEdge,
1394  int trackHeight, TrackView *pTrackView)
1395 {
1396  auto pTrack = pTrackView->FindTrack().get();
1397  if (pTrack &&
1398  pTrack->GetSelected() &&
1399  isSpectralSelectionView(pTrackView)) {
1400  // Spectral selection track is always wave
1401  WaveTrack *const wt = static_cast<WaveTrack*>(pTrack);
1402  // PRL:
1403  // What would happen if center snapping selection began in one spectrogram track,
1404  // then continues inside another? We do not then recalculate
1405  // the spectrum (as was done in StartSnappingFreqSelection)
1406  // but snap according to the peaks in the old track.
1407 
1408  // But if we always supply the original clicked track here that doesn't matter.
1409  const double rate = wt->GetRate();
1410  const double frequency =
1411  PositionToFrequency(wt, false, mouseYCoordinate,
1412  trackTopEdge, trackHeight);
1413  const double snappedFrequency =
1414  mFrequencySnapper->FindPeak(frequency, NULL);
1415  const double maxRatio = findMaxRatio(snappedFrequency, rate);
1416  double ratio = 2.0; // An arbitrary octave on each side, at most
1417  {
1418  const double f0 = viewInfo.selectedRegion.f0();
1419  const double f1 = viewInfo.selectedRegion.f1();
1420  if (f1 >= f0 && f0 >= 0)
1421  // Preserve already chosen ratio instead
1422  ratio = sqrt(f1 / f0);
1423  }
1424  ratio = std::min(ratio, maxRatio);
1425 
1426  mFreqSelPin = snappedFrequency;
1427  viewInfo.selectedRegion.setFrequencies(
1428  snappedFrequency / ratio, snappedFrequency * ratio);
1429 
1430  // A change here would affect what AdjustFreqSelection() does
1431  // in the prototype version where you switch from moving center to
1432  // dragging width with a click. No effect now.
1433  mFreqSelTrack = wt->SharedPointer<const WaveTrack>();
1434 
1435  // SelectNone();
1436  // SelectTrack(pTrack, true);
1437  TrackFocus::Get( *pProject ).Set(pTrack);
1438  }
1439 }
1440 
1442  (SpectrumAnalyst &analyst,
1443  ViewInfo &viewInfo, const WaveTrack *pTrack, bool up)
1444 {
1446  const auto windowSize = settings.GetFFTLength();
1447  const double rate = pTrack->GetRate();
1448  const double nyq = rate / 2.0;
1449  const double binFrequency = rate / windowSize;
1450 
1451  double f1 = viewInfo.selectedRegion.f1();
1452  double centerFrequency = viewInfo.selectedRegion.fc();
1453  if (centerFrequency <= 0) {
1454  centerFrequency = up ? binFrequency : nyq;
1455  f1 = centerFrequency * sqrt(2.0);
1456  }
1457 
1458  double ratio = f1 / centerFrequency;
1459  const int originalBin = floor(0.5 + centerFrequency / binFrequency);
1460  const int limitingBin = up ? floor(0.5 + nyq / binFrequency) : 1;
1461 
1462  // This is crude and wasteful, doing the FFT each time the command is called.
1463  // It would be better to cache the data, but then invalidation of the cache would
1464  // need doing in all places that change the time selection.
1465  StartSnappingFreqSelection(analyst, viewInfo, pTrack);
1466  double snappedFrequency = centerFrequency;
1467  int bin = originalBin;
1468  if (up) {
1469  while (snappedFrequency <= centerFrequency &&
1470  bin < limitingBin)
1471  snappedFrequency = analyst.FindPeak(++bin * binFrequency, NULL);
1472  }
1473  else {
1474  while (snappedFrequency >= centerFrequency &&
1475  bin > limitingBin)
1476  snappedFrequency = analyst.FindPeak(--bin * binFrequency, NULL);
1477  }
1478 
1479  // PRL: added these two lines with the big TrackPanel refactor
1480  const double maxRatio = findMaxRatio(snappedFrequency, rate);
1481  ratio = std::min(ratio, maxRatio);
1482 
1484  (snappedFrequency / ratio, snappedFrequency * ratio);
1485 }
1486 
1487 #if 0
1488 // unused
1489 void SelectHandle::ResetFreqSelectionPin
1490  (const ViewInfo &viewInfo, double hintFrequency, bool logF)
1491 {
1492  switch (mFreqSelMode) {
1493  case FREQ_SEL_INVALID:
1495  mFreqSelPin = -1.0;
1496  break;
1497 
1499  mFreqSelPin = viewInfo.selectedRegion.fc();
1500  break;
1501 
1502  case FREQ_SEL_DRAG_CENTER:
1503  {
1504  // Re-pin the width
1505  const double f0 = viewInfo.selectedRegion.f0();
1506  const double f1 = viewInfo.selectedRegion.f1();
1507  if (f0 >= 0 && f1 >= 0)
1508  mFreqSelPin = sqrt(f1 / f0);
1509  else
1510  mFreqSelPin = -1.0;
1511  }
1512  break;
1513 
1514  case FREQ_SEL_FREE:
1515  // Pin which? Farther from the hint which is the presumed
1516  // mouse position.
1517  {
1518  // If this function finds use again, the following should be
1519  // generalized using NumberScale
1520 
1521  const double f0 = viewInfo.selectedRegion.f0();
1522  const double f1 = viewInfo.selectedRegion.f1();
1523  if (logF) {
1524  if (f1 < 0)
1525  mFreqSelPin = f0;
1526  else {
1527  const double logf1 = log(std::max(1.0, f1));
1528  const double logf0 = log(std::max(1.0, f0));
1529  const double logHint = log(std::max(1.0, hintFrequency));
1530  if (std::abs(logHint - logf1) < std::abs(logHint - logf0))
1531  mFreqSelPin = f0;
1532  else
1533  mFreqSelPin = f1;
1534  }
1535  }
1536  else {
1537  if (f1 < 0 ||
1538  std::abs(hintFrequency - f1) < std::abs(hintFrequency - f0))
1539  mFreqSelPin = f0;
1540  else
1541  mFreqSelPin = f1;
1542  }
1543  }
1544  break;
1545 
1546  case FREQ_SEL_TOP_FREE:
1547  mFreqSelPin = viewInfo.selectedRegion.f0();
1548  break;
1549 
1550  case FREQ_SEL_BOTTOM_FREE:
1551  mFreqSelPin = viewInfo.selectedRegion.f1();
1552  break;
1553 
1554  default:
1555  wxASSERT(false);
1556  }
1557 }
1558 #endif
size
size_t size
Definition: ffmpeg-2.3.6-single-header.h:412
TrackPanelMouseEvent::pCell
std::shared_ptr< TrackPanelCell > pCell
Definition: TrackPanelMouseEvent.h:61
anonymous_namespace{SelectHandle.cpp}::SBRight
@ SBRight
Definition: SelectHandle.cpp:126
ProjectHistory::ModifyState
void ModifyState(bool bWantsAutoSave)
Definition: ProjectHistory.cpp:124
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
ViewInfo::Get
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
SelectHandle::StartSelection
void StartSelection(AudacityProject *pProject)
Reset our selection markers.
Definition: SelectHandle.cpp:1149
TranslatableString::empty
bool empty() const
Definition: TranslatableString.h:72
SpectrumAnalyst::Spectrum
@ Spectrum
Definition: SpectrumAnalyst.h:25
SpectrogramSettings
Spectrogram settings, either for one track or as defaults.
Definition: SpectrogramSettings.h:27
SelectHandle::mSelectionStateChanger
std::shared_ptr< SelectionStateChanger > mSelectionStateChanger
Definition: SelectHandle.h:169
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:75
SelectHandle::mSnapEnd
SnapResults mSnapEnd
Definition: SelectHandle.h:136
SelectHandle::TimerHandler::mParent
SelectHandle * mParent
Definition: SelectHandle.cpp:1072
SelectHandle::FREQ_SEL_SNAPPING_CENTER
@ FREQ_SEL_SNAPPING_CENTER
Definition: SelectHandle.h:147
NormalizedKeyString::Display
wxString Display(bool usesSpecialChars=false) const
Definition: Keyboard.cpp:56
SelectHandle::FREQ_SEL_FREE
@ FREQ_SEL_FREE
Definition: SelectHandle.h:151
anonymous_namespace{SelectHandle.cpp}::ChooseBoundary
SelectionBoundary ChooseBoundary(const ViewInfo &viewInfo, wxCoord xx, wxCoord yy, const TrackView *pTrackView, const wxRect &rect, bool mayDragWidth, bool onlyWithinSnapDistance, double *pPinValue=NULL)
Definition: SelectHandle.cpp:173
RefreshCode::RefreshAll
@ RefreshAll
Definition: RefreshCode.h:26
NumberScale.h
TrackView::Get
static TrackView & Get(Track &)
Definition: TrackView.cpp:69
RefreshCode::RefreshNone
@ RefreshNone
Definition: RefreshCode.h:21
SelectHandle::TimerHandler::mSubscription
Observer::Subscription mSubscription
Definition: SelectHandle.cpp:1074
SelectHandle::Connect
void Connect(AudacityProject *pProject)
Definition: SelectHandle.cpp:1051
SelectHandle::TimerHandler::OnTimer
void OnTimer(Observer::Message)
Definition: SelectHandle.cpp:1077
SelectHandle::mMostRecentX
int mMostRecentX
Definition: SelectHandle.h:165
TrackView.h
SelectHandle::mAutoScrolling
bool mAutoScrolling
Definition: SelectHandle.h:167
TrackList::Lock
std::shared_ptr< Subclass > Lock(const std::weak_ptr< Subclass > &wTrack)
Definition: Track.h:1541
Project.h
anonymous_namespace{SelectHandle.cpp}::SetTipAndCursorForBoundary
void SetTipAndCursorForBoundary(SelectionBoundary boundary, bool frequencySnapping, TranslatableString &tip, wxCursor *&pCursor)
Definition: SelectHandle.cpp:295
NotifyingSelectedRegion::setF0
bool setF0(double f, bool maySwap=true)
Definition: ViewInfo.cpp:115
CommonTrackPanelCell::FindTrack
std::shared_ptr< Track > FindTrack()
Definition: CommonTrackPanelCell.h:47
TrackPanelDrawingContext
Definition: TrackPanelDrawingContext.h:22
SelectHandle::mFreqSelTrack
std::weak_ptr< const WaveTrack > mFreqSelTrack
Definition: SelectHandle.h:155
TrackList
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:1288
TrackArtist::PassSnapping
@ PassSnapping
Definition: TrackArtist.h:51
MakeCursor
std::unique_ptr< wxCursor > MakeCursor(int WXUNUSED(CursorId), const char *const pXpm[36], int HotX, int HotY)
Definition: TrackPanel.cpp:182
SnapResults::snappedTime
bool snappedTime
Definition: Snap.h:50
anonymous_namespace{SelectHandle.cpp}::SetIfNotNull
void SetIfNotNull(T *pValue, const T Value)
Definition: SelectHandle.cpp:104
ViewInfo
Definition: ViewInfo.h:188
SelectHandle::~SelectHandle
virtual ~SelectHandle()
Definition: SelectHandle.cpp:453
Track::SharedPointer
std::shared_ptr< Subclass > SharedPointer()
Definition: Track.h:276
SelectHandle::IsClicked
bool IsClicked() const
Definition: SelectHandle.cpp:56
ProjectWindow::GetPlaybackScroller
PlaybackScroller & GetPlaybackScroller()
Definition: ProjectWindow.h:94
SelectHandle::mMostRecentY
int mMostRecentY
Definition: SelectHandle.h:165
RefreshCode::Cancelled
@ Cancelled
Definition: RefreshCode.h:23
TrackPanel::Get
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:227
SelectHandle::FREQ_SEL_TOP_FREE
@ FREQ_SEL_TOP_FREE
Definition: SelectHandle.h:152
XO
#define XO(s)
Definition: Internat.h:31
NotifyingSelectedRegion::setF1
bool setF1(double f, bool maySwap=true)
Definition: ViewInfo.cpp:125
anonymous_namespace{SelectHandle.cpp}::ChooseTimeBoundary
SelectionBoundary ChooseTimeBoundary(const double t0, const double t1, const ViewInfo &viewInfo, double selend, bool onlyWithinSnapDistance, wxInt64 *pPixelDist, double *pPinValue)
Definition: SelectHandle.cpp:133
ProjectSettings::Get
static ProjectSettings & Get(AudacityProject &project)
Definition: ProjectSettings.cpp:45
SelectHandle::NeedChangeHighlight
static UIHandle::Result NeedChangeHighlight(const SelectHandle &oldState, const SelectHandle &newState)
Definition: SelectHandle.cpp:409
LabelTrack
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:89
anonymous_namespace{SelectHandle.cpp}::EnvelopeCursor
wxCursor * EnvelopeCursor()
Definition: SelectHandle.cpp:286
SelectionState::SelectTrackLength
static void SelectTrackLength(ViewInfo &viewInfo, Track &track, bool syncLocked)
Definition: SelectionState.cpp:35
TrackPanelDrawingContext::dc
wxDC & dc
Definition: TrackPanelDrawingContext.h:23
ProjectWindow::Get
static ProjectWindow & Get(AudacityProject &project)
Definition: ProjectWindow.cpp:525
SelectedRegion::UndefinedFrequency
static const int UndefinedFrequency
Definition: SelectedRegion.h:44
SelectHandle::DrawingArea
wxRect DrawingArea(TrackPanelDrawingContext &, const wxRect &rect, const wxRect &panelRect, unsigned iPass) override
Definition: SelectHandle.cpp:1032
ProjectSettings::GetTool
int GetTool() const
Definition: ProjectSettings.h:93
SelectHandle::FindTrack
std::weak_ptr< Track > FindTrack()
Definition: SelectHandle.cpp:1042
ProjectAudioIO::Get
static ProjectAudioIO & Get(AudacityProject &project)
Definition: ProjectAudioIO.cpp:24
WaveTrack::GetSpectrogramSettings
const SpectrogramSettings & GetSpectrogramSettings() const
Definition: WaveTrack.cpp:801
SelectHandle::mInitialSelection
SelectedRegion mInitialSelection
Definition: SelectHandle.h:133
SelectHandle::StartSnappingFreqSelection
static void StartSnappingFreqSelection(SpectrumAnalyst &analyst, const ViewInfo &viewInfo, const WaveTrack *pTrack)
Definition: SelectHandle.cpp:1349
SnapResults
Definition: Snap.h:45
SelectHandle::mTimerHandler
std::shared_ptr< TimerHandler > mTimerHandler
Definition: SelectHandle.h:173
SelectHandle::FREQ_SEL_INVALID
enum SelectHandle::eFreqSelMode FREQ_SEL_INVALID
fillZero
@ fillZero
Definition: SampleFormat.h:54
TrackPanelMouseState::rect
const wxRect & rect
Definition: TrackPanelMouseEvent.h:39
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:51
SnapResults::outTime
double outTime
Definition: Snap.h:47
ProjectAudioIO::IsAudioActive
bool IsAudioActive() const
Definition: ProjectAudioIO.cpp:53
SelectHandle::StartFreqSelection
void StartFreqSelection(ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge, int trackHeight, TrackView *pTrackView)
Definition: SelectHandle.cpp:1222
anonymous_namespace{SelectHandle.cpp}::FrequencyToPosition
wxInt64 FrequencyToPosition(const WaveTrack *wt, double frequency, wxInt64 trackTopEdge, int trackHeight)
Converts a frequency to screen y position.
Definition: SelectHandle.cpp:64
SelectHandle::FREQ_SEL_PINNED_CENTER
@ FREQ_SEL_PINNED_CENTER
Definition: SelectHandle.h:148
NotifyingSelectedRegion::t1
double t1() const
Definition: ViewInfo.h:35
SelectHandle::HasEscape
bool HasEscape(AudacityProject *pProject) const override
Definition: SelectHandle.cpp:505
SelectHandle::SnapCenterOnce
static void SnapCenterOnce(SpectrumAnalyst &analyst, ViewInfo &viewInfo, const WaveTrack *pTrack, bool up)
Definition: SelectHandle.cpp:1442
SelectHandle::SetUseSnap
void SetUseSnap(bool use, AudacityProject *pProject)
Definition: SelectHandle.cpp:481
SelectHandle::AdjustSelection
void AdjustSelection(AudacityProject *pProject, ViewInfo &viewInfo, int mouseXCoordinate, int trackLeftEdge, Track *pTrack)
Extend or contract the existing selection.
Definition: SelectHandle.cpp:1165
SpectrumAnalyst
Used for finding the peaks, for snapping to peaks.
Definition: SpectrumAnalyst.h:21
NotifyingSelectedRegion::setTimes
bool setTimes(double t0, double t1)
Definition: ViewInfo.cpp:51
NumberScale::ValueToPosition
float ValueToPosition(float val) const
Definition: NumberScale.h:255
Observer::Message
Default message type for Publisher.
Definition: Observer.h:26
SelectHandle::Enter
void Enter(bool forward, AudacityProject *pProject) override
Definition: SelectHandle.cpp:476
WaveClip
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:101
A
#define A(N)
Definition: ToChars.cpp:62
SnapResults::timeSnappedTime
double timeSnappedTime
Definition: Snap.h:46
ViewInfo::selectedRegion
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:215
SelectHandle::TimerHandler::mConnectedProject
AudacityProject * mConnectedProject
Definition: SelectHandle.cpp:1073
UIHandle::mChangeHighlight
Result mChangeHighlight
Definition: UIHandle.h:139
ToolCodes::multiTool
@ multiTool
Definition: ProjectSettings.h:44
SelectHandle::AdjustFreqSelection
void AdjustFreqSelection(const WaveTrack *wt, ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge, int trackHeight)
Definition: SelectHandle.cpp:1242
SnapResults::Snapped
bool Snapped() const
Definition: Snap.h:52
SelectHandle::mUseSnap
bool mUseSnap
Definition: SelectHandle.h:137
SampleTrack::GetFloats
bool GetFloats(float *buffer, sampleCount start, size_t len, fillFormat fill=fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const
Retrieve samples from a track in floating-point format, regardless of the storage format.
Definition: SampleTrack.h:64
SelectHandle::FREQ_SEL_BOTTOM_FREE
@ FREQ_SEL_BOTTOM_FREE
Definition: SelectHandle.h:153
CommandManager::GetKeyFromName
NormalizedKeyString GetKeyFromName(const CommandID &name) const
Definition: CommandManager.cpp:1500
WaveTrack::GetSpectrumBounds
void GetSpectrumBounds(float *min, float *max) const
Definition: WaveTrack.cpp:370
SelectHandle::AssignSelection
void AssignSelection(ViewInfo &viewInfo, double selend, Track *pTrack)
Definition: SelectHandle.cpp:1207
UIHandle::Result
unsigned Result
Definition: UIHandle.h:38
anonymous_namespace{SelectHandle.cpp}::SelectCursor
wxCursor * SelectCursor()
Definition: SelectHandle.cpp:279
SelectHandle::mpView
std::weak_ptr< TrackView > mpView
Definition: SelectHandle.h:131
SelectHandle::Escape
bool Escape(AudacityProject *pProject) override
Definition: SelectHandle.cpp:510
SelectHandle
Definition: SelectHandle.h:31
SpectrumAnalyst::Calculate
bool Calculate(Algorithm alg, int windowFunc, size_t windowSize, double rate, const float *data, size_t dataLen, float *pYMin=NULL, float *pYMax=NULL, FreqGauge *progress=NULL)
Definition: SpectrumAnalyst.cpp:91
UIHandlePtr
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
SnapResults::outCoord
wxInt64 outCoord
Definition: Snap.h:48
Scrubbing.h
HitTestPreview
Definition: HitTestResult.h:20
SelectHandle::Drag
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Definition: SelectHandle.cpp:786
FREQ_SNAP_DISTANCE
@ FREQ_SNAP_DISTANCE
Definition: SelectHandle.cpp:51
SelectHandle::MoveSnappingFreqSelection
void MoveSnappingFreqSelection(AudacityProject *pProject, ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge, int trackHeight, TrackView *pTrackView)
Definition: SelectHandle.cpp:1392
TrackPanelDrawable::MaximizeHeight
static wxRect MaximizeHeight(const wxRect &rect, const wxRect &panelRect)
Definition: TrackPanelDrawable.h:52
anonymous_namespace{SelectHandle.cpp}::findMaxRatio
double findMaxRatio(double center, double rate)
Definition: SelectHandle.cpp:464
TrackFocus::Get
Track * Get()
Definition: TrackPanelAx.cpp:760
SelectHandle::SelectHandle
SelectHandle(const SelectHandle &)
SELECTION_RESIZE_REGION
@ SELECTION_RESIZE_REGION
Definition: SelectHandle.cpp:48
Observer::Subscription
A move-only handle representing a connection to a Publisher.
Definition: Observer.h:70
WaveTrack::GetClipAtTime
WaveClip * GetClipAtTime(double time)
Definition: WaveTrack.cpp:2318
ViewInfo.h
SelectHandle::HasSnap
bool HasSnap() const
Definition: SelectHandle.cpp:499
NotifyingSelectedRegion::f0
double f0() const
Definition: ViewInfo.h:36
SpectrumAnalyst::FindPeak
float FindPeak(float xPos, float *pY) const
Definition: SpectrumAnalyst.cpp:397
SelectHandle::HandleCenterFrequencyClick
void HandleCenterFrequencyClick(const ViewInfo &viewInfo, bool shiftDown, const WaveTrack *pTrack, double value)
Definition: SelectHandle.cpp:1326
SelectHandle::Release
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
Definition: SelectHandle.cpp:991
SelectionState::Get
static SelectionState & Get(AudacityProject &project)
Definition: SelectionState.cpp:21
SelectHandle::TimerHandler
Definition: SelectHandle.cpp:1057
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
NotifyingSelectedRegion::f1
double f1() const
Definition: ViewInfo.h:37
anonymous_namespace{SelectHandle.cpp}::SelectionBoundary
SelectionBoundary
Definition: SelectHandle.cpp:124
anonymous_namespace{SelectHandle.cpp}::SBNone
@ SBNone
Definition: SelectHandle.cpp:125
anonymous_namespace{SelectHandle.cpp}::PositionToFrequency
double PositionToFrequency(const WaveTrack *wt, bool maySnap, wxInt64 mouseYCoordinate, wxInt64 trackTopEdge, int trackHeight)
Definition: SelectHandle.cpp:79
NumberScale::PositionToValue
float PositionToValue(float pp) const
Definition: NumberScale.h:154
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:377
SelectHandle::Click
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Definition: SelectHandle.cpp:520
Track
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:224
TrackView
Definition: TrackView.h:25
SelectHandle::HitTest
static UIHandlePtr HitTest(std::weak_ptr< SelectHandle > &holder, const TrackPanelMouseState &state, const AudacityProject *pProject, const std::shared_ptr< TrackView > &pTrackView)
Definition: SelectHandle.cpp:361
_
#define _(s)
Definition: Internat.h:75
SelectHandle::mFrequencySnapper
std::shared_ptr< SpectrumAnalyst > mFrequencySnapper
Definition: SelectHandle.h:163
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
anonymous_namespace{SelectHandle.cpp}::isSpectralSelectionView
bool isSpectralSelectionView(const TrackView *pTrackView)
Definition: SelectHandle.cpp:112
WaveTrack::GetRate
double GetRate() const override
Definition: WaveTrack.cpp:495
TrackPanelMouseEvent
Definition: TrackPanelMouseEvent.h:46
anonymous_namespace{SelectHandle.cpp}::SBLeft
@ SBLeft
Definition: SelectHandle.cpp:126
SelectHandle::mRect
wxRect mRect
Definition: SelectHandle.h:132
NotifyingSelectedRegion::fc
double fc() const
Definition: ViewInfo.h:38
TrackPanelMouseState
Definition: TrackPanelMouseEvent.h:28
SampleTrack::TimeToLongSamples
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Definition: SampleTrack.cpp:35
SnapResults::snappedPoint
bool snappedPoint
Definition: Snap.h:49
SnapPoint
Definition: Snap.h:31
SelectHandle::mSelStartValid
bool mSelStartValid
Definition: SelectHandle.h:139
NumberScale
Definition: NumberScale.h:31
SelectHandle::mSelStart
double mSelStart
Definition: SelectHandle.h:140
NotifyingSelectedRegion::isPoint
bool isPoint() const
Definition: ViewInfo.h:39
NotifyingSelectedRegion::t0
double t0() const
Definition: ViewInfo.h:34
AssignUIHandlePtr
std::shared_ptr< Subclass > AssignUIHandlePtr(std::weak_ptr< Subclass > &holder, const std::shared_ptr< Subclass > &pNew)
Definition: UIHandle.h:151
SelectUtilities::DoListSelection
void DoListSelection(AudacityProject &project, Track *t, bool shift, bool ctrl, bool modifyState)
Definition: SelectUtilities.cpp:120
CommonTrackPanelCell
Definition: CommonTrackPanelCell.h:31
SelectHandle::Cancel
Result Cancel(AudacityProject *) override
Definition: SelectHandle.cpp:1009
CommandManager::Get
static CommandManager & Get(AudacityProject &project)
Definition: CommandManager.cpp:207
TranslatableString::Join
TranslatableString & Join(TranslatableString arg, const wxString &separator={}) &
Append another translatable string.
Definition: TranslatableString.cpp:124
NotifyingSelectedRegion::setFrequencies
bool setFrequencies(double f0, double f1)
Definition: ViewInfo.cpp:105
settings
static Settings & settings()
Definition: TrackInfo.cpp:87
RefreshCode
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
limitSampleBufferSize
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: SampleCount.cpp:23
SelectHandle::Draw
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
Definition: SelectHandle.cpp:1017
AColor.h
within
bool within(A a, B b, DIST d)
Definition: TrackPanel.cpp:163
TrackView::IsSpectral
virtual bool IsSpectral() const
Definition: TrackView.cpp:136
SelectHandle::mSelectionBoundary
int mSelectionBoundary
Definition: SelectHandle.h:142
SelectHandle::mFreqSelPin
double mFreqSelPin
Definition: SelectHandle.h:162
TrackPanelMouseEvent::event
wxMouseEvent & event
Definition: TrackPanelMouseEvent.h:58
SnapPointArray
std::vector< SnapPoint > SnapPointArray
Definition: Snap.h:43
SelectHandle::mSnapStart
SnapResults mSnapStart
Definition: SelectHandle.h:136
SelectHandle::mSnapManager
std::shared_ptr< SnapManager > mSnapManager
Definition: SelectHandle.h:135
Observer::Publisher::Subscribe
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
TrackPanelMouseState::state
wxMouseState & state
Definition: TrackPanelMouseEvent.h:38
ProjectHistory::Get
static ProjectHistory & Get(AudacityProject &project)
Definition: ProjectHistory.cpp:26
SelectHandle::FREQ_SEL_DRAG_CENTER
@ FREQ_SEL_DRAG_CENTER
Definition: SelectHandle.h:149
SelectHandle::Preview
HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *pProject) override
Definition: SelectHandle.cpp:880
ZoomInfo::PositionToTime
double PositionToTime(wxInt64 position, wxInt64 origin=0, bool ignoreFisheye=false) const
Definition: ZoomInfo.cpp:41
SelectHandle::TimerHandler::TimerHandler
TimerHandler(SelectHandle *pParent, AudacityProject *pProject)
Definition: SelectHandle.cpp:1059
SelectHandle.h