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  , mSnapManager{ std::make_shared<SnapManager>(
434  *trackList.GetOwner(), trackList, viewInfo) }
435 {
436  const wxMouseState &state = st.state;
437  mRect = st.rect;
438 
439  auto time = std::max(0.0, viewInfo.PositionToTime(state.m_x, mRect.x));
440  auto pTrack = pTrackView->FindTrack();
441  mSnapStart = mSnapManager->Snap(pTrack.get(), time, false);
442  if (mSnapStart.snappedPoint)
443  mSnapStart.outCoord += mRect.x;
444  else
445  mSnapStart.outCoord = -1;
446 
447  mUseSnap = useSnap;
448 }
449 
451 {
452 }
453 
454 namespace {
455  // Is the distance between A and B less than D?
456  template < class A, class B, class DIST > bool within(A a, B b, DIST d)
457  {
458  return (a > b - d) && (a < b + d);
459  }
460 
461  inline double findMaxRatio(double center, double rate)
462  {
463  const double minFrequency = 1.0;
464  const double maxFrequency = (rate / 2.0);
465  const double frequency =
466  std::min(maxFrequency,
467  std::max(minFrequency, center));
468  return
469  std::min(frequency / minFrequency, maxFrequency / frequency);
470  }
471 }
472 
474 {
475  SetUseSnap(true, project);
476 }
477 
479 {
480  mUseSnap = use;
481 
482  bool hasSnap = HasSnap();
483  if (hasSnap)
484  // Repaint to turn the snap lines on or off
486 
487  if (IsClicked()) {
488  // Readjust the moving selection end
490  ViewInfo::Get( *project ),
492  nullptr);
493  }
494 }
495 
497 {
498  return
499  (IsClicked() ? mSnapEnd : mSnapStart).snappedPoint;
500 }
501 
503 {
504  return HasSnap() && mUseSnap;
505 }
506 
508 {
509  if (SelectHandle::HasEscape()) {
510  SetUseSnap(false, project);
511  return true;
512  }
513  return false;
514 }
515 
517 (const TrackPanelMouseEvent &evt, AudacityProject *pProject)
518 {
521 
522  using namespace RefreshCode;
523 
524  const auto pView = mpView.lock();
525  if ( !pView )
526  return Cancelled;
527 
528  wxMouseEvent &event = evt.event;
529  const auto sTrack = TrackList::Get( *pProject ).Lock( FindTrack() );
530  const auto pTrack = sTrack.get();
531  auto &trackPanel = TrackPanel::Get( *pProject );
532  auto &viewInfo = ViewInfo::Get( *pProject );
533 
534  mMostRecentX = event.m_x;
535  mMostRecentY = event.m_y;
536 
537  bool selectChange = (
538  event.LeftDown() &&
539  event.ControlDown() &&
540  pTrack->TypeSwitch<bool>( [&](LabelTrack *){
541  // We should reach this, only in default of other hits on glyphs or
542  // text boxes.
543  bool bShift = event.ShiftDown();
544  bool unsafe = ProjectAudioIO::Get( *pProject ).IsAudioActive();
546  *pProject, pTrack, bShift, true, !unsafe);
547  return true;
548  } )
549  );
550  if ( selectChange )
551  // Do not start a drag
552  return RefreshAll | Cancelled;
553 
554  auto &selectionState = SelectionState::Get( *pProject );
555  const auto &settings = ProjectSettings::Get( *pProject );
556  if (event.LeftDClick() && !event.ShiftDown()) {
557  auto &trackList = TrackList::Get( *pProject );
558 
559  // Deselect all other tracks and select this one.
560  selectionState.SelectNone( trackList );
561 
562  selectionState.SelectTrack( *pTrack, true, true );
563 
564  // Default behavior: select whole track
566  ( viewInfo, *pTrack, settings.IsSyncLocked() );
567 
568  // Special case: if we're over a clip in a WaveTrack,
569  // select just that clip
570  pTrack->TypeSwitch( [&] ( WaveTrack *wt ) {
571  auto time = viewInfo.PositionToTime(event.m_x, mRect.x);
572  WaveClip *const selectedClip = wt->GetClipAtTime(time);
573  if (selectedClip) {
574  viewInfo.selectedRegion.setTimes(
575  selectedClip->GetOffset(), selectedClip->GetEndTime());
576  }
577  } );
578 
579  ProjectHistory::Get( *pProject ).ModifyState(false);
580 
581  // Do not start a drag
582  return RefreshAll | Cancelled;
583  }
584  else if (!event.LeftDown())
585  return Cancelled;
586 
587  mInitialSelection = viewInfo.selectedRegion;
588 
589  auto &trackList = TrackList::Get( *pProject );
591  std::make_shared< SelectionStateChanger >( selectionState, trackList );
592 
593  mSelectionBoundary = 0;
594 
595  bool bShiftDown = event.ShiftDown();
596  bool bCtrlDown = event.ControlDown();
597 
599  auto xx = viewInfo.TimeToPosition(mSelStart, mRect.x);
600 
601  // I. Shift-click adjusts an existing selection
602  if (bShiftDown || bCtrlDown) {
603  if (bShiftDown)
604  selectionState.ChangeSelectionOnShiftClick( trackList, *pTrack );
605  if( bCtrlDown ){
606  //Commented out bIsSelected toggles, as in Track Control Panel.
607  //bool bIsSelected = pTrack->GetSelected();
608  //Actual bIsSelected will always add.
609  bool bIsSelected = false;
610  // Don't toggle away the last selected track.
611  if( !bIsSelected || trackPanel.GetSelectedTrackCount() > 1 )
612  selectionState.SelectTrack( *pTrack, !bIsSelected, true );
613  }
614 
615  double value;
616  // Shift-click, choose closest boundary
617  SelectionBoundary boundary =
618  ChooseBoundary(viewInfo, xx, event.m_y,
619  pView.get(), mRect, false, false, &value);
620  mSelectionBoundary = boundary;
621  switch (boundary) {
622  case SBLeft:
623  case SBRight:
624  {
625 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
626  // If drag starts, change time selection only
627  // (also exit frequency snapping)
628  mFreqSelMode = FREQ_SEL_INVALID;
629 #endif
630  mSelStartValid = true;
631  mSelStart = value;
633  AdjustSelection(pProject, viewInfo, event.m_x, mRect.x, pTrack);
634  break;
635  }
636 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
637  case SBBottom:
638  case SBTop:
639  {
640  mFreqSelTrack = pTrack->SharedPointer<const WaveTrack>();
641  mFreqSelPin = value;
642  mFreqSelMode =
643  (boundary == SBBottom)
645 
646  // Drag frequency only, not time:
647  mSelStartValid = false;
649  static_cast<WaveTrack*>(pTrack),
650  viewInfo, event.m_y, mRect.y, mRect.height);
651  break;
652  }
653  case SBCenter:
654  {
655  const auto wt = static_cast<const WaveTrack*>(pTrack);
656  HandleCenterFrequencyClick(viewInfo, true, wt, value);
657  break;
658  }
659 #endif
660  default:
661  wxASSERT(false);
662  };
663 
664  // For persistence of the selection change:
665  ProjectHistory::Get( *pProject ).ModifyState(false);
666 
667  // Get timer events so we can auto-scroll
668  Connect(pProject);
669 
670  // Full refresh since the label area may need to indicate
671  // newly selected tracks.
672  return RefreshAll;
673  }
674 
675  // II. Unmodified click starts a NEW selection
676 
677  //Make sure you are within the selected track
678  bool startNewSelection = true;
679  if (pTrack && pTrack->GetSelected()) {
680  // Adjusting selection edges can be turned off in the
681  // preferences now
682  if (viewInfo.bAdjustSelectionEdges) {
683 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
684  if (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER &&
685  isSpectralSelectionView(pView.get())) {
686  // This code is no longer reachable, but it had a place in the
687  // spectral selection prototype. It used to be that you could be
688  // in a center-frequency-snapping mode that was not a mouse drag
689  // but responded to mouse movements. Click exited that and dragged
690  // width instead. PRL.
691 
692  // Ignore whether we are inside the time selection.
693  // Exit center-snapping, start dragging the width.
694  mFreqSelMode = FREQ_SEL_PINNED_CENTER;
695  mFreqSelTrack = pTrack->SharedPointer<const WaveTrack>();
696  mFreqSelPin = viewInfo.selectedRegion.fc();
697  // Do not adjust time boundaries
698  mSelStartValid = false;
700  static_cast<WaveTrack*>(pTrack),
701  viewInfo, event.m_y, mRect.y, mRect.height);
702  // For persistence of the selection change:
703  ProjectHistory::Get( *pProject ).ModifyState(false);
704  mSelectionBoundary = SBWidth;
705  return RefreshNone;
706  }
707  else
708 #endif
709  {
710  // Not shift-down, choose boundary only within snapping
711  double value;
712  SelectionBoundary boundary =
713  ChooseBoundary(viewInfo, xx, event.m_y,
714  pView.get(), mRect, true, true, &value);
715  mSelectionBoundary = boundary;
716  switch (boundary) {
717  case SBNone:
718  // startNewSelection remains true
719  break;
720  case SBLeft:
721  case SBRight:
722  startNewSelection = false;
723 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
724  // Disable frequency selection
725  mFreqSelMode = FREQ_SEL_INVALID;
726 #endif
727  mSelStartValid = true;
728  mSelStart = value;
730  break;
731 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
732  case SBBottom:
733  case SBTop:
734  case SBWidth:
735  startNewSelection = false;
736  // Disable time selection
737  mSelStartValid = false;
738  mFreqSelTrack = pTrack->SharedPointer<const WaveTrack>();
739  mFreqSelPin = value;
740  mFreqSelMode =
741  (boundary == SBWidth) ? FREQ_SEL_PINNED_CENTER :
742  (boundary == SBBottom) ? FREQ_SEL_BOTTOM_FREE :
744  break;
745  case SBCenter:
746  {
747  const auto wt = static_cast<const WaveTrack*>(pTrack);
748  HandleCenterFrequencyClick(viewInfo, false, wt, value);
749  startNewSelection = false;
750  break;
751  }
752 #endif
753  default:
754  wxASSERT(false);
755  }
756  }
757  } // bAdjustSelectionEdges
758  }
759 
760  // III. Common case for starting a NEW selection
761 
762  if (startNewSelection) {
763  // If we didn't move a selection boundary, start a NEW selection
764  selectionState.SelectNone( trackList );
765 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
766  StartFreqSelection (viewInfo, event.m_y, mRect.y, mRect.height,
767  pView.get());
768 #endif
769  StartSelection(pProject);
770  selectionState.SelectTrack( *pTrack, true, true );
771  TrackFocus::Get( *pProject ).Set(pTrack);
772 
773  Connect(pProject);
774  return RefreshAll;
775  }
776  else {
777  Connect(pProject);
778  return RefreshAll;
779  }
780 }
781 
783 (const TrackPanelMouseEvent &evt, AudacityProject *pProject)
784 {
785  using namespace RefreshCode;
786 
787  const auto pView = mpView.lock();
788  if ( !pView )
789  return Cancelled;
790 
791  auto &viewInfo = ViewInfo::Get( *pProject );
792  const wxMouseEvent &event = evt.event;
793 
794  int x = mAutoScrolling ? mMostRecentX : event.m_x;
795  int y = mAutoScrolling ? mMostRecentY : event.m_y;
796  mMostRecentX = x;
797  mMostRecentY = y;
798 
802 
803  // Fuhggeddaboudit if we're not dragging and not autoscrolling.
804  if (!event.Dragging() && !mAutoScrolling)
805  return RefreshNone;
806 
807  if (event.CmdDown()) {
808  // Ctrl-drag has no meaning, fuhggeddaboudit
809  // JKC YES it has meaning.
810  //return RefreshNone;
811  }
812 
813  // Also fuhggeddaboudit if not in a track.
814  auto pTrack = TrackList::Get( *pProject ).Lock( FindTrack() );
815  if (!pTrack)
816  return RefreshNone;
817 
818  // JKC: Logic to prevent a selection smaller than 5 pixels to
819  // prevent accidental dragging when selecting.
820  // (if user really wants a tiny selection, they should zoom in).
821  // Can someone make this value of '5' configurable in
822  // preferences?
823  enum { minimumSizedSelection = 5 }; //measured in pixels
824 
825  // Might be dragging frequency bounds only, test
826  if (mSelStartValid) {
827  wxInt64 SelStart = viewInfo.TimeToPosition(mSelStart, mRect.x); //cvt time to pixels.
828  // Abandon this drag if selecting < 5 pixels.
829  if (wxLongLong(SelStart - x).Abs() < minimumSizedSelection)
830  return RefreshNone;
831  }
832 
833  if (evt.pCell) {
834  if ( auto clickedTrack =
835  static_cast<CommonTrackPanelCell*>(evt.pCell.get())->FindTrack() ) {
836  // Handle which tracks are selected
837  Track *sTrack = pTrack.get();
838  Track *eTrack = clickedTrack.get();
839  auto &trackList = TrackList::Get( *pProject );
840  if ( sTrack && eTrack && !event.ControlDown() ) {
841  auto &selectionState = SelectionState::Get( *pProject );
842  selectionState.SelectRangeOfTracks( trackList, *sTrack, *eTrack );
843  }
844 
845  #ifdef EXPERIMENTAL_SPECTRAL_EDITING
846  #ifndef SPECTRAL_EDITING_ESC_KEY
847  if (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER &&
848  !viewInfo.selectedRegion.isPoint())
850  (pProject, viewInfo, y, mRect.y, mRect.height, pView.get());
851  else
852  #endif
853  if ( TrackList::Get( *pProject ).Lock(mFreqSelTrack) == pTrack )
855  static_cast<WaveTrack*>(pTrack.get()),
856  viewInfo, y, mRect.y, mRect.height);
857  #endif
858 
859  AdjustSelection(pProject, viewInfo, x, mRect.x, clickedTrack.get());
860  }
861  }
862 
863  return RefreshNone
864 
865  // If scrubbing does not use the helper poller thread, then
866  // don't refresh at every mouse event, because it slows down seek-scrub.
867  // Instead, let OnTimer do it, which is often enough.
868  // And even if scrubbing does use the thread, then skipping refresh does not
869  // bring that advantage, but it is probably still a good idea anyway.
870 
871  // | UpdateSelection
872 
873  ;
874 }
875 
877 (const TrackPanelMouseState &st, AudacityProject *pProject)
878 {
879  if (!HasSnap() && !mUseSnap)
880  // Moved out of snapping; revert to un-escaped state
881  mUseSnap = true;
882 
883  const auto pView = mpView.lock();
884  if ( !pView )
885  return {};
886 
887  auto pTrack = FindTrack().lock();
888  if (!pTrack)
889  return {};
890 
891  TranslatableString tip;
892  wxCursor *pCursor = SelectCursor();
893  if ( IsClicked() )
894  // Use same cursor as at the click
897  (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER),
898  tip, pCursor);
899  else {
900  // Choose one of many cursors for mouse-over
901 
902  auto &viewInfo = ViewInfo::Get( *pProject );
903 
904  auto &state = st.state;
906  auto xx = viewInfo.TimeToPosition(time, mRect.x);
907 
908  const bool bMultiToolMode =
910 
911  //In Multi-tool mode, give multitool prompt if no-special-hit.
912  if (bMultiToolMode) {
913  // Look up the current key binding for Preferences.
914  // (Don't assume it's the default!)
915  auto keyStr =
916  CommandManager::Get( *pProject ).GetKeyFromName(wxT("Preferences"))
917  .Display( true );
918  if (keyStr.empty())
919  // No keyboard preference defined for opening Preferences dialog
920  /* i18n-hint: These are the names of a menu and a command in that menu */
921  keyStr = _("Edit, Preferences...");
922 
923  /* i18n-hint: %s is usually replaced by "Ctrl+P" for Windows/Linux, "Command+," for Mac */
924  tip = XO("Multi-Tool Mode: %s for Mouse and Keyboard Preferences.")
925  .Format( keyStr );
926  // Later in this function we may point to some other string instead.
927  if (!pTrack->GetSelected() ||
928  !viewInfo.bAdjustSelectionEdges)
929  ;
930  else {
931  const wxRect &rect = st.rect;
932  const bool bShiftDown = state.ShiftDown();
933  const bool bCtrlDown = state.ControlDown();
934  const bool bModifierDown = bShiftDown || bCtrlDown;
935 
936  // If not shift-down and not snapping center, then
937  // choose boundaries only in snapping tolerance,
938  // and may choose center.
939  SelectionBoundary boundary =
940  ChooseBoundary(viewInfo, xx, state.m_y,
941  pView.get(), rect, !bModifierDown, !bModifierDown);
942 
943  SetTipAndCursorForBoundary(boundary, !bShiftDown, tip, pCursor);
944  }
945  }
946 
947 #if 0
948  // This is a vestige of an idea in the prototype version.
949  // Center would snap without mouse button down, click would pin the center
950  // and drag width.
951 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
952  if ((mFreqSelMode == FREQ_SEL_SNAPPING_CENTER) &&
953  isSpectralSelectionView(pView)) {
954  // Not shift-down, but center frequency snapping toggle is on
955  tip = XO("Click and drag to set frequency bandwidth.");
956  pCursor = &*envelopeCursor;
957  return {};
958  }
959 #endif
960 #endif
961 
962  if (!pTrack->GetSelected() || !viewInfo.bAdjustSelectionEdges)
963  ;
964  else {
965  const wxRect &rect = st.rect;
966  const bool bShiftDown = state.ShiftDown();
967  const bool bCtrlDown = state.ControlDown();
968  const bool bModifierDown = bShiftDown || bCtrlDown;
970  viewInfo, xx, state.m_y,
971  pView.get(), rect, !bModifierDown, !bModifierDown);
972  SetTipAndCursorForBoundary(boundary, !bShiftDown, tip, pCursor);
973  }
974  }
975  if (tip.empty()) {
976  tip = XO("Click and drag to select audio");
977  }
978  if (HasEscape() && mUseSnap) {
979  tip.Join(
980 /* i18n-hint: "Snapping" means automatic alignment of selection edges to any nearby label or clip boundaries */
981  XO("(snapping)"), wxT(" ")
982  );
983  }
984  return { tip, pCursor };
985 }
986 
988 (const TrackPanelMouseEvent &, AudacityProject *pProject,
989  wxWindow *)
990 {
991  using namespace RefreshCode;
992  ProjectHistory::Get( *pProject ).ModifyState(false);
993  mFrequencySnapper.reset();
994  mSnapManager.reset();
996  mSelectionStateChanger->Commit();
997  mSelectionStateChanger.reset();
998  }
999 
1000  if (mUseSnap && (mSnapStart.outCoord != -1 || mSnapEnd.outCoord != -1))
1001  return RefreshAll;
1002  else
1003  return RefreshNone;
1004 }
1005 
1007 {
1008  mSelectionStateChanger.reset();
1010 
1011  return RefreshCode::RefreshAll;
1012 }
1013 
1015  TrackPanelDrawingContext &context,
1016  const wxRect &rect, unsigned iPass )
1017 {
1018  if ( iPass == TrackArtist::PassSnapping ) {
1019  auto &dc = context.dc;
1020  // Draw snap guidelines if we have any
1021  if ( mSnapManager ) {
1022  auto coord1 = (mUseSnap || IsClicked()) ? mSnapStart.outCoord : -1;
1023  auto coord2 = (!mUseSnap || !IsClicked()) ? -1 : mSnapEnd.outCoord;
1024  mSnapManager->Draw( &dc, coord1, coord2 );
1025  }
1026  }
1027 }
1028 
1031  const wxRect &rect, const wxRect &panelRect, unsigned iPass )
1032 {
1033  if ( iPass == TrackArtist::PassSnapping )
1034  return MaximizeHeight( rect, panelRect );
1035  else
1036  return rect;
1037 }
1038 
1039 std::weak_ptr<Track> SelectHandle::FindTrack()
1040 {
1041  auto pView = mpView.lock();
1042  if (!pView)
1043  return {};
1044  else
1045  return pView->FindTrack();
1046 }
1047 
1049 {
1050  mTimerHandler = std::make_shared<TimerHandler>( this, pProject );
1051 }
1052 
1053 class SelectHandle::TimerHandler : public wxEvtHandler
1054 {
1055 public:
1057  : mParent{ pParent }
1058  , mConnectedProject{ pProject }
1059  {
1060  if (mConnectedProject)
1061  mConnectedProject->Bind(EVT_TRACK_PANEL_TIMER,
1063  this);
1064  }
1065 
1066  // Receives timer event notifications, to implement auto-scroll
1067  void OnTimer(wxCommandEvent &event);
1068 
1069 private:
1072 };
1073 
1074 void SelectHandle::TimerHandler::OnTimer(wxCommandEvent &event)
1075 {
1076  event.Skip();
1077 
1078  // AS: If the user is dragging the mouse and there is a track that
1079  // has captured the mouse, then scroll the screen, as necessary.
1080 
1082 
1083  // DM: If we're "autoscrolling" (which means that we're scrolling
1084  // because the user dragged from inside to outside the window,
1085  // not because the user clicked in the scroll bar), then
1086  // the selection code needs to be handled slightly differently.
1087  // We set this flag ("mAutoScrolling") to tell the selecting
1088  // code that we didn't get here as a result of a mouse event,
1089  // and therefore it should ignore the event,
1090  // and instead use the last known mouse position. Setting
1091  // this flag also causes the Mac to redraw immediately rather
1092  // than waiting for the next update event; this makes scrolling
1093  // smoother on MacOS 9.
1094 
1095  const auto project = mConnectedProject;
1096  const auto &trackPanel = TrackPanel::Get( *project );
1097  auto &window = ProjectWindow::Get( *project );
1098  if (mParent->mMostRecentX >= mParent->mRect.x + mParent->mRect.width) {
1099  mParent->mAutoScrolling = true;
1100  window.TP_ScrollRight();
1101  }
1102  else if (mParent->mMostRecentX < mParent->mRect.x) {
1103  mParent->mAutoScrolling = true;
1104  window.TP_ScrollLeft();
1105  }
1106  else {
1107  // Bug1387: enable autoscroll during drag, if the pointer is at either
1108  // extreme x coordinate of the screen, even if that is still within the
1109  // track area.
1110 
1111  int xx = mParent->mMostRecentX, yy = 0;
1112  trackPanel.ClientToScreen(&xx, &yy);
1113  if (xx == 0) {
1114  mParent->mAutoScrolling = true;
1115  window.TP_ScrollLeft();
1116  }
1117  else {
1118  int width, height;
1119  ::wxDisplaySize(&width, &height);
1120  if (xx == width - 1) {
1121  mParent->mAutoScrolling = true;
1122  window.TP_ScrollRight();
1123  }
1124  }
1125  }
1126 
1127  auto pTrack = mParent->FindTrack().lock(); // TrackList::Lock() ?
1128  if (mParent->mAutoScrolling && pTrack) {
1129  // AS: To keep the selection working properly as we scroll,
1130  // we fake a mouse event (remember, this method is called
1131  // from a timer tick).
1132 
1133  // AS: For some reason, GCC won't let us pass this directly.
1134  wxMouseEvent evt(wxEVT_MOTION);
1135  const auto size = trackPanel.GetSize();
1136  mParent->Drag(
1138  evt, mParent->mRect, size,
1139  TrackView::Get( *pTrack ).shared_from_this() },
1140  project
1141  );
1142  mParent->mAutoScrolling = false;
1143  TrackPanel::Get( *mConnectedProject ).Refresh(false);
1144  }
1145 }
1146 
1149 {
1150  auto &viewInfo = ViewInfo::Get( *pProject );
1151  mSelStartValid = true;
1152 
1153  viewInfo.selectedRegion.setTimes(mSelStart, mSelStart);
1154 
1155  // PRL: commented out the Sonify stuff with the TrackPanel refactor.
1156  // It was no-op anyway.
1157  //SonifyBeginModifyState();
1158  ProjectHistory::Get( *pProject ).ModifyState(false);
1159  //SonifyEndModifyState();
1160 }
1161 
1164 (AudacityProject *pProject,
1165  ViewInfo &viewInfo, int mouseXCoordinate, int trackLeftEdge,
1166  Track *track)
1167 {
1168  if (!mSelStartValid)
1169  // Must be dragging frequency bounds only.
1170  return;
1171 
1172  double selend =
1173  std::max(0.0, viewInfo.PositionToTime(mouseXCoordinate, trackLeftEdge));
1174  double origSelend = selend;
1175 
1176  auto pTrack = Track::SharedPointer( track );
1177  if (!pTrack)
1178  pTrack = TrackList::Get( *pProject ).Lock( FindTrack() );
1179 
1180  if (pTrack && mSnapManager.get()) {
1181  bool rightEdge = (selend > mSelStart);
1182  mSnapEnd = mSnapManager->Snap(pTrack.get(), selend, rightEdge);
1183  if (mSnapEnd.Snapped()) {
1184  if (mUseSnap)
1185  selend = mSnapEnd.outTime;
1186  if (mSnapEnd.snappedPoint)
1187  mSnapEnd.outCoord += trackLeftEdge;
1188  }
1189  if (!mSnapEnd.snappedPoint)
1190  mSnapEnd.outCoord = -1;
1191 
1192  // Check if selection endpoints are too close together to snap (unless
1193  // using snap-to-time -- then we always accept the snap results)
1194  if (mSnapStart.outCoord >= 0 &&
1195  mSnapEnd.outCoord >= 0 &&
1196  std::abs(mSnapStart.outCoord - mSnapEnd.outCoord) < 3) {
1197  if(!mSnapEnd.snappedTime)
1198  selend = origSelend;
1199  mSnapEnd.outCoord = -1;
1200  }
1201  }
1202  AssignSelection(viewInfo, selend, pTrack.get());
1203 }
1204 
1206 (ViewInfo &viewInfo, double selend, Track *pTrack)
1207 {
1208  double sel0, sel1;
1209  if (mSelStart < selend) {
1210  sel0 = mSelStart;
1211  sel1 = selend;
1212  }
1213  else {
1214  sel1 = mSelStart;
1215  sel0 = selend;
1216  }
1217 
1218  viewInfo.selectedRegion.setTimes(sel0, sel1);
1219 }
1220 
1222  int mouseYCoordinate, int trackTopEdge,
1223  int trackHeight, TrackView *pTrackView)
1224 {
1225  mFreqSelTrack.reset();
1226  mFreqSelMode = FREQ_SEL_INVALID;
1228 
1229  if (isSpectralSelectionView(pTrackView)) {
1230  // Spectral selection track is always wave
1231  auto shTrack = pTrackView->FindTrack()->SharedPointer<const WaveTrack>();
1232  mFreqSelTrack = shTrack;
1233  mFreqSelMode = FREQ_SEL_FREE;
1234  mFreqSelPin =
1235  PositionToFrequency(shTrack.get(), false, mouseYCoordinate,
1236  trackTopEdge, trackHeight);
1238  }
1239 }
1240 
1242  const WaveTrack *wt, ViewInfo &viewInfo,
1243  int mouseYCoordinate, int trackTopEdge,
1244  int trackHeight)
1245 {
1246  if (mFreqSelMode == FREQ_SEL_INVALID ||
1247  mFreqSelMode == FREQ_SEL_SNAPPING_CENTER)
1248  return;
1249 
1250  // Extension happens only when dragging in the same track in which we
1251  // started, and that is of a spectrogram display type.
1252 
1253  const double rate = wt->GetRate();
1254  const double frequency =
1255  PositionToFrequency(wt, true, mouseYCoordinate,
1256  trackTopEdge, trackHeight);
1257 
1258  // Dragging center?
1259  if (mFreqSelMode == FREQ_SEL_DRAG_CENTER) {
1260  if (frequency == rate || frequency < 1.0)
1261  // snapped to top or bottom
1262  viewInfo.selectedRegion.setFrequencies(
1265  else {
1266  // mFreqSelPin holds the ratio of top to center
1267  const double maxRatio = findMaxRatio(frequency, rate);
1268  const double ratio = std::min(maxRatio, mFreqSelPin);
1269  viewInfo.selectedRegion.setFrequencies(
1270  frequency / ratio, frequency * ratio);
1271  }
1272  }
1273  else if (mFreqSelMode == FREQ_SEL_PINNED_CENTER) {
1274  if (mFreqSelPin >= 0) {
1275  // Change both upper and lower edges leaving centre where it is.
1276  if (frequency == rate || frequency < 1.0)
1277  // snapped to top or bottom
1278  viewInfo.selectedRegion.setFrequencies(
1281  else {
1282  // Given center and mouse position, find ratio of the larger to the
1283  // smaller, limit that to the frequency scale bounds, and adjust
1284  // top and bottom accordingly.
1285  const double maxRatio = findMaxRatio(mFreqSelPin, rate);
1286  double ratio = frequency / mFreqSelPin;
1287  if (ratio < 1.0)
1288  ratio = 1.0 / ratio;
1289  ratio = std::min(maxRatio, ratio);
1290  viewInfo.selectedRegion.setFrequencies(
1291  mFreqSelPin / ratio, mFreqSelPin * ratio);
1292  }
1293  }
1294  }
1295  else {
1296  // Dragging of upper or lower.
1297  const bool bottomDefined =
1298  !(mFreqSelMode == FREQ_SEL_TOP_FREE && mFreqSelPin < 0);
1299  const bool topDefined =
1300  !(mFreqSelMode == FREQ_SEL_BOTTOM_FREE && mFreqSelPin < 0);
1301  if (!bottomDefined || (topDefined && mFreqSelPin < frequency)) {
1302  // Adjust top
1303  if (frequency == rate)
1304  // snapped high; upper frequency is undefined
1306  else
1307  viewInfo.selectedRegion.setF1(std::max(1.0, frequency));
1308 
1309  viewInfo.selectedRegion.setF0(mFreqSelPin);
1310  }
1311  else {
1312  // Adjust bottom
1313  if (frequency < 1.0)
1314  // snapped low; lower frequency is undefined
1316  else
1317  viewInfo.selectedRegion.setF0(std::min(rate / 2.0, frequency));
1318 
1319  viewInfo.selectedRegion.setF1(mFreqSelPin);
1320  }
1321  }
1322 }
1323 
1325 (const ViewInfo &viewInfo, bool shiftDown, const WaveTrack *pTrack, double value)
1326 {
1327  if (shiftDown) {
1328  // Disable time selection
1329  mSelStartValid = false;
1330  mFreqSelTrack = pTrack->SharedPointer<const WaveTrack>();
1331  mFreqSelPin = value;
1332  mFreqSelMode = FREQ_SEL_DRAG_CENTER;
1333  }
1334  else {
1335 #ifndef SPECTRAL_EDITING_ESC_KEY
1336  // Start center snapping
1337  // Turn center snapping on (the only way to do this)
1338  mFreqSelMode = FREQ_SEL_SNAPPING_CENTER;
1339  // Disable time selection
1340  mSelStartValid = false;
1341  mFrequencySnapper = std::make_shared<SpectrumAnalyst>();
1342  StartSnappingFreqSelection(*mFrequencySnapper, viewInfo, pTrack);
1343 #endif
1344  }
1345 }
1346 
1348  (SpectrumAnalyst &analyst,
1349  const ViewInfo &viewInfo, const WaveTrack *pTrack)
1350 {
1351  static const size_t minLength = 8;
1352 
1353  const double rate = pTrack->GetRate();
1354 
1355  // Grab samples, just for this track, at these times
1356  std::vector<float> frequencySnappingData;
1357  const auto start =
1358  pTrack->TimeToLongSamples(viewInfo.selectedRegion.t0());
1359  const auto end =
1360  pTrack->TimeToLongSamples(viewInfo.selectedRegion.t1());
1361  const auto length =
1362  std::min(frequencySnappingData.max_size(),
1363  limitSampleBufferSize(10485760, // as in FreqWindow.cpp
1364  end - start));
1365  const auto effectiveLength = std::max(minLength, length);
1366  frequencySnappingData.resize(effectiveLength, 0.0f);
1367  pTrack->GetFloats(
1368  &frequencySnappingData[0],
1369  start, length, fillZero,
1370  // Don't try to cope with exceptions, just read zeroes instead.
1371  false);
1372 
1373  // Use same settings as are now used for spectrogram display,
1374  // except, shrink the window as needed so we get some answers
1375 
1377  auto windowSize = settings.GetFFTLength();
1378 
1379  while(windowSize > effectiveLength)
1380  windowSize >>= 1;
1381  const int windowType = settings.windowType;
1382 
1383  analyst.Calculate(
1384  SpectrumAnalyst::Spectrum, windowType, windowSize, rate,
1385  &frequencySnappingData[0], length);
1386 
1387  // We can now throw away the sample data but we keep the spectrum.
1388 }
1389 
1391  (AudacityProject *pProject, ViewInfo &viewInfo, int mouseYCoordinate,
1392  int trackTopEdge,
1393  int trackHeight, TrackView *pTrackView)
1394 {
1395  auto pTrack = pTrackView->FindTrack().get();
1396  if (pTrack &&
1397  pTrack->GetSelected() &&
1398  isSpectralSelectionView(pTrackView)) {
1399  // Spectral selection track is always wave
1400  WaveTrack *const wt = static_cast<WaveTrack*>(pTrack);
1401  // PRL:
1402  // What would happen if center snapping selection began in one spectrogram track,
1403  // then continues inside another? We do not then recalculate
1404  // the spectrum (as was done in StartSnappingFreqSelection)
1405  // but snap according to the peaks in the old track.
1406 
1407  // But if we always supply the original clicked track here that doesn't matter.
1408  const double rate = wt->GetRate();
1409  const double frequency =
1410  PositionToFrequency(wt, false, mouseYCoordinate,
1411  trackTopEdge, trackHeight);
1412  const double snappedFrequency =
1413  mFrequencySnapper->FindPeak(frequency, NULL);
1414  const double maxRatio = findMaxRatio(snappedFrequency, rate);
1415  double ratio = 2.0; // An arbitrary octave on each side, at most
1416  {
1417  const double f0 = viewInfo.selectedRegion.f0();
1418  const double f1 = viewInfo.selectedRegion.f1();
1419  if (f1 >= f0 && f0 >= 0)
1420  // Preserve already chosen ratio instead
1421  ratio = sqrt(f1 / f0);
1422  }
1423  ratio = std::min(ratio, maxRatio);
1424 
1425  mFreqSelPin = snappedFrequency;
1426  viewInfo.selectedRegion.setFrequencies(
1427  snappedFrequency / ratio, snappedFrequency * ratio);
1428 
1429  // A change here would affect what AdjustFreqSelection() does
1430  // in the prototype version where you switch from moving center to
1431  // dragging width with a click. No effect now.
1432  mFreqSelTrack = wt->SharedPointer<const WaveTrack>();
1433 
1434  // SelectNone();
1435  // SelectTrack(pTrack, true);
1436  TrackFocus::Get( *pProject ).Set(pTrack);
1437  }
1438 }
1439 
1441  (SpectrumAnalyst &analyst,
1442  ViewInfo &viewInfo, const WaveTrack *pTrack, bool up)
1443 {
1445  const auto windowSize = settings.GetFFTLength();
1446  const double rate = pTrack->GetRate();
1447  const double nyq = rate / 2.0;
1448  const double binFrequency = rate / windowSize;
1449 
1450  double f1 = viewInfo.selectedRegion.f1();
1451  double centerFrequency = viewInfo.selectedRegion.fc();
1452  if (centerFrequency <= 0) {
1453  centerFrequency = up ? binFrequency : nyq;
1454  f1 = centerFrequency * sqrt(2.0);
1455  }
1456 
1457  double ratio = f1 / centerFrequency;
1458  const int originalBin = floor(0.5 + centerFrequency / binFrequency);
1459  const int limitingBin = up ? floor(0.5 + nyq / binFrequency) : 1;
1460 
1461  // This is crude and wasteful, doing the FFT each time the command is called.
1462  // It would be better to cache the data, but then invalidation of the cache would
1463  // need doing in all places that change the time selection.
1464  StartSnappingFreqSelection(analyst, viewInfo, pTrack);
1465  double snappedFrequency = centerFrequency;
1466  int bin = originalBin;
1467  if (up) {
1468  while (snappedFrequency <= centerFrequency &&
1469  bin < limitingBin)
1470  snappedFrequency = analyst.FindPeak(++bin * binFrequency, NULL);
1471  }
1472  else {
1473  while (snappedFrequency >= centerFrequency &&
1474  bin > limitingBin)
1475  snappedFrequency = analyst.FindPeak(--bin * binFrequency, NULL);
1476  }
1477 
1478  // PRL: added these two lines with the big TrackPanel refactor
1479  const double maxRatio = findMaxRatio(snappedFrequency, rate);
1480  ratio = std::min(ratio, maxRatio);
1481 
1483  (snappedFrequency / ratio, snappedFrequency * ratio);
1484 }
1485 
1486 #if 0
1487 // unused
1488 void SelectHandle::ResetFreqSelectionPin
1489  (const ViewInfo &viewInfo, double hintFrequency, bool logF)
1490 {
1491  switch (mFreqSelMode) {
1492  case FREQ_SEL_INVALID:
1494  mFreqSelPin = -1.0;
1495  break;
1496 
1498  mFreqSelPin = viewInfo.selectedRegion.fc();
1499  break;
1500 
1501  case FREQ_SEL_DRAG_CENTER:
1502  {
1503  // Re-pin the width
1504  const double f0 = viewInfo.selectedRegion.f0();
1505  const double f1 = viewInfo.selectedRegion.f1();
1506  if (f0 >= 0 && f1 >= 0)
1507  mFreqSelPin = sqrt(f1 / f0);
1508  else
1509  mFreqSelPin = -1.0;
1510  }
1511  break;
1512 
1513  case FREQ_SEL_FREE:
1514  // Pin which? Farther from the hint which is the presumed
1515  // mouse position.
1516  {
1517  // If this function finds use again, the following should be
1518  // generalized using NumberScale
1519 
1520  const double f0 = viewInfo.selectedRegion.f0();
1521  const double f1 = viewInfo.selectedRegion.f1();
1522  if (logF) {
1523  if (f1 < 0)
1524  mFreqSelPin = f0;
1525  else {
1526  const double logf1 = log(std::max(1.0, f1));
1527  const double logf0 = log(std::max(1.0, f0));
1528  const double logHint = log(std::max(1.0, hintFrequency));
1529  if (std::abs(logHint - logf1) < std::abs(logHint - logf0))
1530  mFreqSelPin = f0;
1531  else
1532  mFreqSelPin = f1;
1533  }
1534  }
1535  else {
1536  if (f1 < 0 ||
1537  std::abs(hintFrequency - f1) < std::abs(hintFrequency - f0))
1538  mFreqSelPin = f0;
1539  else
1540  mFreqSelPin = f1;
1541  }
1542  }
1543  break;
1544 
1545  case FREQ_SEL_TOP_FREE:
1546  mFreqSelPin = viewInfo.selectedRegion.f0();
1547  break;
1548 
1549  case FREQ_SEL_BOTTOM_FREE:
1550  mFreqSelPin = viewInfo.selectedRegion.f1();
1551  break;
1552 
1553  default:
1554  wxASSERT(false);
1555  }
1556 }
1557 #endif
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:156
SelectHandle::StartSelection
void StartSelection(AudacityProject *pProject)
Reset our selection markers.
Definition: SelectHandle.cpp:1148
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:1070
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:1074
RefreshCode::RefreshAll
@ RefreshAll
Definition: RefreshCode.h:26
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:1048
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:1524
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:121
CommonTrackPanelCell::FindTrack
std::shared_ptr< Track > FindTrack()
Definition: CommonTrackPanelCell.h:44
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:1264
TrackArtist::PassSnapping
@ PassSnapping
Definition: TrackArtist.h:82
MakeCursor
std::unique_ptr< wxCursor > MakeCursor(int WXUNUSED(CursorId), const char *const pXpm[36], int HotX, int HotY)
Definition: TrackPanel.cpp:176
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:173
SelectHandle::~SelectHandle
virtual ~SelectHandle()
Definition: SelectHandle.cpp:450
Track::SharedPointer
std::shared_ptr< Subclass > SharedPointer()
Definition: Track.h:280
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:221
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:131
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:40
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:533
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:1029
ProjectSettings::GetTool
int GetTool() const
Definition: ProjectSettings.h:92
SelectHandle::FindTrack
std::weak_ptr< Track > FindTrack()
Definition: SelectHandle.cpp:1039
ProjectAudioIO::Get
static ProjectAudioIO & Get(AudacityProject &project)
Definition: ProjectAudioIO.cpp:23
WaveTrack::GetSpectrogramSettings
const SpectrogramSettings & GetSpectrogramSettings() const
Definition: WaveTrack.cpp:663
SelectHandle::mInitialSelection
SelectedRegion mInitialSelection
Definition: SelectHandle.h:133
SelectHandle::StartSnappingFreqSelection
static void StartSnappingFreqSelection(SpectrumAnalyst &analyst, const ViewInfo &viewInfo, const WaveTrack *pTrack)
Definition: SelectHandle.cpp:1348
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:53
SnapResults::outTime
double outTime
Definition: Snap.h:47
ProjectAudioIO::IsAudioActive
bool IsAudioActive() const
Definition: ProjectAudioIO.cpp:52
SelectHandle::StartFreqSelection
void StartFreqSelection(ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge, int trackHeight, TrackView *pTrackView)
Definition: SelectHandle.cpp:1221
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:46
SelectHandle::SnapCenterOnce
static void SnapCenterOnce(SpectrumAnalyst &analyst, ViewInfo &viewInfo, const WaveTrack *pTrack, bool up)
Definition: SelectHandle.cpp:1441
SelectHandle::SetUseSnap
void SetUseSnap(bool use, AudacityProject *pProject)
Definition: SelectHandle.cpp:478
SelectHandle::AdjustSelection
void AdjustSelection(AudacityProject *pProject, ViewInfo &viewInfo, int mouseXCoordinate, int trackLeftEdge, Track *pTrack)
Extend or contract the existing selection.
Definition: SelectHandle.cpp:1164
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:57
NumberScale::ValueToPosition
float ValueToPosition(float val) const
Definition: NumberScale.h:256
SelectHandle::Enter
void Enter(bool forward, AudacityProject *pProject) override
Definition: SelectHandle.cpp:473
WaveClip
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:173
SnapResults::timeSnappedTime
double timeSnappedTime
Definition: Snap.h:46
ViewInfo::selectedRegion
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:200
SelectHandle::TimerHandler::mConnectedProject
AudacityProject * mConnectedProject
Definition: SelectHandle.cpp:1071
UIHandle::mChangeHighlight
Result mChangeHighlight
Definition: UIHandle.h:133
ToolCodes::multiTool
@ multiTool
Definition: ProjectSettings.h:41
SelectHandle::AdjustFreqSelection
void AdjustFreqSelection(const WaveTrack *wt, ViewInfo &viewInfo, int mouseYCoordinate, int trackTopEdge, int trackHeight)
Definition: SelectHandle.cpp:1241
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:1454
WaveTrack::GetSpectrumBounds
void GetSpectrumBounds(float *min, float *max) const
Definition: WaveTrack.cpp:267
SelectHandle::AssignSelection
void AssignSelection(ViewInfo &viewInfo, double selend, Track *pTrack)
Definition: SelectHandle.cpp:1206
UIHandle::Result
unsigned Result
Definition: UIHandle.h:37
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:507
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:783
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:1391
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:461
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:2105
SelectHandle::HasSnap
bool HasSnap() const
Definition: SelectHandle.cpp:496
NotifyingSelectedRegion::f0
double f0() const
Definition: ViewInfo.h:47
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:1325
SelectHandle::Release
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
Definition: SelectHandle.cpp:988
SelectionState::Get
static SelectionState & Get(AudacityProject &project)
Definition: SelectionState.cpp:20
SelectHandle::TimerHandler
Definition: SelectHandle.cpp:1054
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
NotifyingSelectedRegion::f1
double f1() const
Definition: ViewInfo.h:48
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:1770
NumberScale::PositionToValue
float PositionToValue(float pp) const
Definition: NumberScale.h:155
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:495
SelectHandle::Click
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Definition: SelectHandle.cpp:517
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:780
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:113
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:49
TrackPanelMouseState
Definition: TrackPanelMouseEvent.h:28
SnapResults::snappedPoint
bool snappedPoint
Definition: Snap.h:49
SelectHandle::mSelStartValid
bool mSelStartValid
Definition: SelectHandle.h:139
NumberScale
Definition: NumberScale.h:32
SelectHandle::mSelStart
double mSelStart
Definition: SelectHandle.h:140
NotifyingSelectedRegion::isPoint
bool isPoint() const
Definition: ViewInfo.h:50
NotifyingSelectedRegion::t0
double t0() const
Definition: ViewInfo.h:45
AssignUIHandlePtr
std::shared_ptr< Subclass > AssignUIHandlePtr(std::weak_ptr< Subclass > &holder, const std::shared_ptr< Subclass > &pNew)
Definition: UIHandle.h:145
SelectUtilities::DoListSelection
void DoListSelection(AudacityProject &project, Track *t, bool shift, bool ctrl, bool modifyState)
Definition: SelectUtilities.cpp:112
CommonTrackPanelCell
Definition: CommonTrackPanelCell.h:26
SelectHandle::Cancel
Result Cancel(AudacityProject *) override
Definition: SelectHandle.cpp:1006
CommandManager::Get
static CommandManager & Get(AudacityProject &project)
Definition: CommandManager.cpp:203
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:111
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:21
SelectHandle::Draw
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
Definition: SelectHandle.cpp:1014
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:261
within
bool within(A a, B b, DIST d)
Definition: TrackPanel.cpp:157
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:502
SelectHandle::mFreqSelPin
double mFreqSelPin
Definition: SelectHandle.h:162
TrackPanelMouseEvent::event
wxMouseEvent & event
Definition: TrackPanelMouseEvent.h:58
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:877
ZoomInfo::PositionToTime
double PositionToTime(wxInt64 position, wxInt64 origin=0, bool ignoreFisheye=false) const
Definition: ZoomInfo.cpp:43
SelectHandle::TimerHandler::TimerHandler
TimerHandler(SelectHandle *pParent, AudacityProject *pProject)
Definition: SelectHandle.cpp:1056
SelectHandle.h
WaveTrack::GetRate
double GetRate() const
Definition: WaveTrack.cpp:358