More control over HitTest behavior moved into the Track Shifter classes

This commit is contained in:
Paul Licameli 2020-09-19 23:56:12 -04:00
parent f204ee3192
commit 6e0b5b690a
5 changed files with 57 additions and 34 deletions

View File

@ -641,9 +641,10 @@ double DoClipMove( AudacityProject &project, Track *track,
std::unique_ptr<TrackShifter> uShifter;
// Find the first channel that has a clip at time t0
auto hitTestResult = TrackShifter::HitTestResult::Track;
for (auto channel : TrackList::Channels(track) ) {
uShifter = MakeTrackShifter::Call( *track, project );
if ( uShifter->HitTest( t0, viewInfo ) ==
if ( (hitTestResult = uShifter->HitTest( t0, viewInfo )) ==
TrackShifter::HitTestResult::Miss )
uShifter.reset();
else
@ -654,7 +655,7 @@ double DoClipMove( AudacityProject &project, Track *track,
return 0.0;
auto pShifter = uShifter.get();
state.Init( project, *track, std::move( uShifter ),
state.Init( project, *track, hitTestResult, std::move( uShifter ),
t0, viewInfo, trackList, syncLocked );
auto desiredT0 = viewInfo.OffsetTimeByPixels( t0, ( right ? 1 : -1 ) );

View File

@ -742,9 +742,16 @@ public:
~NoteTrackShifter() override {}
Track &GetTrack() const override { return *mpTrack; }
HitTestResult HitTest( double, const ViewInfo&, HitTestParams* ) override
HitTestResult HitTest(
double time, const ViewInfo &viewInfo, HitTestParams* ) override
{
return HitTestResult::Intervals;
UnfixAll();
auto t0 = viewInfo.selectedRegion.t0();
auto t1 = viewInfo.selectedRegion.t1();
if ( mpTrack->IsSelected() && time >= t0 && time < t1 )
return HitTestResult::Selection;
else
return HitTestResult::Intervals;
}
void SelectInterval( const TrackInterval &interval ) override

View File

@ -1315,14 +1315,22 @@ public:
Track &GetTrack() const override { return *mpTrack; }
HitTestResult HitTest(
double time, const ViewInfo&, HitTestParams* ) override
double time, const ViewInfo &viewInfo, HitTestParams* ) override
{
auto pClip = mpTrack->GetClipAtTime( time );
if (!pClip)
return HitTestResult::Miss;
// Make a side-effect on our intervals
auto t0 = viewInfo.selectedRegion.t0();
auto t1 = viewInfo.selectedRegion.t1();
if ( mpTrack->IsSelected() && time >= t0 && time < t1 ) {
// Unfix maybe many intervals (at least one because of test above)
SelectInterval({t0, t1});
return HitTestResult::Selection;
}
// Select just one interval
UnfixIntervals( [&](const auto &interval){
return
static_cast<WaveTrack::IntervalData*>(interval.Extra())

View File

@ -261,6 +261,7 @@ template<> auto MakeTrackShifter::Implementation() -> Function {
void ClipMoveState::Init(
AudacityProject &project,
Track &capturedTrack,
TrackShifter::HitTestResult hitTestResult,
std::unique_ptr<TrackShifter> pHit,
double clickTime,
const ViewInfo &viewInfo,
@ -271,16 +272,26 @@ void ClipMoveState::Init(
auto &state = *this;
state.mCapturedTrack = capturedTrack.SharedPointer();
state.movingSelection = capturedTrack.IsSelected() &&
clickTime >= viewInfo.selectedRegion.t0() &&
clickTime < viewInfo.selectedRegion.t1();
switch (hitTestResult) {
case TrackShifter::HitTestResult::Miss:
wxASSERT(false);
pHit.reset();
break;
case TrackShifter::HitTestResult::Track:
pHit.reset();
break;
case TrackShifter::HitTestResult::Intervals:
break;
case TrackShifter::HitTestResult::Selection:
state.movingSelection = true;
break;
default:
break;
}
if (!pHit)
return;
const bool capturedAClip =
pHit && !pHit->MovingIntervals().empty();
state.shifters[&capturedTrack] = std::move( pHit );
// Collect TrackShifters for the rest of the tracks
@ -290,8 +301,6 @@ void ClipMoveState::Init(
pShifter = MakeTrackShifter::Call( *track, project );
}
// Analogy of the steps above, but with TrackShifters, follows below
if ( state.movingSelection ) {
// All selected tracks may move some intervals
const TrackInterval interval{
@ -301,6 +310,9 @@ void ClipMoveState::Init(
for ( const auto &pair : state.shifters ) {
auto &shifter = *pair.second;
auto &track = shifter.GetTrack();
if (&track == &capturedTrack)
// Don't change the choice of intervals made by HitTest
continue;
if ( track.IsSelected() )
shifter.SelectInterval( interval );
}
@ -309,12 +321,8 @@ void ClipMoveState::Init(
// Move intervals only of the chosen channel group
for ( auto channel : TrackList::Channels( &capturedTrack ) ) {
auto &shifter = *state.shifters[channel];
if ( capturedAClip ) {
if ( channel != &capturedTrack )
shifter.SelectInterval(TrackInterval{clickTime, clickTime});
}
else
shifter.UnfixAll();
if ( channel != &capturedTrack )
shifter.SelectInterval(TrackInterval{clickTime, clickTime});
}
}
@ -459,32 +467,28 @@ UIHandle::Result TimeShiftHandle::Click
const double clickTime =
viewInfo.PositionToTime(event.m_x, rect.x);
bool captureClips = false;
auto pShifter = MakeTrackShifter::Call( *pTrack, *pProject );
auto hitTestResult = TrackShifter::HitTestResult::Track;
if (!event.ShiftDown()) {
TrackShifter::HitTestParams params{
rect, event.m_x, event.m_y
};
switch( pShifter->HitTest( clickTime, viewInfo, &params ) ) {
hitTestResult = pShifter->HitTest( clickTime, viewInfo, &params );
switch( hitTestResult ) {
case TrackShifter::HitTestResult::Miss:
return Cancelled;
case TrackShifter::HitTestResult::Intervals: {
captureClips = true;
break;
}
case TrackShifter::HitTestResult::Track:
default:
break;
}
}
else {
// As in the default above: just do shifting of one whole track
// just do shifting of one whole track
}
mClipMoveState.Init( *pProject, *pTrack,
captureClips ? std::move( pShifter ) : nullptr,
hitTestResult,
std::move( pShifter ),
clickTime,
viewInfo, trackList,

View File

@ -37,8 +37,9 @@ public:
//! Possibilities for HitTest on the clicked track
enum class HitTestResult {
Miss, //!< Don't shift anything
Intervals, //<! May shift other tracks' intervals, if clicked in selection
Track //<! Shift selected track only as a whole
Selection, //!< Shfit chosen intervals of this track; may shift other tracks' intervals
Intervals, //!< Shift intervals only of selected track and sister channels
Track //!< Shift selected track and sister channels only, as a whole
};
//! Optional, more complete information for hit testing
@ -48,7 +49,8 @@ public:
};
//! Decide how shift behaves, based on the track that is clicked in
/*! If the return value is Intervals, then some intervals may be marked moving as a side effect */
/*! If the return value is Intervals or Selection,
then some intervals may be marked moving as a side effect */
/*!
@pre `!pParams || (time == pParams->viewInfo.PositionToTime(pParams->xx, pParams->rect.x))`
*/
@ -195,8 +197,9 @@ struct ClipMoveState {
void Init(
AudacityProject &project,
Track &capturedTrack, //<! pHit if not null associates with this track
TrackShifter::HitTestResult hitTestResult, //!< must not be `Miss`
std::unique_ptr<TrackShifter> pHit, /*!<
If null, only capturedTrack (with any sister channels) shifts, as a whole */
If null, implies `Track`, overriding previous argument */
double clickTime,
const ViewInfo &viewInfo,
TrackList &trackList, bool syncLocked );