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 <wx/cursor.h>
15#include <wx/event.h>
16
17#include "../../../../HitTestResult.h"
18#include "ProjectAudioIO.h"
19#include "ProjectHistory.h"
20#include "../../../../RefreshCode.h"
21#include "../../../../Snap.h" // for kPixelTolerance
22#include "../../../../TrackPanelMouseEvent.h"
23#include "UndoManager.h"
24#include "ViewInfo.h"
25#include "WaveTrack.h"
26#include "../../../../../images/Cursors.h"
27
29( const std::shared_ptr<WaveTrack> &pTrack, WaveTrackLocation location )
30 : mpTrack{ pTrack }
31 , mLocation{ location }
32{
33}
34
36{
37#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
39#endif
40}
41
42HitTestPreview CutlineHandle::HitPreview(bool cutline, bool unsafe)
43{
44 static auto disabledCursor =
45 ::MakeCursor(wxCURSOR_NO_ENTRY, DisabledCursorXpm, 16, 16);
46 static wxCursor arrowCursor{ wxCURSOR_ARROW };
47 return {
48 (cutline
49 ? XO("Left-Click to expand, Right-Click to remove")
50 : XO("Left-Click to merge clips")),
51 (unsafe
52 ? &*disabledCursor
53 : &arrowCursor)
54 };
55}
56namespace
57{
58 int FindMergeLine(WaveTrack *track, double time)
59 {
60 const double tolerance = 0.5 / track->GetRate();
61 int ii = 0;
62 for (const auto loc: WaveTrackLocations::Get(*track).Get()) {
64 fabs(time - loc.pos) < tolerance)
65 return ii;
66 ++ii;
67 }
68 return -1;
69 }
70
72 (const ViewInfo &viewInfo, WaveTrack * track,
73 const wxRect &rect, const wxMouseState &state,
74 WaveTrackLocation *pmLocation)
75 {
76 for (auto loc: WaveTrackLocations::Get(*track).Get())
77 {
78 const double x = viewInfo.TimeToPosition(loc.pos);
79 if (x >= 0 && x < rect.width)
80 {
81 wxRect locRect;
82 locRect.width = 2 * kPixelTolerance - 1;
83 locRect.x = (int)(rect.x + x) - locRect.width / 2;
84 locRect.y = rect.y;
85 locRect.height = rect.height;
86 if (locRect.Contains(state.m_x, state.m_y))
87 {
88 if (pmLocation)
89 *pmLocation = loc;
90 return true;
91 }
92 }
93 }
94
95 return false;
96 }
97}
98
100(std::weak_ptr<CutlineHandle> &holder,
101 const wxMouseState &state, const wxRect &rect,
102 const AudacityProject *pProject,
103 const std::shared_ptr<WaveTrack> &pTrack)
104{
105 auto &viewInfo = ViewInfo::Get( *pProject );
108
109 WaveTrackLocation location;
110 if (!IsOverCutline(viewInfo, pTrack.get(), rect, state, &location))
111 return {};
112
113 auto result = std::make_shared<CutlineHandle>( pTrack, location );
114 result = AssignUIHandlePtr( holder, result );
115 return result;
116}
117
119{
120}
121
123{
124 return true;
125}
126
128(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
129{
130 using namespace RefreshCode;
131 const bool unsafe = ProjectAudioIO::Get( *pProject ).IsAudioActive();
132 if ( unsafe )
133 return Cancelled;
134
135 const wxMouseEvent &event = evt.event;
136 auto &viewInfo = ViewInfo::Get( *pProject );
137
138 // Can affect the track by merging clips, expanding a cutline, or
139 // deleting a cutline.
140 // All the change is done at button-down. Button-up just commits the undo item.
141
143
144 // FIXME: Disable this and return true when CutLines aren't showing?
145 // (Don't use gPrefs-> for the fix as registry access is slow).
146
147 // Cutline data changed on either branch, so refresh the track display.
149
150 if (event.LeftDown())
151 {
153 {
155 mStartTime = viewInfo.selectedRegion.t0();
156 mEndTime = viewInfo.selectedRegion.t1();
157
158 // When user presses left button on cut line, expand the line again
159 double cutlineStart = 0, cutlineEnd = 0;
160 double *pCutlineStart = &cutlineStart, *pCutlineEnd = &cutlineEnd;
161
162 for (auto channel :
164 channel->ExpandCutLine(
165 mLocation.pos, pCutlineStart, pCutlineEnd);
166 if ( channel == mpTrack.get() )
167 pCutlineStart = pCutlineEnd = nullptr;
168 }
169
170 viewInfo.selectedRegion.setTimes(cutlineStart, cutlineEnd);
171 }
173 const double pos = mLocation.pos;
174 for (auto channel :
176 // Don't assume correspondence of merge points across channels!
177 int idx = FindMergeLine(channel, pos);
178 if (idx >= 0) {
179 auto location =
180 WaveTrackLocations::Get(*channel).Get()[idx];
181 channel->MergeClips(
182 location.clipidx1, location.clipidx2);
183 }
184 }
185
187 }
188 }
189 else if (event.RightDown())
190 {
191 bool removed = false;
192 for (auto channel :
194 removed = channel->RemoveCutLine(mLocation.pos) || removed;
195
196 if (!removed)
197 // Nothing happened, make no Undo item
198 return Cancelled;
199
201 }
202 else
203 result = RefreshNone;
204
205 return result;
206}
207
210{
212}
213
215(const TrackPanelMouseState &, AudacityProject *pProject)
216{
217 const bool unsafe = ProjectAudioIO::Get( *pProject ).IsAudioActive();
219 return HitPreview( bCutline, unsafe );
220}
221
223(const TrackPanelMouseEvent &, AudacityProject *pProject, wxWindow *)
224{
226
227 // Only now commit the result to the undo stack
228 switch (mOperation) {
229 default:
230 wxASSERT(false);
231 case Merge:
232 ProjectHistory::Get( *pProject )
233 .PushState(XO("Merged Clips"), XO("Merge"), UndoPush::CONSOLIDATE);
234 break;
235 case Expand:
236 ProjectHistory::Get( *pProject )
237 .PushState(XO("Expanded Cut Line"), XO("Expand"));
238 break;
239 case Remove:
240 ProjectHistory::Get( *pProject )
241 .PushState(XO("Removed Cut Line"), XO("Remove"));
242 break;
243 }
244
245 // Nothing to do for the display
246 return result;
247}
248
250{
251 using namespace RefreshCode;
253 ProjectHistory::Get( *pProject ).RollbackState();
254 if (mOperation == Expand) {
255 AudacityProject &project = *pProject;
256 auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
257 selectedRegion.setTimes( mStartTime, mEndTime );
258 }
259 return result;
260}
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
XO("Cut/Copy/Paste")
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:186
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:90
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:1417
Result mChangeHighlight
Definition: UIHandle.h:139
unsigned Result
Definition: UIHandle.h:38
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:219
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
A Track that contains audio waveform data.
Definition: WaveTrack.h:51
double GetRate() const override
Definition: WaveTrack.cpp:421
const std::vector< Location > & Get() const
int64 TimeToPosition(double time, int64 origin=0, bool ignoreFisheye=false) const
STM: Converts a project time to screen x position.
Definition: ZoomInfo.cpp:45
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)