Audacity 3.2.0
LabelTrackShifter.cpp
Go to the documentation of this file.
1
6#include "LabelTrackView.h"
7#include "../../ui/TimeShiftHandle.h"
8#include "../../../LabelTrack.h"
9#include "ViewInfo.h"
10
11class LabelTrackShifter final : public TrackShifter {
12public:
14 : mpTrack{ track.SharedPointer<LabelTrack>() }
15 , mProject{ project }
16 {
18 mSubscription = mpTrack->Subscribe([this](const LabelTrackEvent &e){
19 switch (e.type) {
20 case LabelTrackEvent::Permutation:
21 return OnLabelPermuted(e);
22 case LabelTrackEvent::Addition:
23 return OnLabelAdded(e);
24 case LabelTrackEvent::Deletion:
25 return OnLabelDeleted(e);
26 default:
27 return;
28 }
29 });
30 }
32 {
33 }
34 Track &GetTrack() const override { return *mpTrack; }
35
36 static inline size_t& GetIndex(TrackInterval &interval)
37 {
38 auto pExtra =
39 static_cast<LabelTrack::IntervalData*>( interval.Extra() );
40 return pExtra->index;
41 }
42
43 static inline size_t GetIndex(const TrackInterval &interval)
44 {
45 return GetIndex( const_cast<TrackInterval&>(interval) );
46 }
47
49 double time, const ViewInfo &viewInfo, HitTestParams *pParams ) override
50 {
52 auto t0 = viewInfo.selectedRegion.t0();
53 auto t1 = viewInfo.selectedRegion.t1();
54 if ( mpTrack->IsSelected() && time >= t0 && time < t1 )
56
57 // Prefer the box that the mouse hovers over, else the selected one
58 int iLabel = -1;
59 if ( pParams )
60 iLabel =
61 LabelTrackView::OverATextBox(*mpTrack, pParams->xx, pParams->yy);
62 if (iLabel == -1)
64 if (iLabel != -1) {
65 UnfixIntervals([&](const auto &myInterval){
66 return GetIndex( myInterval ) == iLabel;
67 });
68 return result;
69 }
70 else {
71 // If the pick is within the selection, which overlaps some intervals,
72 // then move those intervals only
73 // Else move all labels (preserving the older beahvior of time shift)
74 if ( result == HitTestResult::Selection )
75 SelectInterval({ t0, t1 });
76 if (mMoving.empty())
78 else
79 return result;
80 }
81 }
82
83 void SelectInterval( const TrackInterval &interval ) override
84 {
85 CommonSelectInterval(interval);
86 }
87
88 bool SyncLocks() override { return false; }
89
90 bool MayMigrateTo( Track &otherTrack ) override
91 {
92 return CommonMayMigrateTo(otherTrack);
93 }
94
95 /* We need to copy a complete label when detaching it because LabelStruct
96 is stored in a vector in LabelTrack without an extra indirection.
97 So the detached intervals handed back to the caller are unlike those
98 reported by LabelTrack, but carry the extra information. */
101 wxString title;
103 : region{label.selectedRegion}
104 , title{label.title}
105 {}
106 };
107
108 Intervals Detach() override
109 {
110 auto pTrack = mpTrack.get();
111 auto moveLabel = [pTrack](TrackInterval &interval) -> TrackInterval {
112 auto &rindex = GetIndex(interval);
113 auto index = rindex;
114 rindex = -1;
115 auto result = TrackInterval{
116 interval.Start(), interval.End(),
117 std::make_unique<IntervalData>( *pTrack->GetLabel(index) ) };
118 pTrack->DeleteLabel(index);
119 return result;
120 };
121 Intervals result;
122 std::transform(
123 // Reverse traversal may lessen the shifting-left in the label array
124 mMoving.rbegin(), mMoving.rend(), std::back_inserter(result),
125 moveLabel );
126 mMoving = Intervals{};
127 return result;
128 }
129
131 const Track &, const Intervals &, double &, double ) override
132 {
133 // Labels have no overlapping constraints, so just...
134 return true;
135 }
136
137 bool Attach( Intervals intervals, double offset ) override
138 {
139 auto pTrack = mpTrack.get();
140 std::for_each( intervals.rbegin(), intervals.rend(),
141 [this, pTrack, offset](auto &interval){
142 auto pData = static_cast<IntervalData*>( interval.Extra() );
143 if(offset != .0)
144 pData->region.move(offset);
145 auto index = pTrack->AddLabel(pData->region, pData->title);
146 // Recreate the simpler TrackInterval as would be reported by LabelTrack
147 mMoving.emplace_back( pTrack->MakeInterval(index) );
148 } );
149 return true;
150 }
151
152 void DoHorizontalOffset( double offset ) override
153 {
154 auto &labels = mpTrack->GetLabels();
155 for ( auto &interval : MovingIntervals() ) {
156 auto index = GetIndex( interval );
157 auto labelStruct = labels[index];
158 labelStruct.selectedRegion.move(offset);
159 mpTrack->SetLabel( index, labelStruct );
160 }
161
162 mpTrack->SortLabels(); // causes callback to OnLabelPermuted
163 }
164
165private:
167 {
168 if ( e.mpTrack.lock() != mpTrack )
169 return;
170
171 auto former = e.mFormerPosition;
172 auto present = e.mPresentPosition;
173
174 // Avoid signed-unsigned comparison below!
175 if (former < 0 || present < 0) {
176 wxASSERT(false);
177 return;
178 }
179
180 auto update = [=]( TrackInterval &interval ){
181 auto &index = GetIndex( interval );
182 if ( index == former )
183 index = present;
184 else if ( former < index && index <= present )
185 -- index;
186 else if ( former > index && index >= present )
187 ++ index;
188 };
189
190 std::for_each(mFixed.begin(), mFixed.end(), update);
191 std::for_each(mMoving.begin(), mMoving.end(), update);
192 }
193
195 {
196 if ( e.mpTrack.lock() != mpTrack )
197 return;
198
199 auto present = e.mPresentPosition;
200
201 // Avoid signed-unsigned comparison below!
202 if (present < 0) {
203 wxASSERT(false);
204 return;
205 }
206
207 auto update = [=]( TrackInterval &interval ){
208 auto pExtra = static_cast<LabelTrack::IntervalData*>(interval.Extra());
209 auto &index = pExtra->index;
210 if ( index >= present )
211 ++ index;
212 };
213
214 std::for_each(mFixed.begin(), mFixed.end(), update);
215 std::for_each(mMoving.begin(), mMoving.end(), update);
216 }
217
219 {
220 if ( e.mpTrack.lock() != mpTrack )
221 return;
222
223 auto former = e.mFormerPosition;
224
225 // Avoid signed-unsigned comparison below!
226 if (former < 0) {
227 wxASSERT(false);
228 return;
229 }
230
231 auto update = [=]( TrackInterval &interval ){
232 auto pExtra = static_cast<LabelTrack::IntervalData*>(interval.Extra());
233 auto &index = pExtra->index;
234 if ( index > former )
235 -- index;
236 else if ( index == former )
237 // It should have been deleted first!
238 wxASSERT( false );
239 };
240
241 std::for_each(mFixed.begin(), mFixed.end(), update);
242 std::for_each(mMoving.begin(), mMoving.end(), update);
243 }
244
246 std::shared_ptr<LabelTrack> mpTrack;
248};
249
252 return [](LabelTrack &track, AudacityProject &project) {
253 return std::make_unique<LabelTrackShifter>(track, project);
254 };
255}
DEFINE_ATTACHED_VIRTUAL_OVERRIDE(MakeLabelTrackShifter)
TranslatableString label
Definition: TagsEditor.cpp:164
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
double Start() const
Definition: Track.h:129
A LabelStruct holds information for ONE label in a LabelTrack.
Definition: LabelTrack.h:29
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:87
Track & GetTrack() const override
There is always an associated track.
static size_t GetIndex(const TrackInterval &interval)
void DoHorizontalOffset(double offset) override
AudacityProject & mProject
std::shared_ptr< LabelTrack > mpTrack
bool MayMigrateTo(Track &otherTrack) override
Whether intervals may migrate to the other track, not yet checking all placement constraints *‍/.
void OnLabelPermuted(const LabelTrackEvent &e)
void SelectInterval(const TrackInterval &interval) override
Notifies the shifter that a region is selected, so it may update its fixed and moving intervals.
Intervals Detach() override
Remove all moving intervals from the track, if possible.
void OnLabelAdded(const LabelTrackEvent &e)
static size_t & GetIndex(TrackInterval &interval)
~LabelTrackShifter() override
LabelTrackShifter(LabelTrack &track, AudacityProject &project)
Observer::Subscription mSubscription
bool SyncLocks() override
Whether unfixing of an interval should propagate to all overlapping intervals in the sync lock group.
bool AdjustFit(const Track &, const Intervals &, double &, double) override
Test whether intervals can fit into another track, maybe adjusting the offset slightly.
HitTestResult HitTest(double time, const ViewInfo &viewInfo, HitTestParams *pParams) override
Decide how shift behaves, based on the track that is clicked in.
bool Attach(Intervals intervals, double offset) override
Put moving intervals into the track, which may have migrated from another.
void OnLabelDeleted(const LabelTrackEvent e)
static LabelTrackView & Get(LabelTrack &)
static int OverATextBox(const LabelTrack &track, int xx, int yy)
int GetNavigationIndex(AudacityProject &project) const
double t1() const
Definition: ViewInfo.h:36
double t0() const
Definition: ViewInfo.h:35
A move-only handle representing a connection to a Publisher.
Definition: Observer.h:70
Defines a selected portion of a project.
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:162
A start and an end time, and mutative access to optional extra information.
Definition: Track.h:142
TrackIntervalData * Extra() const
Definition: Track.h:149
Abstract base class for policies to manipulate a track type with the Time Shift tool.
Intervals mFixed
std::vector< TrackInterval > Intervals
void CommonSelectInterval(const TrackInterval &interval)
void UnfixIntervals(std::function< bool(const TrackInterval &) > pred)
Change intervals satisfying a predicate from fixed to moving.
void InitIntervals()
Derived class constructor can initialize all intervals reported by the track as fixed,...
const Intervals & MovingIntervals() const
Return special intervals of the track that may move.
bool CommonMayMigrateTo(Track &otherTrack)
HitTestResult
Possibilities for HitTest on the clicked track.
@ Selection
Shift 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.
Intervals mMoving
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:219
For defining overrides of the method.
const std::weak_ptr< Track > mpTrack
Definition: LabelTrack.h:211
enum LabelTrackEvent::Type type
IntervalData(const LabelStruct &label)
Optional extra information about an interval, appropriate to a subtype of Track.
Definition: Track.h:109
Optional, more complete information for hit testing.