Audacity 3.2.0
CutlineHandle.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5CutlineHandle.cpp
6
7Paul Licameli split from TrackPanel.cpp
8
9**********************************************************************/
10
11
12#include "CutlineHandle.h"
13
14#include "../../../../HitTestResult.h"
15#include "../../../../ProjectAudioIO.h"
16#include "ProjectHistory.h"
17#include "../../../../RefreshCode.h"
18#include "../../../../Snap.h" // for kPixelTolerance
19#include "../../../../TrackPanelMouseEvent.h"
20#include "UndoManager.h"
21#include "ViewInfo.h"
22#include "../../../../WaveTrack.h"
23#include "../../../../../images/Cursors.h"
24
26( const std::shared_ptr<WaveTrack> &pTrack, WaveTrackLocation location )
27 : mpTrack{ pTrack }
28 , mLocation{ location }
29{
30}
31
33{
34#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
36#endif
37}
38
39HitTestPreview CutlineHandle::HitPreview(bool cutline, bool unsafe)
40{
41 static auto disabledCursor =
42 ::MakeCursor(wxCURSOR_NO_ENTRY, DisabledCursorXpm, 16, 16);
43 static wxCursor arrowCursor{ wxCURSOR_ARROW };
44 return {
45 (cutline
46 ? XO("Left-Click to expand, Right-Click to remove")
47 : XO("Left-Click to merge clips")),
48 (unsafe
49 ? &*disabledCursor
50 : &arrowCursor)
51 };
52}
53namespace
54{
55 int FindMergeLine(WaveTrack *track, double time)
56 {
57 const double tolerance = 0.5 / track->GetRate();
58 int ii = 0;
59 for (const auto loc: track->GetCachedLocations()) {
61 fabs(time - loc.pos) < tolerance)
62 return ii;
63 ++ii;
64 }
65 return -1;
66 }
67
69 (const ViewInfo &viewInfo, WaveTrack * track,
70 const wxRect &rect, const wxMouseState &state,
71 WaveTrackLocation *pmLocation)
72 {
73 for (auto loc: track->GetCachedLocations())
74 {
75 const double x = viewInfo.TimeToPosition(loc.pos);
76 if (x >= 0 && x < rect.width)
77 {
78 wxRect locRect;
79 locRect.width = 2 * kPixelTolerance - 1;
80 locRect.x = (int)(rect.x + x) - locRect.width / 2;
81 locRect.y = rect.y;
82 locRect.height = rect.height;
83 if (locRect.Contains(state.m_x, state.m_y))
84 {
85 if (pmLocation)
86 *pmLocation = loc;
87 return true;
88 }
89 }
90 }
91
92 return false;
93 }
94}
95
97(std::weak_ptr<CutlineHandle> &holder,
98 const wxMouseState &state, const wxRect &rect,
99 const AudacityProject *pProject,
100 const std::shared_ptr<WaveTrack> &pTrack)
101{
102 auto &viewInfo = ViewInfo::Get( *pProject );
105
106 WaveTrackLocation location;
107 if (!IsOverCutline(viewInfo, pTrack.get(), rect, state, &location))
108 return {};
109
110 auto result = std::make_shared<CutlineHandle>( pTrack, location );
111 result = AssignUIHandlePtr( holder, result );
112 return result;
113}
114
116{
117}
118
120{
121 return true;
122}
123
125(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
126{
127 using namespace RefreshCode;
128 const bool unsafe = ProjectAudioIO::Get( *pProject ).IsAudioActive();
129 if ( unsafe )
130 return Cancelled;
131
132 const wxMouseEvent &event = evt.event;
133 auto &viewInfo = ViewInfo::Get( *pProject );
134
135 // Can affect the track by merging clips, expanding a cutline, or
136 // deleting a cutline.
137 // All the change is done at button-down. Button-up just commits the undo item.
138
140
141 // FIXME: Disable this and return true when CutLines aren't showing?
142 // (Don't use gPrefs-> for the fix as registry access is slow).
143
144 // Cutline data changed on either branch, so refresh the track display.
146
147 if (event.LeftDown())
148 {
150 {
152 mStartTime = viewInfo.selectedRegion.t0();
153 mEndTime = viewInfo.selectedRegion.t1();
154
155 // When user presses left button on cut line, expand the line again
156 double cutlineStart = 0, cutlineEnd = 0;
157 double *pCutlineStart = &cutlineStart, *pCutlineEnd = &cutlineEnd;
158
159 for (auto channel :
161 channel->ExpandCutLine(
162 mLocation.pos, pCutlineStart, pCutlineEnd);
163 if ( channel == mpTrack.get() )
164 pCutlineStart = pCutlineEnd = nullptr;
165 }
166
167 viewInfo.selectedRegion.setTimes(cutlineStart, cutlineEnd);
168 }
170 const double pos = mLocation.pos;
171 for (auto channel :
173 // Don't assume correspondence of merge points across channels!
174 int idx = FindMergeLine(channel, pos);
175 if (idx >= 0) {
176 WaveTrack::Location location =
177 channel->GetCachedLocations()[idx];
178 channel->MergeClips(
179 location.clipidx1, location.clipidx2);
180 }
181 }
182
184 }
185 }
186 else if (event.RightDown())
187 {
188 bool removed = false;
189 for (auto channel :
191 removed = channel->RemoveCutLine(mLocation.pos) || removed;
192
193 if (!removed)
194 // Nothing happened, make no Undo item
195 return Cancelled;
196
198 }
199 else
200 result = RefreshNone;
201
202 return result;
203}
204
207{
209}
210
212(const TrackPanelMouseState &, AudacityProject *pProject)
213{
214 const bool unsafe = ProjectAudioIO::Get( *pProject ).IsAudioActive();
216 return HitPreview( bCutline, unsafe );
217}
218
220(const TrackPanelMouseEvent &, AudacityProject *pProject, wxWindow *)
221{
223
224 // Only now commit the result to the undo stack
225 switch (mOperation) {
226 default:
227 wxASSERT(false);
228 case Merge:
229 ProjectHistory::Get( *pProject )
230 .PushState(XO("Merged Clips"), XO("Merge"), UndoPush::CONSOLIDATE);
231 break;
232 case Expand:
233 ProjectHistory::Get( *pProject )
234 .PushState(XO("Expanded Cut Line"), XO("Expand"));
235 break;
236 case Remove:
237 ProjectHistory::Get( *pProject )
238 .PushState(XO("Removed Cut Line"), XO("Remove"));
239 break;
240 }
241
242 // Nothing to do for the display
243 return result;
244}
245
247{
248 using namespace RefreshCode;
250 ProjectHistory::Get( *pProject ).RollbackState();
251 if (mOperation == Expand) {
252 AudacityProject &project = *pProject;
253 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
254 selectedRegion.setTimes( mStartTime, mEndTime );
255 }
256 return result;
257}
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
#define XO(s)
Definition: Internat.h:31
const int kPixelTolerance
Definition: Snap.h:28
std::unique_ptr< wxCursor > MakeCursor(int WXUNUSED(CursorId), const char *const pXpm[36], int HotX, int HotY)
Definition: TrackPanel.cpp:185
std::shared_ptr< Subclass > AssignUIHandlePtr(std::weak_ptr< Subclass > &holder, const std::shared_ptr< Subclass > &pNew)
Definition: UIHandle.h:151
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
Operation mOperation
Definition: CutlineHandle.h:71
CutlineHandle(const CutlineHandle &)=delete
static HitTestPreview HitPreview(bool cutline, bool unsafe)
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
WaveTrackLocation mLocation
Definition: CutlineHandle.h:73
HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *pProject) override
std::shared_ptr< WaveTrack > mpTrack
Definition: CutlineHandle.h:69
virtual ~CutlineHandle()
double mStartTime
Definition: CutlineHandle.h:72
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
void Enter(bool forward, AudacityProject *) override
static UIHandlePtr HitTest(std::weak_ptr< CutlineHandle > &holder, const wxMouseState &state, const wxRect &rect, const AudacityProject *pProject, const std::shared_ptr< WaveTrack > &pTrack)
bool HandlesRightClick() override
Whether the handle has any special right-button handling.
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Result Cancel(AudacityProject *pProject) override
bool setTimes(double t0, double t1)
Definition: ViewInfo.cpp:51
bool IsAudioActive() const
static ProjectAudioIO & Get(AudacityProject &project)
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
static ProjectHistory & Get(AudacityProject &project)
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1539
Result mChangeHighlight
Definition: UIHandle.h:139
unsigned Result
Definition: UIHandle.h:38
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:216
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
const std::vector< Location > & GetCachedLocations() const
Definition: WaveTrack.h:489
double GetRate() const override
Definition: WaveTrack.cpp:479
wxInt64 TimeToPosition(double time, wxInt64 origin=0, bool ignoreFisheye=false) const
STM: Converts a project time to screen x position.
Definition: ZoomInfo.cpp:51
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
int FindMergeLine(WaveTrack *track, double time)
bool IsOverCutline(const ViewInfo &viewInfo, WaveTrack *track, const wxRect &rect, const wxMouseState &state, WaveTrackLocation *pmLocation)