Audacity  2.2.2
Public Member Functions | Static Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes | List of all members
TimeShiftHandle Class Referencefinal

#include <TimeShiftHandle.h>

Inheritance diagram for TimeShiftHandle:
UIHandle

Public Member Functions

 TimeShiftHandle (const std::shared_ptr< Track > &pTrack, bool gripHit)
 
TimeShiftHandleoperator= (const TimeShiftHandle &)=default
 
bool IsGripHit () const
 
std::shared_ptr< TrackGetTrack () const
 
virtual ~TimeShiftHandle ()
 
void Enter (bool forward) override
 
Result Click (const TrackPanelMouseEvent &event, AudacityProject *pProject) override
 
Result Drag (const TrackPanelMouseEvent &event, AudacityProject *pProject) override
 
HitTestPreview Preview (const TrackPanelMouseState &state, const AudacityProject *pProject) override
 
Result Release (const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
 
Result Cancel (AudacityProject *pProject) override
 
void DrawExtras (DrawingPass pass, wxDC *dc, const wxRegion &, const wxRect &panelRect) override
 
bool StopsOnKeystroke () override
 
- Public Member Functions inherited from UIHandle
virtual ~UIHandle ()=0
 
virtual bool HasRotation () const
 
virtual bool Rotate (bool forward)
 
virtual bool HasEscape () const
 
virtual bool Escape ()
 
virtual void OnProjectChange (AudacityProject *pProject)
 
Result GetChangeHighlight () const
 
void SetChangeHighlight (Result val)
 

Static Public Member Functions

static void CreateListOfCapturedClips (ClipMoveState &state, const ViewInfo &viewInfo, Track &capturedTrack, TrackList &trackList, bool syncLocked, double clickTime)
 
static void DoSlideHorizontal (ClipMoveState &state, TrackList &trackList, Track &capturedTrack)
 
static UIHandlePtr HitAnywhere (std::weak_ptr< TimeShiftHandle > &holder, const std::shared_ptr< Track > &pTrack, bool gripHit)
 
static UIHandlePtr HitTest (std::weak_ptr< TimeShiftHandle > &holder, const wxMouseState &state, const wxRect &rect, const std::shared_ptr< Track > &pTrack)
 
- Static Public Member Functions inherited from UIHandle
static UIHandle::Result NeedChangeHighlight (const UIHandle &, const UIHandle &)
 

Private Member Functions

 TimeShiftHandle (const TimeShiftHandle &)=delete
 

Static Private Member Functions

static HitTestPreview HitPreview (const AudacityProject *pProject, bool unsafe)
 

Private Attributes

std::shared_ptr< TrackmCapturedTrack
 
wxRect mRect {}
 
bool mDidSlideVertically {}
 
bool mSlideUpDownOnly {}
 
bool mSnapPreferRightEdge {}
 
int mMouseClickX {}
 
std::shared_ptr< SnapManagermSnapManager {}
 
ClipMoveState mClipMoveState {}
 
bool mGripHit {}
 

Additional Inherited Members

- Public Types inherited from UIHandle
enum  DrawingPass { Cells, Panel }
 
using Result = unsigned
 
using Cell = TrackPanelCell
 
- Protected Attributes inherited from UIHandle
Result mChangeHighlight { 0 }
 

Detailed Description

Definition at line 44 of file TimeShiftHandle.h.

Constructor & Destructor Documentation

TimeShiftHandle::TimeShiftHandle ( const TimeShiftHandle )
privatedelete
TimeShiftHandle::TimeShiftHandle ( const std::shared_ptr< Track > &  pTrack,
bool  gripHit 
)
explicit

Definition at line 27 of file TimeShiftHandle.cpp.

28  : mCapturedTrack{ pTrack }
29  , mGripHit{ gripHit }
30 {
31 }
std::shared_ptr< Track > mCapturedTrack
TimeShiftHandle::~TimeShiftHandle ( )
virtual

Definition at line 96 of file TimeShiftHandle.cpp.

97 {
98 }

Member Function Documentation

UIHandle::Result TimeShiftHandle::Cancel ( AudacityProject pProject)
overridevirtual

Implements UIHandle.

Definition at line 895 of file TimeShiftHandle.cpp.

References RefreshCode::RefreshAll, and AudacityProject::RollbackState().

896 {
897  pProject->RollbackState();
899 }
void RollbackState()
Definition: Project.cpp:4742
UIHandle::Result TimeShiftHandle::Click ( const TrackPanelMouseEvent event,
AudacityProject pProject 
)
overridevirtual

Implements UIHandle.

Definition at line 422 of file TimeShiftHandle.cpp.

References RefreshCode::Cancelled, TrackList::clear(), TrackPanelMouseEvent::event, WaveTrack::GetClipAtX(), WaveTrack::GetKind(), Track::GetSelected(), AudacityProject::GetToolsToolBar(), AudacityProject::GetTracks(), AudacityProject::GetViewInfo(), AudacityProject::IsAudioActive(), AudacityProject::IsSyncLocked(), multiTool, TrackPanelMouseEvent::pCell, ZoomInfo::PositionToTime(), TrackPanelMouseEvent::rect, RefreshCode::RefreshNone, ViewInfo::selectedRegion, SelectedRegion::t0(), SelectedRegion::t1(), and Track::Wave.

423 {
424  using namespace RefreshCode;
425  const bool unsafe = pProject->IsAudioActive();
426  if ( unsafe )
427  return Cancelled;
428 
429  const wxMouseEvent &event = evt.event;
430  const wxRect &rect = evt.rect;
431  const ViewInfo &viewInfo = pProject->GetViewInfo();
432 
433  const auto pTrack = std::static_pointer_cast<Track>(evt.pCell);
434 
435  TrackList *const trackList = pProject->GetTracks();
436 
438  mDidSlideVertically = false;
439 
440  ToolsToolBar *const ttb = pProject->GetToolsToolBar();
441  const bool multiToolModeActive = (ttb && ttb->IsDown(multiTool));
442 
443  const double clickTime =
444  viewInfo.PositionToTime(event.m_x, rect.x);
446  (pTrack->GetSelected() &&
447  clickTime >= viewInfo.selectedRegion.t0() &&
448  clickTime < viewInfo.selectedRegion.t1());
449 
450  WaveTrack *wt = pTrack->GetKind() == Track::Wave
451  ? static_cast<WaveTrack*>(pTrack.get()) : nullptr;
452 
453  if ((wt
454 #ifdef USE_MIDI
455  || pTrack->GetKind() == Track::Note
456 #endif
457  ) && !event.ShiftDown())
458  {
459 #ifdef USE_MIDI
460  if (!wt)
461  mClipMoveState.capturedClip = nullptr;
462  else
463 #endif
464  {
465  mClipMoveState.capturedClip = wt->GetClipAtX(event.m_x);
466  if (mClipMoveState.capturedClip == NULL)
467  return Cancelled;
468  }
469 
471  ( mClipMoveState, viewInfo, *pTrack, *trackList,
472  pProject->IsSyncLocked(), clickTime );
473  }
474  else {
475  // Shift was down, or track was not Wave or Note
478  }
479 
480  mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive;
481  mRect = rect;
482  mMouseClickX = event.m_x;
483  const double selStart = viewInfo.PositionToTime(event.m_x, mRect.x);
484  mSnapManager = std::make_shared<SnapManager>(trackList,
485  &viewInfo,
488  true); // don't snap to time
493  (fabs(selStart - mClipMoveState.capturedClip->GetEndTime()) <
494  fabs(selStart - mClipMoveState.capturedClip->GetStartTime()));
495 
496  return RefreshNone;
497 }
int GetKind() const override
Definition: WaveTrack.h:121
A list of TrackListNode items.
Definition: Track.h:619
ViewInfo is used mainly to hold the zooming, selection and scroll information. It also has some statu...
Definition: ViewInfo.h:141
double GetStartTime() const
Definition: WaveClip.cpp:421
bool capturedClipIsSelection
WaveClip * capturedClip
ToolsToolBar * GetToolsToolBar()
Definition: Project.cpp:5066
ClipMoveState mClipMoveState
std::shared_ptr< SnapManager > mSnapManager
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:102
TrackClipArray capturedClipArray
bool IsAudioActive() const
Definition: Project.cpp:1454
bool IsSyncLocked()
Definition: Project.cpp:5658
static void CreateListOfCapturedClips(ClipMoveState &state, const ViewInfo &viewInfo, Track &capturedTrack, TrackList &trackList, bool syncLocked, double clickTime)
A kind of ToolBar with Tools on it.
Definition: ToolsToolBar.h:49
double GetEndTime() const
Definition: WaveClip.cpp:427
TrackArray trackExclusions
TrackList * GetTracks()
Definition: Project.h:192
const ViewInfo & GetViewInfo() const
Definition: Project.h:207
void TimeShiftHandle::CreateListOfCapturedClips ( ClipMoveState state,
const ViewInfo viewInfo,
Track capturedTrack,
TrackList trackList,
bool  syncLocked,
double  clickTime 
)
static

Definition at line 266 of file TimeShiftHandle.cpp.

References ClipMoveState::capturedClip, ClipMoveState::capturedClipArray, ClipMoveState::capturedClipIsSelection, TrackListIterator::First(), Track::GetEndTime(), Track::GetKind(), Track::GetLink(), Track::GetSelected(), Track::GetStartTime(), TrackListIterator::Next(), SyncLockedTracksIterator::Next(), SyncLockedTracksIterator::StartWith(), ClipMoveState::trackExclusions, and Track::Wave.

Referenced by AudacityProject::OnClipMove().

268 {
269 // The captured clip is the focus, but we need to create a list
270  // of all clips that have to move, also...
271 
272  state.capturedClipArray.clear();
273 
274  // First, if click was in selection, capture selected clips; otherwise
275  // just the clicked-on clip
276  if ( state.capturedClipIsSelection ) {
277  TrackListIterator iter( &trackList );
278  for (Track *t = iter.First(); t; t = iter.Next()) {
279  if (t->GetSelected()) {
280  AddClipsToCaptured( state, viewInfo, t, true );
281  if (t->GetKind() != Track::Wave)
282  state.trackExclusions.push_back(t);
283  }
284  }
285  }
286  else {
287  state.capturedClipArray.push_back
288  (TrackClip( &capturedTrack, state.capturedClip ));
289 
290  // Check for stereo partner
291  Track *partner = capturedTrack.GetLink();
292  WaveTrack *wt;
293  if (state.capturedClip &&
294  // Assume linked track is wave or null
295  nullptr != (wt = static_cast<WaveTrack*>(partner))) {
296  WaveClip *const clip = FindClipAtTime(wt, clickTime);
297 
298  if (clip)
299  state.capturedClipArray.push_back(TrackClip(partner, clip));
300  }
301  }
302 
303  // Now, if sync-lock is enabled, capture any clip that's linked to a
304  // captured clip.
305  if ( syncLocked ) {
306  // AWD: mCapturedClipArray expands as the loop runs, so newly-added
307  // clips are considered (the effect is like recursion and terminates
308  // because AddClipsToCaptured doesn't add duplicate clips); to remove
309  // this behavior just store the array size beforehand.
310  for (unsigned int i = 0; i < state.capturedClipArray.size(); ++i) {
311  // Capture based on tracks that have clips -- that means we
312  // don't capture based on links to label tracks for now (until
313  // we can treat individual labels as clips)
314  if ( state.capturedClipArray[i].clip ) {
315  // Iterate over sync-lock group tracks.
316  SyncLockedTracksIterator git( &trackList );
317  for (Track *t = git.StartWith( state.capturedClipArray[i].track );
318  t; t = git.Next() )
319  {
320  AddClipsToCaptured(state, t,
321  state.capturedClipArray[i].clip->GetStartTime(),
322  state.capturedClipArray[i].clip->GetEndTime() );
323  if (t->GetKind() != Track::Wave)
324  state.trackExclusions.push_back(t);
325  }
326  }
327 #ifdef USE_MIDI
328  // Capture additional clips from NoteTracks
329  Track *nt = state.capturedClipArray[i].track;
330  if (nt->GetKind() == Track::Note) {
331  // Iterate over sync-lock group tracks.
332  SyncLockedTracksIterator git( &trackList );
333  for (Track *t = git.StartWith(nt); t; t = git.Next())
334  {
335  AddClipsToCaptured
336  ( state, t, nt->GetStartTime(), nt->GetEndTime() );
337  if (t->GetKind() != Track::Wave)
338  state.trackExclusions.push_back(t);
339  }
340  }
341 #endif
342  }
343  }
344 }
virtual double GetEndTime() const =0
Definition: Snap.h:34
bool capturedClipIsSelection
WaveClip * capturedClip
virtual double GetStartTime() const =0
virtual int GetKind() const
Definition: Track.h:330
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:176
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:102
TrackClipArray capturedClipArray
An iterator for a TrackList.
Definition: Track.h:402
Track * GetLink() const
Definition: Track.cpp:269
TrackArray trackExclusions
void TimeShiftHandle::DoSlideHorizontal ( ClipMoveState state,
TrackList trackList,
Track capturedTrack 
)
static

Definition at line 347 of file TimeShiftHandle.cpp.

References WaveTrack::CanOffsetClip(), ClipMoveState::capturedClip, ClipMoveState::capturedClipArray, TrackList::GetEndTime(), Track::GetLink(), TrackList::GetStartTime(), ClipMoveState::hSlideAmount, if(), WaveClip::Offset(), Track::Offset(), ClipMoveState::snapLeft, and ClipMoveState::snapRight.

Referenced by AudacityProject::OnClipMove().

348 {
349 #ifdef USE_MIDI
350  if ( state.capturedClipArray.size() )
351 #else
352  if ( state.capturedClip )
353 #endif
354  {
355  double allowed;
356  double initialAllowed;
357  double safeBigDistance = 1000 + 2.0 * ( trackList.GetEndTime() -
358  trackList.GetStartTime() );
359 
360  do { // loop to compute allowed, does not actually move anything yet
361  initialAllowed = state.hSlideAmount;
362 
363  unsigned int i, j;
364  for ( i = 0; i < state.capturedClipArray.size(); ++i ) {
365  WaveTrack *track = (WaveTrack *)state.capturedClipArray[i].track;
366  WaveClip *clip = state. capturedClipArray[i].clip;
367 
368  if (clip) { // only audio clips are used to compute allowed
369  // Move all other selected clips totally out of the way
370  // temporarily because they're all moving together and
371  // we want to find out if OTHER clips are in the way,
372  // not one of the moving ones
373  for ( j = 0; j < state.capturedClipArray.size(); j++ ) {
374  WaveClip *clip2 = state.capturedClipArray[j].clip;
375  if (clip2 && clip2 != clip)
376  clip2->Offset(-safeBigDistance);
377  }
378 
379  if ( track->CanOffsetClip(clip, state.hSlideAmount, &allowed) ) {
380  if ( state.hSlideAmount != allowed ) {
381  state.hSlideAmount = allowed;
382  state.snapLeft = state.snapRight = -1; // see bug 1067
383  }
384  }
385  else {
386  state.hSlideAmount = 0.0;
387  state.snapLeft = state.snapRight = -1; // see bug 1067
388  }
389 
390  for ( j = 0; j < state.capturedClipArray.size(); ++j ) {
391  WaveClip *clip2 = state.capturedClipArray[j].clip;
392  if (clip2 && clip2 != clip)
393  clip2->Offset(safeBigDistance);
394  }
395  }
396  }
397  } while ( state.hSlideAmount != initialAllowed );
398 
399  if ( state.hSlideAmount != 0.0 ) { // finally, here is where clips are moved
400  unsigned int i;
401  for ( i = 0; i < state.capturedClipArray.size(); ++i ) {
402  Track *track = state.capturedClipArray[i].track;
403  WaveClip *clip = state.capturedClipArray[i].clip;
404  if (clip)
405  clip->Offset( state.hSlideAmount );
406  else
407  track->Offset( state.hSlideAmount );
408  }
409  }
410  }
411  else {
412  // For Shift key down, or
413  // For non wavetracks, specifically label tracks ...
414  capturedTrack.Offset( state.hSlideAmount );
415  Track* link = capturedTrack.GetLink();
416  if (link)
417  link->Offset( state.hSlideAmount );
418  }
419 }
double GetStartTime() const
Definition: Track.cpp:1413
void Offset(double delta)
Definition: WaveClip.h:223
double GetEndTime() const
Definition: Track.cpp:1418
void Offset(double t)
Definition: Track.h:289
WaveClip * capturedClip
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:176
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
bool CanOffsetClip(WaveClip *clip, double amount, double *allowedAmount=NULL)
Definition: WaveTrack.cpp:2295
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:102
TrackClipArray capturedClipArray
if(pTrack &&pTrack->GetDisplay()!=WaveTrack::Spectrum)
Track * GetLink() const
Definition: Track.cpp:269
UIHandle::Result TimeShiftHandle::Drag ( const TrackPanelMouseEvent event,
AudacityProject pProject 
)
overridevirtual

Implements UIHandle.

Definition at line 500 of file TimeShiftHandle.cpp.

References WaveTrack::AddClip(), RefreshCode::Cancelled, WaveTrack::CanInsertClip(), TrackClip::clip, TrackClip::dstTrack, TrackPanelMouseEvent::event, WaveTrack::GetKind(), Track::GetLink(), Track::GetLinked(), WaveTrack::GetRate(), AudacityProject::GetTracks(), AudacityProject::GetViewInfo(), TrackClip::holder, AudacityProject::IsAudioActive(), SelectedRegion::move(), Track::Offset(), TrackPanelMouseEvent::pCell, Track::Pointer(), ZoomInfo::PositionToTime(), RefreshCode::RefreshAll, RefreshCode::RefreshNone, ViewInfo::selectedRegion, ZoomInfo::TimeToPosition(), TrackClip::track, and Track::Wave.

501 {
502  const wxMouseEvent &event = evt.event;
503  ViewInfo &viewInfo = pProject->GetViewInfo();
504 
505  // We may switch pTrack to its stereo partner below
506  Track *track = dynamic_cast<Track*>(evt.pCell.get());
507 
508  // Uncommenting this permits drag to continue to work even over the controls area
509  /*
510  pTrack = static_cast<CommonTrackPanelCell*>(evt.pCell)->FindTrack().get();
511  */
512 
513  if (!track) {
514  // Allow sliding if the pointer is not over any track, but only if x is
515  // within the bounds of the tracks area.
516  if (event.m_x >= mRect.GetX() &&
517  event.m_x < mRect.GetX() + mRect.GetWidth())
518  track = mCapturedTrack.get();
519  }
520 
521  // May need a shared_ptr to reassign mCapturedTrack below
522  auto pTrack = Track::Pointer( track );
523  if (!pTrack)
525 
526 
527  using namespace RefreshCode;
528  const bool unsafe = pProject->IsAudioActive();
529  if (unsafe) {
530  this->Cancel(pProject);
531  return RefreshAll | Cancelled;
532  }
533 
534  TrackList *const trackList = pProject->GetTracks();
535 
536  // GM: DoSlide now implementing snap-to
537  // samples functionality based on sample rate.
538 
539  // Start by undoing the current slide amount; everything
540  // happens relative to the original horizontal position of
541  // each clip...
542 #ifdef USE_MIDI
544 #else
546 #endif
547  {
548  for (unsigned ii = 0; ii < mClipMoveState.capturedClipArray.size(); ++ii) {
549  if (mClipMoveState.capturedClipArray[ii].clip)
550  mClipMoveState.capturedClipArray[ii].clip->Offset
552  else
553  mClipMoveState.capturedClipArray[ii].track->Offset
555  }
556  }
557  else {
558  // Was a shift-click
560  Track *const link = mCapturedTrack->GetLink();
561  if (link)
563  }
564 
566  // Slide the selection, too
568  }
570 
571  double desiredSlideAmount;
572  if (mSlideUpDownOnly) {
573  desiredSlideAmount = 0.0;
574  }
575  else {
576  desiredSlideAmount =
577  viewInfo.PositionToTime(event.m_x) -
578  viewInfo.PositionToTime(mMouseClickX);
579  bool trySnap = false;
580  double clipLeft = 0, clipRight = 0;
581 #ifdef USE_MIDI
582  if (pTrack->GetKind() == Track::Wave) {
583  WaveTrack *const mtw = static_cast<WaveTrack*>(pTrack.get());
584  const double rate = mtw->GetRate();
585  // set it to a sample point
586  desiredSlideAmount = rint(desiredSlideAmount * rate) / rate;
587  }
588 
589  // Adjust desiredSlideAmount using SnapManager
590  if (mSnapManager.get() && mClipMoveState.capturedClipArray.size()) {
591  trySnap = true;
594  + desiredSlideAmount;
595  clipRight = mClipMoveState.capturedClip->GetEndTime()
596  + desiredSlideAmount;
597  }
598  else {
599  clipLeft = mCapturedTrack->GetStartTime() + desiredSlideAmount;
600  clipRight = mCapturedTrack->GetEndTime() + desiredSlideAmount;
601  }
602  }
603 #else
604  {
605  trySnap = true;
606  if (pTrack->GetKind() == Track::Wave) {
607  auto wt = static_cast<const WaveTrack *>(pTrack.get());
608  const double rate = wt->GetRate();
609  // set it to a sample point
610  desiredSlideAmount = rint(desiredSlideAmount * rate) / rate;
613  + desiredSlideAmount;
614  clipRight = mClipMoveState.capturedClip->GetEndTime()
615  + desiredSlideAmount;
616  }
617  }
618  }
619 #endif
620  if (trySnap)
621  {
622  auto results =
623  mSnapManager->Snap(mCapturedTrack.get(), clipLeft, false);
624  auto newClipLeft = results.outTime;
625  results =
626  mSnapManager->Snap(mCapturedTrack.get(), clipRight, false);
627  auto newClipRight = results.outTime;
628 
629  // Only one of them is allowed to snap
630  if (newClipLeft != clipLeft && newClipRight != clipRight) {
631  // Un-snap the un-preferred edge
633  newClipLeft = clipLeft;
634  else
635  newClipRight = clipRight;
636  }
637 
638  // Take whichever one snapped (if any) and compute the NEW desiredSlideAmount
641  if (newClipLeft != clipLeft) {
642  const double difference = (newClipLeft - clipLeft);
643  desiredSlideAmount += difference;
645  viewInfo.TimeToPosition(newClipLeft, mRect.x);
646  }
647  else if (newClipRight != clipRight) {
648  const double difference = (newClipRight - clipRight);
649  desiredSlideAmount += difference;
651  viewInfo.TimeToPosition(newClipRight, mRect.x);
652  }
653  }
654  }
655 
656  // Scroll during vertical drag.
657  // EnsureVisible(pTrack); //vvv Gale says this has problems on Linux, per bug 393 thread. Revert for 2.0.2.
658  bool slidVertically = false;
659 
660  // If the mouse is over a track that isn't the captured track,
661  // decide which tracks the captured clips should go to.
663  pTrack != mCapturedTrack &&
664  pTrack->GetKind() == Track::Wave
665  /* && !mCapturedClipIsSelection*/)
666  {
667  const int diff =
668  TrackPosition(*trackList, pTrack.get()) -
669  TrackPosition(*trackList, mCapturedTrack.get());
670  for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size();
671  ii < nn; ++ii ) {
672  TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
673  if (trackClip.clip) {
674  // Move all clips up or down by an equal count of audio tracks.
675  Track *const pSrcTrack = trackClip.track;
676  auto pDstTrack = NthAudioTrack(*trackList,
677  diff + TrackPosition(*trackList, pSrcTrack));
678  // Can only move mono to mono, or left to left, or right to right
679  // And that must be so for each captured clip
680  bool stereo = (pSrcTrack->GetLink() != 0);
681  if (pDstTrack && stereo && !pSrcTrack->GetLinked())
682  // Assume linked track is wave or null
683  pDstTrack = static_cast<WaveTrack*>(pDstTrack->GetLink());
684  bool ok = pDstTrack &&
685  (stereo == (pDstTrack->GetLink() != 0)) &&
686  (!stereo || (pSrcTrack->GetLinked() == pDstTrack->GetLinked()));
687  if (ok)
688  trackClip.dstTrack = pDstTrack;
689  else
690  return RefreshAll;
691  }
692  }
693 
694  // Having passed that test, remove clips temporarily from their
695  // tracks, so moving clips don't interfere with each other
696  // when we call CanInsertClip()
697  for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size();
698  ii < nn; ++ii ) {
699  TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
700  WaveClip *const pSrcClip = trackClip.clip;
701  if (pSrcClip)
702  trackClip.holder =
703  // Assume track is wave because it has a clip
704  static_cast<WaveTrack*>(trackClip.track)->
705  RemoveAndReturnClip(pSrcClip);
706  }
707 
708  // Now check that the move is possible
709  bool ok = true;
710  // The test for tolerance will need review with FishEye!
711  // The tolerance is supposed to be the time for one pixel, i.e. one pixel tolerance
712  // at current zoom.
713  double slide = desiredSlideAmount; // remember amount requested.
714  double tolerance = viewInfo.PositionToTime(event.m_x+1) - viewInfo.PositionToTime(event.m_x);
715 
716  // The desiredSlideAmount may change and the tolerance may get used up.
717  for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size();
718  ok && ii < nn; ++ii) {
719  TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
720  WaveClip *const pSrcClip = trackClip.clip;
721  if (pSrcClip)
722  ok = trackClip.dstTrack->CanInsertClip(pSrcClip, desiredSlideAmount, tolerance);
723  }
724 
725  if( ok ) {
726  // fits ok, but desiredSlideAmount could have been updated to get the clip to fit.
727  // Check again, in the new position, this time with zero tolerance.
728  tolerance = 0.0;
729  for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size();
730  ok && ii < nn; ++ii) {
731  TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
732  WaveClip *const pSrcClip = trackClip.clip;
733  if (pSrcClip)
734  ok = trackClip.dstTrack->CanInsertClip(pSrcClip, desiredSlideAmount, tolerance);
735  }
736  }
737 
738  if (!ok) {
739  // Failure, even with using tolerance.
740  // Failure -- we'll put clips back where they were
741  // ok will next indicate if a horizontal slide is OK.
742  ok = true; // assume slide is OK.
743  tolerance = 0.0;
744  desiredSlideAmount = slide;
745  for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size();
746  ii < nn; ++ii) {
747  TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
748  WaveClip *const pSrcClip = trackClip.clip;
749  if (pSrcClip){
750  // back to the track it came from...
751  trackClip.dstTrack = static_cast<WaveTrack*>(trackClip.track);
752  ok = ok && trackClip.dstTrack->CanInsertClip(pSrcClip, desiredSlideAmount, tolerance);
753  }
754  }
755  for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size();
756  ii < nn; ++ii) {
757  TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
758  WaveClip *const pSrcClip = trackClip.clip;
759  if (pSrcClip){
760 
761  // Attempt to move to a new track did not work.
762  // Put the clip back appropriately shifted!
763  if( ok)
764  trackClip.holder->Offset(slide);
765  // Assume track is wave because it has a clip
766  static_cast<WaveTrack*>(trackClip.track)->
767  AddClip(std::move(trackClip.holder));
768  }
769  }
770  // Make the offset permanent; start from a "clean slate"
771  if( ok ) {
772  mMouseClickX = event.m_x;
774  // Slide the selection, too
775  viewInfo.selectedRegion.move( slide );
776  }
778  }
779 
780  return RefreshAll;
781  }
782  else {
783  // Do the vertical moves of clips
784  for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size();
785  ii < nn; ++ii ) {
786  TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
787  WaveClip *const pSrcClip = trackClip.clip;
788  if (pSrcClip) {
789  const auto dstTrack = trackClip.dstTrack;
790  dstTrack->AddClip(std::move(trackClip.holder));
791  trackClip.track = dstTrack;
792  }
793  }
794 
795  mCapturedTrack = pTrack;
796  mDidSlideVertically = true;
797 
798  // Make the offset permanent; start from a "clean slate"
799  mMouseClickX = event.m_x;
800  }
801 
802  // Not done yet, check for horizontal movement.
803  slidVertically = true;
804  }
805 
806  if (desiredSlideAmount == 0.0)
807  return RefreshAll;
808 
809  mClipMoveState.hSlideAmount = desiredSlideAmount;
810 
812 
814  // Slide the selection, too
816  }
817 
818  if (slidVertically) {
819  // NEW origin
821  }
822 
823  return RefreshAll;
824 }
static void DoSlideHorizontal(ClipMoveState &state, TrackList &trackList, Track &capturedTrack)
A list of TrackListNode items.
Definition: Track.h:619
std::shared_ptr< WaveClip > holder
Definition: Snap.h:45
ViewInfo is used mainly to hold the zooming, selection and scroll information. It also has some statu...
Definition: ViewInfo.h:141
SelectedRegion selectedRegion
Definition: ViewInfo.h:160
double GetStartTime() const
Definition: WaveClip.cpp:421
void Offset(double t)
Definition: Track.h:289
double PositionToTime(wxInt64 position, wxInt64 origin=0, bool ignoreFisheye=false) const
Definition: ViewInfo.cpp:49
Definition: Snap.h:34
bool GetLinked() const
Definition: Track.h:279
bool capturedClipIsSelection
WaveClip * capturedClip
void move(double delta)
ClipMoveState mClipMoveState
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:176
std::shared_ptr< SnapManager > mSnapManager
Track * track
Definition: Snap.h:41
WaveTrack * dstTrack
Definition: Snap.h:43
A Track that contains audio waveform data.
Definition: WaveTrack.h:60
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:102
TrackClipArray capturedClipArray
Result Cancel(AudacityProject *pProject) override
wxInt64 TimeToPosition(double time, wxInt64 origin=0, bool ignoreFisheye=false) const
STM: Converts a project time to screen x position.
Definition: ViewInfo.cpp:59
bool IsAudioActive() const
Definition: Project.cpp:1454
void AddClip(std::shared_ptr< WaveClip > &&clip)
Definition: WaveTrack.cpp:1003
Track * GetLink() const
Definition: Track.cpp:269
std::shared_ptr< Track > mCapturedTrack
double GetEndTime() const
Definition: WaveClip.cpp:427
double GetRate() const
Definition: WaveTrack.cpp:398
TrackList * GetTracks()
Definition: Project.h:192
bool CanInsertClip(WaveClip *clip, double &slideBy, double &tolerance)
Definition: WaveTrack.cpp:2342
static std::shared_ptr< Subclass > Pointer(Track *t)
Definition: Track.h:137
const ViewInfo & GetViewInfo() const
Definition: Project.h:207
WaveClip * clip
Definition: Snap.h:44
void TimeShiftHandle::DrawExtras ( DrawingPass  pass,
wxDC *  dc,
const wxRegion &  ,
const wxRect &  panelRect 
)
overridevirtual

Reimplemented from UIHandle.

Definition at line 902 of file TimeShiftHandle.cpp.

904 {
905  if (pass == Panel) {
906  // Draw snap guidelines if we have any
907  if ( mSnapManager )
908  mSnapManager->Draw
910  }
911 }
ClipMoveState mClipMoveState
std::shared_ptr< SnapManager > mSnapManager
void TimeShiftHandle::Enter ( bool  forward)
overridevirtual

Reimplemented from UIHandle.

Definition at line 33 of file TimeShiftHandle.cpp.

References UIHandle::mChangeHighlight, and RefreshCode::RefreshCell.

34 {
35 #ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
37 #endif
38 }
Result mChangeHighlight
Definition: UIHandle.h:150
std::shared_ptr<Track> TimeShiftHandle::GetTrack ( ) const
inline

Definition at line 57 of file TimeShiftHandle.h.

References mCapturedTrack.

57 { return mCapturedTrack; }
std::shared_ptr< Track > mCapturedTrack
UIHandlePtr TimeShiftHandle::HitAnywhere ( std::weak_ptr< TimeShiftHandle > &  holder,
const std::shared_ptr< Track > &  pTrack,
bool  gripHit 
)
static

Definition at line 61 of file TimeShiftHandle.cpp.

References AssignUIHandlePtr().

Referenced by WaveTrack::DetailedHitTest(), HitPreview(), and Track::HitTest().

63 {
64  // After all that, it still may be unsafe to drag.
65  // Even if so, make an informative cursor change from default to "banned."
66  auto result = std::make_shared<TimeShiftHandle>( pTrack, gripHit );
67  result = AssignUIHandlePtr(holder, result);
68  return result;
69 }
std::shared_ptr< Subclass > AssignUIHandlePtr(std::weak_ptr< Subclass > &holder, const std::shared_ptr< Subclass > &pNew)
Definition: UIHandle.h:162
HitTestPreview TimeShiftHandle::HitPreview ( const AudacityProject pProject,
bool  unsafe 
)
staticprivate

Definition at line 41 of file TimeShiftHandle.cpp.

References _(), HitAnywhere(), and MakeCursor().

42 {
43  static auto disabledCursor =
44  ::MakeCursor(wxCURSOR_NO_ENTRY, DisabledCursorXpm, 16, 16);
45  static auto slideCursor =
46  MakeCursor(wxCURSOR_SIZEWE, TimeCursorXpm, 16, 16);
47  // TODO: Should it say "track or clip" ? Non-wave tracks can move, or clips in a wave track.
48  // TODO: mention effects of shift (move all clips of selected wave track) and ctrl (move vertically only) ?
49  // -- but not all of that is available in multi tool.
50  auto message = _("Click and drag to move a track in time");
51 
52  return {
53  message,
54  (unsafe
55  ? &*disabledCursor
56  : &*slideCursor)
57  };
58 }
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
std::unique_ptr< wxCursor > MakeCursor(int WXUNUSED(CursorId), const char *const pXpm[36], int HotX, int HotY)
Definition: TrackPanel.cpp:274
UIHandlePtr TimeShiftHandle::HitTest ( std::weak_ptr< TimeShiftHandle > &  holder,
const wxMouseState &  state,
const wxRect &  rect,
const std::shared_ptr< Track > &  pTrack 
)
static

method that tells us if the mouse event landed on a time-slider that allows us to time shift the sequence. (Those are the two "grips" drawn at left and right edges for multi tool mode.)

Definition at line 72 of file TimeShiftHandle.cpp.

Referenced by WaveTrack::DetailedHitTest().

75 {
79 
80  // Perhaps we should delegate this to TrackArtist as only TrackArtist
81  // knows what the real sizes are??
82 
83  // The drag Handle width includes border, width and a little extra margin.
84  const int adjustedDragHandleWidth = 14;
85  // The hotspot for the cursor isn't at its centre. Adjust for this.
86  const int hotspotOffset = 5;
87 
88  // We are doing an approximate test here - is the mouse in the right or left border?
89  if (!(state.m_x + hotspotOffset < rect.x + adjustedDragHandleWidth ||
90  state.m_x + hotspotOffset >= rect.x + rect.width - adjustedDragHandleWidth))
91  return {};
92 
93  return HitAnywhere( holder, pTrack, true );
94 }
static UIHandlePtr HitAnywhere(std::weak_ptr< TimeShiftHandle > &holder, const std::shared_ptr< Track > &pTrack, bool gripHit)
bool TimeShiftHandle::IsGripHit ( ) const
inline

Definition at line 56 of file TimeShiftHandle.h.

References mGripHit.

Referenced by TrackArtist::DrawWaveform().

56 { return mGripHit; }
TimeShiftHandle& TimeShiftHandle::operator= ( const TimeShiftHandle )
default
HitTestPreview TimeShiftHandle::Preview ( const TrackPanelMouseState state,
const AudacityProject pProject 
)
overridevirtual

Implements UIHandle.

Definition at line 827 of file TimeShiftHandle.cpp.

References AudacityProject::IsAudioActive().

828 {
829  // After all that, it still may be unsafe to drag.
830  // Even if so, make an informative cursor change from default to "banned."
831  const bool unsafe = pProject->IsAudioActive();
832  return HitPreview(pProject, unsafe);
833 }
static HitTestPreview HitPreview(const AudacityProject *pProject, bool unsafe)
bool IsAudioActive() const
Definition: Project.cpp:1454
UIHandle::Result TimeShiftHandle::Release ( const TrackPanelMouseEvent event,
AudacityProject pProject,
wxWindow *  pParent 
)
overridevirtual

Implements UIHandle.

Definition at line 836 of file TimeShiftHandle.cpp.

References _(), AUTOSAVE, TrackClip::clip, CONSOLIDATE, RefreshCode::FixScrollbars, AudacityProject::IsAudioActive(), WaveClip::MarkChanged(), TrackClip::origTrack, AudacityProject::PushState(), RefreshCode::RefreshAll, RefreshCode::RefreshNone, WaveClip::Resample(), and TrackClip::track.

838 {
839  using namespace RefreshCode;
840  const bool unsafe = pProject->IsAudioActive();
841  if (unsafe)
842  return this->Cancel(pProject);
843 
844  Result result = RefreshNone;
845 
846  // Do not draw yellow lines
847  if ( mClipMoveState.snapLeft != -1 || mClipMoveState.snapRight != -1) {
849  result |= RefreshAll;
850  }
851 
853  return result;
854 
855  for ( size_t ii = 0; ii < mClipMoveState.capturedClipArray.size(); ++ii )
856  {
857  TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
858  WaveClip* pWaveClip = trackClip.clip;
859  // Note that per AddClipsToCaptured(Track *t, double t0, double t1),
860  // in the non-WaveTrack case, the code adds a NULL clip to mCapturedClipArray,
861  // so we have to check for that any time we're going to deref it.
862  // Previous code did not check it here, and that caused bug 367 crash.
863  if (pWaveClip &&
864  trackClip.track != trackClip.origTrack)
865  {
866  // Now that user has dropped the clip into a different track,
867  // make sure the sample rate matches the destination track (mCapturedTrack).
868  // Assume the clip was dropped in a wave track
869  pWaveClip->Resample
870  (static_cast<WaveTrack*>(trackClip.track)->GetRate());
871  pWaveClip->MarkChanged();
872  }
873  }
874 
875  wxString msg;
876  bool consolidate;
877  if (mDidSlideVertically) {
878  msg = _("Moved clips to another track");
879  consolidate = false;
880  }
881  else {
882  msg.Printf(
884  ? _("Time shifted tracks/clips right %.02f seconds")
885  : _("Time shifted tracks/clips left %.02f seconds") ),
886  fabs( mClipMoveState.hSlideAmount ) );
887  consolidate = true;
888  }
889  pProject->PushState(msg, _("Time-Shift"),
890  consolidate ? (UndoPush::CONSOLIDATE) : (UndoPush::AUTOSAVE));
891 
892  return result | FixScrollbars;
893 }
void MarkChanged()
Definition: WaveClip.h:255
Definition: Snap.h:34
void Resample(int rate, ProgressDialog *progress=NULL)
Definition: WaveClip.cpp:1898
unsigned Result
Definition: UIHandle.h:37
ClipMoveState mClipMoveState
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:176
Track * track
Definition: Snap.h:41
TrackClipArray capturedClipArray
Result Cancel(AudacityProject *pProject) override
bool IsAudioActive() const
Definition: Project.cpp:1454
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
void PushState(const wxString &desc, const wxString &shortDesc)
Definition: Project.cpp:4702
WaveClip * clip
Definition: Snap.h:44
Track * origTrack
Definition: Snap.h:42
bool TimeShiftHandle::StopsOnKeystroke ( )
inlineoverridevirtual

Reimplemented from UIHandle.

Definition at line 100 of file TimeShiftHandle.h.

100 { return true; }

Member Data Documentation

std::shared_ptr<Track> TimeShiftHandle::mCapturedTrack
private

Definition at line 103 of file TimeShiftHandle.h.

Referenced by GetTrack().

ClipMoveState TimeShiftHandle::mClipMoveState {}
private

Definition at line 119 of file TimeShiftHandle.h.

bool TimeShiftHandle::mDidSlideVertically {}
private

Definition at line 106 of file TimeShiftHandle.h.

bool TimeShiftHandle::mGripHit {}
private

Definition at line 120 of file TimeShiftHandle.h.

Referenced by IsGripHit().

int TimeShiftHandle::mMouseClickX {}
private

Definition at line 111 of file TimeShiftHandle.h.

wxRect TimeShiftHandle::mRect {}
private

Definition at line 104 of file TimeShiftHandle.h.

bool TimeShiftHandle::mSlideUpDownOnly {}
private

Definition at line 107 of file TimeShiftHandle.h.

std::shared_ptr<SnapManager> TimeShiftHandle::mSnapManager {}
private

Definition at line 117 of file TimeShiftHandle.h.

bool TimeShiftHandle::mSnapPreferRightEdge {}
private

Definition at line 109 of file TimeShiftHandle.h.


The documentation for this class was generated from the following files: