Audacity  3.0.3
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 
11 class LabelTrackShifter final : public TrackShifter {
12 public:
14  : mpTrack{ track.SharedPointer<LabelTrack>() }
15  , mProject{ project }
16  {
17  InitIntervals();
18  mpTrack->Bind(
19  EVT_LABELTRACK_PERMUTED, &LabelTrackShifter::OnLabelPermuted, this );
20  mpTrack->Bind(
21  EVT_LABELTRACK_ADDITION, &LabelTrackShifter::OnLabelAdded, this );
22  mpTrack->Bind(
23  EVT_LABELTRACK_DELETION, &LabelTrackShifter::OnLabelDeleted, this );
24  }
25  ~LabelTrackShifter() override
26  {
27  mpTrack->Unbind(
28  EVT_LABELTRACK_PERMUTED, &LabelTrackShifter::OnLabelPermuted, this );
29  mpTrack->Unbind(
30  EVT_LABELTRACK_ADDITION, &LabelTrackShifter::OnLabelAdded, this );
31  mpTrack->Unbind(
32  EVT_LABELTRACK_DELETION, &LabelTrackShifter::OnLabelDeleted, this );
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 )
55  result = HitTestResult::Selection;
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())
77  return HitTestResult::Track;
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 
130  bool AdjustFit(
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 ) override
138  {
139  auto pTrack = mpTrack.get();
140  std::for_each( intervals.rbegin(), intervals.rend(),
141  [this, pTrack](auto &interval){
142  auto pData = static_cast<IntervalData*>( interval.Extra() );
143  auto index = pTrack->AddLabel(pData->region, pData->title);
144  // Recreate the simpler TrackInterval as would be reported by LabelTrack
145  mMoving.emplace_back( pTrack->MakeInterval(index) );
146  } );
147  return true;
148  }
149 
150  void DoHorizontalOffset( double offset ) override
151  {
152  auto &labels = mpTrack->GetLabels();
153  for ( auto &interval : MovingIntervals() ) {
154  auto index = GetIndex( interval );
155  auto labelStruct = labels[index];
156  labelStruct.selectedRegion.move(offset);
157  mpTrack->SetLabel( index, labelStruct );
158  }
159 
160  mpTrack->SortLabels(); // causes callback to OnLabelPermuted
161  }
162 
163 private:
165  {
166  e.Skip();
167  if ( e.mpTrack.lock() != mpTrack )
168  return;
169 
170  auto former = e.mFormerPosition;
171  auto present = e.mPresentPosition;
172 
173  // Avoid signed-unsigned comparison below!
174  if (former < 0 || present < 0) {
175  wxASSERT(false);
176  return;
177  }
178 
179  auto update = [=]( TrackInterval &interval ){
180  auto &index = GetIndex( interval );
181  if ( index == former )
182  index = present;
183  else if ( former < index && index <= present )
184  -- index;
185  else if ( former > index && index >= present )
186  ++ index;
187  };
188 
189  std::for_each(mFixed.begin(), mFixed.end(), update);
190  std::for_each(mMoving.begin(), mMoving.end(), update);
191  }
192 
194  {
195  e.Skip();
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  e.Skip();
221  if ( e.mpTrack.lock() != mpTrack )
222  return;
223 
224  auto former = e.mFormerPosition;
225 
226  // Avoid signed-unsigned comparison below!
227  if (former < 0) {
228  wxASSERT(false);
229  return;
230  }
231 
232  auto update = [=]( TrackInterval &interval ){
233  auto pExtra = static_cast<LabelTrack::IntervalData*>(interval.Extra());
234  auto &index = pExtra->index;
235  if ( index > former )
236  -- index;
237  else if ( index == former )
238  // It should have been deleted first!
239  wxASSERT( false );
240  };
241 
242  std::for_each(mFixed.begin(), mFixed.end(), update);
243  std::for_each(mMoving.begin(), mMoving.end(), update);
244  }
245 
246  std::shared_ptr<LabelTrack> mpTrack;
248 };
249 
252  return [](LabelTrack &track, AudacityProject &project) {
253  return std::make_unique<LabelTrackShifter>(track, project);
254  };
255 }
TrackShifter::mFixed
Intervals mFixed
Definition: TimeShiftHandle.h:174
LabelTrackShifter::OnLabelDeleted
void OnLabelDeleted(LabelTrackEvent &e)
Definition: LabelTrackShifter.cpp:218
TrackShifter::HitTestResult::Track
@ Track
Shift selected track and sister channels only, as a whole.
LabelTrackShifter::SyncLocks
bool SyncLocks() override
Whether unfixing of an interval should propagate to all overlapping intervals in the sync lock group.
Definition: LabelTrackShifter.cpp:88
DEFINE_ATTACHED_VIRTUAL_OVERRIDE
DEFINE_ATTACHED_VIRTUAL_OVERRIDE(MakeLabelTrackShifter)
Definition: LabelTrackShifter.cpp:251
ViewInfo
Definition: ViewInfo.h:202
TrackIntervalData
Optional extra information about an interval, appropriate to a subtype of Track.
Definition: Track.h:186
LabelTrackShifter::Attach
bool Attach(Intervals intervals) override
Put moving intervals into the track, which may have migrated from another.
Definition: LabelTrackShifter.cpp:137
Track::SharedPointer
std::shared_ptr< Subclass > SharedPointer()
Definition: Track.h:291
LabelTrackEvent::mFormerPosition
int mFormerPosition
Definition: LabelTrack.h:207
LabelTrackShifter::LabelTrackShifter
LabelTrackShifter(LabelTrack &track, AudacityProject &project)
Definition: LabelTrackShifter.cpp:13
TrackShifter::MovingIntervals
const Intervals & MovingIntervals() const
Return special intervals of the track that may move.
Definition: TimeShiftHandle.h:75
LabelTrack
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:88
LabelTrackShifter::mpTrack
std::shared_ptr< LabelTrack > mpTrack
Definition: LabelTrackShifter.cpp:246
LabelTrackShifter::AdjustFit
bool AdjustFit(const Track &, const Intervals &, double &, double) override
Test whether intervals can fit into another track, maybe adjusting the offset slightly.
Definition: LabelTrackShifter.cpp:130
TrackInterval
A start and an end time, and mutative access to optional extra information.
Definition: Track.h:219
LabelTrackShifter::OnLabelAdded
void OnLabelAdded(LabelTrackEvent &e)
Definition: LabelTrackShifter.cpp:193
TrackInterval::Extra
TrackIntervalData * Extra() const
Definition: Track.h:226
LabelTrackEvent::mPresentPosition
int mPresentPosition
Definition: LabelTrack.h:210
LabelStruct
A LabelStruct holds information for ONE label in a LabelTrack.
Definition: LabelTrack.h:30
NotifyingSelectedRegion::t1
double t1() const
Definition: ViewInfo.h:48
TrackShifter::CommonMayMigrateTo
bool CommonMayMigrateTo(Track &otherTrack)
Definition: TimeShiftHandle.cpp:187
LabelTrackShifter::HitTest
HitTestResult HitTest(double time, const ViewInfo &viewInfo, HitTestParams *pParams) override
Decide how shift behaves, based on the track that is clicked in.
Definition: LabelTrackShifter.cpp:48
TrackShifter
Abstract base class for policies to manipulate a track type with the Time Shift tool.
Definition: TimeShiftHandle.h:33
LabelTrackShifter::MayMigrateTo
bool MayMigrateTo(Track &otherTrack) override
Whether intervals may migrate to the other track, not yet checking all placement constraints *‍/.
Definition: LabelTrackShifter.cpp:90
TrackShifter::HitTestResult::Selection
@ Selection
Shift chosen intervals of this track; may shift other tracks' intervals.
TrackShifter::HitTestResult
HitTestResult
Possibilities for HitTest on the clicked track.
Definition: TimeShiftHandle.h:44
ViewInfo::selectedRegion
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:229
LabelTrackView::OverATextBox
static int OverATextBox(const LabelTrack &track, int xx, int yy)
Definition: LabelTrackView.cpp:1277
TrackShifter::mMoving
Intervals mMoving
Definition: TimeShiftHandle.h:175
LabelTrackShifter::IntervalData::title
wxString title
Definition: LabelTrackShifter.cpp:101
label
TranslatableString label
Definition: Tags.cpp:756
LabelTrackView.h
LabelTrackShifter::IntervalData::IntervalData
IntervalData(const LabelStruct &label)
Definition: LabelTrackShifter.cpp:102
TrackShifter::InitIntervals
void InitIntervals()
Derived class constructor can initialize all intervals reported by the track as fixed,...
Definition: TimeShiftHandle.cpp:250
LabelTrackView::Get
static LabelTrackView & Get(LabelTrack &)
Definition: LabelTrackView.cpp:162
LabelTrackEvent
Definition: LabelTrack.h:184
LabelTrackShifter::DoHorizontalOffset
void DoHorizontalOffset(double offset) override
Definition: LabelTrackShifter.cpp:150
ViewInfo.h
LabelTrackView::GetNavigationIndex
int GetNavigationIndex(AudacityProject &project) const
Definition: LabelTrackView.cpp:1019
LabelTrackShifter::IntervalData
Definition: LabelTrackShifter.cpp:99
LabelTrack::IntervalData
Definition: LabelTrack.h:160
LabelTrackShifter
Definition: LabelTrackShifter.cpp:11
LabelTrackShifter::GetIndex
static size_t & GetIndex(TrackInterval &interval)
Definition: LabelTrackShifter.cpp:36
LabelTrackShifter::IntervalData::region
SelectedRegion region
Definition: LabelTrackShifter.cpp:100
Track
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:239
TrackShifter::HitTestResult::Intervals
@ Intervals
Shift intervals only of selected track and sister channels.
LabelTrackShifter::~LabelTrackShifter
~LabelTrackShifter() override
Definition: LabelTrackShifter.cpp:25
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
LabelTrackShifter::mProject
AudacityProject & mProject
Definition: LabelTrackShifter.cpp:247
TrackShifter::HitTestParams::yy
wxCoord yy
Definition: TimeShiftHandle.h:54
AttachedVirtualFunction::Override
For defining overrides of the method.
Definition: AttachedVirtualFunction.h:184
LabelTrackShifter::OnLabelPermuted
void OnLabelPermuted(LabelTrackEvent &e)
Definition: LabelTrackShifter.cpp:164
NotifyingSelectedRegion::t0
double t0() const
Definition: ViewInfo.h:47
TrackListEvent::mpTrack
std::weak_ptr< Track > mpTrack
Definition: Track.h:1238
ConstTrackInterval::Start
double Start() const
Definition: Track.h:206
LabelTrackShifter::Detach
Intervals Detach() override
Remove all moving intervals from the track, if possible.
Definition: LabelTrackShifter.cpp:108
LabelTrackShifter::GetTrack
Track & GetTrack() const override
There is always an associated track.
Definition: LabelTrackShifter.cpp:34
TrackShifter::UnfixIntervals
void UnfixIntervals(std::function< bool(const TrackInterval &) > pred)
Change intervals satisfying a predicate from fixed to moving.
Definition: TimeShiftHandle.cpp:133
LabelTrackShifter::SelectInterval
void SelectInterval(const TrackInterval &interval) override
Notifies the shifter that a region is selected, so it may update its fixed and moving intervals.
Definition: LabelTrackShifter.cpp:83
TrackShifter::HitTestParams::xx
wxCoord xx
Definition: TimeShiftHandle.h:54
LabelTrack::IntervalData::index
size_t index
Definition: LabelTrack.h:161
LabelTrackShifter::GetIndex
static size_t GetIndex(const TrackInterval &interval)
Definition: LabelTrackShifter.cpp:43
TrackShifter::CommonSelectInterval
void CommonSelectInterval(const TrackInterval &interval)
Definition: TimeShiftHandle.cpp:159
TrackShifter::Intervals
std::vector< TrackInterval > Intervals
Definition: TimeShiftHandle.h:69
TrackShifter::HitTestParams
Optional, more complete information for hit testing.
Definition: TimeShiftHandle.h:52
SelectedRegion
Defines a selected portion of a project.
Definition: SelectedRegion.h:35