1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-15 15:49:36 +02:00

Lower more into Init(); ClipMenus uses ClipMoveState opaquely

This commit is contained in:
Paul Licameli 2020-09-12 12:49:02 -04:00
parent 00f761eb5e
commit 329221b392
3 changed files with 103 additions and 74 deletions

View File

@ -639,22 +639,25 @@ double DoClipMove
auto t0 = selectedRegion.t0(); auto t0 = selectedRegion.t0();
std::unique_ptr<TrackShifter> uShifter;
// Find the first channel that has a clip at time t0 // Find the first channel that has a clip at time t0
for (auto channel : TrackList::Channels(wt) ) { for (auto channel : TrackList::Channels(wt) ) {
if( nullptr != (state.capturedClip = channel->GetClipAtTime( t0 )) ) { uShifter = MakeTrackShifter::Call( *wt );
if( uShifter->HitTest( t0 ) == TrackShifter::HitTestResult::Miss )
uShifter.reset();
else {
wt = channel; wt = channel;
break; break;
} }
} }
if (state.capturedClip == nullptr) if (!uShifter)
return 0.0; return 0.0;
auto pShifter = uShifter.get();
state.capturedClipIsSelection = state.Init( *track, std::move( uShifter ),
track->GetSelected() && !selectedRegion.isPoint(); t0, viewInfo, trackList, syncLocked );
TimeShiftHandle::Init(
state, viewInfo, *track, trackList, syncLocked, t0 );
auto desiredT0 = viewInfo.OffsetTimeByPixels( t0, ( right ? 1 : -1 ) ); auto desiredT0 = viewInfo.OffsetTimeByPixels( t0, ( right ? 1 : -1 ) );
auto desiredSlideAmount = desiredT0 - t0; auto desiredSlideAmount = desiredT0 - t0;
@ -668,21 +671,26 @@ double DoClipMove
if (!right) if (!right)
desiredSlideAmount *= -1; desiredSlideAmount *= -1;
state.hSlideAmount = desiredSlideAmount; auto hSlideAmount = state.DoSlideHorizontal(
TimeShiftHandle::DoSlideHorizontal( state, trackList, *track ); desiredSlideAmount, trackList, *track );
// 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.
double newT0 = t0 + state.hSlideAmount; double newT0 = t0 + hSlideAmount;
if (newT0 < state.capturedClip->GetStartTime()) // pShifter is still undestroyed in the ClipMoveState
newT0 = state.capturedClip->GetStartTime(); auto &intervals = pShifter->MovingIntervals();
if (newT0 > state.capturedClip->GetEndTime()) if ( !intervals.empty() ) {
newT0 = state.capturedClip->GetEndTime(); auto &interval = intervals[0];
double diff = selectedRegion.duration(); if (newT0 < interval.Start())
selectedRegion.setTimes(newT0, newT0 + diff); newT0 = interval.Start();
if (newT0 > interval.End())
newT0 = interval.End();
double diff = selectedRegion.duration();
selectedRegion.setTimes(newT0, newT0 + diff);
}
return state.hSlideAmount; return hSlideAmount;
} ); } );
return 0.0; return 0.0;
} }

View File

@ -304,19 +304,57 @@ template<> auto MakeTrackShifter::Implementation() -> Function {
}; };
} }
void TimeShiftHandle::Init void ClipMoveState::Init(
( ClipMoveState &state, const ViewInfo &viewInfo, Track &capturedTrack, Track &capturedTrack,
TrackList &trackList, bool syncLocked, double clickTime, std::unique_ptr<TrackShifter> pHit,
bool capturedAClip ) double clickTime,
const ViewInfo &viewInfo,
TrackList &trackList, bool syncLocked )
{ {
capturedClipArray.clear();
shifters.clear();
auto cleanup = finally([&]{
// In transition, this class holds two representations of what to shift.
// Be sure each is filled only if the other is.
wxASSERT( capturedClipArray.empty() == shifters.empty() );
});
auto &state = *this;
state.movingSelection = capturedTrack.IsSelected() &&
clickTime >= viewInfo.selectedRegion.t0() &&
clickTime < viewInfo.selectedRegion.t1();
if (!pHit)
return;
const bool capturedAClip =
pHit && !pHit->MovingIntervals().empty();
if ( capturedAClip ) {
// There is still some code special to WaveTracks here that
// needs to go elsewhere
auto &interval = pHit->MovingIntervals()[0];
auto pInfo =
dynamic_cast<WaveTrack::IntervalData*>(interval.Extra());
if ( pInfo )
state.capturedClip = pInfo->GetClip().get();
}
state.shifters[&capturedTrack] = std::move( pHit );
// Collect TrackShifters for the rest of the tracks
for ( auto track : trackList.Any() ) {
auto &pShifter = state.shifters[track];
if (!pShifter)
pShifter = MakeTrackShifter::Call( *track );
}
// 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...
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 ( state.capturedClipIsSelection ) if ( state.movingSelection )
// All selected tracks may move some intervals // All selected tracks may move some intervals
for (auto t : trackList.Selected()) for (auto t : trackList.Selected())
AddClipsToCaptured( state, viewInfo, t ); AddClipsToCaptured( state, viewInfo, t );
@ -372,7 +410,7 @@ void TimeShiftHandle::Init
// Analogy of the steps above, but with TrackShifters, follows below // Analogy of the steps above, but with TrackShifters, follows below
if ( state.capturedClipIsSelection ) { if ( state.movingSelection ) {
// All selected tracks may move some intervals // All selected tracks may move some intervals
const TrackInterval interval{ const TrackInterval interval{
viewInfo.selectedRegion.t0(), viewInfo.selectedRegion.t0(),
@ -435,9 +473,12 @@ void TimeShiftHandle::Init
} }
} }
void TimeShiftHandle::DoSlideHorizontal double ClipMoveState::DoSlideHorizontal(
( ClipMoveState &state, TrackList &trackList, Track &capturedTrack ) double desiredSlideAmount, TrackList &trackList, Track &capturedTrack )
{ {
auto &state = *this;
state.hSlideAmount = desiredSlideAmount;
// Given a signed slide distance, move clips, but subject to constraint of // Given a signed slide distance, move clips, but subject to constraint of
// non-overlapping with other clips, so the distance may be adjusted toward // non-overlapping with other clips, so the distance may be adjusted toward
// zero. // zero.
@ -486,6 +527,8 @@ void TimeShiftHandle::DoSlideHorizontal
// For Shift key down, or // For Shift key down, or
// For non wavetracks, specifically label tracks ... // For non wavetracks, specifically label tracks ...
DoOffset( state, &capturedTrack, state.hSlideAmount ); DoOffset( state, &capturedTrack, state.hSlideAmount );
return state.hSlideAmount;
} }
namespace { namespace {
@ -536,16 +579,11 @@ UIHandle::Result TimeShiftHandle::Click
const double clickTime = const double clickTime =
viewInfo.PositionToTime(event.m_x, rect.x); viewInfo.PositionToTime(event.m_x, rect.x);
mClipMoveState.capturedClipIsSelection =
(pTrack->GetSelected() &&
clickTime >= viewInfo.selectedRegion.t0() &&
clickTime < viewInfo.selectedRegion.t1());
mClipMoveState.capturedClip = NULL; mClipMoveState.capturedClip = NULL;
mClipMoveState.capturedClipArray.clear(); mClipMoveState.capturedClipArray.clear();
bool captureClips = false; bool captureClips = false;
bool capturedAClip = false;
auto pShifter = MakeTrackShifter::Call( *pTrack ); auto pShifter = MakeTrackShifter::Call( *pTrack );
@ -555,17 +593,6 @@ UIHandle::Result TimeShiftHandle::Click
return Cancelled; return Cancelled;
case TrackShifter::HitTestResult::Intervals: { case TrackShifter::HitTestResult::Intervals: {
captureClips = true; captureClips = true;
if ( !pShifter->MovingIntervals().empty() ) {
capturedAClip = true;
// There is still some code special to WaveTracks here that
// needs to go elsewhere
auto &interval = pShifter->MovingIntervals()[0];
auto pInfo =
dynamic_cast<WaveTrack::IntervalData*>(interval.Extra());
if ( pInfo )
mClipMoveState.capturedClip = pInfo->GetClip().get();
}
break; break;
} }
case TrackShifter::HitTestResult::Track: case TrackShifter::HitTestResult::Track:
@ -577,20 +604,12 @@ UIHandle::Result TimeShiftHandle::Click
// As in the default above: just do shifting of one whole track // As in the default above: just do shifting of one whole track
} }
if ( captureClips ) { mClipMoveState.Init( *pTrack,
mClipMoveState.shifters[pTrack] = std::move( pShifter ); captureClips ? std::move( pShifter ) : nullptr,
clickTime,
// Collect TrackShifters for the rest of the tracks viewInfo, trackList,
for ( auto track : trackList.Any() ) { ProjectSettings::Get( *pProject ).IsSyncLocked() );
auto &pShifter = mClipMoveState.shifters[track];
if (!pShifter)
pShifter = MakeTrackShifter::Call( *track );
}
Init(
mClipMoveState, viewInfo, *pTrack, trackList,
ProjectSettings::Get( *pProject ).IsSyncLocked(), clickTime, capturedAClip );
}
mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive; mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive;
mRect = rect; mRect = rect;
@ -836,7 +855,7 @@ bool TimeShiftHandle::DoSlideVertical
// Make the offset permanent; start from a "clean slate" // Make the offset permanent; start from a "clean slate"
if( ok ) { if( ok ) {
state.mMouseClickX = xx; state.mMouseClickX = xx;
if (state.capturedClipIsSelection) { if (state.movingSelection) {
// Slide the selection, too // Slide the selection, too
viewInfo.selectedRegion.move( slide ); viewInfo.selectedRegion.move( slide );
} }
@ -897,7 +916,7 @@ UIHandle::Result TimeShiftHandle::Drag
DoOffset( DoOffset(
mClipMoveState, mCapturedTrack.get(), -mClipMoveState.hSlideAmount ); mClipMoveState, mCapturedTrack.get(), -mClipMoveState.hSlideAmount );
if ( mClipMoveState.capturedClipIsSelection ) { if ( mClipMoveState.movingSelection ) {
// Slide the selection, too // Slide the selection, too
viewInfo.selectedRegion.move( -mClipMoveState.hSlideAmount ); viewInfo.selectedRegion.move( -mClipMoveState.hSlideAmount );
} }
@ -939,11 +958,10 @@ UIHandle::Result TimeShiftHandle::Drag
if (desiredSlideAmount == 0.0) if (desiredSlideAmount == 0.0)
return RefreshAll; return RefreshAll;
mClipMoveState.hSlideAmount = desiredSlideAmount; mClipMoveState.DoSlideHorizontal(
desiredSlideAmount, trackList, *mCapturedTrack );
DoSlideHorizontal( mClipMoveState, trackList, *mCapturedTrack ); if (mClipMoveState.movingSelection) {
if (mClipMoveState.capturedClipIsSelection) {
// Slide the selection, too // Slide the selection, too
viewInfo.selectedRegion.move( mClipMoveState.hSlideAmount ); viewInfo.selectedRegion.move( mClipMoveState.hSlideAmount );
} }

View File

@ -122,10 +122,23 @@ using TrackClipArray = std::vector <TrackClip>;
struct ClipMoveState { struct ClipMoveState {
using ShifterMap = std::unordered_map<Track*, std::unique_ptr<TrackShifter>>; using ShifterMap = std::unordered_map<Track*, std::unique_ptr<TrackShifter>>;
//! Will associate a TrackShifter with each track in the list
void Init(
Track &capturedTrack, //<! pHit if not null associates with this track
std::unique_ptr<TrackShifter> pHit, /*!<
If null, only capturedTrack (with any sister channels) shifts, as a whole */
double clickTime,
const ViewInfo &viewInfo,
TrackList &trackList, bool syncLocked );
/*! @return actual slide amount, maybe adjusted toward zero from desired */
double DoSlideHorizontal(
double desiredSlideAmount, TrackList &trackList, Track &capturedTrack );
// non-NULL only if click was in a WaveTrack and without Shift key: // non-NULL only if click was in a WaveTrack and without Shift key:
WaveClip *capturedClip {}; WaveClip *capturedClip {};
bool capturedClipIsSelection {}; bool movingSelection {};
double hSlideAmount {}; double hSlideAmount {};
ShifterMap shifters; ShifterMap shifters;
TrackClipArray capturedClipArray {}; TrackClipArray capturedClipArray {};
@ -136,7 +149,7 @@ struct ClipMoveState {
void clear() void clear()
{ {
capturedClip = nullptr; capturedClip = nullptr;
capturedClipIsSelection = false; movingSelection = false;
hSlideAmount = 0; hSlideAmount = 0;
shifters.clear(); shifters.clear();
capturedClipArray.clear(); capturedClipArray.clear();
@ -160,16 +173,6 @@ public:
bool IsGripHit() const { return mGripHit; } bool IsGripHit() const { return mGripHit; }
std::shared_ptr<Track> GetTrack() const { return mCapturedTrack; } std::shared_ptr<Track> GetTrack() const { return mCapturedTrack; }
// A utility function also used by menu commands
static void Init
( ClipMoveState &state, const ViewInfo &viewInfo, Track &capturedTrack,
TrackList &trackList, bool syncLocked, double clickTime,
bool capturedAClip = true );
// A utility function also used by menu commands
static void DoSlideHorizontal
( ClipMoveState &state, TrackList &trackList, Track &capturedTrack );
// Try to move clips from one WaveTrack to another, before also moving // Try to move clips from one WaveTrack to another, before also moving
// by some horizontal amount, which may be slightly adjusted to fit the // by some horizontal amount, which may be slightly adjusted to fit the
// destination tracks. // destination tracks.