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 897 of file TimeShiftHandle.cpp.

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

898 {
899  pProject->RollbackState();
901 }
void RollbackState()
Definition: Project.cpp:4754
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  if (!pTrack)
435  return RefreshCode::Cancelled;
436 
437  TrackList *const trackList = pProject->GetTracks();
438 
440  mDidSlideVertically = false;
441 
442  ToolsToolBar *const ttb = pProject->GetToolsToolBar();
443  const bool multiToolModeActive = (ttb && ttb->IsDown(multiTool));
444 
445  const double clickTime =
446  viewInfo.PositionToTime(event.m_x, rect.x);
448  (pTrack->GetSelected() &&
449  clickTime >= viewInfo.selectedRegion.t0() &&
450  clickTime < viewInfo.selectedRegion.t1());
451 
452  WaveTrack *wt = pTrack->GetKind() == Track::Wave
453  ? static_cast<WaveTrack*>(pTrack.get()) : nullptr;
454 
455  if ((wt
456 #ifdef USE_MIDI
457  || pTrack->GetKind() == Track::Note
458 #endif
459  ) && !event.ShiftDown())
460  {
461 #ifdef USE_MIDI
462  if (!wt)
463  mClipMoveState.capturedClip = nullptr;
464  else
465 #endif
466  {
467  mClipMoveState.capturedClip = wt->GetClipAtX(event.m_x);
468  if (mClipMoveState.capturedClip == NULL)
469  return Cancelled;
470  }
471 
473  ( mClipMoveState, viewInfo, *pTrack, *trackList,
474  pProject->IsSyncLocked(), clickTime );
475  }
476  else {
477  // Shift was down, or track was not Wave or Note
480  }
481 
482  mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive;
483  mRect = rect;
484  mMouseClickX = event.m_x;
485  const double selStart = viewInfo.PositionToTime(event.m_x, mRect.x);
486  mSnapManager = std::make_shared<SnapManager>(trackList,
487  &viewInfo,
490  true); // don't snap to time
495  (fabs(selStart - mClipMoveState.capturedClip->GetEndTime()) <
496  fabs(selStart - mClipMoveState.capturedClip->GetStartTime()));
497 
498  return RefreshNone;
499 }
int GetKind() const override
Definition: WaveTrack.h:121
A list of TrackListNode items.
Definition: Track.h:623
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:5078
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:1457
bool IsSyncLocked()
Definition: Project.cpp:5682
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:334
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:406
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:293
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 502 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.

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

906 {
907  if (pass == Panel) {
908  // Draw snap guidelines if we have any
909  if ( mSnapManager )
910  mSnapManager->Draw
912  }
913 }
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:266
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 829 of file TimeShiftHandle.cpp.

References AudacityProject::IsAudioActive().

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

Implements UIHandle.

Definition at line 838 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.

840 {
841  using namespace RefreshCode;
842  const bool unsafe = pProject->IsAudioActive();
843  if (unsafe)
844  return this->Cancel(pProject);
845 
846  Result result = RefreshNone;
847 
848  // Do not draw yellow lines
849  if ( mClipMoveState.snapLeft != -1 || mClipMoveState.snapRight != -1) {
851  result |= RefreshAll;
852  }
853 
855  return result;
856 
857  for ( size_t ii = 0; ii < mClipMoveState.capturedClipArray.size(); ++ii )
858  {
859  TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
860  WaveClip* pWaveClip = trackClip.clip;
861  // Note that per AddClipsToCaptured(Track *t, double t0, double t1),
862  // in the non-WaveTrack case, the code adds a NULL clip to mCapturedClipArray,
863  // so we have to check for that any time we're going to deref it.
864  // Previous code did not check it here, and that caused bug 367 crash.
865  if (pWaveClip &&
866  trackClip.track != trackClip.origTrack)
867  {
868  // Now that user has dropped the clip into a different track,
869  // make sure the sample rate matches the destination track (mCapturedTrack).
870  // Assume the clip was dropped in a wave track
871  pWaveClip->Resample
872  (static_cast<WaveTrack*>(trackClip.track)->GetRate());
873  pWaveClip->MarkChanged();
874  }
875  }
876 
877  wxString msg;
878  bool consolidate;
879  if (mDidSlideVertically) {
880  msg = _("Moved clips to another track");
881  consolidate = false;
882  }
883  else {
884  msg.Printf(
886  ? _("Time shifted tracks/clips right %.02f seconds")
887  : _("Time shifted tracks/clips left %.02f seconds") ),
888  fabs( mClipMoveState.hSlideAmount ) );
889  consolidate = true;
890  }
891  pProject->PushState(msg, _("Time-Shift"),
892  consolidate ? (UndoPush::CONSOLIDATE) : (UndoPush::AUTOSAVE));
893 
894  return result | FixScrollbars;
895 }
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:1457
_("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:4714
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: