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