KiCad PCB EDA Suite
wx_view_controls.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
5  * Copyright (C) 2013-2015 CERN
6  * Copyright (C) 2012-2016 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
9  * @author Maciej Suminski <maciej.suminski@cern.ch>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, you may find one here:
23  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
24  * or you may search the http://www.gnu.org website for the version 2 license,
25  * or you may write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28 
29 #include <pgm_base.h>
30 #include <view/view.h>
31 #include <view/wx_view_controls.h>
32 #include <view/zoom_controller.h>
34 #include <tool/tool_dispatcher.h>
35 #include <trace_helpers.h>
37 #include <math/util.h> // for KiROUND
38 
39 
40 using namespace KIGFX;
41 
42 const wxEventType WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE = wxNewEventType();
43 
44 
45 static std::unique_ptr<ZOOM_CONTROLLER> GetZoomControllerForPlatform()
46 {
47 #ifdef __WXMAC__
48  // On Apple pointer devices, wheel events occur frequently and with
49  // smaller rotation values. For those devices, let's handle zoom
50  // based on the rotation amount rather than the time difference.
51  return std::make_unique<CONSTANT_ZOOM_CONTROLLER>( CONSTANT_ZOOM_CONTROLLER::MAC_SCALE );
52 #elif __WXGTK3__
53  // GTK3 is similar, but the scale constant is smaller
54  return std::make_unique<CONSTANT_ZOOM_CONTROLLER>( CONSTANT_ZOOM_CONTROLLER::GTK3_SCALE );
55 #else
56  return std::make_unique<ACCELERATING_ZOOM_CONTROLLER>();
57 #endif
58 }
59 
60 
61 WX_VIEW_CONTROLS::WX_VIEW_CONTROLS( VIEW* aView, wxScrolledCanvas* aParentPanel ) :
62  VIEW_CONTROLS( aView ),
63  m_state( IDLE ),
64  m_parentPanel( aParentPanel ),
65  m_scrollScale( 1.0, 1.0 ),
66  m_initialZoomScale( 0.0 ),
67 #ifdef __WXGTK3__
68  m_lastTimestamp( 0 ),
69 #endif
70  m_cursorPos( 0, 0 ),
71  m_updateCursor( true )
72 {
73  LoadSettings();
74 
75  m_parentPanel->Connect( wxEVT_MOTION,
76  wxMouseEventHandler( WX_VIEW_CONTROLS::onMotion ), NULL, this );
77 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
78  m_parentPanel->Connect( wxEVT_MAGNIFY,
79  wxMouseEventHandler( WX_VIEW_CONTROLS::onMagnify ), NULL, this );
80 #endif
81  m_parentPanel->Connect( wxEVT_MOUSEWHEEL,
82  wxMouseEventHandler( WX_VIEW_CONTROLS::onWheel ), NULL, this );
83  m_parentPanel->Connect( wxEVT_MIDDLE_UP,
84  wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), NULL, this );
85  m_parentPanel->Connect( wxEVT_MIDDLE_DOWN,
86  wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), NULL, this );
87  m_parentPanel->Connect( wxEVT_LEFT_UP,
88  wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), NULL, this );
89  m_parentPanel->Connect( wxEVT_LEFT_DOWN,
90  wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), NULL, this );
91  m_parentPanel->Connect( wxEVT_RIGHT_UP,
92  wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), NULL, this );
93  m_parentPanel->Connect( wxEVT_RIGHT_DOWN,
94  wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), NULL, this );
95 #if defined _WIN32 || defined _WIN64
96  m_parentPanel->Connect( wxEVT_ENTER_WINDOW,
97  wxMouseEventHandler( WX_VIEW_CONTROLS::onEnter ), NULL, this );
98 #endif
99  m_parentPanel->Connect( wxEVT_LEAVE_WINDOW,
100  wxMouseEventHandler( WX_VIEW_CONTROLS::onLeave ), NULL, this );
101  m_parentPanel->Connect( wxEVT_SCROLLWIN_THUMBTRACK,
102  wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), NULL, this );
103  m_parentPanel->Connect( wxEVT_SCROLLWIN_PAGEUP,
104  wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), NULL, this );
105  m_parentPanel->Connect( wxEVT_SCROLLWIN_PAGEDOWN,
106  wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), NULL, this );
107 
108  m_parentPanel->Connect( wxEVT_SCROLLWIN_BOTTOM,
109  wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), NULL, this );
110  m_parentPanel->Connect( wxEVT_SCROLLWIN_TOP,
111  wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), NULL, this );
112  m_parentPanel->Connect( wxEVT_SCROLLWIN_LINEUP,
113  wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), NULL, this );
114  m_parentPanel->Connect( wxEVT_SCROLLWIN_LINEDOWN,
115  wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), NULL, this );
116 
117  m_cursorWarped = false;
118 
119  m_panTimer.SetOwner( this );
120  this->Connect( wxEVT_TIMER, wxTimerEventHandler( WX_VIEW_CONTROLS::onTimer ), NULL, this );
121 
125 }
126 
127 
129 {
130 }
131 
132 
134 {
135  COMMON_SETTINGS* cfg = Pgm().GetCommonSettings();
136 
147  m_settings.m_dragMiddle = static_cast<MOUSE_DRAG_ACTION>( cfg->m_Input.drag_middle );
148  m_settings.m_dragRight = static_cast<MOUSE_DRAG_ACTION>( cfg->m_Input.drag_right );
149 
150  m_zoomController.reset();
151 
152  if( cfg->m_Input.zoom_speed_auto )
153  {
154  // TODO(JE) this ignores the acceleration option
156  }
157  else
158  {
159  if( cfg->m_Input.zoom_acceleration )
160  {
162  std::make_unique<ACCELERATING_ZOOM_CONTROLLER>( cfg->m_Input.zoom_speed );
163  }
164  else
165  {
167 
168  m_zoomController = std::make_unique<CONSTANT_ZOOM_CONTROLLER>( scale );
169  }
170  }
171 }
172 
173 
174 void WX_VIEW_CONTROLS::onMotion( wxMouseEvent& aEvent )
175 {
176  bool isAutoPanning = false;
177  VECTOR2D mousePos( aEvent.GetX(), aEvent.GetY() );
178 
180  isAutoPanning = handleAutoPanning( aEvent );
181 
182  if( !isAutoPanning && aEvent.Dragging() )
183  {
184  if( m_state == DRAG_PANNING )
185  {
186  VECTOR2D d = m_dragStartPoint - mousePos;
187  VECTOR2D delta = m_view->ToWorld( d, false );
188 
189  m_view->SetCenter( m_lookStartPoint + delta );
190  aEvent.StopPropagation();
191  }
192  else if( m_state == DRAG_ZOOMING )
193  {
194  VECTOR2D d = m_dragStartPoint - mousePos;
195 
196  double scale = 1 + ( d.y * m_settings.m_zoomSpeed * 0.001 );
197 
198  wxLogTrace( traceZoomScroll, wxString::Format( "dy: %f scale: %f", d.y, scale ) );
199 
201  aEvent.StopPropagation();
202  }
203  }
204 
205  if( m_updateCursor ) // do not update the cursor position if it was explicitly set
206  m_cursorPos = m_view->ToWorld( mousePos );
207  else
208  m_updateCursor = true;
209 
210  aEvent.Skip();
211 }
212 
213 
214 void WX_VIEW_CONTROLS::onWheel( wxMouseEvent& aEvent )
215 {
216 #ifdef __WXGTK3__
217  if( aEvent.GetTimestamp() == m_lastTimestamp )
218  {
219  aEvent.Skip( false );
220  return;
221  }
222 
223  m_lastTimestamp = aEvent.GetTimestamp();
224 #endif
225 
226  const double wheelPanSpeed = 0.001;
227  const int axis = aEvent.GetWheelAxis();
228 
229  if( axis == wxMOUSE_WHEEL_HORIZONTAL && !m_settings.m_horizontalPan )
230  return;
231 
232  // Pick the modifier, if any. Shift beats control beats alt, we don't support more than one.
233  int modifiers =
234  aEvent.ShiftDown() ? WXK_SHIFT :
235  ( aEvent.ControlDown() ? WXK_CONTROL : ( aEvent.AltDown() ? WXK_ALT : 0 ) );
236 
237  // Restrict zoom handling to the vertical axis, otherwise horizontal
238  // scrolling events (e.g. touchpads and some mice) end up interpreted
239  // as vertical scroll events and confuse the user.
240  if( axis == wxMOUSE_WHEEL_VERTICAL && modifiers == m_settings.m_scrollModifierZoom )
241  {
242  const int rotation = aEvent.GetWheelRotation();
243  const double zoomScale = m_zoomController->GetScaleForRotation( rotation );
244 
245  if( IsCursorWarpingEnabled() )
246  {
247  CenterOnCursor();
248  m_view->SetScale( m_view->GetScale() * zoomScale );
249  }
250  else
251  {
252  const VECTOR2D anchor = m_view->ToWorld( VECTOR2D( aEvent.GetX(), aEvent.GetY() ) );
253  m_view->SetScale( m_view->GetScale() * zoomScale, anchor );
254  }
255  }
256  else
257  {
258  // Scrolling
259  VECTOR2D scrollVec = m_view->ToWorld( m_view->GetScreenPixelSize(), false ) *
260  ( (double) aEvent.GetWheelRotation() * wheelPanSpeed );
261  double scrollX = 0.0;
262  double scrollY = 0.0;
263 
264  if( axis == wxMOUSE_WHEEL_HORIZONTAL || modifiers == m_settings.m_scrollModifierPanH )
265  scrollX = scrollVec.x;
266  else
267  scrollY = -scrollVec.y;
268 
269  VECTOR2D delta( scrollX, scrollY );
270 
271  m_view->SetCenter( m_view->GetCenter() + delta );
272  refreshMouse();
273  }
274 
275  // Do not skip this event, otherwise wxWidgets will fire
276  // 3 wxEVT_SCROLLWIN_LINEUP or wxEVT_SCROLLWIN_LINEDOWN (normal wxWidgets behavior)
277  // and we do not want that.
278  m_parentPanel->Refresh();
279 }
280 
281 
282 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
283 void WX_VIEW_CONTROLS::onMagnify( wxMouseEvent& aEvent )
284 {
285  // Scale based on the magnification from our underlying magnification event.
286  VECTOR2D anchor = m_view->ToWorld( VECTOR2D( aEvent.GetX(), aEvent.GetY() ) );
287  m_view->SetScale( m_view->GetScale() * ( aEvent.GetMagnification() + 1.0f ), anchor );
288 
289  aEvent.Skip();
290 }
291 #endif
292 
293 
294 void WX_VIEW_CONTROLS::onButton( wxMouseEvent& aEvent )
295 {
296  switch( m_state )
297  {
298  case IDLE:
299  case AUTO_PANNING:
300  if( ( aEvent.MiddleDown() && m_settings.m_dragMiddle == MOUSE_DRAG_ACTION::PAN ) ||
301  ( aEvent.RightDown() && m_settings.m_dragRight == MOUSE_DRAG_ACTION::PAN ) )
302  {
303  m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() );
306  }
307  else if( ( aEvent.MiddleDown() && m_settings.m_dragMiddle == MOUSE_DRAG_ACTION::ZOOM ) ||
308  ( aEvent.RightDown() && m_settings.m_dragRight == MOUSE_DRAG_ACTION::ZOOM ) )
309  {
310  m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() );
313  }
314 
315  if( aEvent.LeftUp() )
316  m_state = IDLE; // Stop autopanning when user release left mouse button
317 
318  break;
319 
320  case DRAG_ZOOMING:
321  case DRAG_PANNING:
322  if( aEvent.MiddleUp() || aEvent.LeftUp() || aEvent.RightUp() )
323  m_state = IDLE;
324 
325  break;
326  }
327 
328  aEvent.Skip();
329 }
330 
331 
332 void WX_VIEW_CONTROLS::onEnter( wxMouseEvent& aEvent )
333 {
334  m_parentPanel->SetFocus();
335 }
336 
337 
338 void WX_VIEW_CONTROLS::onLeave( wxMouseEvent& aEvent )
339 {
341  {
342  bool warp = false;
343  int x = aEvent.GetX();
344  int y = aEvent.GetY();
345  wxSize parentSize = m_parentPanel->GetClientSize();
346 
347  if( x < 0 )
348  {
349  x = 0;
350  warp = true;
351  }
352  else if( x >= parentSize.x )
353  {
354  x = parentSize.x - 1;
355  warp = true;
356  }
357 
358  if( y < 0 )
359  {
360  y = 0;
361  warp = true;
362  }
363  else if( y >= parentSize.y )
364  {
365  y = parentSize.y - 1;
366  warp = true;
367  }
368 
369  if( warp )
370  m_parentPanel->WarpPointer( x, y );
371  }
372 }
373 
374 
375 void WX_VIEW_CONTROLS::onTimer( wxTimerEvent& aEvent )
376 {
377  switch( m_state )
378  {
379  case AUTO_PANNING:
380  {
382  {
383  m_state = IDLE;
384  return;
385  }
386 
387  if( !m_parentPanel->HasFocus() )
388  break;
389 
390  double borderSize = std::min( m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().x,
392 
393  VECTOR2D dir( m_panDirection );
394 
395  float accel = 0.5f + ( m_settings.m_autoPanAcceleration / 5.0f );
396 
397  if( dir.EuclideanNorm() > borderSize / 2 )
398  dir = dir.Resize( pow( borderSize, accel ) );
399  else if( dir.EuclideanNorm() > borderSize )
400  dir = dir.Resize( borderSize );
401 
402  dir = m_view->ToWorld( dir, false );
403  m_view->SetCenter( m_view->GetCenter() + dir );
404 
405  refreshMouse();
406  }
407  break;
408 
409  case IDLE: // Just remove unnecessary warnings
410  case DRAG_PANNING:
411  case DRAG_ZOOMING:
412  break;
413  }
414 }
415 
416 
417 void WX_VIEW_CONTROLS::onScroll( wxScrollWinEvent& aEvent )
418 {
419  const double linePanDelta = 0.05;
420  const double pagePanDelta = 0.5;
421 
422  int type = aEvent.GetEventType();
423  int dir = aEvent.GetOrientation();
424 
425  if( type == wxEVT_SCROLLWIN_THUMBTRACK )
426  {
427  auto center = m_view->GetCenter();
428  const auto& boundary = m_view->GetBoundary();
429 
430  // Flip scroll direction in flipped view
431  const double xstart = ( m_view->IsMirroredX() ?
432  boundary.GetRight() : boundary.GetLeft() );
433  const double xdelta = ( m_view->IsMirroredX() ? -1 : 1 );
434 
435  if( dir == wxHORIZONTAL )
436  center.x = xstart + xdelta * ( aEvent.GetPosition() / m_scrollScale.x );
437  else
438  center.y = boundary.GetTop() + aEvent.GetPosition() / m_scrollScale.y;
439 
440  m_view->SetCenter( center );
441  }
442  else
443  {
444  double dist = 0;
445 
446  if( type == wxEVT_SCROLLWIN_PAGEUP )
447  dist = pagePanDelta;
448  else if( type == wxEVT_SCROLLWIN_PAGEDOWN )
449  dist = -pagePanDelta;
450  else if( type == wxEVT_SCROLLWIN_LINEUP )
451  dist = linePanDelta;
452  else if( type == wxEVT_SCROLLWIN_LINEDOWN )
453  dist = -linePanDelta;
454  else
455  {
456  wxASSERT( "Unhandled event type" );
457  return;
458  }
459 
460  VECTOR2D scroll = m_view->ToWorld( m_view->GetScreenPixelSize(), false ) * dist;
461 
462  double scrollX = 0.0;
463  double scrollY = 0.0;
464 
465  if ( dir == wxHORIZONTAL )
466  scrollX = -scroll.x;
467  else
468  scrollY = -scroll.y;
469 
470  VECTOR2D delta( scrollX, scrollY );
471 
472  m_view->SetCenter( m_view->GetCenter() + delta );
473  }
474 
475  m_parentPanel->Refresh();
476 }
477 
478 
479 void WX_VIEW_CONTROLS::SetGrabMouse( bool aEnabled )
480 {
481  if( aEnabled && !m_settings.m_grabMouse )
482  m_parentPanel->CaptureMouse();
483  else if( !aEnabled && m_settings.m_grabMouse )
484  m_parentPanel->ReleaseMouse();
485 
486  VIEW_CONTROLS::SetGrabMouse( aEnabled );
487 }
488 
489 
490 VECTOR2D WX_VIEW_CONTROLS::GetMousePosition( bool aWorldCoordinates ) const
491 {
493  VECTOR2D screenPos( msp.x, msp.y );
494 
495  return aWorldCoordinates ? m_view->ToWorld( screenPos ) : screenPos;
496 }
497 
498 
500 {
501  if( aEnableSnapping )
502  {
503  return m_view->GetGAL()->GetGridPoint( m_cursorPos );
504  }
505  else
506  {
507  return m_cursorPos;
508  }
509 }
510 
511 
512 VECTOR2D WX_VIEW_CONTROLS::GetCursorPosition( bool aEnableSnapping ) const
513 {
515  {
517  }
518  else
519  {
520  return GetRawCursorPosition( aEnableSnapping );
521  }
522 }
523 
524 
525 void WX_VIEW_CONTROLS::SetCursorPosition( const VECTOR2D& aPosition, bool aWarpView,
526  bool aTriggeredByArrows, long aArrowCommand )
527 {
528  m_updateCursor = false;
529 
530  if( aTriggeredByArrows )
531  {
534  m_settings.m_lastKeyboardCursorCommand = aArrowCommand;
535  m_cursorWarped = false;
536  }
537  else
538  {
542  m_cursorWarped = true;
543  }
544 
545  WarpCursor( aPosition, true, aWarpView );
546  m_cursorPos = aPosition;
547 }
548 
549 
550 void WX_VIEW_CONTROLS::SetCrossHairCursorPosition( const VECTOR2D& aPosition, bool aWarpView = true )
551 {
552  m_updateCursor = false;
553 
554  const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
555  BOX2I screen( VECTOR2I( 0, 0 ), screenSize );
556  VECTOR2D screenPos = m_view->ToScreen( aPosition );
557 
558  if( aWarpView && !screen.Contains( screenPos ) )
559  m_view->SetCenter( aPosition );
560 
561  m_cursorPos = aPosition;
562 }
563 
564 
565 void WX_VIEW_CONTROLS::WarpCursor( const VECTOR2D& aPosition, bool aWorldCoordinates,
566  bool aWarpView )
567 {
568  if( aWorldCoordinates )
569  {
570  const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
571  BOX2I screen( VECTOR2I( 0, 0 ), screenSize );
572  VECTOR2D screenPos = m_view->ToScreen( aPosition );
573 
574  if( !screen.Contains( screenPos ) )
575  {
576  if( aWarpView )
577  {
578  m_view->SetCenter( aPosition );
579  m_parentPanel->WarpPointer( screenSize.x / 2, screenSize.y / 2 );
580  }
581  }
582  else
583  {
584  m_parentPanel->WarpPointer( screenPos.x, screenPos.y );
585  }
586  }
587  else
588  {
589  m_parentPanel->WarpPointer( aPosition.x, aPosition.y );
590  }
591 
592  refreshMouse();
593 }
594 
595 
597 {
598  const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
599  VECTOR2I screenCenter( screenSize / 2 );
600 
601  if( GetMousePosition( false ) != screenCenter )
602  {
604  m_parentPanel->WarpPointer( KiROUND( screenSize.x / 2 ), KiROUND( screenSize.y / 2 ) );
605  }
606 }
607 
608 
609 bool WX_VIEW_CONTROLS::handleAutoPanning( const wxMouseEvent& aEvent )
610 {
611  VECTOR2I p( aEvent.GetX(), aEvent.GetY() );
613 
615  {
616  // last cursor move event came from keyboard cursor control. If auto-panning is enabled and
617  // the next position is inside the autopan zone, check if it really came from a mouse event, otherwise
618  // disable autopan temporarily. Also temporaly disable autopan if the cursor is in the autopan zone
619  // because the application warped the cursor.
620 
621  m_cursorWarped = false;
622  return true;
623  }
624 
625  m_cursorWarped = false;
626 
627  // Compute areas where autopanning is active
628  int borderStart = std::min( m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().x,
630  borderStart = std::max( borderStart, 2 );
631  int borderEndX = m_view->GetScreenPixelSize().x - borderStart;
632  int borderEndY = m_view->GetScreenPixelSize().y - borderStart;
633 
634  if( p.x < borderStart )
635  m_panDirection.x = -( borderStart - p.x );
636  else if( p.x > borderEndX )
637  m_panDirection.x = ( p.x - borderEndX );
638  else
639  m_panDirection.x = 0;
640 
641  if( p.y < borderStart )
642  m_panDirection.y = -( borderStart - p.y );
643  else if( p.y > borderEndY )
644  m_panDirection.y = ( p.y - borderEndY );
645  else
646  m_panDirection.y = 0;
647 
648  bool borderHit = ( m_panDirection.x != 0 || m_panDirection.y != 0 );
649 
650  switch( m_state )
651  {
652  case AUTO_PANNING:
653  if( !borderHit )
654  {
655  m_panTimer.Stop();
656  m_state = IDLE;
657 
658  return false;
659  }
660 
661  return true;
662  break;
663 
664  case IDLE:
665  if( borderHit )
666  {
668  m_panTimer.Start( (int) ( 250.0 / 60.0 ) );
669 
670  return true;
671  }
672 
673  return false;
674  break;
675 
676  case DRAG_PANNING:
677  case DRAG_ZOOMING:
678  return false;
679  }
680 
681  wxASSERT_MSG( false, wxT( "This line should never be reached" ) );
682  return false; // Should not be reached, just avoid the compiler warnings..
683 }
684 
685 
687 {
688  // Notify tools that the cursor position has changed in the world coordinates
689  wxMouseEvent moveEvent( EVT_REFRESH_MOUSE );
691  moveEvent.SetX( msp.x );
692  moveEvent.SetY( msp.y );
693 
694  // Set the modifiers state
695  moveEvent.SetControlDown( wxGetKeyState( WXK_CONTROL ) );
696  moveEvent.SetShiftDown( wxGetKeyState( WXK_SHIFT ) );
697  moveEvent.SetAltDown( wxGetKeyState( WXK_ALT ) );
698 
699  m_cursorPos = m_view->ToWorld( VECTOR2D( msp.x, msp.y ) );
700  wxPostEvent( m_parentPanel, moveEvent );
701 }
702 
703 
705 {
706  wxPoint msp = wxGetMousePosition();
707  m_parentPanel->ScreenToClient( &msp.x, &msp.y );
708  return msp;
709 }
710 
711 
713 {
714  const BOX2D viewport = m_view->GetViewport();
715  const BOX2D& boundary = m_view->GetBoundary();
716 
717  m_scrollScale.x = 2e3 / viewport.GetWidth(); // TODO it does not have to be updated so often
718  m_scrollScale.y = 2e3 / viewport.GetHeight();
719  VECTOR2I newScroll( ( viewport.Centre().x - boundary.GetLeft() ) * m_scrollScale.x,
720  ( viewport.Centre().y - boundary.GetTop() ) * m_scrollScale.y );
721 
722  // We add the width of the scroll bar thumb to the range because the scroll range is given by
723  // the full bar while the position is given by the left/top position of the thumb
724  VECTOR2I newRange( m_scrollScale.x * boundary.GetWidth() + m_parentPanel->GetScrollThumb( wxSB_HORIZONTAL ),
725  m_scrollScale.y * boundary.GetHeight() + m_parentPanel->GetScrollThumb( wxSB_VERTICAL ) );
726 
727  // Flip scroll direction in flipped view
728  if( m_view->IsMirroredX() )
729  newScroll.x = ( boundary.GetRight() - viewport.Centre().x ) * m_scrollScale.x;
730 
731  // Adjust scrollbars only if it is needed. Otherwise there are cases when canvas is continuously
732  // refreshed (Windows)
733  if( m_scrollPos != newScroll || newRange.x != m_parentPanel->GetScrollRange( wxSB_HORIZONTAL )
734  || newRange.y != m_parentPanel->GetScrollRange( wxSB_VERTICAL ) )
735  {
736  m_parentPanel->SetScrollbars( 1, 1, newRange.x, newRange.y, newScroll.x, newScroll.y, true );
737  m_scrollPos = newScroll;
738 
739 #ifndef __APPLE__
740  // Trigger a mouse refresh to get the canvas update in GTK (re-draws the scrollbars).
741  // Note that this causes an infinite loop on OSX as it generates a paint event.
742  refreshMouse();
743 #endif
744  }
745 }
746 
747 void WX_VIEW_CONTROLS::ForceCursorPosition( bool aEnabled, const VECTOR2D& aPosition )
748 {
750  m_settings.m_forcedPosition = aPosition;
751 }
VECTOR2D m_lookStartPoint
Stores information about the center of viewport when dragging has started.
BOX2D GetViewport() const
Function GetViewport() Returns the current viewport visible area rectangle.
Definition: view.cpp:538
const wxChar *const traceZoomScroll
Flag to enable debug output of zoom-scrolling calculations in KIGFX::ZOOM_CONTROLLER and derivatives.
void LoadSettings() override
Applies VIEW_CONTROLS settings from the program COMMON_SETTINGS
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:104
MOUSE_DRAG_ACTION m_dragRight
What drag action to perform when the right button is pressed
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:175
const BOX2D & GetBoundary() const
Function GetBoundary()
Definition: view.h:287
static std::unique_ptr< ZOOM_CONTROLLER > GetZoomControllerForPlatform()
static const wxEventType EVT_REFRESH_MOUSE
Event that forces mouse move event in the dispatcher (eg.
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Function ToWorld() Converts a screen space point/vector to a point/vector in world space coordinates.
Definition: view.cpp:475
coord_type GetTop() const
Definition: box2.h:203
const VECTOR2D & GetCenter() const
Function GetCenter() Returns the center point of this VIEW (in world space coordinates)
Definition: view.h:328
wxPoint getMouseScreenPosition() const
Gets the cursor position in the screen coordinates.
bool m_grabMouse
Flag for grabbing the mouse cursor
Definition: view_controls.h:81
VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const override
Function GetMousePosition() Returns the current mouse pointer position.
std::unique_ptr< ZOOM_CONTROLLER > m_zoomController
a ZOOM_CONTROLLER that determines zoom steps. This is platform-specific.
void onButton(wxMouseEvent &aEvent)
VC_SETTINGS m_settings
Current VIEW_CONTROLS settings
VECTOR2D m_forcedPosition
Forced cursor position (world coordinates)
Definition: view_controls.h:69
coord_type GetRight() const
Definition: box2.h:198
GAL * GetGAL() const
Function GetGAL() Returns the GAL this view is using to draw graphical primitives.
Definition: view.h:180
VIEW * m_view
Pointer to controlled VIEW.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:594
VECTOR2D m_scrollScale
Ratio used for scaling world coordinates to scrollbar position.
WX_VIEW_CONTROLS class definition.
static constexpr double GTK3_SCALE
A suitable (magic) scale factor for GTK3 systems.
void UpdateScrollbars()
Adjusts the scrollbars position to match the current viewport.
VECTOR2D GetGridPoint(const VECTOR2D &aPoint) const
Function GetGridPoint() For a given point it returns the nearest point belonging to the grid in world...
Panning on approaching borders of the frame.
double dist(const double ax, const double ay, const double bx, const double by)
Definition: delauney.h:168
const VECTOR2I & GetScreenPixelSize() const
Returns GAL canvas size in pixels.
int m_scrollModifierPanH
What modifier key to enable horizontal pan with the (vertical) scroll wheel
VECTOR2D m_lastKeyboardCursorPosition
Position of the above event
VECTOR2D GetRawCursorPosition(bool aSnappingEnabled=true) const override
Returns the current cursor position in world coordinates - ingoring the cursorUp position force mode.
bool m_autoPanSettingEnabled
Flag for turning on autopanning
Definition: view_controls.h:87
void onWheel(wxMouseEvent &aEvent)
Handler functions.
void SetCenter(const VECTOR2D &aCenter)
Function SetCenter() Sets the center point of the VIEW (i.e.
Definition: view.cpp:604
Panning with mouse button pressed.
bool m_forceCursorPosition
Is the forced cursor position enabled
Definition: view_controls.h:72
#define NULL
VECTOR2< double > VECTOR2D
Definition: vector2d.h:593
MOUSE_DRAG_ACTION m_dragMiddle
What drag action to perform when the middle button is pressed
bool m_zoomSpeedAuto
When true, ignore zoom_speed and pick a platform-specific default
coord_type GetWidth() const
Definition: box2.h:196
int m_scrollModifierZoom
What modifier key to enable zoom with the (vertical) scroll wheel
bool Contains(const Vec &aPoint) const
Function Contains.
Definition: box2.h:150
void SetCrossHairCursorPosition(const VECTOR2D &aPosition, bool aWarpView) override
Moves the graphic crosshair cursor to the requested position expressed in world coordinates.
float m_autoPanAcceleration
How fast does panning accelerate when approaching the window boundary
Definition: view_controls.h:96
int m_zoomSpeed
Zoom speed for the non-accelerating zoom controller
const VECTOR2I & GetScreenPixelSize() const
Function GetScreenPixelSize() Returns the size of the our rendering area, in pixels.
Definition: view.cpp:1177
bool IsCursorWarpingEnabled() const
Function IsCursorWarpingEnabled()
VIEW_CONTROLS is an interface for classes handling user events controlling the view behaviour (such a...
bool m_warpCursor
If the cursor is allowed to be warped
Definition: view_controls.h:99
static constexpr double MAC_SCALE
A suitable (magic) scale factor for Mac systems.
wxLogTrace helper definitions.
float m_autoPanMargin
Distance from cursor to VIEW edge when panning is active
Definition: view_controls.h:90
void SetGrabMouse(bool aEnabled) override
Function SetGrabMouse() Enables/disables mouse cursor grabbing (limits the movement field only to the...
bool m_horizontalPan
Enable horizontal panning with the horizontal scroll/trackpad input
bool m_cursorWarped
Application warped the cursor, not the user (keyboard)
void refreshMouse()
Sends an event to refresh mouse position.
VECTOR2D ToScreen(const VECTOR2D &aCoord, bool aAbsolute=true) const
Function ToScreen() Converts a world space point/vector to a point/vector in screen space coordinates...
Definition: view.cpp:494
bool m_autoPanEnabled
Flag for turning on autopanning
Definition: view_controls.h:84
bool m_zoomAcceleration
Enable the accelerating zoom controller
int m_scrollModifierPanV
What modifier key to enable vertical with the (vertical) scroll wheel
void onMotion(wxMouseEvent &aEvent)
void WarpCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false) override
bool IsMirroredX() const
Function IsMirroredX() Returns true if view is flipped across the X axis.
Definition: view.h:230
void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0)) override
Function ForceCursorPosition() Places the cursor immediately at a given point.
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Function SetScale() Sets the scaling factor, zooming around a given anchor point.
Definition: view.cpp:578
wxScrolledCanvas * m_parentPanel
Panel that is affected by VIEW_CONTROLS.
void onTimer(wxTimerEvent &WXUNUSED(aEvent))
const int scale
see class PGM_BASE
Vec Centre() const
Definition: box2.h:78
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
VECTOR2D m_panDirection
Current direction of panning (only autopanning mode)
long m_lastKeyboardCursorCommand
ACTIONS::CURSOR_UP, ACTIONS::CURSOR_DOWN, etc.
static constexpr double MANUAL_SCALE_FACTOR
Multipler for manual scale ssetting.
bool m_updateCursor
Flag deciding whether the cursor position should be calculated using the mouse position.
bool m_lastKeyboardCursorPositionValid
Is last cursor motion event coming from keyboard arrow cursor motion action
double m_initialZoomScale
The zoom scale when a drag zoom started.
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:68
virtual void SetGrabMouse(bool aEnabled)
Function SetGrabMouse Turns on/off mouse grabbing.
VECTOR2I m_scrollPos
Current scrollbar position.
coord_type GetHeight() const
Definition: box2.h:197
WX_VIEW_CONTROLS(VIEW *aView, wxScrolledCanvas *aParentPanel)
bool handleAutoPanning(const wxMouseEvent &aEvent)
Function handleAutoPanning() Computes new viewport settings while in autopanning mode.
void onEnter(wxMouseEvent &WXUNUSED(aEvent))
VECTOR2D m_dragStartPoint
Stores information about point where dragging has started.
void SetCursorPosition(const VECTOR2D &aPosition, bool warpView, bool aTriggeredByArrows, long aArrowCommand) override
Moves cursor to the requested position expressed in world coordinates.
STATE m_state
Current state of VIEW_CONTROLS.
coord_type GetLeft() const
Definition: box2.h:202
VIEW.
Definition: view.h:61
double GetScale() const
Function GetScale()
Definition: view.h:257
void CenterOnCursor() const override
Function CenterOnCursor() Sets the viewport center to the current cursor position and warps the curso...
bool m_cursorCaptured
Should the cursor be locked within the parent window area
Definition: view_controls.h:75
void onScroll(wxScrollWinEvent &aEvent)
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
void onLeave(wxMouseEvent &WXUNUSED(aEvent))
VECTOR2D m_cursorPos
Current cursor position (world coordinates)
wxTimer m_panTimer
Timer repsonsible for handling autopanning.