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

Some last changes to TimeShiftHandle anticipating LabelTrack needs

This commit is contained in:
Paul Licameli 2020-09-20 00:33:28 -04:00
commit 583d347ae0
5 changed files with 94 additions and 48 deletions

View File

@ -627,10 +627,10 @@ void DoCursorClipBoundary
}
// This function returns the amount moved. Possibly 0.0.
double DoClipMove
( ViewInfo &viewInfo, Track *track,
double DoClipMove( AudacityProject &project, Track *track,
TrackList &trackList, bool syncLocked, bool right )
{
auto &viewInfo = ViewInfo::Get(project);
auto &selectedRegion = viewInfo.selectedRegion;
if (track) {
@ -641,9 +641,11 @@ double DoClipMove
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 );
if( uShifter->HitTest( t0 ) == TrackShifter::HitTestResult::Miss )
uShifter = MakeTrackShifter::Call( *track, project );
if ( (hitTestResult = uShifter->HitTest( t0, viewInfo )) ==
TrackShifter::HitTestResult::Miss )
uShifter.reset();
else
break;
@ -653,7 +655,7 @@ double DoClipMove
return 0.0;
auto pShifter = uShifter.get();
state.Init( *track, std::move( uShifter ),
state.Init( project, *track, hitTestResult, std::move( uShifter ),
t0, viewInfo, trackList, syncLocked );
auto desiredT0 = viewInfo.OffsetTimeByPixels( t0, ( right ? 1 : -1 ) );
@ -700,7 +702,7 @@ void DoClipLeftOrRight
auto &tracks = TrackList::Get( project );
auto isSyncLocked = settings.IsSyncLocked();
auto amount = DoClipMove( viewInfo, trackFocus.Get(),
auto amount = DoClipMove( project, trackFocus.Get(),
tracks, isSyncLocked, right );
window.ScrollIntoView(selectedRegion.t0());

View File

@ -742,9 +742,16 @@ public:
~NoteTrackShifter() override {}
Track &GetTrack() const override { return *mpTrack; }
HitTestResult HitTest( double ) 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
@ -760,7 +767,7 @@ private:
using MakeNoteTrackShifter = MakeTrackShifter::Override<NoteTrack>;
template<> template<> auto MakeNoteTrackShifter::Implementation() -> Function {
return [](NoteTrack &track) {
return [](NoteTrack &track, AudacityProject&) {
return std::make_unique<NoteTrackShifter>(track);
};
}

View File

@ -1314,14 +1314,23 @@ public:
~WaveTrackShifter() override {}
Track &GetTrack() const override { return *mpTrack; }
HitTestResult HitTest( double time ) override
HitTestResult HitTest(
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())
@ -1458,7 +1467,7 @@ private:
using MakeWaveTrackShifter = MakeTrackShifter::Override<WaveTrack>;
template<> template<> auto MakeWaveTrackShifter::Implementation() -> Function {
return [](WaveTrack &track) {
return [](WaveTrack &track, AudacityProject&) {
return std::make_unique<WaveTrackShifter>(track);
};
}

View File

@ -241,7 +241,8 @@ CoarseTrackShifter::CoarseTrackShifter( Track &track )
CoarseTrackShifter::~CoarseTrackShifter() = default;
auto CoarseTrackShifter::HitTest( double ) -> HitTestResult
auto CoarseTrackShifter::HitTest(
double, const ViewInfo&, HitTestParams* ) -> HitTestResult
{
return HitTestResult::Track;
}
@ -252,13 +253,15 @@ bool CoarseTrackShifter::SyncLocks()
}
template<> auto MakeTrackShifter::Implementation() -> Function {
return [](Track &track) {
return [](Track &track, AudacityProject&) {
return std::make_unique<CoarseTrackShifter>(track);
};
}
void ClipMoveState::Init(
AudacityProject &project,
Track &capturedTrack,
TrackShifter::HitTestResult hitTestResult,
std::unique_ptr<TrackShifter> pHit,
double clickTime,
const ViewInfo &viewInfo,
@ -269,27 +272,35 @@ 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
for ( auto track : trackList.Any() ) {
auto &pShifter = state.shifters[track];
if (!pShifter)
pShifter = MakeTrackShifter::Call( *track );
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{
@ -299,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 );
}
@ -307,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});
}
}
@ -457,29 +467,28 @@ UIHandle::Result TimeShiftHandle::Click
const double clickTime =
viewInfo.PositionToTime(event.m_x, rect.x);
bool captureClips = false;
auto pShifter = MakeTrackShifter::Call( *pTrack );
auto pShifter = MakeTrackShifter::Call( *pTrack, *pProject );
auto hitTestResult = TrackShifter::HitTestResult::Track;
if (!event.ShiftDown()) {
switch( pShifter->HitTest( clickTime ) ) {
TrackShifter::HitTestParams params{
rect, event.m_x, event.m_y
};
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( *pTrack,
captureClips ? std::move( pShifter ) : nullptr,
mClipMoveState.Init( *pProject, *pTrack,
hitTestResult,
std::move( pShifter ),
clickTime,
viewInfo, trackList,

View File

@ -25,6 +25,8 @@ class TrackList;
class Track;
class TrackInterval;
class ViewInfo;
//! Abstract base class for policies to manipulate a track type with the Time Shift tool
class TrackShifter {
public:
@ -35,13 +37,28 @@ 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
struct HitTestParams {
wxRect rect;
wxCoord xx, yy;
};
//! 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 */
virtual HitTestResult HitTest( double time ) = 0;
/*! 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))`
*/
virtual HitTestResult HitTest(
double time, //!< A time value to test
const ViewInfo &viewInfo,
HitTestParams *pParams = nullptr //!< Optional extra information
) = 0;
using Intervals = std::vector<TrackInterval>;
@ -158,7 +175,7 @@ public:
~CoarseTrackShifter() override;
Track &GetTrack() const override { return *mpTrack; }
HitTestResult HitTest( double ) override;
HitTestResult HitTest( double, const ViewInfo&, HitTestParams* ) override;
//! Returns false
bool SyncLocks() override;
@ -169,7 +186,7 @@ private:
struct MakeTrackShifterTag;
using MakeTrackShifter = AttachedVirtualFunction<
MakeTrackShifterTag, std::unique_ptr<TrackShifter>, Track>;
MakeTrackShifterTag, std::unique_ptr<TrackShifter>, Track, AudacityProject&>;
class ViewInfo;
@ -178,9 +195,11 @@ struct ClipMoveState {
//! Will associate a TrackShifter with each track in the list
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 );