1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-15 23:59:37 +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();
std::unique_ptr<TrackShifter> uShifter;
// Find the first channel that has a clip at time t0
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;
break;
}
}
if (state.capturedClip == nullptr)
if (!uShifter)
return 0.0;
auto pShifter = uShifter.get();
state.capturedClipIsSelection =
track->GetSelected() && !selectedRegion.isPoint();
TimeShiftHandle::Init(
state, viewInfo, *track, trackList, syncLocked, t0 );
state.Init( *track, std::move( uShifter ),
t0, viewInfo, trackList, syncLocked );
auto desiredT0 = viewInfo.OffsetTimeByPixels( t0, ( right ? 1 : -1 ) );
auto desiredSlideAmount = desiredT0 - t0;
@ -668,21 +671,26 @@ double DoClipMove
if (!right)
desiredSlideAmount *= -1;
state.hSlideAmount = desiredSlideAmount;
TimeShiftHandle::DoSlideHorizontal( state, trackList, *track );
auto hSlideAmount = state.DoSlideHorizontal(
desiredSlideAmount, trackList, *track );
// update t0 and t1. There is the possibility that the updated
// t0 may no longer be within the clip due to rounding errors,
// so t0 is adjusted so that it is.
double newT0 = t0 + state.hSlideAmount;
if (newT0 < state.capturedClip->GetStartTime())
newT0 = state.capturedClip->GetStartTime();
if (newT0 > state.capturedClip->GetEndTime())
newT0 = state.capturedClip->GetEndTime();
double diff = selectedRegion.duration();
selectedRegion.setTimes(newT0, newT0 + diff);
double newT0 = t0 + hSlideAmount;
// pShifter is still undestroyed in the ClipMoveState
auto &intervals = pShifter->MovingIntervals();
if ( !intervals.empty() ) {
auto &interval = intervals[0];
if (newT0 < interval.Start())
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;
}

View File

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

View File

@ -122,10 +122,23 @@ using TrackClipArray = std::vector <TrackClip>;
struct ClipMoveState {
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:
WaveClip *capturedClip {};
bool capturedClipIsSelection {};
bool movingSelection {};
double hSlideAmount {};
ShifterMap shifters;
TrackClipArray capturedClipArray {};
@ -136,7 +149,7 @@ struct ClipMoveState {
void clear()
{
capturedClip = nullptr;
capturedClipIsSelection = false;
movingSelection = false;
hSlideAmount = 0;
shifters.clear();
capturedClipArray.clear();
@ -160,16 +173,6 @@ public:
bool IsGripHit() const { return mGripHit; }
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
// by some horizontal amount, which may be slightly adjusted to fit the
// destination tracks.