Audacity  3.0.3
CellularPanel.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  CellularPanel.cpp
6 
7  Dominic Mazzoni
8  and lots of other contributors
9 
10  Implements CellularPanel.
11 
12 ********************************************************************//*****************************************************************/
29 
30 
31 #include "CellularPanel.h"
32 
33 #include <wx/eventfilter.h>
34 #include <wx/setup.h> // for wxUSE_* macros
35 #include "KeyboardCapture.h"
36 #include "UIHandle.h"
37 #include "TrackPanelMouseEvent.h"
38 #include "HitTestResult.h"
39 #include "RefreshCode.h"
40 #include "TrackPanelCell.h"
41 
42 // A singleton class that intercepts escape key presses when some cellular
43 // panel is dragging
44 struct CellularPanel::Filter : wxEventFilter
45 {
47  {
48  wxEvtHandler::AddFilter( this );
49  }
50 
52  {
53  wxEvtHandler::RemoveFilter( this );
54  }
55 
56  static void Create()
57  {
58  static Filter instance;
59  }
60 
61  int FilterEvent( wxEvent &event ) override
62  {
63  if ( spActivePanel &&
64  event.GetEventType() == wxEVT_KEY_DOWN &&
65  static_cast< wxKeyEvent& >( event ).GetKeyCode() == WXK_ESCAPE ) {
66  spActivePanel->HandleEscapeKey( true );
67  return Event_Processed;
68  }
69  else
70  return Event_Skip;
71  }
72 
73  static wxWeakRef< CellularPanel > spActivePanel;
74 };
75 
76 wxWeakRef< CellularPanel > CellularPanel::Filter::spActivePanel = nullptr;
77 
79 {
81 
82  std::weak_ptr<TrackPanelCell> mLastCell;
83  std::vector<UIHandlePtr> mTargets;
84  size_t mTarget {};
86 
89 
90  std::weak_ptr<TrackPanelCell> mpClickedCell;
91 
92  bool mEnableTab{};
93 };
94 
95 
96 BEGIN_EVENT_TABLE(CellularPanel, OverlayPanel)
97  EVT_MOUSE_EVENTS(CellularPanel::OnMouseEvent)
98  EVT_MOUSE_CAPTURE_LOST(CellularPanel::OnCaptureLost)
99  EVT_COMMAND(wxID_ANY, EVT_CAPTURE_KEY, CellularPanel::OnCaptureKey)
100  EVT_KEY_DOWN(CellularPanel::OnKeyDown)
101  EVT_KEY_UP(CellularPanel::OnKeyUp)
102  EVT_CHAR(CellularPanel::OnChar)
103  EVT_SET_FOCUS(CellularPanel::OnSetFocus)
104  EVT_KILL_FOCUS(CellularPanel::OnKillFocus)
105  EVT_CONTEXT_MENU(CellularPanel::OnContextMenu)
107 
109  wxWindow * parent, wxWindowID id,
110  const wxPoint & pos, const wxSize & size,
111  ViewInfo *viewInfo,
112  long style)
113 : OverlayPanel(parent, id, pos, size, style)
114 , mViewInfo( viewInfo )
115 , mState{ std::make_unique<State>() }
116 {
117  // Create the global event filter instance for CellularPanels only when the
118  // first CellularPanel is created, not sooner, so that the filter will be
119  // invoked before that for the application.
120  Filter::Create();
121 }
122 
124 
126 {
127  auto &state = *mState;
128  if (state.mUIHandle &&
129  state.mUIHandle->StopsOnKeystroke() ) {
130  // The bogus id isn't used anywhere, but may help with debugging.
131  // as this is sending a bogus mouse up. The mouse button is still actually down
132  // and may go up again.
133  const int idBogusUp = 2;
134  wxMouseEvent evt { wxEVT_LEFT_UP };
135  evt.SetId( idBogusUp );
136  evt.SetPosition(this->ScreenToClient(::wxGetMousePosition()));
137  this->ProcessEvent(evt);
138  }
139 }
140 
141 void CellularPanel::Uncapture(bool escaping, wxMouseState *pState)
142 {
143  auto state = ::wxGetMouseState();
144  if (!pState) {
145  // Remap the position
146  state.SetPosition(this->ScreenToClient(state.GetPosition()));
147  pState = &state;
148  }
149 
150  if (HasCapture())
151  ReleaseMouse();
152  HandleMotion( *pState );
153 
154  if ( escaping || !AcceptsFocus() )
155  Filter::spActivePanel = nullptr;
156 }
157 
158 bool CellularPanel::CancelDragging( bool escaping )
159 {
160  auto &state = *mState;
161  if (state.mUIHandle) {
162  // copy shared_ptr for safety, as in HandleClick
163  auto handle = state.mUIHandle;
164  // UIHANDLE CANCEL
165  UIHandle::Result refreshResult = handle->Cancel(GetProject());
166  auto pClickedCell = state.mpClickedCell.lock();
167  if (pClickedCell)
169  pClickedCell.get(), {},
170  refreshResult | state.mMouseOverUpdateFlags );
171  state.mpClickedCell.reset();
172  state.mUIHandle.reset(), handle.reset(), ClearTargets();
173  Uncapture( escaping );
174  return true;
175  }
176  return false;
177 }
178 
180 {
181  if (!down)
182  return false;
183 
184  {
185  auto target = Target();
186  if (target && target->HasEscape() && target->Escape(GetProject())) {
188  return true;
189  }
190  }
191 
192  auto &state = *mState;
193  if (state.mUIHandle) {
194  CancelDragging( true );
195  return true;
196  }
197 
198  if (ChangeTarget(true, false)) {
200  return true;
201  }
202 
203  return false;
204 }
205 
206 void CellularPanel::UpdateMouseState(const wxMouseState &state)
207 {
208  mLastMouseState = state;
209 
210  // Simulate a down button if none, so hit test routines can anticipate
211  // which button will be clicked
212  if (!state.ButtonIsDown(wxMOUSE_BTN_ANY)) {
213 #ifdef __WXOSX__
214  if (state.RawControlDown())
215  // On Mac we can distinctly anticipate "right" click (as Control+click)
216  mLastMouseState.SetRightDown( true ),
217  mLastMouseState.SetLeftDown( false );
218  else
219 #endif
220  // Anticipate a left click by default
221  mLastMouseState.SetRightDown( false ),
222  mLastMouseState.SetLeftDown( true );
223  }
224 }
225 
227 {
229 }
230 
232 {
233  // Come here on modifier key or mouse button transitions,
234  // or on starting or stopping of play or record,
235  // or change of toolbar button,
236  // and change the cursor appropriately.
237 
238  // Get the button and key states
239  auto state = ::wxGetMouseState();
240  // Remap the position
241  state.SetPosition(this->ScreenToClient(state.GetPosition()));
242 
243  HandleMotion( state, doHit );
244 }
245 
253 void CellularPanel::HandleMotion( wxMouseState &inState, bool doHit )
254 {
255  UpdateMouseState( inState );
256 
257  const auto foundCell = FindCell( inState.m_x, inState.m_y );
258  auto &rect = foundCell.rect;
259  auto &pCell = foundCell.pCell;
260  const TrackPanelMouseState tpmState{ mLastMouseState, rect, pCell };
261  HandleMotion( tpmState, doHit );
262 }
263 
265 ( const TrackPanelMouseState &tpmState, bool doHit )
266 {
267  auto &state = *mState;
268  auto handle = state.mUIHandle;
269 
270  auto newCell = tpmState.pCell;
271  auto oldCell = state.mLastCell.lock();
272  auto oldHandle = Target();
273 
274  TranslatableString status, tooltip;
275  wxCursor *pCursor{};
276  unsigned refreshCode = 0;
277  if ( ! doHit ) {
278  // Dragging or not
279  handle = Target();
280 
281  // Assume cell does not change but target does
282  refreshCode = state.mMouseOverUpdateFlags;
283  state.mMouseOverUpdateFlags = 0;
284  }
285  else if ( !state.mUIHandle ) {
286  // Not yet dragging.
287 
288  unsigned updateFlags = state.mMouseOverUpdateFlags;
289 
290  // First check whether crossing cell to cell
291  if ( newCell == oldCell )
292  oldCell.reset();
293  else {
294  // Forget old targets
295  ClearTargets();
296  // Re-draw any highlighting
297  if (oldCell) {
299  oldCell.get(), oldCell.get(), updateFlags);
300  }
301  }
302 
303  auto oldPosition = state.mTarget;
304 
305  // Now do the
306  // UIHANDLE HIT TEST !
307  state.mTargets.clear();
308  if (newCell)
309  state.mTargets = newCell->HitTest(tpmState, GetProject());
310  state.mTarget = 0;
311 
312  // Find the old target's NEW place if we can
313  if (oldHandle) {
314  auto begin = state.mTargets.begin(), end = state.mTargets.end(),
315  iter = std::find(begin, end, oldHandle);
316  if (iter != end) {
317  size_t newPosition = iter - begin;
318  if (newPosition <= oldPosition)
319  state.mTarget = newPosition;
320  // else, some NEW hit at this position takes priority
321  }
322  }
323 
324  handle = Target();
325 
326  state.mLastCell = newCell;
327 
328  // These lines caused P2 Bug 2617, repeated refreshing using all CPU.
329  // Disabling them might be causing something to not refresh,
330  // but so far I have not found a downside to disabling them. JKC
331 
332  // VS: https://github.com/audacity/audacity/issues/1363
333  // Extensive refresh request fixed by using std::move on
334  // new envelope handle instance
335  if (!oldCell && oldHandle != handle)
336  // Did not move cell to cell, but did change the target
337  refreshCode = updateFlags;
338 
339 
340  if (handle && handle != oldHandle)
341  handle->Enter(true, GetProject());
342 
343  if (oldHandle == handle)
344  oldHandle.reset();
345  }
346 
347  // UIHANDLE PREVIEW
348  // Update status message and cursor, whether dragging or not
349  if (handle) {
350  auto preview = handle->Preview( tpmState, GetProject() );
351  status = preview.message;
352  tooltip = preview.tooltip;
353  pCursor = preview.cursor;
354  auto code = handle->GetChangeHighlight();
355  handle->SetChangeHighlight(RefreshCode::RefreshNone);
356  refreshCode |= code;
357  state.mMouseOverUpdateFlags |= code;
358  }
359  if (newCell &&
360  (!pCursor || status.empty() || tooltip.empty())) {
361  // Defaulting of cursor, tooltip, and status if there is no handle,
362  // or if the handle does not specify them
363  const auto preview = newCell->DefaultPreview( tpmState, GetProject() );
364  if (!pCursor)
365  pCursor = preview.cursor;
366  if (status.empty())
367  status = preview.message;
368  if (tooltip.empty())
369  tooltip = preview.tooltip;
370  }
371  if (!pCursor) {
372  // Ultimate default cursor
373  static wxCursor defaultCursor{ wxCURSOR_DEFAULT };
374  pCursor = &defaultCursor;
375  }
376 
377  // Update status, tooltip, and cursor only if we're dragging, or the mouse
378  // was in one of our cells and nobody else is dragging
379  if (handle || (newCell && !wxWindow::GetCapture())) {
380  UpdateStatusMessage(status);
381 
382 #if wxUSE_TOOLTIPS
383  if (tooltip.Translation() != GetToolTipText()) {
384  // Unset first, by analogy with AButton
385  UnsetToolTip();
386  if (handle != oldHandle)
387  SetToolTip(tooltip);
388  }
389 #endif
390 
391  if (pCursor)
392  SetCursor( *pCursor );
393  }
394  else if ( oldCell || oldHandle )
395  // Leaving a cell or hit test target with no replacement
396  UpdateStatusMessage( {} );
397 
398  if (newCell)
399  ProcessUIHandleResult(newCell.get(), newCell.get(), refreshCode);
400 }
401 
403 {
404  // Make transition into an empty CellularPanel state
405  auto state = ::wxGetMouseState();
406  const wxRect rect;
407  std::shared_ptr<TrackPanelCell> pCell;
408  TrackPanelMouseState tpmState{ state, rect, pCell };
409  HandleMotion( tpmState );
410 }
411 
413 {
414  auto &state = *mState;
415  // Is there a nontrivial TAB key rotation?
416  if ( state.mTargets.size() > 1 )
417  return true;
418  auto target = Target();
419  return target && target->HasRotation();
420 }
421 
423 {
424  if (IsMouseCaptured())
425  return true;
426 
427  auto &state = *mState;
428  if (state.mTarget + 1 == state.mTargets.size() &&
429  Target() &&
430  !Target()->HasEscape())
431  return false;
432 
433  return state.mTargets.size() > 0;
434 }
435 
436 bool CellularPanel::ChangeTarget(bool forward, bool cycle)
437 {
438  auto &state = *mState;
439  auto size = state.mTargets.size();
440 
441  auto target = Target();
442  if (target && target->HasRotation()) {
443  if(target->Rotate(forward))
444  return true;
445  else if (cycle && (size == 1 || IsMouseCaptured())) {
446  // Rotate through the states of this target only.
447  target->Enter(forward, GetProject());
448  return true;
449  }
450  }
451 
452  if (!cycle &&
453  ((forward && state.mTarget + 1 == size) ||
454  (!forward && state.mTarget == 0)))
455  return false;
456 
457  if (size > 1) {
458  if (forward)
459  ++state.mTarget;
460  else
461  state.mTarget += size - 1;
462  state.mTarget %= size;
463  if (Target())
464  Target()->Enter(forward, GetProject());
465  return true;
466  }
467 
468  return false;
469 }
470 
473 {
474  auto &state = *mState;
475  return state.mUIHandle != NULL;
476 }
477 
478 void CellularPanel::OnContextMenu(wxContextMenuEvent & WXUNUSED(event))
479 {
480  DoContextMenu();
481 }
482 
485 {
486  auto pCell = tpmEvent.pCell;
487  if (!pCell)
488  return;
489 
490  auto &event = tpmEvent.event;
491  double steps {};
492 #if defined(__WXMAC__) && defined(EVT_MAGNIFY)
493  // PRL:
494  // Pinch and spread implemented in wxWidgets 3.1.0, or cherry-picked from
495  // the future in custom build of 3.0.2
496  if (event.Magnify()) {
497  event.SetControlDown(true);
498  steps = 2 * event.GetMagnification();
499  }
500  else
501 #endif
502  {
503  steps = event.m_wheelRotation /
504  (event.m_wheelDelta > 0 ? (double)event.m_wheelDelta : 120.0);
505  }
506 
507  if(event.GetWheelAxis() == wxMOUSE_WHEEL_HORIZONTAL) {
508  // Two-fingered horizontal swipe on mac is treated like shift-mousewheel
509  event.SetShiftDown(true);
510  // This makes the wave move in the same direction as the fingers, and the scrollbar
511  // thumb moves oppositely
512  steps *= -1;
513  }
514 
515  tpmEvent.steps = steps;
516 
517  if(!event.HasAnyModifiers()) {
518  // We will later un-skip if we do anything, but if we don't,
519  // propagate the event up for the sake of the scrubber
520  event.Skip();
521  event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
522  }
523 
524  unsigned result =
525  pCell->HandleWheelRotation( tpmEvent, GetProject() );
527  pCell.get(), pCell.get(), result);
528 }
529 
530 void CellularPanel::OnCaptureKey(wxCommandEvent & event)
531 {
532  auto &state = *mState;
533  state.mEnableTab = false;
534  wxKeyEvent *kevent = static_cast<wxKeyEvent *>(event.GetEventObject());
535  const auto code = kevent->GetKeyCode();
536  if ( WXK_ESCAPE != code )
538 
539  // Give focused cell precedence
540  const auto t = GetFocusedCell();
541  if (t) {
542  const unsigned refreshResult =
543  t->CaptureKey(*kevent, *mViewInfo, this, GetProject());
544  ProcessUIHandleResult(t, t, refreshResult);
545  event.Skip(kevent->GetSkipped());
546  }
547 
548 #if 0
549  // Special TAB key handling, but only if the cell didn't capture it
550  if ( !(t && !kevent->GetSkipped()) &&
551  WXK_TAB == code && HasRotation() ) {
552  // Override TAB navigation in wxWidgets, by not skipping
553  event.Skip(false);
554  mEnableTab = true;
555  return;
556  }
557  else
558 #endif
559  if (!t)
560  event.Skip();
561 }
562 
563 void CellularPanel::OnKeyDown(wxKeyEvent & event)
564 {
565  switch (event.GetKeyCode())
566  {
567  case WXK_ESCAPE:
568  // This switch case is now redundant with the global filter
569  if(HandleEscapeKey(true))
570  // Don't skip the event, eat it so that
571  // AudacityApp does not also stop any playback.
572  return;
573  else
574  break;
575 
576  case WXK_ALT:
577  case WXK_SHIFT:
578  case WXK_CONTROL:
579 #ifdef __WXOSX__
580  case WXK_RAW_CONTROL:
581 #endif
583  break;
584 
585 #if 0
586  case WXK_TAB:
587  if ( mEnableTab && HasRotation() ) {
588  ChangeTarget( !event.ShiftDown(), true );
590  return;
591  }
592  else
593  break;
594 #endif
595  }
596 
597  const auto t = GetFocusedCell();
598 
599  if (t) {
600  const unsigned refreshResult =
601  t->KeyDown(event, *mViewInfo, this, GetProject());
602  ProcessUIHandleResult(t, t, refreshResult);
603  }
604  else
605  event.Skip();
606 }
607 
608 void CellularPanel::OnChar(wxKeyEvent & event)
609 {
610  switch (event.GetKeyCode())
611  {
612  case WXK_ESCAPE:
613  case WXK_ALT:
614  case WXK_SHIFT:
615  case WXK_CONTROL:
616  case WXK_PAGEUP:
617  case WXK_PAGEDOWN:
618  return;
619  }
620 
621  const auto t = GetFocusedCell();
622  if (t) {
623  const unsigned refreshResult =
624  t->Char(event, *mViewInfo, this, GetProject());
625  ProcessUIHandleResult(t, t, refreshResult);
626  }
627  else
628  event.Skip();
629 }
630 
631 void CellularPanel::OnKeyUp(wxKeyEvent & event)
632 {
633  bool didSomething = false;
634  switch (event.GetKeyCode())
635  {
636  case WXK_ESCAPE:
637  didSomething = HandleEscapeKey(false);
638  break;
639 
640  case WXK_ALT:
641  case WXK_SHIFT:
642  case WXK_CONTROL:
643 #ifdef __WXOSX__
644  case WXK_RAW_CONTROL:
645 #endif
647  break;
648  }
649 
650  if (didSomething)
651  return;
652 
653  const auto t = GetFocusedCell();
654  if (t) {
655  const unsigned refreshResult =
656  t->KeyUp(event, *mViewInfo, this, GetProject());
657  ProcessUIHandleResult(t, t, refreshResult);
658  return;
659  }
660 
661  event.Skip();
662 }
663 
665 void CellularPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
666 {
667  auto &state = *mState;
668  state.mUIHandle.reset();
669  Leave();
670 
671  // This is bad. We are lying abou the event by saying it is a mouse up.
672  wxMouseEvent e(wxEVT_LEFT_UP);
673  e.SetId( kCaptureLostEventId );
674 
675  e.m_x = state.mMouseMostRecentX;
676  e.m_y = state.mMouseMostRecentY;
677 
678  OnMouseEvent(e);
679 }
680 
684 void CellularPanel::OnMouseEvent(wxMouseEvent & event)
685 try
686 {
687  const auto foundCell = FindCell( event.m_x, event.m_y );
688  auto &rect = foundCell.rect;
689  auto &pCell = foundCell.pCell;
690 
691  const auto size = GetSize();
692  TrackPanelMouseEvent tpmEvent{ event, rect, size, pCell };
693 
694 #if defined(__WXMAC__) && defined(EVT_MAGNIFY)
695  // PRL:
696  // Pinch and spread implemented in wxWidgets 3.1.0, or cherry-picked from
697  // the future in custom build of 3.0.2
698  if (event.Magnify()) {
699  HandleWheelRotation( tpmEvent );
700  }
701 #endif
702 
703  // If a mouse event originates from a keyboard context menu event then
704  // event.GetPosition() == wxDefaultPosition. wxContextMenu events are handled in
705  // CellularPanel::OnContextMenu(), and therefore associated mouse events are ignored here.
706  // Not ignoring them was causing bug 613: the mouse events were interpreted as clicking
707  // outside the tracks.
708  if (event.GetPosition() == wxDefaultPosition && (event.RightDown() || event.RightUp())) {
709  event.Skip();
710  return;
711  }
712 
713  if (event.m_wheelRotation != 0)
714  HandleWheelRotation( tpmEvent );
715 
716  if (event.LeftDown() || event.LeftIsDown() || event.Moving()) {
717  // Skip, even if we do something, so that the left click or drag
718  // may have an additional effect in the scrubber.
719  event.Skip();
720  event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
721  }
722 
723  auto &state = *mState;
724  state.mMouseMostRecentX = event.m_x;
725  state.mMouseMostRecentY = event.m_y;
726 
727  if (event.LeftDown()) {
728  // The activate event is used to make the
729  // parent window 'come alive' if it didn't have focus.
730  wxActivateEvent e;
731  GetParent()->GetEventHandler()->ProcessEvent(e);
732  }
733 
734  if (event.Entering())
735  {
736  Filter::spActivePanel = this;
737  }
738  else if (event.Leaving())
739  {
740  Leave();
741 
742  auto buttons =
743  // Bug 1325: button state in Leaving events is unreliable on Mac.
744  // Poll the global state instead.
745  // event.ButtonIsDown(wxMOUSE_BTN_ANY);
746  ::wxGetMouseState().ButtonIsDown(wxMOUSE_BTN_ANY);
747 
748  if(!buttons) {
749  CancelDragging( false );
750 
751 #if defined(__WXMAC__)
752 
753  // We must install the cursor ourselves since the window under
754  // the mouse is no longer this one and wx2.8.12 makes that check.
755  // Should re-evaluate with wx3.
756  wxSTANDARD_CURSOR->MacInstall();
757 #endif
758  }
759  }
760 
761  if (state.mUIHandle) {
762  auto pClickedCell = state.mpClickedCell.lock();
763  if (event.Dragging()) {
764  // UIHANDLE DRAG
765  // copy shared_ptr for safety, as in HandleClick
766  auto handle = state.mUIHandle;
767  const UIHandle::Result refreshResult =
768  handle->Drag( tpmEvent, GetProject() );
770  (pClickedCell.get(), pCell.get(), refreshResult);
771  state.mMouseOverUpdateFlags |= refreshResult;
772  if (refreshResult & RefreshCode::Cancelled) {
773  // Drag decided to abort itself
774  state.mUIHandle.reset(), handle.reset(), ClearTargets();
775  state.mpClickedCell.reset();
776  Uncapture( false, &event );
777  }
778  else {
779  UpdateMouseState(event);
780  TrackPanelMouseState tpmState{ mLastMouseState, rect, pCell };
781  HandleMotion( tpmState );
782  }
783  }
784  else if (event.ButtonUp()) {
785  // UIHANDLE RELEASE
786  // copy shared_ptr for safety, as in HandleClick
787  auto handle = state.mUIHandle;
788  unsigned moreFlags = state.mMouseOverUpdateFlags;
789  UIHandle::Result refreshResult =
790  handle->Release( tpmEvent, GetProject(), this );
792  (pClickedCell.get(), pCell.get(),
793  refreshResult | moreFlags);
794  state.mUIHandle.reset(), handle.reset(), ClearTargets();
795  state.mpClickedCell.reset();
796  // will also Uncapture() below
797  }
798  }
799  else if ( event.GetEventType() == wxEVT_MOTION )
800  // Update status message and cursor, not during drag
801  // consider it not a drag, even if button is down during motion, if
802  // mUIHandle is null, as it becomes during interrupted drag
803  // (e.g. by hitting space to play while dragging an envelope point)
804  HandleMotion( event );
805  else if ( event.ButtonDown() || event.ButtonDClick() )
806  HandleClick( tpmEvent );
807 
808  if (event.ButtonDown() && IsMouseCaptured()) {
809  if (!HasCapture())
810  CaptureMouse();
811  }
812 
813  if (event.ButtonUp())
814  Uncapture( false );
815 }
816 catch( ... )
817 {
818  // Abort any dragging, as if by hitting Esc
819  if ( CancelDragging( true ) )
820  ;
821  else {
822  Uncapture( true );
823  Refresh(false);
824  }
825  throw;
826 }
827 
828 namespace {
829 
831 public:
833  const std::shared_ptr<TrackPanelCell> &pCell )
834  : mwCell{ pCell }
835  {}
836 
837  ~DefaultRightButtonHandler() override;
838 
839  virtual Result Click
840  (const TrackPanelMouseEvent &event, AudacityProject *pProject) override
841  {
843  }
844 
845  virtual Result Drag
846  (const TrackPanelMouseEvent &event, AudacityProject *pProject) override
847  {
849  }
850 
852  (const TrackPanelMouseState &state, AudacityProject *pProject) override
853  {
854  return {};
855  }
856 
857  virtual Result Release
858  (const TrackPanelMouseEvent &event, AudacityProject *pProject,
859  wxWindow *pParent) override
860  {
861  if (auto pCell = mwCell.lock()) {
862  auto point = event.event.GetPosition();
863  return pCell->DoContextMenu(event.rect, pParent, &point, pProject);
864  }
866  }
867 
868  virtual Result Cancel(AudacityProject *pProject) override
869  {
871  }
872 
873 private:
874  std::weak_ptr<TrackPanelCell> mwCell;
875 };
876 
877 DefaultRightButtonHandler::~DefaultRightButtonHandler()
878 {
879 }
880 
881 }
882 
884 {
885  auto pCell = tpmEvent.pCell;
886  // Do hit test once more, in case the button really pressed was not the
887  // one "anticipated."
888  {
889  TrackPanelMouseState tpmState{
890  tpmEvent.event,
891  tpmEvent.rect,
892  tpmEvent.pCell
893  };
894  HandleMotion( tpmState );
895  }
896 
897  auto &state = *mState;
898  state.mUIHandle = Target();
899  if (tpmEvent.event.RightDown() &&
900  !(state.mUIHandle && state.mUIHandle->HandlesRightClick())) {
901  if (auto pCell = state.mLastCell.lock())
902  state.mUIHandle = std::make_shared<DefaultRightButtonHandler>(pCell);
903  }
904 
905  if (state.mUIHandle) {
906  // UIHANDLE CLICK
907  // Make another shared pointer to the handle, in case recursive
908  // event dispatching otherwise tries to delete the handle.
909  auto handle = state.mUIHandle;
910  UIHandle::Result refreshResult =
911  handle->Click( tpmEvent, GetProject() );
912  if (refreshResult & RefreshCode::Cancelled)
913  state.mUIHandle.reset(), handle.reset(), ClearTargets();
914  else {
915  Filter::spActivePanel = this;
916 
917 #if wxUSE_TOOLTIPS
918  // Remove any outstanding tooltip
919  UnsetToolTip();
920 #endif
921 
922  if( !HasFocus() && AcceptsFocus() )
923  SetFocusIgnoringChildren();
924 
925  state.mpClickedCell = pCell;
926 
927  // Perhaps the clicked handle wants to update cursor and state message
928  // after a click.
929  TrackPanelMouseState tpmState{
930  tpmEvent.event,
931  tpmEvent.rect,
932  tpmEvent.pCell
933  };
934  HandleMotion( tpmState );
935  }
937  pCell.get(), pCell.get(), refreshResult);
938  state.mMouseOverUpdateFlags |= refreshResult;
939  }
940 }
941 
943 {
944  if( !pCell ) {
945  pCell = GetFocusedCell();
946  if( !pCell )
947  return;
948  }
949 
950  const auto delegate = pCell->ContextMenuDelegate();
951  if (!delegate)
952  return;
953 
954  auto rect = FindRect( *delegate );
955  const UIHandle::Result refreshResult =
956  delegate->DoContextMenu(rect, this, nullptr, GetProject());
957 
958  // To do: use safer shared_ptr to pCell
959  ProcessUIHandleResult(pCell, pCell, refreshResult);
960 }
961 
962 void CellularPanel::OnSetFocus(wxFocusEvent &event)
963 {
964  SetFocusedCell();
965  Refresh( false);
966 }
967 
968 void CellularPanel::OnKillFocus(wxFocusEvent & WXUNUSED(event))
969 {
970  if (auto pCell = GetFocusedCell()) {
971  auto refreshResult = pCell->LoseFocus(GetProject());
972  auto &state = *mState;
973  auto pClickedCell = state.mpClickedCell.lock();
974  if (pClickedCell)
975  ProcessUIHandleResult( pClickedCell.get(), {}, refreshResult );
976  }
977  if (KeyboardCapture::IsHandler(this))
978  {
980  }
981  Refresh( false);
982 }
983 
984 // Empty out-of-line default functions to fill Visitor's vtable
987  const wxRect &rect, TrackPanelCell &cell ) {}
989  const wxRect &rect, TrackPanelGroup &group ) {}
991  const wxRect &rect, TrackPanelGroup &group ) {}
992 
993 // Public, top-level entry for generalized Visit
995 {
996  Visit( GetClientRect(), Root(), visitor );
997 }
998 
999 // Common utility class for the functions that follow
1000 namespace {
1004 
1005  // Visit cells only
1006  Adaptor( const SimpleCellVisitor& function_ )
1007  : function{ [&](const wxRect &rect, TrackPanelNode &cell) {
1008  return function_( rect, static_cast<TrackPanelCell&>(cell) );
1009  } }
1010  {}
1011 
1012  // Visit cells and groups, each once only, choosing pre- or post- ordering
1013  // for the groups
1014  Adaptor( const SimpleNodeVisitor &function_, bool pre_ )
1015  : function{ function_ }, pre{ pre_ }, post{ ! pre_ } {}
1016 
1017  void VisitCell( const wxRect &rect, TrackPanelCell &cell ) override
1018  { return function( rect, cell ); }
1019  void BeginGroup( const wxRect &rect, TrackPanelGroup &group ) override
1020  { if (pre) return function( rect, group ); }
1021  void EndGroup( const wxRect &rect, TrackPanelGroup &group ) override
1022  { if (post) return function( rect, group ); }
1023 
1025  const bool pre{ false }, post{ false };
1026  };
1027 }
1028 
1029 // Simplified entry points for visits that don't need all the generality of
1030 // CellularPanel::Visitor
1032 {
1033  Adaptor adaptor{ visitor };
1034  Visit( adaptor );
1035 }
1036 
1038 {
1039  Adaptor adaptor{ visitor, true };
1040  Visit( adaptor );
1041 }
1042 
1044 {
1045  Adaptor adaptor{ visitor, false };
1046  Visit( adaptor );
1047 }
1048 
1049 namespace {
1050  wxRect Subdivide(
1051  const wxRect &rect, bool divideX,
1052  const TrackPanelGroup::Refinement &children,
1053  const TrackPanelGroup::Refinement::const_iterator iter)
1054  {
1055  const auto next = iter + 1;
1056  const auto end = children.end();
1057  wxCoord nextCoord;
1058  if (next == end)
1059  nextCoord = std::max( iter->first,
1060  divideX ? rect.GetRight() : rect.GetBottom() );
1061  else
1062  nextCoord = next->first - 1;
1063 
1064  auto lesser = iter->first;
1065  auto greater = nextCoord;
1066 
1067  auto result = rect;
1068  if (divideX)
1069  result.SetLeft(lesser), result.SetRight(greater);
1070  else
1071  result.SetTop(lesser), result.SetBottom(greater);
1072 
1073  return result;
1074  };
1075 }
1076 
1077 // Private, recursive implementation function of Visit
1079  const wxRect &rect, const std::shared_ptr<TrackPanelNode> &node,
1080  Visitor &visitor )
1081 {
1082  if (auto pCell = dynamic_cast<TrackPanelCell*>(node.get()))
1083  visitor.VisitCell( rect, *pCell );
1084  else if (auto pGroup = dynamic_cast<TrackPanelGroup*>(node.get())) {
1085  visitor.BeginGroup( rect, *pGroup );
1086 
1087  // Recur on children
1088  const auto results = pGroup->Children( rect );
1089  const bool divideX = results.first == TrackPanelGroup::Axis::X;
1090  const auto &children = results.second;
1091  const auto begin = children.begin(), end = children.end();
1092  for (auto iter = begin; iter != end; ++iter)
1093  Visit(
1094  Subdivide(rect, divideX, children, iter), iter->second, visitor );
1095 
1096  visitor.EndGroup( rect, *pGroup );
1097  }
1098  else
1099  return;
1100 }
1101 
1102 auto CellularPanel::FindCell(int mouseX, int mouseY) -> FoundCell
1103 {
1104  auto rect = this->GetClientRect();
1105  auto node = Root();
1106  while (node) {
1107  if ( auto pCell = std::dynamic_pointer_cast< TrackPanelCell >( node ) )
1108  // Found the bottom of the hierarchy
1109  return { pCell, rect };
1110  else if ( auto pGroup = dynamic_cast< TrackPanelGroup* >( node.get() ) ) {
1111  // Ask node for its subdivision
1112  const auto results = pGroup->Children( rect );
1113  const bool divideX = results.first == TrackPanelGroup::Axis::X;
1114  const auto &children = results.second;
1115 
1116  // Find the correct child
1117  const auto begin = children.begin(), end = children.end();
1118  auto iter = std::upper_bound( begin, end,
1119  (divideX ? mouseX : mouseY),
1120  [&]( wxCoord coord, const TrackPanelGroup::Child &child ) {
1121  return coord < child.first;
1122  }
1123  );
1124  if (iter == begin)
1125  break;
1126  --iter;
1127 
1128  // Descend the hierarchy of nodes
1129  rect = Subdivide(rect, divideX, children, iter);
1130  node = iter->second;
1131  }
1132  else
1133  // Nulls in the array of children are allowed, to define a void with
1134  // no cell
1135  break;
1136  }
1137 
1138  return { {}, {} };
1139 }
1140 
1142 {
1143  wxRect result;
1144 
1145  struct Stop{};
1146  try { VisitCells( [&]( const wxRect &rect, TrackPanelCell &visited ) {
1147  if ( &visited == &cell )
1148  result = rect, throw Stop{};
1149  } ); }
1150  catch ( const Stop& ) {}
1151 
1152  return result;
1153 }
1154 
1156  const std::function< bool( TrackPanelNode& ) > &pred)
1157 {
1158  wxRect result;
1159 
1160  struct Stop{};
1161  try { VisitPreorder( [&]( const wxRect &rect, TrackPanelNode &visited ) {
1162  if ( pred( visited ) )
1163  result = rect, throw Stop{};
1164  } ); }
1165  catch ( const Stop& ) {}
1166 
1167  return result;
1168 }
1169 
1171 {
1172  auto &state = *mState;
1173  if (state.mTargets.size())
1174  return state.mTargets[state.mTarget];
1175  else
1176  return {};
1177 }
1178 
1180 {
1181  auto &state = *mState;
1182  return state.mMouseMostRecentX;
1183 }
1184 
1186 {
1187  auto &state = *mState;
1188  // Forget the rotation of hit test candidates when the mouse moves from
1189  // cell to cell or outside of the panel entirely.
1190  state.mLastCell.reset();
1191  state.mTargets.clear();
1192  state.mTarget = 0;
1193  state.mMouseOverUpdateFlags = 0;
1194 }
1195 
1196 std::shared_ptr<TrackPanelCell> CellularPanel::LastCell() const
1197 {
1198  auto &state = *mState;
1199  return state.mLastCell.lock();
1200 }
1201 
1202 void CellularPanel::Draw( TrackPanelDrawingContext &context, unsigned nPasses )
1203 {
1204  const auto panelRect = GetClientRect();
1205  auto lastCell = LastCell();
1206  for ( unsigned iPass = 0; iPass < nPasses; ++iPass ) {
1207 
1208  VisitPostorder( [&]( const wxRect &rect, TrackPanelNode &node ) {
1209 
1210  // Draw the node
1211  const auto newRect = node.DrawingArea(
1212  context, rect, panelRect, iPass );
1213  if ( newRect.Intersects( panelRect ) )
1214  node.Draw( context, newRect, iPass );
1215 
1216  // Draw the current handle if it is associated with the node
1217  if ( &node == lastCell.get() ) {
1218  auto target = Target();
1219  if ( target ) {
1220  const auto targetRect =
1221  target->DrawingArea( context, rect, panelRect, iPass );
1222  if ( targetRect.Intersects( panelRect ) )
1223  target->Draw( context, targetRect, iPass );
1224  }
1225  }
1226 
1227  } ); // nodes
1228 
1229  } // passes
1230 }
size
size_t size
Definition: ffmpeg-2.3.6-single-header.h:412
anonymous_namespace{CellularPanel.cpp}::Adaptor::Adaptor
Adaptor(const SimpleNodeVisitor &function_, bool pre_)
Definition: CellularPanel.cpp:1014
TrackPanelMouseEvent::pCell
std::shared_ptr< TrackPanelCell > pCell
Definition: TrackPanelMouseEvent.h:61
anonymous_namespace{CellularPanel.cpp}::Adaptor
Definition: CellularPanel.cpp:1001
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
CellularPanel::Uncapture
void Uncapture(bool escaping, wxMouseState *pState=nullptr)
Definition: CellularPanel.cpp:141
CellularPanel::GetFocusedCell
virtual TrackPanelCell * GetFocusedCell()=0
TrackPanelMouseState::pCell
std::shared_ptr< TrackPanelCell > pCell
Definition: TrackPanelMouseEvent.h:40
TrackPanelGroup::Refinement
std::vector< Child > Refinement
Definition: TrackPanelCell.h:64
TrackPanelMouseEvent.h
TranslatableString::empty
bool empty() const
Definition: TranslatableString.h:72
anonymous_namespace{CellularPanel.cpp}::DefaultRightButtonHandler
Definition: CellularPanel.cpp:830
wxPanelWrapper::SetToolTip
void SetToolTip(const TranslatableString &toolTip)
Definition: wxPanelWrapper.cpp:56
CellularPanel::HandleCursorForPresentMouseState
void HandleCursorForPresentMouseState(bool doHit=true)
Definition: CellularPanel.cpp:231
CellularPanel::VisitPostorder
void VisitPostorder(const SimpleNodeVisitor &visitor)
Definition: CellularPanel.cpp:1043
CellularPanel::LastCell
std::shared_ptr< TrackPanelCell > LastCell() const
Definition: CellularPanel.cpp:1196
CellularPanel::Filter::spActivePanel
static wxWeakRef< CellularPanel > spActivePanel
Definition: CellularPanel.cpp:73
TrackPanelMouseEvent::rect
const wxRect & rect
Definition: TrackPanelMouseEvent.h:59
CellularPanel::FoundCell
Definition: CellularPanel.h:85
anonymous_namespace{CellularPanel.cpp}::DefaultRightButtonHandler::mwCell
std::weak_ptr< TrackPanelCell > mwCell
Definition: CellularPanel.cpp:874
RefreshCode::RefreshNone
@ RefreshNone
Definition: RefreshCode.h:21
CellularPanel::State::mEnableTab
bool mEnableTab
Definition: CellularPanel.cpp:92
KeyboardCapture::Release
void Release(wxWindow *handler)
Definition: KeyboardCapture.cpp:75
EVT_COMMAND
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
Definition: LabelDialog.cpp:92
KeyboardCapture::IsHandler
bool IsHandler(const wxWindow *handler)
Definition: KeyboardCapture.cpp:60
CellularPanel::mViewInfo
ViewInfo * mViewInfo
Definition: CellularPanel.h:161
CellularPanel::Filter::Create
static void Create()
Definition: CellularPanel.cpp:56
KeyboardCapture.h
TrackPanelDrawingContext
Definition: TrackPanelDrawingContext.h:22
ViewInfo
Definition: ViewInfo.h:202
anonymous_namespace{CellularPanel.cpp}::Adaptor::Adaptor
Adaptor(const SimpleCellVisitor &function_)
Definition: CellularPanel.cpp:1006
anonymous_namespace{CellularPanel.cpp}::DefaultRightButtonHandler::Click
virtual Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Definition: CellularPanel.cpp:840
CellularPanel::Leave
void Leave()
Definition: CellularPanel.cpp:402
RefreshCode::Cancelled
@ Cancelled
Definition: RefreshCode.h:23
TrackPanelDrawable::DrawingArea
virtual wxRect DrawingArea(TrackPanelDrawingContext &context, const wxRect &rect, const wxRect &panelRect, unsigned iPass)
Definition: TrackPanelDrawable.cpp:22
anonymous_namespace{CellularPanel.cpp}::Adaptor::VisitCell
void VisitCell(const wxRect &rect, TrackPanelCell &cell) override
Definition: CellularPanel.cpp:1017
CellularPanel::OnCaptureLost
void OnCaptureLost(wxMouseCaptureLostEvent &event)
Should handle the case when the mouse capture is lost. (MSW only)
Definition: CellularPanel.cpp:665
CellularPanel::ClearTargets
void ClearTargets()
Definition: CellularPanel.cpp:1185
CellularPanel::Filter::Filter
Filter()
Definition: CellularPanel.cpp:46
CellularPanel::FindRect
wxRect FindRect(const TrackPanelCell &cell)
Definition: CellularPanel.cpp:1141
CellularPanel::Visitor::VisitCell
virtual void VisitCell(const wxRect &rect, TrackPanelCell &cell)
Definition: CellularPanel.cpp:986
HitTestResult.h
CellularPanel::OnCaptureKey
void OnCaptureKey(wxCommandEvent &event)
Definition: CellularPanel.cpp:530
anonymous_namespace{CellularPanel.cpp}::DefaultRightButtonHandler::Preview
virtual HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *pProject) override
Definition: CellularPanel.cpp:852
CellularPanel::SimpleCellVisitor
std::function< void(const wxRect &rect, TrackPanelCell &cell) > SimpleCellVisitor
Definition: CellularPanel.h:75
TrackPanelGroup::Child
std::pair< wxCoord, std::shared_ptr< TrackPanelNode > > Child
Definition: TrackPanelCell.h:63
CellularPanel::OnSetFocus
void OnSetFocus(wxFocusEvent &event)
Definition: CellularPanel.cpp:962
CellularPanel::State::mTarget
size_t mTarget
Definition: CellularPanel.cpp:84
CellularPanel::ProcessUIHandleResult
virtual void ProcessUIHandleResult(TrackPanelCell *pClickedCell, TrackPanelCell *pLatestCell, unsigned refreshResult)=0
UIHandle
Short-lived drawing and event-handling object associated with a TrackPanelCell.
Definition: UIHandle.h:35
anonymous_namespace{CellularPanel.cpp}::DefaultRightButtonHandler::DefaultRightButtonHandler
DefaultRightButtonHandler(const std::shared_ptr< TrackPanelCell > &pCell)
Definition: CellularPanel.cpp:832
CellularPanel::Root
virtual std::shared_ptr< TrackPanelNode > Root()=0
TrackPanelGroup::Axis::X
@ X
CellularPanel::VisitPreorder
void VisitPreorder(const SimpleNodeVisitor &visitor)
Definition: CellularPanel.cpp:1037
CellularPanel::CancelDragging
bool CancelDragging(bool escaping)
Definition: CellularPanel.cpp:158
TrackPanelNode
The TrackPanel is built up of nodes, subtrees of the CellularPanel's area Common base class for Track...
Definition: TrackPanelCell.h:39
CellularPanel::MostRecentXCoord
wxCoord MostRecentXCoord() const
Definition: CellularPanel.cpp:1179
CellularPanel::OnMouseEvent
void OnMouseEvent(wxMouseEvent &event)
Definition: CellularPanel.cpp:684
anonymous_namespace{CellularPanel.cpp}::DefaultRightButtonHandler::Drag
virtual Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Definition: CellularPanel.cpp:846
CellularPanel::HasEscape
bool HasEscape()
Definition: CellularPanel.cpp:422
CellularPanel::HandleEscapeKey
bool HandleEscapeKey(bool down)
Definition: CellularPanel.cpp:179
CellularPanel::State
Definition: CellularPanel.cpp:79
CellularPanel::Visit
void Visit(Visitor &visitor)
Definition: CellularPanel.cpp:994
CellularPanel::ChangeTarget
bool ChangeTarget(bool forward, bool cycle)
Definition: CellularPanel.cpp:436
CellularPanel::Filter::~Filter
~Filter()
Definition: CellularPanel.cpp:51
CellularPanel::State::mLastCell
std::weak_ptr< TrackPanelCell > mLastCell
Definition: CellularPanel.cpp:82
CellularPanel::mState
std::unique_ptr< State > mState
Definition: CellularPanel.h:167
CellularPanel::Filter::FilterEvent
int FilterEvent(wxEvent &event) override
Definition: CellularPanel.cpp:61
UIHandle::Result
unsigned Result
Definition: UIHandle.h:38
anonymous_namespace{CellularPanel.cpp}::DefaultRightButtonHandler::Cancel
virtual Result Cancel(AudacityProject *pProject) override
Definition: CellularPanel.cpp:868
CellularPanel::HandleInterruptedDrag
void HandleInterruptedDrag()
Definition: CellularPanel.cpp:125
UIHandlePtr
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
CellularPanel::UpdateMouseState
void UpdateMouseState(const wxMouseState &state)
Definition: CellularPanel.cpp:206
TrackPanelCell
Definition: TrackPanelCell.h:74
CellularPanel::Visitor::~Visitor
virtual ~Visitor()
Definition: CellularPanel.cpp:985
HitTestPreview
Definition: HitTestResult.h:20
CellularPanel::IsMouseCaptured
bool IsMouseCaptured()
Determines if a modal tool is active.
Definition: CellularPanel.cpp:472
CellularPanel::OnChar
void OnChar(wxKeyEvent &event)
Definition: CellularPanel.cpp:608
CellularPanel::Target
UIHandlePtr Target()
Definition: CellularPanel.cpp:1170
CellularPanel::Visitor::BeginGroup
virtual void BeginGroup(const wxRect &rect, TrackPanelGroup &group)
Definition: CellularPanel.cpp:988
CellularPanel::SimpleNodeVisitor
std::function< void(const wxRect &rect, TrackPanelNode &node) > SimpleNodeVisitor
Definition: CellularPanel.h:80
TrackPanelGroup
Definition: TrackPanelCell.h:47
CellularPanel::State::mMouseOverUpdateFlags
unsigned mMouseOverUpdateFlags
Definition: CellularPanel.cpp:85
CellularPanel::Draw
void Draw(TrackPanelDrawingContext &context, unsigned nPasses)
Definition: CellularPanel.cpp:1202
anonymous_namespace{CellularPanel.cpp}::Adaptor::SimpleCellVisitor
CellularPanel::SimpleCellVisitor SimpleCellVisitor
Definition: CellularPanel.cpp:1002
TrackPanelCell::ContextMenuDelegate
virtual std::shared_ptr< TrackPanelCell > ContextMenuDelegate()
Definition: TrackPanelCell.h:104
CellularPanel.h
CellularPanel::SetFocusedCell
virtual void SetFocusedCell()=0
CellularPanel::OnKeyDown
void OnKeyDown(wxKeyEvent &event)
Definition: CellularPanel.cpp:563
CellularPanel::State::mTargets
std::vector< UIHandlePtr > mTargets
Definition: CellularPanel.cpp:83
UIHandle.h
CellularPanel::UpdateStatusMessage
virtual void UpdateStatusMessage(const TranslatableString &)=0
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
TrackPanelCell.h
CellularPanel::OnKeyUp
void OnKeyUp(wxKeyEvent &event)
Definition: CellularPanel.cpp:631
CellularPanel::State::mMouseMostRecentX
int mMouseMostRecentX
Definition: CellularPanel.cpp:87
CellularPanel
Formerly part of TrackPanel, this abstract base class has no special knowledge of Track objects and i...
Definition: CellularPanel.h:34
CellularPanel::State::mUIHandle
UIHandlePtr mUIHandle
Definition: CellularPanel.cpp:80
CellularPanel::HandleWheelRotation
void HandleWheelRotation(TrackPanelMouseEvent &tpmEvent)
Handle mouse wheel rotation (for zoom in/out, vertical and horizontal scrolling)
Definition: CellularPanel.cpp:484
TrackPanelMouseEvent
Definition: TrackPanelMouseEvent.h:46
anonymous_namespace{CellularPanel.cpp}::Adaptor::BeginGroup
void BeginGroup(const wxRect &rect, TrackPanelGroup &group) override
Definition: CellularPanel.cpp:1019
CellularPanel::State::mpClickedCell
std::weak_ptr< TrackPanelCell > mpClickedCell
Definition: CellularPanel.cpp:90
CellularPanel::State::mMouseMostRecentY
int mMouseMostRecentY
Definition: CellularPanel.cpp:88
CellularPanel::OnContextMenu
void OnContextMenu(wxContextMenuEvent &event)
Definition: CellularPanel.cpp:478
TrackPanelMouseState
Definition: TrackPanelMouseEvent.h:28
CellularPanel::HasRotation
bool HasRotation()
Definition: CellularPanel.cpp:412
CellularPanel::mLastMouseState
wxMouseState mLastMouseState
Definition: CellularPanel.h:164
OverlayPanel
Definition: OverlayPanel.h:18
CellularPanel::VisitCells
void VisitCells(const SimpleCellVisitor &visitor)
Definition: CellularPanel.cpp:1031
CellularPanel::HandleClick
void HandleClick(const TrackPanelMouseEvent &tpmEvent)
Definition: CellularPanel.cpp:883
kCaptureLostEventId
const int kCaptureLostEventId
Definition: TrackPanelMouseEvent.h:23
RefreshCode.h
anonymous_namespace{CellularPanel.cpp}::Adaptor::EndGroup
void EndGroup(const wxRect &rect, TrackPanelGroup &group) override
Definition: CellularPanel.cpp:1021
CellularPanel::DoContextMenu
void DoContextMenu(TrackPanelCell *pCell=nullptr)
Definition: CellularPanel.cpp:942
CellularPanel::Visitor
Definition: CellularPanel.h:63
CellularPanel::HandleMotion
void HandleMotion(wxMouseState &state, bool doHit=true)
Definition: CellularPanel.cpp:253
anonymous_namespace{CellularPanel.cpp}::DefaultRightButtonHandler::Release
virtual Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
Definition: CellularPanel.cpp:858
TranslatableString::Translation
wxString Translation() const
Definition: TranslatableString.h:79
CellularPanel::HandleModifierKey
void HandleModifierKey()
Definition: CellularPanel.cpp:226
CellularPanel::Visitor::EndGroup
virtual void EndGroup(const wxRect &rect, TrackPanelGroup &group)
Definition: CellularPanel.cpp:990
CellularPanel::~CellularPanel
~CellularPanel() override
END_EVENT_TABLE
END_EVENT_TABLE()
CellularPanel::FindCell
FoundCell FindCell(int mouseX, int mouseY)
Definition: CellularPanel.cpp:1102
anonymous_namespace{CellularPanel.cpp}::Adaptor::SimpleNodeVisitor
CellularPanel::SimpleNodeVisitor SimpleNodeVisitor
Definition: CellularPanel.cpp:1003
anonymous_namespace{CellularPanel.cpp}::Subdivide
wxRect Subdivide(const wxRect &rect, bool divideX, const TrackPanelGroup::Refinement &children, const TrackPanelGroup::Refinement::const_iterator iter)
Definition: CellularPanel.cpp:1050
TrackPanelMouseEvent::event
wxMouseEvent & event
Definition: TrackPanelMouseEvent.h:58
CellularPanel::Filter
Definition: CellularPanel.cpp:45
TrackPanelMouseEvent::steps
double steps
Definition: TrackPanelMouseEvent.h:62
CellularPanel::OnKillFocus
void OnKillFocus(wxFocusEvent &event)
Definition: CellularPanel.cpp:968
CellularPanel::GetProject
virtual AudacityProject * GetProject() const =0
mState
struct State mState
TrackPanelDrawable::Draw
virtual void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass)
Definition: TrackPanelDrawable.cpp:17