1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-25 16:48:44 +02:00

Make new clip move commands compatible with TrackPanel refactor...

... Don't use any TrackPanel member variabls when moving clips via command.

Still to do: push undo state.
This commit is contained in:
Paul Licameli 2017-05-18 07:13:41 -04:00
commit dc64fabe88
4 changed files with 249 additions and 224 deletions

View File

@ -1438,8 +1438,8 @@ void AudacityProject::CreateMenusAndCommands()
c->AddItem(wxT("CursorLongJumpLeft"), _("Cursor Long Jump Left"), FN(OnCursorLongJumpLeft), wxT("Shift+,")); c->AddItem(wxT("CursorLongJumpLeft"), _("Cursor Long Jump Left"), FN(OnCursorLongJumpLeft), wxT("Shift+,"));
c->AddItem(wxT("CursorLongJumpRight"), _("Cursor Long Jump Right"), FN(OnCursorLongJumpRight), wxT("Shift+.")); c->AddItem(wxT("CursorLongJumpRight"), _("Cursor Long Jump Right"), FN(OnCursorLongJumpRight), wxT("Shift+."));
c->AddItem(wxT("ClipLeft"), _("Clip Left"), FN(OnClipLeft), wxT("\twantKeyup")); c->AddItem(wxT("ClipLeft"), _("Clip Left"), FN(OnClipLeft), wxT(""));
c->AddItem(wxT("ClipRight"), _("Clip Right"), FN(OnClipRight), wxT("\twantKeyup")); c->AddItem(wxT("ClipRight"), _("Clip Right"), FN(OnClipRight), wxT(""));
c->EndSubMenu(); c->EndSubMenu();
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -3081,26 +3081,29 @@ void AudacityProject::OnSelContractRight(const wxEvent * evt)
OnCursorLeft( true, true, bKeyUp ); OnCursorLeft( true, true, bKeyUp );
} }
void AudacityProject::OnClipLeft(const wxEvent* evt) void AudacityProject::DoClipLeftOrRight( bool right )
{ {
if (evt) { auto &panel = *GetTrackPanel();
mTrackPanel->OnClipMove(false, evt->GetEventType() == wxEVT_KEY_UP);
} auto amount = TrackPanel::OnClipMove
else { // called from menu item, so simulate keydown and keyup ( mViewInfo, panel.GetFocusedTrack(),
mTrackPanel->OnClipMove(false, false); *GetTracks(), IsSyncLocked(), right );
mTrackPanel->OnClipMove(false, true);
} panel.ScrollIntoView(mViewInfo.selectedRegion.t0());
panel.Refresh(false);
if ( amount == 0.0 )
panel.MessageForScreenReader( _("clip not moved"));
} }
void AudacityProject::OnClipRight(const wxEvent* evt) void AudacityProject::OnClipLeft()
{ {
if (evt) { DoClipLeftOrRight( false );
mTrackPanel->OnClipMove(true, evt->GetEventType() == wxEVT_KEY_UP); }
}
else { // called from menu item, so simulate keydown and keyup void AudacityProject::OnClipRight()
mTrackPanel->OnClipMove(true, false); {
mTrackPanel->OnClipMove(true, true); DoClipLeftOrRight( true );
}
} }
//this pops up a dialog which allows the left selection to be set. //this pops up a dialog which allows the left selection to be set.

View File

@ -160,8 +160,9 @@ void OnSelExtendRight(const wxEvent * evt);
void OnSelContractLeft(const wxEvent * evt); void OnSelContractLeft(const wxEvent * evt);
void OnSelContractRight(const wxEvent * evt); void OnSelContractRight(const wxEvent * evt);
void OnClipLeft(const wxEvent* evt); void DoClipLeftOrRight( bool right );
void OnClipRight(const wxEvent* evt); void OnClipLeft();
void OnClipRight();
void OnCursorShortJumpLeft(); void OnCursorShortJumpLeft();
void OnCursorShortJumpRight(); void OnCursorShortJumpRight();

View File

@ -455,7 +455,6 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
mMouseCapture = IsUncaptured; mMouseCapture = IsUncaptured;
mSlideUpDownOnly = false; mSlideUpDownOnly = false;
mHSlideAmountTotal = 0.0;
mLabelTrackStartXPos=-1; mLabelTrackStartXPos=-1;
mCircularTrackNavigation = false; mCircularTrackNavigation = false;
@ -535,8 +534,6 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
// This is used to snap the cursor to the nearest track that // This is used to snap the cursor to the nearest track that
// lines up with it. // lines up with it.
mSnapManager = NULL; mSnapManager = NULL;
mSnapLeft = -1;
mSnapRight = -1;
// Register for tracklist updates // Register for tracklist updates
mTracks->Connect(EVT_TRACKLIST_RESIZED, mTracks->Connect(EVT_TRACKLIST_RESIZED,
@ -1884,7 +1881,7 @@ void TrackPanel::HandleSelect(wxMouseEvent & event)
selectedClip->GetOffset(), selectedClip->GetEndTime()); selectedClip->GetOffset(), selectedClip->GetEndTime());
} }
//Also, capture this track for dragging until we up-click. //Also, capture this track for dragging until we up-click.
mCapturedClipArray.push_back(TrackClip(w, selectedClip)); mClipMoveState.capturedClipArray.push_back(TrackClip(w, selectedClip));
mMouseCapture = IsSliding; mMouseCapture = IsSliding;
@ -2065,8 +2062,7 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
// We create a NEW snap manager in case any snap-points have changed // We create a NEW snap manager in case any snap-points have changed
mSnapManager = std::make_unique<SnapManager>(GetTracks(), mViewInfo); mSnapManager = std::make_unique<SnapManager>(GetTracks(), mViewInfo);
mSnapLeft = -1; mSnapLeft = mSnapRight = -1;
mSnapRight = -1;
#ifdef USE_MIDI #ifdef USE_MIDI
mStretching = false; mStretching = false;
@ -2347,8 +2343,7 @@ void TrackPanel::StartSelection(int mouseXCoordinate, int trackLeftEdge)
double s = mSelStart; double s = mSelStart;
if (mSnapManager) { if (mSnapManager) {
mSnapLeft = -1; mSnapLeft = mSnapRight = -1;
mSnapRight = -1;
bool snappedPoint, snappedTime; bool snappedPoint, snappedTime;
if (mSnapManager->Snap(mCapturedTrack, mSelStart, false, if (mSnapManager->Snap(mCapturedTrack, mSelStart, false,
&s, &snappedPoint, &snappedTime)) { &s, &snappedPoint, &snappedTime)) {
@ -2394,8 +2389,7 @@ void TrackPanel::ExtendSelection(int mouseXCoordinate, int trackLeftEdge,
origSel1 = sel1; origSel1 = sel1;
if (mSnapManager) { if (mSnapManager) {
mSnapLeft = -1; mSnapLeft = mSnapRight = -1;
mSnapRight = -1;
bool snappedPoint, snappedTime; bool snappedPoint, snappedTime;
if (mSnapManager->Snap(mCapturedTrack, sel0, false, if (mSnapManager->Snap(mCapturedTrack, sel0, false,
&sel0, &snappedPoint, &snappedTime)) { &sel0, &snappedPoint, &snappedTime)) {
@ -2414,8 +2408,7 @@ void TrackPanel::ExtendSelection(int mouseXCoordinate, int trackLeftEdge,
!snappedTime) { !snappedTime) {
sel0 = origSel0; sel0 = origSel0;
sel1 = origSel1; sel1 = origSel1;
mSnapLeft = -1; mSnapLeft = mSnapRight = -1;
mSnapRight = -1;
} }
} }
@ -3332,7 +3325,7 @@ void TrackPanel::ForwardEventToEnvelope(wxMouseEvent & event)
} }
} }
void TrackPanel::HandleSlide(wxMouseEvent & event) void TrackPanel::HandleSlide( wxMouseEvent & event )
{ {
if (event.LeftDown()) if (event.LeftDown())
StartSlide(event); StartSlide(event);
@ -3350,17 +3343,17 @@ void TrackPanel::HandleSlide(wxMouseEvent & event)
mSnapManager.reset(); mSnapManager.reset();
// Do not draw yellow lines // Do not draw yellow lines
if (mSnapLeft != -1 || mSnapRight != -1) { if ( mClipMoveState.snapLeft != -1 || mClipMoveState.snapRight != -1) {
mSnapLeft = mSnapRight = -1; mClipMoveState.snapLeft = mClipMoveState.snapRight = -1;
Refresh(false); Refresh(false);
} }
if (!mDidSlideVertically && mHSlideAmount==0) if (!mDidSlideVertically && mClipMoveState.hSlideAmount == 0)
return; return;
for (size_t i = 0; i < mCapturedClipArray.size(); i++) for (size_t i = 0; i < mClipMoveState.capturedClipArray.size(); i++)
{ {
TrackClip &trackClip = mCapturedClipArray[i]; TrackClip &trackClip = mClipMoveState.capturedClipArray[i];
WaveClip* pWaveClip = trackClip.clip; WaveClip* pWaveClip = trackClip.clip;
// Note that per TrackPanel::AddClipsToCaptured(Track *t, double t0, double t1), // Note that per TrackPanel::AddClipsToCaptured(Track *t, double t0, double t1),
// in the non-WaveTrack case, the code adds a NULL clip to mCapturedClipArray, // in the non-WaveTrack case, the code adds a NULL clip to mCapturedClipArray,
@ -3387,14 +3380,14 @@ void TrackPanel::HandleSlide(wxMouseEvent & event)
consolidate = false; consolidate = false;
} }
else { else {
wxString direction = mHSlideAmount>0 ? wxString direction = mClipMoveState.hSlideAmount > 0 ?
/* i18n-hint: a direction as in left or right.*/ /* i18n-hint: a direction as in left or right.*/
_("right") : _("right") :
/* i18n-hint: a direction as in left or right.*/ /* i18n-hint: a direction as in left or right.*/
_("left"); _("left");
/* i18n-hint: %s is a direction like left or right */ /* i18n-hint: %s is a direction like left or right */
msg.Printf(_("Time shifted tracks/clips %s %.02f seconds"), msg.Printf(_("Time shifted tracks/clips %s %.02f seconds"),
direction.c_str(), fabs(mHSlideAmount)); direction.c_str(), fabs( mClipMoveState.hSlideAmount ));
consolidate = true; consolidate = true;
} }
MakeParentPushState(msg, _("Time-Shift"), MakeParentPushState(msg, _("Time-Shift"),
@ -3450,10 +3443,9 @@ namespace {
/// Prepare for sliding. /// Prepare for sliding.
void TrackPanel::StartSlide(wxMouseEvent & event) void TrackPanel::StartSlide(wxMouseEvent & event)
{ {
mHSlideAmount = 0.0; mClipMoveState = ClipMoveState{};
mDidSlideVertically = false;
mTrackExclusions.clear(); mDidSlideVertically = false;
const auto foundCell = FindCell(event.m_x, event.m_y); const auto foundCell = FindCell(event.m_x, event.m_y);
auto &vt = foundCell.pTrack; auto &vt = foundCell.pTrack;
@ -3466,7 +3458,7 @@ void TrackPanel::StartSlide(wxMouseEvent & event)
double clickTime = double clickTime =
mViewInfo->PositionToTime(event.m_x, GetLeftOffset()); mViewInfo->PositionToTime(event.m_x, GetLeftOffset());
mCapturedClipIsSelection = mClipMoveState.capturedClipIsSelection =
(vt->GetSelected() && (vt->GetSelected() &&
clickTime > mViewInfo->selectedRegion.t0() && clickTime > mViewInfo->selectedRegion.t0() &&
clickTime < mViewInfo->selectedRegion.t1()); clickTime < mViewInfo->selectedRegion.t1());
@ -3482,21 +3474,23 @@ void TrackPanel::StartSlide(wxMouseEvent & event)
{ {
#ifdef USE_MIDI #ifdef USE_MIDI
if (!wt) if (!wt)
mCapturedClip = NULL; mClipMoveState.capturedClip = NULL;
else else
#endif #endif
{ {
mCapturedClip = wt->GetClipAtX(event.m_x); mClipMoveState.capturedClip = wt->GetClipAtX(event.m_x);
if (mCapturedClip == NULL) if (mClipMoveState.capturedClip == NULL)
return; return;
} }
mCapturedTrack = vt; mCapturedTrack = vt;
CreateListOfCapturedClips(clickTime); CreateListOfCapturedClips
( mClipMoveState, *mViewInfo, *mCapturedTrack, *GetTracks(),
GetProject()->IsSyncLocked(), clickTime );
} else { } else {
mCapturedClip = NULL; mClipMoveState.capturedClip = NULL;
mCapturedClipArray.clear(); mClipMoveState.capturedClipArray.clear();
mCapturedTrack = vt; mCapturedTrack = vt;
} }
@ -3512,91 +3506,95 @@ void TrackPanel::StartSlide(wxMouseEvent & event)
mSnapManager = std::make_unique<SnapManager>(GetTracks(), mSnapManager = std::make_unique<SnapManager>(GetTracks(),
mViewInfo, mViewInfo,
&mCapturedClipArray, &mClipMoveState.capturedClipArray,
&mTrackExclusions, &mClipMoveState.trackExclusions,
true); // don't snap to time true); // don't snap to time
mSnapLeft = -1; mClipMoveState.snapLeft = -1;
mSnapRight = -1; mClipMoveState.snapRight = -1;
mSnapPreferRightEdge = false; mSnapPreferRightEdge = false;
if (mCapturedClip) { if (mClipMoveState.capturedClip) {
if (fabs(mSelStart - mCapturedClip->GetEndTime()) < if (fabs(mSelStart - mClipMoveState.capturedClip->GetEndTime()) <
fabs(mSelStart - mCapturedClip->GetStartTime())) fabs(mSelStart - mClipMoveState.capturedClip->GetStartTime()))
mSnapPreferRightEdge = true; mSnapPreferRightEdge = true;
} }
mMouseCapture = IsSliding; mMouseCapture = IsSliding;
} }
void TrackPanel::CreateListOfCapturedClips(double clickTime) void TrackPanel::CreateListOfCapturedClips
( ClipMoveState &state, const ViewInfo &viewInfo, Track &capturedTrack,
TrackList &trackList, bool syncLocked, double clickTime )
{ {
// The captured clip is the focus, but we need to create a list // The captured clip is the focus, but we need to create a list
// of all clips that have to move, also... // of all clips that have to move, also...
mCapturedClipArray.clear(); state.capturedClipArray.clear();
// First, if click was in selection, capture selected clips; otherwise // First, if click was in selection, capture selected clips; otherwise
// just the clicked-on clip // just the clicked-on clip
if (mCapturedClipIsSelection) { if ( state.capturedClipIsSelection ) {
TrackListIterator iter(GetTracks()); TrackListIterator iter( &trackList );
for (Track *t = iter.First(); t; t = iter.Next()) { for (Track *t = iter.First(); t; t = iter.Next()) {
if (t->GetSelected()) { if (t->GetSelected()) {
AddClipsToCaptured(t, true); AddClipsToCaptured( state, viewInfo, t, true );
if (t->GetKind() != Track::Wave) if (t->GetKind() != Track::Wave)
mTrackExclusions.push_back(t); state.trackExclusions.push_back(t);
} }
} }
} }
else { else {
mCapturedClipArray.push_back(TrackClip(mCapturedTrack, mCapturedClip)); state.capturedClipArray.push_back
(TrackClip( &capturedTrack, state.capturedClip ));
// Check for stereo partner // Check for stereo partner
Track *partner = mCapturedTrack->GetLink(); Track *partner = capturedTrack.GetLink();
WaveTrack *wt; WaveTrack *wt;
if (mCapturedClip && if (state.capturedClip &&
// Assume linked track is wave or null // Assume linked track is wave or null
nullptr != (wt = static_cast<WaveTrack*>(partner))) { nullptr != (wt = static_cast<WaveTrack*>(partner))) {
WaveClip *const clip = FindClipAtTime(wt, clickTime); WaveClip *const clip = FindClipAtTime(wt, clickTime);
if (clip) if (clip)
mCapturedClipArray.push_back(TrackClip(partner, clip)); state.capturedClipArray.push_back(TrackClip(partner, clip));
} }
} }
// Now, if sync-lock is enabled, capture any clip that's linked to a // Now, if sync-lock is enabled, capture any clip that's linked to a
// captured clip. // captured clip.
if (GetProject()->IsSyncLocked()) { if ( syncLocked ) {
// AWD: mCapturedClipArray expands as the loop runs, so newly-added // AWD: mCapturedClipArray expands as the loop runs, so newly-added
// clips are considered (the effect is like recursion and terminates // clips are considered (the effect is like recursion and terminates
// because AddClipsToCaptured doesn't add duplicate clips); to remove // because AddClipsToCaptured doesn't add duplicate clips); to remove
// this behavior just store the array size beforehand. // this behavior just store the array size beforehand.
for (unsigned int i = 0; i < mCapturedClipArray.size(); ++i) { for (unsigned int i = 0; i < state.capturedClipArray.size(); ++i) {
// Capture based on tracks that have clips -- that means we // Capture based on tracks that have clips -- that means we
// don't capture based on links to label tracks for now (until // don't capture based on links to label tracks for now (until
// we can treat individual labels as clips) // we can treat individual labels as clips)
if (mCapturedClipArray[i].clip) { if ( state.capturedClipArray[i].clip ) {
// Iterate over sync-lock group tracks. // Iterate over sync-lock group tracks.
SyncLockedTracksIterator git(GetTracks()); SyncLockedTracksIterator git( &trackList );
for (Track *t = git.StartWith(mCapturedClipArray[i].track); for (Track *t = git.StartWith( state.capturedClipArray[i].track );
t; t = git.Next() ) t; t = git.Next() )
{ {
AddClipsToCaptured(t, AddClipsToCaptured(state, t,
mCapturedClipArray[i].clip->GetStartTime(), state.capturedClipArray[i].clip->GetStartTime(),
mCapturedClipArray[i].clip->GetEndTime() ); state.capturedClipArray[i].clip->GetEndTime() );
if (t->GetKind() != Track::Wave) if (t->GetKind() != Track::Wave)
mTrackExclusions.push_back(t); state.trackExclusions.push_back(t);
} }
} }
#ifdef USE_MIDI #ifdef USE_MIDI
// Capture additional clips from NoteTracks // Capture additional clips from NoteTracks
Track *nt = mCapturedClipArray[i].track; Track *nt = state.capturedClipArray[i].track;
if (nt->GetKind() == Track::Note) { if (nt->GetKind() == Track::Note) {
// Iterate over sync-lock group tracks. // Iterate over sync-lock group tracks.
SyncLockedTracksIterator git(GetTracks()); SyncLockedTracksIterator git( &trackList );
for (Track *t = git.StartWith(nt); t; t = git.Next()) for (Track *t = git.StartWith(nt); t; t = git.Next())
{ {
AddClipsToCaptured(t, nt->GetStartTime(), nt->GetEndTime()); AddClipsToCaptured
( state, t, nt->GetStartTime(), nt->GetEndTime() );
if (t->GetKind() != Track::Wave) if (t->GetKind() != Track::Wave)
mTrackExclusions.push_back(t); state.trackExclusions.push_back(t);
} }
} }
#endif #endif
@ -3606,17 +3604,20 @@ void TrackPanel::CreateListOfCapturedClips(double clickTime)
// Helper for the above, adds a track's clips to mCapturedClipArray (eliminates // Helper for the above, adds a track's clips to mCapturedClipArray (eliminates
// duplication of this logic) // duplication of this logic)
void TrackPanel::AddClipsToCaptured(Track *t, bool withinSelection) void TrackPanel::AddClipsToCaptured
( ClipMoveState &state, const ViewInfo &viewInfo,
Track *t, bool withinSelection )
{ {
if (withinSelection) if (withinSelection)
AddClipsToCaptured(t, mViewInfo->selectedRegion.t0(), AddClipsToCaptured( state, t, viewInfo.selectedRegion.t0(),
mViewInfo->selectedRegion.t1()); viewInfo.selectedRegion.t1() );
else else
AddClipsToCaptured(t, t->GetStartTime(), t->GetEndTime()); AddClipsToCaptured( state, t, t->GetStartTime(), t->GetEndTime() );
} }
// Adds a track's clips to mCapturedClipArray within a specified time // Adds a track's clips to mCapturedClipArray within a specified time
void TrackPanel::AddClipsToCaptured(Track *t, double t0, double t1) void TrackPanel::AddClipsToCaptured
( ClipMoveState &state, Track *t, double t0, double t1 )
{ {
if (t->GetKind() == Track::Wave) if (t->GetKind() == Track::Wave)
{ {
@ -3626,15 +3627,15 @@ void TrackPanel::AddClipsToCaptured(Track *t, double t0, double t1)
{ {
// Avoid getting clips that were already captured // Avoid getting clips that were already captured
bool newClip = true; bool newClip = true;
for (unsigned int i = 0; i < mCapturedClipArray.size(); ++i) { for (unsigned int i = 0; i < state.capturedClipArray.size(); ++i) {
if (mCapturedClipArray[i].clip == clip.get()) { if ( state.capturedClipArray[i].clip == clip.get() ) {
newClip = false; newClip = false;
break; break;
} }
} }
if (newClip) if (newClip)
mCapturedClipArray.push_back(TrackClip(t, clip.get())); state.capturedClipArray.push_back( TrackClip(t, clip.get()) );
} }
} }
} }
@ -3645,8 +3646,8 @@ void TrackPanel::AddClipsToCaptured(Track *t, double t0, double t1)
// Avoid adding a track twice // Avoid adding a track twice
bool newClip = true; bool newClip = true;
for (unsigned int i = 0; i < mCapturedClipArray.size(); ++i) { for ( unsigned int i = 0; i < state.capturedClipArray.size(); ++i ) {
if (mCapturedClipArray[i].track == t) { if ( state.capturedClipArray[i].track == t ) {
newClip = false; newClip = false;
break; break;
} }
@ -3660,7 +3661,7 @@ void TrackPanel::AddClipsToCaptured(Track *t, double t0, double t1)
return; return;
} }
#endif #endif
mCapturedClipArray.push_back(TrackClip(t, NULL)); state.capturedClipArray.push_back(TrackClip(t, NULL));
} }
} }
} }
@ -3693,30 +3694,32 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
// happens relative to the original horizontal position of // happens relative to the original horizontal position of
// each clip... // each clip...
#ifdef USE_MIDI #ifdef USE_MIDI
if (mCapturedClipArray.size()) if ( mClipMoveState.capturedClipArray.size() )
#else #else
if (mCapturedClip) if ( mClipMoveState.capturedClip )
#endif #endif
{ {
for(i=0; i<mCapturedClipArray.size(); i++) { for ( i = 0; i < mClipMoveState.capturedClipArray.size(); ++i ) {
if (mCapturedClipArray[i].clip) if ( mClipMoveState.capturedClipArray[i].clip )
mCapturedClipArray[i].clip->Offset(-mHSlideAmount); mClipMoveState.capturedClipArray[i].clip->Offset
( -mClipMoveState.hSlideAmount );
else else
mCapturedClipArray[i].track->Offset(-mHSlideAmount); mClipMoveState.capturedClipArray[i].track->Offset
( -mClipMoveState.hSlideAmount );
} }
} }
else { else {
mCapturedTrack->Offset(-mHSlideAmount); mCapturedTrack->Offset( -mClipMoveState.hSlideAmount );
Track* link = mCapturedTrack->GetLink(); Track* link = mCapturedTrack->GetLink();
if (link) if (link)
link->Offset(-mHSlideAmount); link->Offset( -mClipMoveState.hSlideAmount );
} }
if (mCapturedClipIsSelection) { if ( mClipMoveState.capturedClipIsSelection ) {
// Slide the selection, too // Slide the selection, too
mViewInfo->selectedRegion.move(-mHSlideAmount); mViewInfo->selectedRegion.move( -mClipMoveState.hSlideAmount );
} }
mHSlideAmount = 0.0; mClipMoveState.hSlideAmount = 0.0;
// Implement sliding within the track(s) // Implement sliding within the track(s)
double desiredSlideAmount; double desiredSlideAmount;
@ -3736,11 +3739,13 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
mtw->GetRate(); // set it to a sample point mtw->GetRate(); // set it to a sample point
} }
// Adjust desiredSlideAmount using SnapManager // Adjust desiredSlideAmount using SnapManager
if (mSnapManager && mCapturedClipArray.size()) { if (mSnapManager && mClipMoveState.capturedClipArray.size()) {
trySnap = true; trySnap = true;
if (mCapturedClip) { if ( mClipMoveState.capturedClip ) {
clipLeft = mCapturedClip->GetStartTime() + desiredSlideAmount; clipLeft = mClipMoveState.capturedClip->GetStartTime()
clipRight = mCapturedClip->GetEndTime() + desiredSlideAmount; + desiredSlideAmount;
clipRight = mClipMoveState.capturedClip->GetEndTime()
+ desiredSlideAmount;
} }
else { else {
clipLeft = mCapturedTrack->GetStartTime() + desiredSlideAmount; clipLeft = mCapturedTrack->GetStartTime() + desiredSlideAmount;
@ -3755,9 +3760,9 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
desiredSlideAmount = rint(mtw->GetRate() * desiredSlideAmount) / desiredSlideAmount = rint(mtw->GetRate() * desiredSlideAmount) /
mtw->GetRate(); // set it to a sample point mtw->GetRate(); // set it to a sample point
} }
if (mSnapManager && mCapturedClip) { if (mSnapManager && mClipMoveState.capturedClip) {
clipLeft = mCapturedClip->GetStartTime() + desiredSlideAmount; clipLeft = mClipMoveState.capturedClip->GetStartTime() + desiredSlideAmount;
clipRight = mCapturedClip->GetEndTime() + desiredSlideAmount; clipRight = mClipMoveState.capturedClip->GetEndTime() + desiredSlideAmount;
} }
} }
#endif #endif
@ -3780,17 +3785,19 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
} }
// Take whichever one snapped (if any) and compute the NEW desiredSlideAmount // Take whichever one snapped (if any) and compute the NEW desiredSlideAmount
mSnapLeft = -1; mClipMoveState.snapLeft = -1;
mSnapRight = -1; mClipMoveState.snapRight = -1;
if (newClipLeft != clipLeft) { if (newClipLeft != clipLeft) {
double difference = (newClipLeft - clipLeft); double difference = (newClipLeft - clipLeft);
desiredSlideAmount += difference; desiredSlideAmount += difference;
mSnapLeft = mViewInfo->TimeToPosition(newClipLeft, GetLeftOffset()); mClipMoveState.snapLeft =
mViewInfo->TimeToPosition(newClipLeft, GetLeftOffset());
} }
else if (newClipRight != clipRight) { else if (newClipRight != clipRight) {
double difference = (newClipRight - clipRight); double difference = (newClipRight - clipRight);
desiredSlideAmount += difference; desiredSlideAmount += difference;
mSnapRight = mViewInfo->TimeToPosition(newClipRight, GetLeftOffset()); mClipMoveState.snapRight =
mViewInfo->TimeToPosition(newClipRight, GetLeftOffset());
} }
} }
} }
@ -3801,14 +3808,14 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
// If the mouse is over a track that isn't the captured track, // If the mouse is over a track that isn't the captured track,
// decide which tracks the captured clips should go to. // decide which tracks the captured clips should go to.
if (mCapturedClip && mouseTrack != mCapturedTrack /*&& if ( mClipMoveState.capturedClip && mouseTrack != mCapturedTrack /*&&
!mCapturedClipIsSelection*/) !mCapturedClipIsSelection*/ )
{ {
const int diff = const int diff =
TrackPosition(*mTracks, mouseTrack) - TrackPosition(*mTracks, mouseTrack) -
TrackPosition(*mTracks, mCapturedTrack); TrackPosition(*mTracks, mCapturedTrack);
for (unsigned ii = 0, nn = mCapturedClipArray.size(); ii < nn; ++ii) { for ( unsigned ii = 0, nn = mClipMoveState.capturedClipArray.size(); ii < nn; ++ii ) {
TrackClip &trackClip = mCapturedClipArray[ii]; TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
if (trackClip.clip) { if (trackClip.clip) {
// Move all clips up or down by an equal count of audio tracks. // Move all clips up or down by an equal count of audio tracks.
Track *const pSrcTrack = trackClip.track; Track *const pSrcTrack = trackClip.track;
@ -3833,8 +3840,9 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
// Having passed that test, remove clips temporarily from their // Having passed that test, remove clips temporarily from their
// tracks, so moving clips don't interfere with each other // tracks, so moving clips don't interfere with each other
// when we call CanInsertClip() // when we call CanInsertClip()
for (unsigned ii = 0, nn = mCapturedClipArray.size(); ii < nn; ++ii) { for ( unsigned ii = 0,
TrackClip &trackClip = mCapturedClipArray[ii]; nn = mClipMoveState.capturedClipArray.size(); ii < nn; ++ii ) {
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
WaveClip *const pSrcClip = trackClip.clip; WaveClip *const pSrcClip = trackClip.clip;
if (pSrcClip) if (pSrcClip)
trackClip.holder = trackClip.holder =
@ -3845,8 +3853,9 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
// Now check that the move is possible // Now check that the move is possible
bool ok = true; bool ok = true;
for (unsigned ii = 0, nn = mCapturedClipArray.size(); ok && ii < nn; ++ii) { for ( unsigned ii = 0,
TrackClip &trackClip = mCapturedClipArray[ii]; nn = mClipMoveState.capturedClipArray.size(); ok && ii < nn; ++ii) {
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
WaveClip *const pSrcClip = trackClip.clip; WaveClip *const pSrcClip = trackClip.clip;
if (pSrcClip) if (pSrcClip)
ok = trackClip.dstTrack->CanInsertClip(pSrcClip); ok = trackClip.dstTrack->CanInsertClip(pSrcClip);
@ -3854,8 +3863,9 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
if (!ok) { if (!ok) {
// Failure -- put clips back where they were // Failure -- put clips back where they were
for (unsigned ii = 0, nn = mCapturedClipArray.size(); ii < nn; ++ii) { for ( unsigned ii = 0,
TrackClip &trackClip = mCapturedClipArray[ii]; nn = mClipMoveState.capturedClipArray.size(); ii < nn; ++ii) {
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
WaveClip *const pSrcClip = trackClip.clip; WaveClip *const pSrcClip = trackClip.clip;
if (pSrcClip) if (pSrcClip)
// Assume track is wave because it has a clip // Assume track is wave because it has a clip
@ -3866,8 +3876,9 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
} }
else { else {
// Do the vertical moves of clips // Do the vertical moves of clips
for (unsigned ii = 0, nn = mCapturedClipArray.size(); ii < nn; ++ii) { for ( unsigned ii = 0,
TrackClip &trackClip = mCapturedClipArray[ii]; nn = mClipMoveState.capturedClipArray.size(); ii < nn; ++ii) {
TrackClip &trackClip = mClipMoveState.capturedClipArray[ii];
WaveClip *const pSrcClip = trackClip.clip; WaveClip *const pSrcClip = trackClip.clip;
if (pSrcClip) { if (pSrcClip) {
const auto dstTrack = trackClip.dstTrack; const auto dstTrack = trackClip.dstTrack;
@ -3892,135 +3903,122 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
return; return;
} }
mHSlideAmount = desiredSlideAmount; mClipMoveState.hSlideAmount = desiredSlideAmount;
DoSlideHorizontal(); DoSlideHorizontal( mClipMoveState, *GetTracks(), *mCapturedTrack );
if (mCapturedClipIsSelection) { if ( mClipMoveState.capturedClipIsSelection ) {
// Slide the selection, too // Slide the selection, too
mViewInfo->selectedRegion.move(mHSlideAmount); mViewInfo->selectedRegion.move( mClipMoveState.hSlideAmount );
} }
if (slidVertically) { if (slidVertically) {
// NEW origin // NEW origin
mHSlideAmount = 0; mClipMoveState.hSlideAmount = 0;
} }
Refresh(false); Refresh(false);
} }
void TrackPanel::DoSlideHorizontal() void TrackPanel::DoSlideHorizontal
( ClipMoveState &state, TrackList &trackList, Track &capturedTrack )
{ {
#ifdef USE_MIDI #ifdef USE_MIDI
if (mCapturedClipArray.size()) if ( state.capturedClipArray.size() )
#else #else
if (mCapturedClip) if ( state.capturedClip )
#endif #endif
{ {
double allowed; double allowed;
double initialAllowed; double initialAllowed;
double safeBigDistance = 1000 + 2.0 * (mTracks->GetEndTime() - double safeBigDistance = 1000 + 2.0 * ( trackList.GetEndTime() -
mTracks->GetStartTime()); trackList.GetStartTime() );
do { // loop to compute allowed, does not actually move anything yet do { // loop to compute allowed, does not actually move anything yet
initialAllowed = mHSlideAmount; initialAllowed = state.hSlideAmount;
unsigned int i, j; unsigned int i, j;
for(i=0; i<mCapturedClipArray.size(); i++) { for ( i = 0; i < state.capturedClipArray.size(); ++i ) {
WaveTrack *track = (WaveTrack *)mCapturedClipArray[i].track; WaveTrack *track = (WaveTrack *)state.capturedClipArray[i].track;
WaveClip *clip = mCapturedClipArray[i].clip; WaveClip *clip = state. capturedClipArray[i].clip;
if (clip) { // only audio clips are used to compute allowed if (clip) { // only audio clips are used to compute allowed
// Move all other selected clips totally out of the way // Move all other selected clips totally out of the way
// temporarily because they're all moving together and // temporarily because they're all moving together and
// we want to find out if OTHER clips are in the way, // we want to find out if OTHER clips are in the way,
// not one of the moving ones // not one of the moving ones
for(j=0; j<mCapturedClipArray.size(); j++) { for ( j = 0; j < state.capturedClipArray.size(); j++ ) {
WaveClip *clip2 = mCapturedClipArray[j].clip; WaveClip *clip2 = state.capturedClipArray[j].clip;
if (clip2 && clip2 != clip) if (clip2 && clip2 != clip)
clip2->Offset(-safeBigDistance); clip2->Offset(-safeBigDistance);
} }
if (track->CanOffsetClip(clip, mHSlideAmount, &allowed)) { if ( track->CanOffsetClip(clip, state.hSlideAmount, &allowed) ) {
if (mHSlideAmount != allowed) { if ( state.hSlideAmount != allowed ) {
mHSlideAmount = allowed; state.hSlideAmount = allowed;
mSnapLeft = mSnapRight = -1; // see bug 1067 state.snapLeft = state.snapRight = -1; // see bug 1067
} }
} }
else { else {
mHSlideAmount = 0.0; state.hSlideAmount = 0.0;
mSnapLeft = mSnapRight = -1; // see bug 1067 state.snapLeft = state.snapRight = -1; // see bug 1067
} }
for(j=0; j<mCapturedClipArray.size(); j++) { for ( j = 0; j < state.capturedClipArray.size(); ++j ) {
WaveClip *clip2 = mCapturedClipArray[j].clip; WaveClip *clip2 = state.capturedClipArray[j].clip;
if (clip2 && clip2 != clip) if (clip2 && clip2 != clip)
clip2->Offset(safeBigDistance); clip2->Offset(safeBigDistance);
} }
} }
} }
} while (mHSlideAmount != initialAllowed); } while ( state.hSlideAmount != initialAllowed );
if (mHSlideAmount != 0.0) { // finally, here is where clips are moved if ( state.hSlideAmount != 0.0 ) { // finally, here is where clips are moved
unsigned int i; unsigned int i;
for(i=0; i<mCapturedClipArray.size(); i++) { for ( i = 0; i < state.capturedClipArray.size(); ++i ) {
Track *track = mCapturedClipArray[i].track; Track *track = state.capturedClipArray[i].track;
WaveClip *clip = mCapturedClipArray[i].clip; WaveClip *clip = state.capturedClipArray[i].clip;
if (clip) if (clip)
clip->Offset(mHSlideAmount); clip->Offset( state.hSlideAmount );
else else
track->Offset(mHSlideAmount); track->Offset( state.hSlideAmount );
} }
} }
} }
else { else {
// For Shift key down, or // For Shift key down, or
// For non wavetracks, specifically label tracks ... // For non wavetracks, specifically label tracks ...
mCapturedTrack->Offset(mHSlideAmount); capturedTrack.Offset( state.hSlideAmount );
Track* link = mCapturedTrack->GetLink(); Track* link = capturedTrack.GetLink();
if (link) if (link)
link->Offset(mHSlideAmount); link->Offset( state.hSlideAmount );
} }
} }
void TrackPanel::OnClipMove(bool right, bool keyUp) double TrackPanel::OnClipMove
( ViewInfo &viewInfo, Track *track,
TrackList &trackList, bool syncLocked, bool right )
{ {
if (keyUp) {
if (mHSlideAmountTotal != 0.0) {
wxString message;
message.Printf(wxT("%s %s %.03f %s"),
_("Time shifted clips"),
mHSlideAmountTotal > 0 ?
/* i18n-hint: a direction as in left or right */
_("right") :
/* i18n-hint: a direction as in left or right */
_("left"),
fabs(mHSlideAmountTotal),
_("seconds"));
MakeParentPushState(message, _("Time-Shift"), UndoPush::CONSOLIDATE);
mHSlideAmountTotal = 0.0;
}
return;
}
auto track = GetFocusedTrack();
// just dealing with clips in wave tracks for the moment. Note tracks?? // just dealing with clips in wave tracks for the moment. Note tracks??
if (track && track->GetKind() == Track::Wave) { if (track && track->GetKind() == Track::Wave) {
ClipMoveState state;
auto wt = static_cast<WaveTrack*>(track); auto wt = static_cast<WaveTrack*>(track);
mCapturedClip = wt->GetClipAtTime(mViewInfo->selectedRegion.t0()); auto t0 = viewInfo.selectedRegion.t0();
if (mCapturedClip == nullptr)
state.capturedClip = wt->GetClipAtTime( t0 );
if (state.capturedClip == nullptr)
return; return;
mCapturedTrack = track; state.capturedClipIsSelection =
mCapturedClipIsSelection = track->GetSelected() && !mViewInfo->selectedRegion.isPoint(); track->GetSelected() && !viewInfo.selectedRegion.isPoint();
mTrackExclusions.clear(); state.trackExclusions.clear();
auto t0 = mViewInfo->selectedRegion.t0(); CreateListOfCapturedClips
CreateListOfCapturedClips( t0 ); ( state, viewInfo, *track, trackList, syncLocked, t0 );
auto newT0 = mViewInfo->OffsetTimeByPixels( t0, ( right ? 1 : -1 ) ); auto newT0 = viewInfo.OffsetTimeByPixels( t0, ( right ? 1 : -1 ) );
auto desiredSlideAmount = newT0 - t0; auto desiredSlideAmount = newT0 - t0;
// set it to a sample point, and minimum of 1 sample point // set it to a sample point, and minimum of 1 sample point
@ -4032,26 +4030,23 @@ void TrackPanel::OnClipMove(bool right, bool keyUp)
if (!right) if (!right)
desiredSlideAmount *= -1; desiredSlideAmount *= -1;
mHSlideAmount = desiredSlideAmount; state.hSlideAmount = desiredSlideAmount;
DoSlideHorizontal(); DoSlideHorizontal( state, trackList, *track );
mHSlideAmountTotal += mHSlideAmount;
// update t0 and t1. There is the possibility that the updated // update t0 and t1. There is the possibility that the updated
// t0 may no longer be within the clip due to rounding errors, // t0 may no longer be within the clip due to rounding errors,
// so t0 is adjusted so that it is. // so t0 is adjusted so that it is.
if (newT0 < mCapturedClip->GetStartTime()) if (newT0 < state.capturedClip->GetStartTime())
newT0 = mCapturedClip->GetStartTime(); newT0 = state.capturedClip->GetStartTime();
if (newT0 > mCapturedClip->GetEndTime()) if (newT0 > state.capturedClip->GetEndTime())
newT0 = mCapturedClip->GetEndTime(); newT0 = state.capturedClip->GetEndTime();
double diff = mViewInfo->selectedRegion.duration(); double diff = viewInfo.selectedRegion.duration();
mViewInfo->selectedRegion.setTimes(newT0, newT0 + diff); viewInfo.selectedRegion.setTimes(newT0, newT0 + diff);
ScrollIntoView(mViewInfo->selectedRegion.t0()); return state.hSlideAmount;
Refresh(false);
if (mHSlideAmount == 0.0)
MessageForScreenReader( _("clip not moved"));
} }
return 0.0;
} }
@ -7211,13 +7206,13 @@ void TrackPanel::DrawEverythingElse(wxDC * dc,
} }
// Draw snap guidelines if we have any // Draw snap guidelines if we have any
if (mSnapManager && (mSnapLeft >= 0 || mSnapRight >= 0)) { if ( mSnapManager && ( GetSnapLeft() >= 0 || GetSnapRight() >= 0 )) {
AColor::SnapGuidePen(dc); AColor::SnapGuidePen(dc);
if (mSnapLeft >= 0) { if ( GetSnapLeft() >= 0 ) {
AColor::Line(*dc, (int)mSnapLeft, 0, mSnapLeft, 30000); AColor::Line(*dc, (int)GetSnapLeft(), 0, GetSnapLeft(), 30000);
} }
if (mSnapRight >= 0) { if ( GetSnapRight() >= 0 ) {
AColor::Line(*dc, (int)mSnapRight, 0, mSnapRight, 30000); AColor::Line(*dc, (int)GetSnapRight(), 0, GetSnapRight(), 30000);
} }
} }
} }

View File

@ -155,6 +155,15 @@ private:
const int DragThreshold = 3;// Anything over 3 pixels is a drag, else a click. const int DragThreshold = 3;// Anything over 3 pixels is a drag, else a click.
struct ClipMoveState {
WaveClip *capturedClip {};
bool capturedClipIsSelection {};
TrackArray trackExclusions {};
double hSlideAmount {};
TrackClipArray capturedClipArray {};
wxInt64 snapLeft { -1 }, snapRight { -1 };
};
class AUDACITY_DLL_API TrackPanel final : public OverlayPanel { class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
public: public:
@ -256,7 +265,9 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
// (ignoring any fisheye) // (ignoring any fisheye)
virtual double GetScreenEndTime() const; virtual double GetScreenEndTime() const;
virtual void OnClipMove(bool right, bool keyUp); static double OnClipMove
(ViewInfo &viewInfo, Track *track,
TrackList &trackList, bool syncLocked, bool right);
protected: protected:
virtual MixerBoard* GetMixerBoard(); virtual MixerBoard* GetMixerBoard();
@ -383,10 +394,16 @@ protected:
virtual void HandleSlide(wxMouseEvent & event); virtual void HandleSlide(wxMouseEvent & event);
virtual void StartSlide(wxMouseEvent &event); virtual void StartSlide(wxMouseEvent &event);
virtual void DoSlide(wxMouseEvent &event); virtual void DoSlide(wxMouseEvent &event);
virtual void DoSlideHorizontal(); static void DoSlideHorizontal
virtual void CreateListOfCapturedClips(double clickTime); ( ClipMoveState &state, TrackList &trackList, Track &capturedTrack );
virtual void AddClipsToCaptured(Track *t, bool withinSelection); static void CreateListOfCapturedClips
virtual void AddClipsToCaptured(Track *t, double t0, double t1); ( ClipMoveState &state, const ViewInfo &viewInfo, Track &capturedTrack,
TrackList &trackList, bool syncLocked, double clickTime );
static void AddClipsToCaptured
( ClipMoveState &state, const ViewInfo &viewInfo,
Track *t, bool withinSelection );
static void AddClipsToCaptured
( ClipMoveState &state, Track *t, double t0, double t1 );
// AS: Handle zooming into tracks // AS: Handle zooming into tracks
virtual void HandleZoom(wxMouseEvent & event); virtual void HandleZoom(wxMouseEvent & event);
@ -658,10 +675,7 @@ protected:
Track *mCapturedTrack; Track *mCapturedTrack;
Envelope *mCapturedEnvelope; Envelope *mCapturedEnvelope;
WaveClip *mCapturedClip; ClipMoveState mClipMoveState;
TrackClipArray mCapturedClipArray;
TrackArray mTrackExclusions;
bool mCapturedClipIsSelection;
WaveTrackLocation mCapturedTrackLocation; WaveTrackLocation mCapturedTrackLocation;
wxRect mCapturedTrackLocationRect; wxRect mCapturedTrackLocationRect;
wxRect mCapturedRect; wxRect mCapturedRect;
@ -678,12 +692,6 @@ protected:
wxBaseArrayDouble mSlideSnapToPoints; wxBaseArrayDouble mSlideSnapToPoints;
wxArrayInt mSlideSnapLinePixels; wxArrayInt mSlideSnapLinePixels;
// The amount that clips are sliding horizontally; this allows
// us to undo the slide and then slide it by another amount
double mHSlideAmount;
double mHSlideAmountTotal; // used for sliding horizontally using the keyboard
bool mDidSlideVertically; bool mDidSlideVertically;
bool mRedrawAfterStop; bool mRedrawAfterStop;
@ -704,10 +712,28 @@ protected:
// are the horizontal index of pixels to display user feedback // are the horizontal index of pixels to display user feedback
// guidelines so the user knows when such snapping is taking place. // guidelines so the user knows when such snapping is taking place.
std::unique_ptr<SnapManager> mSnapManager; std::unique_ptr<SnapManager> mSnapManager;
wxInt64 mSnapLeft; wxInt64 mSnapLeft { -1 };
wxInt64 mSnapRight; wxInt64 mSnapRight { -1 };
bool mSnapPreferRightEdge; bool mSnapPreferRightEdge;
public:
wxInt64 GetSnapLeft () const
{
if ( mMouseCapture == IsSliding )
return mClipMoveState.snapLeft ;
else
return mSnapLeft ;
}
wxInt64 GetSnapRight() const
{
if ( mMouseCapture == IsSliding )
return mClipMoveState.snapRight;
else
return mSnapRight;
}
protected:
NumericConverter mConverter; NumericConverter mConverter;
WaveTrack * mDrawingTrack; // Keeps track of which track you are drawing on between events cf. HandleDraw() WaveTrack * mDrawingTrack; // Keeps track of which track you are drawing on between events cf. HandleDraw()