mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-17 00:20:06 +02:00
Some last changes to TimeShiftHandle anticipating LabelTrack needs
This commit is contained in:
commit
583d347ae0
@ -627,10 +627,10 @@ void DoCursorClipBoundary
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This function returns the amount moved. Possibly 0.0.
|
// This function returns the amount moved. Possibly 0.0.
|
||||||
double DoClipMove
|
double DoClipMove( AudacityProject &project, Track *track,
|
||||||
( ViewInfo &viewInfo, Track *track,
|
|
||||||
TrackList &trackList, bool syncLocked, bool right )
|
TrackList &trackList, bool syncLocked, bool right )
|
||||||
{
|
{
|
||||||
|
auto &viewInfo = ViewInfo::Get(project);
|
||||||
auto &selectedRegion = viewInfo.selectedRegion;
|
auto &selectedRegion = viewInfo.selectedRegion;
|
||||||
|
|
||||||
if (track) {
|
if (track) {
|
||||||
@ -641,9 +641,11 @@ double DoClipMove
|
|||||||
std::unique_ptr<TrackShifter> uShifter;
|
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
|
||||||
|
auto hitTestResult = TrackShifter::HitTestResult::Track;
|
||||||
for (auto channel : TrackList::Channels(track) ) {
|
for (auto channel : TrackList::Channels(track) ) {
|
||||||
uShifter = MakeTrackShifter::Call( *track );
|
uShifter = MakeTrackShifter::Call( *track, project );
|
||||||
if( uShifter->HitTest( t0 ) == TrackShifter::HitTestResult::Miss )
|
if ( (hitTestResult = uShifter->HitTest( t0, viewInfo )) ==
|
||||||
|
TrackShifter::HitTestResult::Miss )
|
||||||
uShifter.reset();
|
uShifter.reset();
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
@ -653,7 +655,7 @@ double DoClipMove
|
|||||||
return 0.0;
|
return 0.0;
|
||||||
auto pShifter = uShifter.get();
|
auto pShifter = uShifter.get();
|
||||||
|
|
||||||
state.Init( *track, std::move( uShifter ),
|
state.Init( project, *track, hitTestResult, std::move( uShifter ),
|
||||||
t0, viewInfo, trackList, syncLocked );
|
t0, viewInfo, trackList, syncLocked );
|
||||||
|
|
||||||
auto desiredT0 = viewInfo.OffsetTimeByPixels( t0, ( right ? 1 : -1 ) );
|
auto desiredT0 = viewInfo.OffsetTimeByPixels( t0, ( right ? 1 : -1 ) );
|
||||||
@ -700,7 +702,7 @@ void DoClipLeftOrRight
|
|||||||
auto &tracks = TrackList::Get( project );
|
auto &tracks = TrackList::Get( project );
|
||||||
auto isSyncLocked = settings.IsSyncLocked();
|
auto isSyncLocked = settings.IsSyncLocked();
|
||||||
|
|
||||||
auto amount = DoClipMove( viewInfo, trackFocus.Get(),
|
auto amount = DoClipMove( project, trackFocus.Get(),
|
||||||
tracks, isSyncLocked, right );
|
tracks, isSyncLocked, right );
|
||||||
|
|
||||||
window.ScrollIntoView(selectedRegion.t0());
|
window.ScrollIntoView(selectedRegion.t0());
|
||||||
|
@ -742,8 +742,15 @@ public:
|
|||||||
~NoteTrackShifter() override {}
|
~NoteTrackShifter() override {}
|
||||||
Track &GetTrack() const override { return *mpTrack; }
|
Track &GetTrack() const override { return *mpTrack; }
|
||||||
|
|
||||||
HitTestResult HitTest( double ) override
|
HitTestResult HitTest(
|
||||||
|
double time, const ViewInfo &viewInfo, HitTestParams* ) override
|
||||||
{
|
{
|
||||||
|
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;
|
return HitTestResult::Intervals;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -760,7 +767,7 @@ private:
|
|||||||
|
|
||||||
using MakeNoteTrackShifter = MakeTrackShifter::Override<NoteTrack>;
|
using MakeNoteTrackShifter = MakeTrackShifter::Override<NoteTrack>;
|
||||||
template<> template<> auto MakeNoteTrackShifter::Implementation() -> Function {
|
template<> template<> auto MakeNoteTrackShifter::Implementation() -> Function {
|
||||||
return [](NoteTrack &track) {
|
return [](NoteTrack &track, AudacityProject&) {
|
||||||
return std::make_unique<NoteTrackShifter>(track);
|
return std::make_unique<NoteTrackShifter>(track);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1314,14 +1314,23 @@ public:
|
|||||||
~WaveTrackShifter() override {}
|
~WaveTrackShifter() override {}
|
||||||
Track &GetTrack() const override { return *mpTrack; }
|
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 );
|
auto pClip = mpTrack->GetClipAtTime( time );
|
||||||
|
|
||||||
if (!pClip)
|
if (!pClip)
|
||||||
return HitTestResult::Miss;
|
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){
|
UnfixIntervals( [&](const auto &interval){
|
||||||
return
|
return
|
||||||
static_cast<WaveTrack::IntervalData*>(interval.Extra())
|
static_cast<WaveTrack::IntervalData*>(interval.Extra())
|
||||||
@ -1458,7 +1467,7 @@ private:
|
|||||||
|
|
||||||
using MakeWaveTrackShifter = MakeTrackShifter::Override<WaveTrack>;
|
using MakeWaveTrackShifter = MakeTrackShifter::Override<WaveTrack>;
|
||||||
template<> template<> auto MakeWaveTrackShifter::Implementation() -> Function {
|
template<> template<> auto MakeWaveTrackShifter::Implementation() -> Function {
|
||||||
return [](WaveTrack &track) {
|
return [](WaveTrack &track, AudacityProject&) {
|
||||||
return std::make_unique<WaveTrackShifter>(track);
|
return std::make_unique<WaveTrackShifter>(track);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,8 @@ CoarseTrackShifter::CoarseTrackShifter( Track &track )
|
|||||||
|
|
||||||
CoarseTrackShifter::~CoarseTrackShifter() = default;
|
CoarseTrackShifter::~CoarseTrackShifter() = default;
|
||||||
|
|
||||||
auto CoarseTrackShifter::HitTest( double ) -> HitTestResult
|
auto CoarseTrackShifter::HitTest(
|
||||||
|
double, const ViewInfo&, HitTestParams* ) -> HitTestResult
|
||||||
{
|
{
|
||||||
return HitTestResult::Track;
|
return HitTestResult::Track;
|
||||||
}
|
}
|
||||||
@ -252,13 +253,15 @@ bool CoarseTrackShifter::SyncLocks()
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<> auto MakeTrackShifter::Implementation() -> Function {
|
template<> auto MakeTrackShifter::Implementation() -> Function {
|
||||||
return [](Track &track) {
|
return [](Track &track, AudacityProject&) {
|
||||||
return std::make_unique<CoarseTrackShifter>(track);
|
return std::make_unique<CoarseTrackShifter>(track);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClipMoveState::Init(
|
void ClipMoveState::Init(
|
||||||
|
AudacityProject &project,
|
||||||
Track &capturedTrack,
|
Track &capturedTrack,
|
||||||
|
TrackShifter::HitTestResult hitTestResult,
|
||||||
std::unique_ptr<TrackShifter> pHit,
|
std::unique_ptr<TrackShifter> pHit,
|
||||||
double clickTime,
|
double clickTime,
|
||||||
const ViewInfo &viewInfo,
|
const ViewInfo &viewInfo,
|
||||||
@ -269,27 +272,35 @@ void ClipMoveState::Init(
|
|||||||
auto &state = *this;
|
auto &state = *this;
|
||||||
state.mCapturedTrack = capturedTrack.SharedPointer();
|
state.mCapturedTrack = capturedTrack.SharedPointer();
|
||||||
|
|
||||||
state.movingSelection = capturedTrack.IsSelected() &&
|
switch (hitTestResult) {
|
||||||
clickTime >= viewInfo.selectedRegion.t0() &&
|
case TrackShifter::HitTestResult::Miss:
|
||||||
clickTime < viewInfo.selectedRegion.t1();
|
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)
|
if (!pHit)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const bool capturedAClip =
|
|
||||||
pHit && !pHit->MovingIntervals().empty();
|
|
||||||
|
|
||||||
state.shifters[&capturedTrack] = std::move( pHit );
|
state.shifters[&capturedTrack] = std::move( pHit );
|
||||||
|
|
||||||
// Collect TrackShifters for the rest of the tracks
|
// Collect TrackShifters for the rest of the tracks
|
||||||
for ( auto track : trackList.Any() ) {
|
for ( auto track : trackList.Any() ) {
|
||||||
auto &pShifter = state.shifters[track];
|
auto &pShifter = state.shifters[track];
|
||||||
if (!pShifter)
|
if (!pShifter)
|
||||||
pShifter = MakeTrackShifter::Call( *track );
|
pShifter = MakeTrackShifter::Call( *track, project );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Analogy of the steps above, but with TrackShifters, follows below
|
|
||||||
|
|
||||||
if ( state.movingSelection ) {
|
if ( state.movingSelection ) {
|
||||||
// All selected tracks may move some intervals
|
// All selected tracks may move some intervals
|
||||||
const TrackInterval interval{
|
const TrackInterval interval{
|
||||||
@ -299,6 +310,9 @@ void ClipMoveState::Init(
|
|||||||
for ( const auto &pair : state.shifters ) {
|
for ( const auto &pair : state.shifters ) {
|
||||||
auto &shifter = *pair.second;
|
auto &shifter = *pair.second;
|
||||||
auto &track = shifter.GetTrack();
|
auto &track = shifter.GetTrack();
|
||||||
|
if (&track == &capturedTrack)
|
||||||
|
// Don't change the choice of intervals made by HitTest
|
||||||
|
continue;
|
||||||
if ( track.IsSelected() )
|
if ( track.IsSelected() )
|
||||||
shifter.SelectInterval( interval );
|
shifter.SelectInterval( interval );
|
||||||
}
|
}
|
||||||
@ -307,13 +321,9 @@ void ClipMoveState::Init(
|
|||||||
// Move intervals only of the chosen channel group
|
// Move intervals only of the chosen channel group
|
||||||
for ( auto channel : TrackList::Channels( &capturedTrack ) ) {
|
for ( auto channel : TrackList::Channels( &capturedTrack ) ) {
|
||||||
auto &shifter = *state.shifters[channel];
|
auto &shifter = *state.shifters[channel];
|
||||||
if ( capturedAClip ) {
|
|
||||||
if ( channel != &capturedTrack )
|
if ( channel != &capturedTrack )
|
||||||
shifter.SelectInterval(TrackInterval{clickTime, clickTime});
|
shifter.SelectInterval(TrackInterval{clickTime, clickTime});
|
||||||
}
|
}
|
||||||
else
|
|
||||||
shifter.UnfixAll();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync lock propagation of unfixing of intervals
|
// Sync lock propagation of unfixing of intervals
|
||||||
@ -457,29 +467,28 @@ UIHandle::Result TimeShiftHandle::Click
|
|||||||
const double clickTime =
|
const double clickTime =
|
||||||
viewInfo.PositionToTime(event.m_x, rect.x);
|
viewInfo.PositionToTime(event.m_x, rect.x);
|
||||||
|
|
||||||
bool captureClips = false;
|
auto pShifter = MakeTrackShifter::Call( *pTrack, *pProject );
|
||||||
|
|
||||||
auto pShifter = MakeTrackShifter::Call( *pTrack );
|
|
||||||
|
|
||||||
|
auto hitTestResult = TrackShifter::HitTestResult::Track;
|
||||||
if (!event.ShiftDown()) {
|
if (!event.ShiftDown()) {
|
||||||
switch( pShifter->HitTest( clickTime ) ) {
|
TrackShifter::HitTestParams params{
|
||||||
|
rect, event.m_x, event.m_y
|
||||||
|
};
|
||||||
|
hitTestResult = pShifter->HitTest( clickTime, viewInfo, ¶ms );
|
||||||
|
switch( hitTestResult ) {
|
||||||
case TrackShifter::HitTestResult::Miss:
|
case TrackShifter::HitTestResult::Miss:
|
||||||
return Cancelled;
|
return Cancelled;
|
||||||
case TrackShifter::HitTestResult::Intervals: {
|
|
||||||
captureClips = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TrackShifter::HitTestResult::Track:
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// As in the default above: just do shifting of one whole track
|
// just do shifting of one whole track
|
||||||
}
|
}
|
||||||
|
|
||||||
mClipMoveState.Init( *pTrack,
|
mClipMoveState.Init( *pProject, *pTrack,
|
||||||
captureClips ? std::move( pShifter ) : nullptr,
|
hitTestResult,
|
||||||
|
std::move( pShifter ),
|
||||||
clickTime,
|
clickTime,
|
||||||
|
|
||||||
viewInfo, trackList,
|
viewInfo, trackList,
|
||||||
|
@ -25,6 +25,8 @@ class TrackList;
|
|||||||
class Track;
|
class Track;
|
||||||
class TrackInterval;
|
class TrackInterval;
|
||||||
|
|
||||||
|
class ViewInfo;
|
||||||
|
|
||||||
//! Abstract base class for policies to manipulate a track type with the Time Shift tool
|
//! Abstract base class for policies to manipulate a track type with the Time Shift tool
|
||||||
class TrackShifter {
|
class TrackShifter {
|
||||||
public:
|
public:
|
||||||
@ -35,13 +37,28 @@ public:
|
|||||||
//! Possibilities for HitTest on the clicked track
|
//! Possibilities for HitTest on the clicked track
|
||||||
enum class HitTestResult {
|
enum class HitTestResult {
|
||||||
Miss, //!< Don't shift anything
|
Miss, //!< Don't shift anything
|
||||||
Intervals, //<! May shift other tracks' intervals, if clicked in selection
|
Selection, //!< Shfit chosen intervals of this track; may shift other tracks' intervals
|
||||||
Track //<! Shift selected track only as a whole
|
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
|
//! 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,
|
||||||
virtual HitTestResult HitTest( double time ) = 0;
|
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>;
|
using Intervals = std::vector<TrackInterval>;
|
||||||
|
|
||||||
@ -158,7 +175,7 @@ public:
|
|||||||
~CoarseTrackShifter() override;
|
~CoarseTrackShifter() override;
|
||||||
Track &GetTrack() const override { return *mpTrack; }
|
Track &GetTrack() const override { return *mpTrack; }
|
||||||
|
|
||||||
HitTestResult HitTest( double ) override;
|
HitTestResult HitTest( double, const ViewInfo&, HitTestParams* ) override;
|
||||||
|
|
||||||
//! Returns false
|
//! Returns false
|
||||||
bool SyncLocks() override;
|
bool SyncLocks() override;
|
||||||
@ -169,7 +186,7 @@ private:
|
|||||||
|
|
||||||
struct MakeTrackShifterTag;
|
struct MakeTrackShifterTag;
|
||||||
using MakeTrackShifter = AttachedVirtualFunction<
|
using MakeTrackShifter = AttachedVirtualFunction<
|
||||||
MakeTrackShifterTag, std::unique_ptr<TrackShifter>, Track>;
|
MakeTrackShifterTag, std::unique_ptr<TrackShifter>, Track, AudacityProject&>;
|
||||||
|
|
||||||
class ViewInfo;
|
class ViewInfo;
|
||||||
|
|
||||||
@ -178,9 +195,11 @@ struct ClipMoveState {
|
|||||||
|
|
||||||
//! Will associate a TrackShifter with each track in the list
|
//! Will associate a TrackShifter with each track in the list
|
||||||
void Init(
|
void Init(
|
||||||
|
AudacityProject &project,
|
||||||
Track &capturedTrack, //<! pHit if not null associates with this track
|
Track &capturedTrack, //<! pHit if not null associates with this track
|
||||||
|
TrackShifter::HitTestResult hitTestResult, //!< must not be `Miss`
|
||||||
std::unique_ptr<TrackShifter> pHit, /*!<
|
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,
|
double clickTime,
|
||||||
const ViewInfo &viewInfo,
|
const ViewInfo &viewInfo,
|
||||||
TrackList &trackList, bool syncLocked );
|
TrackList &trackList, bool syncLocked );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user