mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-15 07:40:23 +02:00
Snap does not depend on subclasses of Track
This commit is contained in:
commit
b75ab214cf
@ -1900,7 +1900,8 @@ void AdornedRulerPanel::HandleSnapping()
|
||||
if (handle) {
|
||||
auto &pSnapManager = handle->mSnapManager;
|
||||
if (! pSnapManager)
|
||||
pSnapManager = std::make_unique<SnapManager>(mTracks, mViewInfo);
|
||||
pSnapManager =
|
||||
std::make_unique<SnapManager>(*mProject, *mTracks, *mViewInfo);
|
||||
|
||||
auto results = pSnapManager->Snap(NULL, mQuickPlayPos, false);
|
||||
mQuickPlayPos = results.outTime;
|
||||
|
@ -84,6 +84,28 @@ LabelTrack::LabelTrack(const LabelTrack &orig) :
|
||||
}
|
||||
}
|
||||
|
||||
template< typename Container >
|
||||
static Container MakeIntervals(const LabelArray &labels)
|
||||
{
|
||||
Container result;
|
||||
size_t ii = 0;
|
||||
for (const auto &label : labels)
|
||||
result.emplace_back(
|
||||
label.getT0(), label.getT1(),
|
||||
std::make_unique<LabelTrack::IntervalData>( ii++ ) );
|
||||
return result;
|
||||
}
|
||||
|
||||
auto LabelTrack::GetIntervals() const -> ConstIntervals
|
||||
{
|
||||
return MakeIntervals<ConstIntervals>(mLabels);
|
||||
}
|
||||
|
||||
auto LabelTrack::GetIntervals() -> Intervals
|
||||
{
|
||||
return MakeIntervals<Intervals>(mLabels);
|
||||
}
|
||||
|
||||
void LabelTrack::SetLabel( size_t iLabel, const LabelStruct &newLabel )
|
||||
{
|
||||
if( iLabel >= mLabels.size() ) {
|
||||
|
@ -155,6 +155,13 @@ public:
|
||||
int FindNextLabel(const SelectedRegion& currentSelection);
|
||||
int FindPrevLabel(const SelectedRegion& currentSelection);
|
||||
|
||||
struct IntervalData final : Track::IntervalData {
|
||||
size_t index;
|
||||
explicit IntervalData(size_t index) : index{index} {};
|
||||
};
|
||||
ConstIntervals GetIntervals() const override;
|
||||
Intervals GetIntervals() override;
|
||||
|
||||
public:
|
||||
void SortLabels();
|
||||
|
||||
|
@ -683,6 +683,20 @@ QuantizedTimeAndBeat NoteTrack::NearestBeatTime( double time ) const
|
||||
return { seq_time + GetOffset(), beat };
|
||||
}
|
||||
|
||||
auto NoteTrack::GetIntervals() const -> ConstIntervals
|
||||
{
|
||||
ConstIntervals results;
|
||||
results.emplace_back( GetStartTime(), GetEndTime() );
|
||||
return results;
|
||||
}
|
||||
|
||||
auto NoteTrack::GetIntervals() -> Intervals
|
||||
{
|
||||
Intervals results;
|
||||
results.emplace_back( GetStartTime(), GetEndTime() );
|
||||
return results;
|
||||
}
|
||||
|
||||
void NoteTrack::AddToDuration( double delta )
|
||||
{
|
||||
auto &seq = GetSeq();
|
||||
|
@ -185,6 +185,9 @@ public:
|
||||
mVisibleChannels = CHANNEL_BIT(c);
|
||||
}
|
||||
|
||||
ConstIntervals GetIntervals() const override;
|
||||
Intervals GetIntervals() override;
|
||||
|
||||
private:
|
||||
|
||||
TrackKind GetKind() const override { return TrackKind::Note; }
|
||||
|
131
src/Snap.cpp
131
src/Snap.cpp
@ -16,57 +16,57 @@
|
||||
|
||||
#include "Project.h"
|
||||
#include "ProjectSettings.h"
|
||||
#include "LabelTrack.h"
|
||||
#include "NoteTrack.h"
|
||||
#include "WaveClip.h"
|
||||
#include "Track.h"
|
||||
#include "ViewInfo.h"
|
||||
#include "WaveTrack.h"
|
||||
|
||||
inline bool operator < (SnapPoint s1, SnapPoint s2)
|
||||
{
|
||||
return s1.t < s2.t;
|
||||
}
|
||||
|
||||
TrackClip::TrackClip(Track *t, WaveClip *c)
|
||||
{
|
||||
track = origTrack = t;
|
||||
dstTrack = NULL;
|
||||
clip = c;
|
||||
}
|
||||
|
||||
TrackClip::~TrackClip()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SnapManager::SnapManager(const TrackList *tracks,
|
||||
const ZoomInfo *zoomInfo,
|
||||
const TrackClipArray *clipExclusions,
|
||||
const TrackArray *trackExclusions,
|
||||
SnapManager::SnapManager(const AudacityProject &project,
|
||||
SnapPointArray candidates,
|
||||
const ZoomInfo &zoomInfo,
|
||||
bool noTimeSnap,
|
||||
int pixelTolerance)
|
||||
: mConverter(NumericConverter::TIME)
|
||||
: mProject{ &project }
|
||||
, mZoomInfo{ &zoomInfo }
|
||||
, mPixelTolerance{ pixelTolerance }
|
||||
, mNoTimeSnap{ noTimeSnap }
|
||||
, mCandidates{ std::move( candidates ) }
|
||||
, mSnapPoints{}
|
||||
, mConverter{ NumericConverter::TIME }
|
||||
{
|
||||
mTracks = tracks;
|
||||
mZoomInfo = zoomInfo;
|
||||
mClipExclusions = clipExclusions;
|
||||
mTrackExclusions = trackExclusions;
|
||||
mPixelTolerance = pixelTolerance;
|
||||
mNoTimeSnap = noTimeSnap;
|
||||
|
||||
mProject = tracks->GetOwner();
|
||||
wxASSERT(mProject);
|
||||
|
||||
mSnapTo = 0;
|
||||
mRate = 0.0;
|
||||
mFormat = {};
|
||||
|
||||
// Two time points closer than this are considered the same
|
||||
mEpsilon = 1 / 44100.0;
|
||||
|
||||
Reinit();
|
||||
}
|
||||
|
||||
namespace {
|
||||
SnapPointArray FindCandidates( const TrackList &tracks )
|
||||
{
|
||||
SnapPointArray candidates;
|
||||
for ( const auto track : tracks.Any() ) {
|
||||
auto intervals = track->GetIntervals();
|
||||
for (const auto &interval : intervals) {
|
||||
candidates.emplace_back( interval.Start(), track );
|
||||
if ( interval.Start() != interval.End() )
|
||||
candidates.emplace_back( interval.End(), track );
|
||||
}
|
||||
}
|
||||
return candidates;
|
||||
}
|
||||
}
|
||||
|
||||
SnapManager::SnapManager(const AudacityProject &project,
|
||||
const TrackList &tracks,
|
||||
const ZoomInfo &zoomInfo,
|
||||
bool noTimeSnap,
|
||||
int pixelTolerance)
|
||||
: SnapManager{ project,
|
||||
FindCandidates( tracks ),
|
||||
zoomInfo, noTimeSnap, pixelTolerance }
|
||||
{
|
||||
}
|
||||
|
||||
SnapManager::~SnapManager()
|
||||
{
|
||||
}
|
||||
@ -105,58 +105,9 @@ void SnapManager::Reinit()
|
||||
// Add a SnapPoint at t=0
|
||||
mSnapPoints.push_back(SnapPoint{});
|
||||
|
||||
auto trackRange =
|
||||
mTracks->Any()
|
||||
- [&](const Track *pTrack){
|
||||
return mTrackExclusions &&
|
||||
make_iterator_range( *mTrackExclusions ).contains( pTrack );
|
||||
};
|
||||
trackRange.Visit(
|
||||
[&](const LabelTrack *labelTrack) {
|
||||
for (int i = 0, cnt = labelTrack->GetNumLabels(); i < cnt; ++i)
|
||||
{
|
||||
const LabelStruct *label = labelTrack->GetLabel(i);
|
||||
const double t0 = label->getT0();
|
||||
const double t1 = label->getT1();
|
||||
CondListAdd(t0, labelTrack);
|
||||
if (t1 != t0)
|
||||
{
|
||||
CondListAdd(t1, labelTrack);
|
||||
}
|
||||
}
|
||||
},
|
||||
[&](const WaveTrack *waveTrack) {
|
||||
for (const auto &clip: waveTrack->GetClips())
|
||||
{
|
||||
if (mClipExclusions)
|
||||
{
|
||||
bool skip = false;
|
||||
for (size_t j = 0, cnt = mClipExclusions->size(); j < cnt; ++j)
|
||||
{
|
||||
if ((*mClipExclusions)[j].track == waveTrack &&
|
||||
(*mClipExclusions)[j].clip == clip.get())
|
||||
{
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip)
|
||||
continue;
|
||||
}
|
||||
|
||||
CondListAdd(clip->GetStartTime(), waveTrack);
|
||||
CondListAdd(clip->GetEndTime(), waveTrack);
|
||||
}
|
||||
}
|
||||
#ifdef USE_MIDI
|
||||
,
|
||||
[&](const NoteTrack *track) {
|
||||
CondListAdd(track->GetStartTime(), track);
|
||||
CondListAdd(track->GetEndTime(), track);
|
||||
}
|
||||
#endif
|
||||
);
|
||||
// Adjust and filter the candidate points
|
||||
for (const auto &candidate : mCandidates)
|
||||
CondListAdd( candidate.t, candidate.track );
|
||||
|
||||
// Sort all by time
|
||||
std::sort(mSnapPoints.begin(), mSnapPoints.end());
|
||||
|
51
src/Snap.h
51
src/Snap.h
@ -21,32 +21,10 @@
|
||||
|
||||
class AudacityProject;
|
||||
class Track;
|
||||
using TrackArray = std::vector< Track* >;
|
||||
class TrackClipArray;
|
||||
class WaveClip;
|
||||
class WaveTrack;
|
||||
class TrackList;
|
||||
class ZoomInfo;
|
||||
class wxDC;
|
||||
|
||||
class TrackClip
|
||||
{
|
||||
public:
|
||||
TrackClip(Track *t, WaveClip *c);
|
||||
|
||||
~TrackClip();
|
||||
|
||||
Track *track;
|
||||
Track *origTrack;
|
||||
WaveClip *clip;
|
||||
|
||||
// These fields are used only during time-shift dragging
|
||||
WaveTrack *dstTrack;
|
||||
std::shared_ptr<WaveClip> holder;
|
||||
};
|
||||
|
||||
class TrackClipArray : public std::vector < TrackClip > {};
|
||||
|
||||
const int kPixelTolerance = 4;
|
||||
|
||||
class SnapPoint
|
||||
@ -77,12 +55,18 @@ struct SnapResults {
|
||||
class SnapManager
|
||||
{
|
||||
public:
|
||||
SnapManager(const TrackList *tracks,
|
||||
const ZoomInfo *zoomInfo,
|
||||
const TrackClipArray *clipExclusions = NULL,
|
||||
const TrackArray *trackExclusions = NULL,
|
||||
SnapManager(const AudacityProject &project,
|
||||
SnapPointArray candidates,
|
||||
const ZoomInfo &zoomInfo,
|
||||
bool noTimeSnap = false,
|
||||
int pixelTolerance = kPixelTolerance);
|
||||
|
||||
SnapManager(const AudacityProject &project,
|
||||
const TrackList &tracks,
|
||||
const ZoomInfo &zoomInfo,
|
||||
bool noTimeSnap = false,
|
||||
int pixelTolerance = kPixelTolerance);
|
||||
|
||||
~SnapManager();
|
||||
|
||||
// The track may be NULL.
|
||||
@ -111,23 +95,22 @@ private:
|
||||
private:
|
||||
|
||||
const AudacityProject *mProject;
|
||||
const TrackList *mTracks;
|
||||
const TrackClipArray *mClipExclusions;
|
||||
const TrackArray *mTrackExclusions;
|
||||
const ZoomInfo *mZoomInfo;
|
||||
int mPixelTolerance;
|
||||
bool mNoTimeSnap;
|
||||
|
||||
double mEpsilon;
|
||||
//! Two time points closer than this are considered the same
|
||||
double mEpsilon{ 1 / 44100.0 };
|
||||
SnapPointArray mCandidates;
|
||||
SnapPointArray mSnapPoints;
|
||||
|
||||
// Info for snap-to-time
|
||||
NumericConverter mConverter;
|
||||
bool mSnapToTime;
|
||||
bool mSnapToTime{ false };
|
||||
|
||||
int mSnapTo;
|
||||
double mRate;
|
||||
NumericFormatSymbol mFormat;
|
||||
int mSnapTo{ 0 };
|
||||
double mRate{ 0.0 };
|
||||
NumericFormatSymbol mFormat{};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1224,6 +1224,16 @@ std::shared_ptr<const Track> Track::SubstituteOriginalTrack() const
|
||||
return SharedPointer();
|
||||
}
|
||||
|
||||
auto Track::GetIntervals() const -> ConstIntervals
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Track::GetIntervals() -> Intervals
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
// Serialize, not with tags of its own, but as attributes within a tag.
|
||||
void Track::WriteCommonXMLAttributes(
|
||||
XMLWriter &xmlFile, bool includeNameAndSelected) const
|
||||
@ -1269,6 +1279,8 @@ void Track::AdjustPositions()
|
||||
}
|
||||
}
|
||||
|
||||
TrackIntervalData::~TrackIntervalData() = default;
|
||||
|
||||
bool TrackList::HasPendingTracks() const
|
||||
{
|
||||
if ( !mPendingUpdates.empty() )
|
||||
|
61
src/Track.h
61
src/Track.h
@ -181,6 +181,50 @@ private:
|
||||
long mValue;
|
||||
};
|
||||
|
||||
//! Optional extra information about an interval, appropriate to a subtype of Track
|
||||
struct TrackIntervalData {
|
||||
virtual ~TrackIntervalData();
|
||||
};
|
||||
|
||||
//! A start and an end time, and non-mutative access to optional extra information
|
||||
/*! @invariant `Start() <= End()` */
|
||||
class ConstTrackInterval {
|
||||
public:
|
||||
|
||||
/*! @pre `start <= end` */
|
||||
ConstTrackInterval( double start, double end,
|
||||
std::unique_ptr<TrackIntervalData> pExtra = {} )
|
||||
: start{ start }, end{ end }, pExtra{ std::move( pExtra ) }
|
||||
{
|
||||
wxASSERT( start <= end );
|
||||
}
|
||||
|
||||
ConstTrackInterval( ConstTrackInterval&& ) = default;
|
||||
ConstTrackInterval &operator=( ConstTrackInterval&& ) = default;
|
||||
|
||||
double Start() const { return start; }
|
||||
double End() const { return end; }
|
||||
const TrackIntervalData *Extra() const { return pExtra.get(); }
|
||||
|
||||
private:
|
||||
double start, end;
|
||||
protected:
|
||||
// TODO C++17: use std::any instead
|
||||
std::unique_ptr< TrackIntervalData > pExtra;
|
||||
};
|
||||
|
||||
//! A start and an end time, and mutative access to optional extra information
|
||||
/*! @invariant `Start() <= End()` */
|
||||
class TrackInterval : public ConstTrackInterval {
|
||||
public:
|
||||
using ConstTrackInterval::ConstTrackInterval;
|
||||
|
||||
TrackInterval(TrackInterval&&) = default;
|
||||
TrackInterval &operator= (TrackInterval&&) = default;
|
||||
|
||||
TrackIntervalData *Extra() const { return pExtra.get(); }
|
||||
};
|
||||
|
||||
//! Template generated base class for Track lets it host opaque UI related objects
|
||||
using AttachedTrackObjects = ClientData::Site<
|
||||
Track, ClientData::Base, ClientData::SkipCopying, std::shared_ptr
|
||||
@ -268,6 +312,23 @@ class AUDACITY_DLL_API Track /* not final */
|
||||
// original; else return this track
|
||||
std::shared_ptr<const Track> SubstituteOriginalTrack() const;
|
||||
|
||||
using IntervalData = TrackIntervalData;
|
||||
using Interval = TrackInterval;
|
||||
using Intervals = std::vector< Interval >;
|
||||
using ConstInterval = ConstTrackInterval;
|
||||
using ConstIntervals = std::vector< ConstInterval >;
|
||||
|
||||
//! Report times on the track where important intervals begin and end, for UI to snap to
|
||||
/*!
|
||||
Some intervals may be empty, and no ordering of the intervals is assumed.
|
||||
*/
|
||||
virtual ConstIntervals GetIntervals() const;
|
||||
|
||||
/*! @copydoc GetIntervals()
|
||||
This overload exposes the extra data of the intervals as non-const
|
||||
*/
|
||||
virtual Intervals GetIntervals();
|
||||
|
||||
public:
|
||||
mutable wxSize vrulerSize;
|
||||
|
||||
|
@ -323,6 +323,27 @@ int WaveTrack::ZeroLevelYCoordinate(wxRect rect) const
|
||||
(int)((mDisplayMax / (mDisplayMax - mDisplayMin)) * rect.height);
|
||||
}
|
||||
|
||||
template< typename Container >
|
||||
static Container MakeIntervals(const std::vector<WaveClipHolder> &clips)
|
||||
{
|
||||
Container result;
|
||||
for (const auto &clip: clips) {
|
||||
result.emplace_back( clip->GetStartTime(), clip->GetEndTime(),
|
||||
std::make_unique<WaveTrack::IntervalData>( clip ) );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto WaveTrack::GetIntervals() const -> ConstIntervals
|
||||
{
|
||||
return MakeIntervals<ConstIntervals>( mClips );
|
||||
}
|
||||
|
||||
auto WaveTrack::GetIntervals() -> Intervals
|
||||
{
|
||||
return MakeIntervals<Intervals>( mClips );
|
||||
}
|
||||
|
||||
Track::Holder WaveTrack::Clone() const
|
||||
{
|
||||
return std::make_shared<WaveTrack>( *this );
|
||||
|
@ -523,6 +523,20 @@ private:
|
||||
// bottom and top. Maybe that is out of bounds.
|
||||
int ZeroLevelYCoordinate(wxRect rect) const;
|
||||
|
||||
class IntervalData final : public Track::IntervalData {
|
||||
public:
|
||||
explicit IntervalData( const std::shared_ptr<WaveClip> &pClip )
|
||||
: pClip{ pClip }
|
||||
{}
|
||||
std::shared_ptr<const WaveClip> GetClip() const { return pClip; }
|
||||
std::shared_ptr<WaveClip> &GetClip() { return pClip; }
|
||||
private:
|
||||
std::shared_ptr<WaveClip> pClip;
|
||||
};
|
||||
|
||||
ConstIntervals GetIntervals() const override;
|
||||
Intervals GetIntervals() override;
|
||||
|
||||
protected:
|
||||
//
|
||||
// Protected variables
|
||||
|
@ -432,7 +432,8 @@ SelectHandle::SelectHandle
|
||||
const TrackList &trackList,
|
||||
const TrackPanelMouseState &st, const ViewInfo &viewInfo )
|
||||
: mpView{ pTrackView }
|
||||
, mSnapManager{ std::make_shared<SnapManager>(&trackList, &viewInfo) }
|
||||
, mSnapManager{ std::make_shared<SnapManager>(
|
||||
*trackList.GetOwner(), trackList, viewInfo) }
|
||||
{
|
||||
const wxMouseState &state = st.state;
|
||||
mRect = st.rect;
|
||||
|
@ -21,6 +21,7 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../../ProjectHistory.h"
|
||||
#include "../../ProjectSettings.h"
|
||||
#include "../../RefreshCode.h"
|
||||
#include "../../Snap.h"
|
||||
#include "../../TrackArtist.h"
|
||||
#include "../../TrackPanelDrawingContext.h"
|
||||
#include "../../TrackPanelMouseEvent.h"
|
||||
@ -30,6 +31,18 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#include "../../WaveTrack.h"
|
||||
#include "../../../images/Cursors.h"
|
||||
|
||||
TrackClip::TrackClip(Track *t, WaveClip *c)
|
||||
{
|
||||
track = origTrack = t;
|
||||
dstTrack = NULL;
|
||||
clip = c;
|
||||
}
|
||||
|
||||
TrackClip::~TrackClip()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TimeShiftHandle::TimeShiftHandle
|
||||
( const std::shared_ptr<Track> &pTrack, bool gripHit )
|
||||
: mCapturedTrack{ pTrack }
|
||||
@ -350,6 +363,64 @@ void TimeShiftHandle::DoSlideHorizontal
|
||||
DoOffset( state, &capturedTrack, state.hSlideAmount );
|
||||
}
|
||||
|
||||
#include "LabelTrack.h"
|
||||
namespace {
|
||||
SnapPointArray FindCandidates(
|
||||
const TrackList &tracks,
|
||||
const TrackClipArray &clipExclusions, const TrackArray &trackExclusions )
|
||||
{
|
||||
// Special case restricted candidates for time shift
|
||||
SnapPointArray candidates;
|
||||
auto trackRange =
|
||||
tracks.Any()
|
||||
- [&](const Track *pTrack){
|
||||
return
|
||||
make_iterator_range( trackExclusions ).contains( pTrack );
|
||||
};
|
||||
trackRange.Visit(
|
||||
[&](const LabelTrack *labelTrack) {
|
||||
for (const auto &label : labelTrack->GetLabels())
|
||||
{
|
||||
const double t0 = label.getT0();
|
||||
const double t1 = label.getT1();
|
||||
candidates.emplace_back(t0, labelTrack);
|
||||
if (t1 != t0)
|
||||
candidates.emplace_back(t1, labelTrack);
|
||||
}
|
||||
},
|
||||
[&](const WaveTrack *waveTrack) {
|
||||
for (const auto &clip: waveTrack->GetClips())
|
||||
{
|
||||
bool skip = false;
|
||||
for (const auto &exclusion : clipExclusions)
|
||||
{
|
||||
if (exclusion.track == waveTrack &&
|
||||
exclusion.clip == clip.get())
|
||||
{
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip)
|
||||
continue;
|
||||
|
||||
candidates.emplace_back(clip->GetStartTime(), waveTrack);
|
||||
candidates.emplace_back(clip->GetEndTime(), waveTrack);
|
||||
}
|
||||
}
|
||||
#ifdef USE_MIDI
|
||||
,
|
||||
[&](const NoteTrack *track) {
|
||||
candidates.emplace_back(track->GetStartTime(), track);
|
||||
candidates.emplace_back(track->GetEndTime(), track);
|
||||
}
|
||||
#endif
|
||||
);
|
||||
return candidates;
|
||||
}
|
||||
}
|
||||
|
||||
UIHandle::Result TimeShiftHandle::Click
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
|
||||
{
|
||||
@ -414,11 +485,13 @@ UIHandle::Result TimeShiftHandle::Click
|
||||
mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive;
|
||||
mRect = rect;
|
||||
mClipMoveState.mMouseClickX = event.m_x;
|
||||
mSnapManager = std::make_shared<SnapManager>(&trackList,
|
||||
&viewInfo,
|
||||
&mClipMoveState.capturedClipArray,
|
||||
&mClipMoveState.trackExclusions,
|
||||
true); // don't snap to time
|
||||
mSnapManager =
|
||||
std::make_shared<SnapManager>(*trackList.GetOwner(),
|
||||
FindCandidates( trackList,
|
||||
mClipMoveState.capturedClipArray, mClipMoveState.trackExclusions),
|
||||
viewInfo,
|
||||
true, // don't snap to time
|
||||
kPixelTolerance);
|
||||
mClipMoveState.snapLeft = -1;
|
||||
mClipMoveState.snapRight = -1;
|
||||
mSnapPreferRightEdge =
|
||||
|
@ -13,10 +13,31 @@ Paul Licameli
|
||||
|
||||
#include "../../UIHandle.h"
|
||||
|
||||
#include "../../Snap.h"
|
||||
|
||||
class SnapManager;
|
||||
class Track;
|
||||
using TrackArray = std::vector<Track*>;
|
||||
class TrackList;
|
||||
class ViewInfo;
|
||||
class WaveClip;
|
||||
class WaveTrack;
|
||||
|
||||
class TrackClip
|
||||
{
|
||||
public:
|
||||
TrackClip(Track *t, WaveClip *c);
|
||||
|
||||
~TrackClip();
|
||||
|
||||
Track *track;
|
||||
Track *origTrack;
|
||||
WaveClip *clip;
|
||||
|
||||
// These fields are used only during time-shift dragging
|
||||
WaveTrack *dstTrack;
|
||||
std::shared_ptr<WaveClip> holder;
|
||||
};
|
||||
|
||||
using TrackClipArray = std::vector <TrackClip>;
|
||||
|
||||
struct ClipMoveState {
|
||||
// non-NULL only if click was in a WaveTrack and without Shift key:
|
||||
|
Loading…
x
Reference in New Issue
Block a user