Audacity  3.0.3
LabelTextHandle.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 LabelTextHandle.cpp
6 
7 Paul 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 
73 void 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)
154  return RefreshCode::Cancelled;
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 }
LabelTextHandle::HitPreview
static HitTestPreview HitPreview()
Definition: LabelTextHandle.cpp:42
ViewInfo::Get
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:241
LabelDefaultClickHandle::Drag
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Definition: LabelDefaultClickHandle.cpp:83
LabelDefaultClickHandle::Click
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Definition: LabelDefaultClickHandle.cpp:60
RefreshCode::RefreshAll
@ RefreshAll
Definition: RefreshCode.h:26
RefreshCode::RefreshNone
@ RefreshNone
Definition: RefreshCode.h:21
TrackList::Lock
std::shared_ptr< Subclass > Lock(const std::weak_ptr< Subclass > &wTrack)
Definition: Track.h:1542
MakeCursor
std::unique_ptr< wxCursor > MakeCursor(int WXUNUSED(CursorId), const char *const pXpm[36], int HotX, int HotY)
Definition: TrackPanel.cpp:182
RefreshCode::Cancelled
@ Cancelled
Definition: RefreshCode.h:23
XO
#define XO(s)
Definition: Internat.h:31
LabelTextHandle.h
LabelTextHandle::LabelTextHandle
LabelTextHandle(const std::shared_ptr< LabelTrack > &pLT, int labelNum)
Definition: LabelTextHandle.cpp:29
LabelTextHandle::Cancel
Result Cancel(AudacityProject *pProject) override
Definition: LabelTextHandle.cpp:281
LabelTrackView::OverTextBox
static bool OverTextBox(const LabelStruct *pLabel, int x, int y)
Definition: LabelTrackView.cpp:1291
LabelTextHandle::HandleTextClick
void HandleTextClick(AudacityProject &project, const wxMouseEvent &evt)
Definition: LabelTextHandle.cpp:73
LabelTextHandle::mpLT
std::weak_ptr< LabelTrack > mpLT
Definition: LabelTextHandle.h:67
LabelTextHandle::mLabelTrackStartXPos
int mLabelTrackStartXPos
Definition: LabelTextHandle.h:69
LabelTextHandle::mLabelTrackStartYPos
int mLabelTrackStartYPos
Definition: LabelTextHandle.h:70
LabelTextHandle::HitTest
static UIHandlePtr HitTest(std::weak_ptr< LabelTextHandle > &holder, const wxMouseState &state, const std::shared_ptr< LabelTrack > &pLT)
Definition: LabelTextHandle.cpp:53
LabelTrackView::OverATextBox
static int OverATextBox(const LabelTrack &track, int xx, int yy)
Definition: LabelTrackView.cpp:1277
UIHandle::mChangeHighlight
Result mChangeHighlight
Definition: UIHandle.h:139
LabelDefaultClickHandle::Cancel
Result Cancel(AudacityProject *pProject) override
Definition: LabelDefaultClickHandle.cpp:96
UIHandle::Result
unsigned Result
Definition: UIHandle.h:38
LabelTextHandle::HandlesRightClick
bool HandlesRightClick() override
Whether the handle has any special right-button handling.
Definition: LabelTextHandle.cpp:144
LabelTrackView.h
UIHandlePtr
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
HitTestPreview
Definition: HitTestResult.h:20
LabelTrackView::Get
static LabelTrackView & Get(LabelTrack &)
Definition: LabelTrackView.cpp:162
RefreshCode::RefreshCell
@ RefreshCell
Definition: RefreshCode.h:24
ViewInfo.h
LabelTextHandle::Enter
void Enter(bool forward, AudacityProject *) override
Definition: LabelTextHandle.cpp:35
LabelDefaultClickHandle::Release
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
Definition: LabelDefaultClickHandle.cpp:89
LabelTextHandle::~LabelTextHandle
virtual ~LabelTextHandle()
Definition: LabelTextHandle.cpp:69
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:506
LabelTextHandle::Preview
HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *pProject) override
Definition: LabelTextHandle.cpp:255
LabelTextHandle::Release
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
Definition: LabelTextHandle.cpp:261
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
TrackPanelMouseEvent
Definition: TrackPanelMouseEvent.h:46
LabelTextHandle::HandleTextDragRelease
void HandleTextDragRelease(AudacityProject &project, const wxMouseEvent &evt)
Definition: LabelTextHandle.cpp:166
TrackPanelMouseState
Definition: TrackPanelMouseEvent.h:28
AssignUIHandlePtr
std::shared_ptr< Subclass > AssignUIHandlePtr(std::weak_ptr< Subclass > &holder, const std::shared_ptr< Subclass > &pNew)
Definition: UIHandle.h:151
LabelTextHandle::mRightDragging
bool mRightDragging
flag to tell if it's a valid dragging
Definition: LabelTextHandle.h:73
RefreshCode
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16
LabelTextHandle::Click
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Definition: LabelTextHandle.cpp:150
LabelTextHandle::Drag
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Definition: LabelTextHandle.cpp:220
TrackPanelMouseEvent::event
wxMouseEvent & event
Definition: TrackPanelMouseEvent.h:58
SelectedRegion
Defines a selected portion of a project.
Definition: SelectedRegion.h:35