Audacity 3.2.0
LabelTextHandle.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5LabelTextHandle.cpp
6
7Paul Licameli split from TrackPanel.cpp
8
9**********************************************************************/
10
11
12#include "LabelTextHandle.h"
13
14#include "LabelTrackView.h"
15
16#include "../../../HitTestResult.h"
17#include "../../../LabelTrack.h"
18#include "../../../ProjectAudioIO.h"
19#include "ProjectHistory.h"
20#include "../../../RefreshCode.h"
21#include "../../../SelectionState.h"
22#include "../../../TrackPanelMouseEvent.h"
23#include "ViewInfo.h"
24#include "../../../../images/Cursors.h"
25
26#include <wx/clipbrd.h>
27
29( const std::shared_ptr<LabelTrack> &pLT, int labelNum )
30 : mpLT{ pLT }
31 , mLabelNum{ labelNum }
32{
33}
34
36{
37#ifdef EXPERIMENTAL_TRACK_PANEL_HIGHLIGHTING
39#endif
40}
41
43{
44 static auto ibeamCursor =
45 ::MakeCursor(wxCURSOR_IBEAM, IBeamCursorXpm, 17, 16);
46 return {
47 XO("Click to edit label text"),
48 ibeamCursor.get()
49 };
50}
51
53(std::weak_ptr<LabelTextHandle> &holder,
54 const wxMouseState &state, const std::shared_ptr<LabelTrack> &pLT)
55{
56 // If Control is down, let the select handle be hit instead
57 int labelNum;
58 if (!state.ControlDown() &&
59 (labelNum =
60 LabelTrackView::OverATextBox(*pLT, state.m_x, state.m_y) ) >= 0) {
61 auto result = std::make_shared<LabelTextHandle>( pLT, labelNum );
62 result = AssignUIHandlePtr(holder, result);
63 return result;
64 }
65
66 return {};
67}
68
70{
71}
72
73void LabelTextHandle::HandleTextClick(AudacityProject &project, const wxMouseEvent & evt)
74{
75 auto pTrack = mpLT.lock();
76 if (!pTrack)
77 return;
78
79 auto &view = LabelTrackView::Get( *pTrack );
80 if (evt.ButtonDown())
81 {
82 const auto selIndex = LabelTrackView::OverATextBox( *pTrack, evt.m_x, evt.m_y );
83 if ( selIndex != -1 ) {
84 if (evt.LeftDown()) {
85 mRightDragging = false;
86 // Find the NEW drag end
87 auto position = view.FindCursorPosition(selIndex, evt.m_x );
88
89 // Anchor shift-drag at the farther end of the previous highlight
90 // that is farther from the click, on Mac, for consistency with
91 // its text editors, but on the others, re-use the previous
92 // anchor.
93 auto initial = view.GetInitialCursorPosition();
94 if (evt.ShiftDown()) {
95#ifdef __WXMAC__
96 // Set the drag anchor at the end of the previous selection
97 // that is farther from the NEW drag end
98 const auto current = view.GetCurrentCursorPosition();
99 if ( abs( position - current ) > abs( position - initial ) )
100 initial = current;
101#else
102 // initial position remains as before
103#endif
104 }
105 else
106 initial = position;
107
108 view.SetTextSelection(selIndex, initial, position );
109 }
110 else
111 {
112 if (!view.IsTextSelected(project))
113 {
114 auto position = view.FindCursorPosition(selIndex, evt.m_x);
115 view.SetTextSelection(selIndex, position, position);
116 }
117 // Actually this might be right or middle down
118 mRightDragging = true;
119 }
120 // Middle click on GTK: paste from primary selection
121#if defined(__WXGTK__) && (HAVE_GTK)
122 if (evt.MiddleDown()) {
123 // Check for a click outside of the selected label's text box; in this
124 // case PasteSelectedText() will start a NEW label at the click
125 // location
126 if (!LabelTrackView::OverTextBox(&labelStruct, evt.m_x, evt.m_y))
127 view.ResetTextSelection();
128 double t = zoomInfo.PositionToTime(evt.m_x, r.x);
129 newSel = SelectedRegion(t, t);
130 }
131#endif
132 }
133#if defined(__WXGTK__) && (HAVE_GTK)
134 if (evt.MiddleDown()) {
135 // Paste text, making a NEW label if none is selected.
136 wxTheClipboard->UsePrimarySelection(true);
137 view.PasteSelectedText(project, newSel.t0(), newSel.t1());
138 wxTheClipboard->UsePrimarySelection(false);
139 }
140#endif
141 }
142}
143
145{
146 return true;
147}
148
150(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
151{
152 auto pLT = mpLT.lock();
153 if (!pLT)
155
156 auto result = LabelDefaultClickHandle::Click( evt, pProject );
157
158 const wxMouseEvent &event = evt.event;
159 auto &viewInfo = ViewInfo::Get( *pProject );
160
161 HandleTextClick(*pProject, event);
162
163 return result | RefreshCode::RefreshCell;
164}
165
167 AudacityProject &project, const wxMouseEvent & evt)
168{
169 auto pTrack = mpLT.lock();
170 if (!pTrack)
171 return;
172 auto &view = LabelTrackView::Get( *pTrack );
173
174 if(evt.LeftUp())
175 {
176#if 0
177 // AWD: Due to wxWidgets bug #7491 (fix not ported to 2.8 branch) we
178 // should never write the primary selection. We can enable this block
179 // when we move to the 3.0 branch (or if a fixed 2.8 version is released
180 // and we can do a runtime version check)
181#if defined (__WXGTK__) && defined (HAVE_GTK)
182 // On GTK, if we just dragged out a text selection, set the primary
183 // selection
184 if (mInitialCursorPos != mCurrentCursorPos) {
185 wxTheClipboard->UsePrimarySelection(true);
186 CopySelectedText();
187 wxTheClipboard->UsePrimarySelection(false);
188 }
189#endif
190#endif
191
192 return;
193 }
194
195 if(evt.Dragging())
196 {
197 auto index = view.GetTextEditIndex(project);
198 if (!mRightDragging && index != -1)
199 // Update drag end
200 view.SetCurrentCursorPosition(view.FindCursorPosition(index, evt.m_x ));
201 return;
202 }
203
204 if (evt.RightUp())
205 {
206 auto index = view.GetTextEditIndex(project);
207 if(index != -1 &&
208 LabelTrackView::OverTextBox(pTrack->GetLabel(index), evt.m_x, evt.m_y))
209 {
210 // popup menu for editing
211 // TODO: handle context menus via CellularPanel?
212 view.ShowContextMenu( project );
213 }
214 }
215
216 return;
217}
218
220(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
221{
222 auto &project = *pProject;
223 using namespace RefreshCode;
224 auto result = LabelDefaultClickHandle::Drag( evt, pProject );
225
226 const wxMouseEvent &event = evt.event;
227 auto pLT = TrackList::Get( *pProject ).Lock(mpLT);
228 if(pLT)
229 HandleTextDragRelease( project, event );
230
231 // locate the initial mouse position
232 if (event.LeftIsDown()) {
233 if (mLabelTrackStartXPos == -1) {
234 mLabelTrackStartXPos = event.m_x;
235 mLabelTrackStartYPos = event.m_y;
236
237 auto pView = pLT ? &LabelTrackView::Get( *pLT ) : nullptr;
238 if (pLT && (pView->GetTextEditIndex( project ) != -1) &&
240 pLT->GetLabel(pView->GetTextEditIndex( project )),
244 }
245 // if initial mouse position in the text box
246 // then only drag text
247 if (mLabelTrackStartYPos == -1)
248 result |= RefreshCell;
249 }
250
251 return result;
252}
253
256{
257 return HitPreview();
258}
259
261(const TrackPanelMouseEvent &evt, AudacityProject *pProject,
262 wxWindow *pParent)
263{
264 auto result = LabelDefaultClickHandle::Release( evt, pProject, pParent );
265
266 // Only selected a part of a text string and changed track selectedness.
267 // No undoable effects.
268
269 const wxMouseEvent &event = evt.event;
270 auto pLT = TrackList::Get( *pProject ).Lock(mpLT);
271 if (pLT)
272 HandleTextDragRelease( *pProject, event );
273
274 // handle mouse left button up
275 if (event.LeftUp())
277
278 return result | RefreshCode::RefreshNone;
279}
280
282{
283 auto result = LabelDefaultClickHandle::Cancel( pProject );
284 return result | RefreshCode::RefreshAll;
285}
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
#define XO(s)
Definition: Internat.h:31
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
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Result Cancel(AudacityProject *pProject) override
HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *pProject) override
Result Cancel(AudacityProject *pProject) override
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
void HandleTextDragRelease(AudacityProject &project, const wxMouseEvent &evt)
virtual ~LabelTextHandle()
static UIHandlePtr HitTest(std::weak_ptr< LabelTextHandle > &holder, const wxMouseState &state, const std::shared_ptr< LabelTrack > &pLT)
void HandleTextClick(AudacityProject &project, const wxMouseEvent &evt)
bool mRightDragging
flag to tell if it's a valid dragging
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
void Enter(bool forward, AudacityProject *) override
LabelTextHandle(const std::shared_ptr< LabelTrack > &pLT, int labelNum)
bool HandlesRightClick() override
Whether the handle has any special right-button handling.
static HitTestPreview HitPreview()
std::weak_ptr< LabelTrack > mpLT
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
static LabelTrackView & Get(LabelTrack &)
static bool OverTextBox(const LabelStruct *pLabel, int x, int y)
static int OverATextBox(const LabelTrack &track, int xx, int yy)
Defines a selected portion of a project.
std::shared_ptr< Subclass > Lock(const std::weak_ptr< Subclass > &wTrack)
Definition: Track.h:1601
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:486
Result mChangeHighlight
Definition: UIHandle.h:139
unsigned Result
Definition: UIHandle.h:38
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16