KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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-2024 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * @author Tomasz Wlostowski <[email protected]>
9 * @author Maciej Suminski <[email protected]>
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 <core/profile.h>
31#include <view/view.h>
36#include <trace_helpers.h>
38#include <math/util.h> // for KiROUND
40#include <widgets/ui_common.h>
42#include <eda_draw_frame.h>
43#include <kiway.h>
44#include <kiplatform/ui.h>
45#include <wx/log.h>
46
47#ifdef __WXMSW__
48 #define USE_MOUSE_CAPTURE
49#endif
50
51using namespace KIGFX;
52
53const wxEventType WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE = wxNewEventType();
54
55
56static std::unique_ptr<ZOOM_CONTROLLER> GetZoomControllerForPlatform( bool aAcceleration )
57{
58#ifdef __WXMAC__
59 // On Apple pointer devices, wheel events occur frequently and with
60 // smaller rotation values. For those devices, let's handle zoom
61 // based on the rotation amount rather than the time difference.
62 return std::make_unique<CONSTANT_ZOOM_CONTROLLER>( CONSTANT_ZOOM_CONTROLLER::MAC_SCALE );
63#elif __WXGTK3__
64 // GTK3 is similar, but the scale constant is smaller
65 return std::make_unique<CONSTANT_ZOOM_CONTROLLER>( CONSTANT_ZOOM_CONTROLLER::GTK3_SCALE );
66#else
67 if( aAcceleration )
68 return std::make_unique<ACCELERATING_ZOOM_CONTROLLER>();
69 else
70 return std::make_unique<CONSTANT_ZOOM_CONTROLLER>( CONSTANT_ZOOM_CONTROLLER::MSW_SCALE );
71#endif
72}
73
74
76 VIEW_CONTROLS( aView ),
77 m_state( IDLE ),
78 m_parentPanel( aParentPanel ),
79 m_scrollScale( 1.0, 1.0 ),
80#ifdef __WXGTK3__
81 m_lastTimestamp( 0 ),
82#endif
83 m_cursorPos( 0, 0 ),
84 m_updateCursor( true ),
85 m_infinitePanWorks( false ),
86 m_gestureLastZoomFactor( 1.0 )
87{
89
90 m_MotionEventCounter = std::make_unique<PROF_COUNTER>( "Mouse motion events" );
91
92 m_parentPanel->Connect( wxEVT_MOTION,
93 wxMouseEventHandler( WX_VIEW_CONTROLS::onMotion ), nullptr, this );
94 m_parentPanel->Connect( wxEVT_MAGNIFY,
95 wxMouseEventHandler( WX_VIEW_CONTROLS::onMagnify ), nullptr, this );
96 m_parentPanel->Connect( wxEVT_MOUSEWHEEL,
97 wxMouseEventHandler( WX_VIEW_CONTROLS::onWheel ), nullptr, this );
98 m_parentPanel->Connect( wxEVT_MIDDLE_UP,
99 wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), nullptr, this );
100 m_parentPanel->Connect( wxEVT_MIDDLE_DOWN,
101 wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), nullptr, this );
102 m_parentPanel->Connect( wxEVT_LEFT_UP,
103 wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), nullptr, this );
104 m_parentPanel->Connect( wxEVT_LEFT_DOWN,
105 wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), nullptr, this );
106 m_parentPanel->Connect( wxEVT_RIGHT_UP,
107 wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), nullptr, this );
108 m_parentPanel->Connect( wxEVT_RIGHT_DOWN,
109 wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), nullptr, this );
110#if defined __WXMSW__
111 m_parentPanel->Connect( wxEVT_ENTER_WINDOW,
112 wxMouseEventHandler( WX_VIEW_CONTROLS::onEnter ), nullptr, this );
113#endif
114 m_parentPanel->Connect( wxEVT_LEAVE_WINDOW,
115 wxMouseEventHandler( WX_VIEW_CONTROLS::onLeave ), nullptr, this );
116 m_parentPanel->Connect( wxEVT_SCROLLWIN_THUMBTRACK,
117 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
118 m_parentPanel->Connect( wxEVT_SCROLLWIN_PAGEUP,
119 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
120 m_parentPanel->Connect( wxEVT_SCROLLWIN_PAGEDOWN,
121 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
122
123 m_parentPanel->Connect( wxEVT_SCROLLWIN_BOTTOM,
124 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
125 m_parentPanel->Connect( wxEVT_SCROLLWIN_TOP,
126 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
127 m_parentPanel->Connect( wxEVT_SCROLLWIN_LINEUP,
128 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
129 m_parentPanel->Connect( wxEVT_SCROLLWIN_LINEDOWN,
130 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
131#if defined USE_MOUSE_CAPTURE
132 m_parentPanel->Connect( wxEVT_MOUSE_CAPTURE_LOST,
133 wxMouseEventHandler( WX_VIEW_CONTROLS::onCaptureLost ), nullptr, this );
134#endif
135
136#ifdef __WXMSW__
137 if( m_parentPanel->EnableTouchEvents( wxTOUCH_ZOOM_GESTURE | wxTOUCH_PAN_GESTURES ) )
138 {
139 m_parentPanel->Connect( wxEVT_GESTURE_ZOOM,
140 wxZoomGestureEventHandler( WX_VIEW_CONTROLS::onZoomGesture ),
141 nullptr, this );
142
143 m_parentPanel->Connect( wxEVT_GESTURE_PAN,
144 wxPanGestureEventHandler( WX_VIEW_CONTROLS::onPanGesture ), nullptr,
145 this );
146 }
147#endif
148
149 m_cursorWarped = false;
150
151 m_panTimer.SetOwner( this );
152 this->Connect( wxEVT_TIMER, wxTimerEventHandler( WX_VIEW_CONTROLS::onTimer ), nullptr, this );
153
157}
158
159
161{
162#if defined USE_MOUSE_CAPTURE
163 if( m_parentPanel->HasCapture() )
164 m_parentPanel->ReleaseMouse();
165#endif
166}
167
168
170{
172
188
189 m_zoomController.reset();
190
191 if( cfg->m_Input.zoom_speed_auto )
192 {
194 }
195 else
196 {
197 if( cfg->m_Input.zoom_acceleration )
198 {
200 std::make_unique<ACCELERATING_ZOOM_CONTROLLER>( cfg->m_Input.zoom_speed );
201 }
202 else
203 {
205
206 m_zoomController = std::make_unique<CONSTANT_ZOOM_CONTROLLER>( scale );
207 }
208 }
209}
210
211
212void WX_VIEW_CONTROLS::onMotion( wxMouseEvent& aEvent )
213{
214 ( *m_MotionEventCounter )++;
215
216 // Because Weston sends a motion event to previous location after warping the pointer
217 wxPoint mouseRel = m_parentPanel->ScreenToClient( KIPLATFORM::UI::GetMousePosition() );
218
219 bool isAutoPanning = false;
220 int x = mouseRel.x;
221 int y = mouseRel.y;
222 VECTOR2D mousePos( x, y );
223
224 // Automatic focus switching between SCH and PCB windows on canvas mouse motion
226 {
228 {
229 KIWAY_PLAYER* otherFrame = nullptr;
230
231 if( frame->IsType( FRAME_PCB_EDITOR ) )
232 {
233 otherFrame = frame->Kiway().Player( FRAME_SCH, false );
234 }
235 else if( frame->IsType( FRAME_SCH ) )
236 {
237 otherFrame = frame->Kiway().Player( FRAME_PCB_EDITOR, false );
238 }
239
240 if( otherFrame && KIPLATFORM::UI::IsWindowActive( otherFrame )
241 && !KIPLATFORM::UI::IsWindowActive( frame ) )
242 {
243 frame->Raise();
244 }
245 }
246 }
247
249 handleCursorCapture( x, y );
250
252 isAutoPanning = handleAutoPanning( aEvent );
253
254 if( !isAutoPanning && aEvent.Dragging() )
255 {
256 if( m_state == DRAG_PANNING )
257 {
258 static bool justWarped = false;
259 int warpX = 0;
260 int warpY = 0;
261 wxSize parentSize = m_parentPanel->GetClientSize();
262
263 if( x < 0 )
264 {
265 warpX = parentSize.x;
266 }
267 else if(x >= parentSize.x )
268 {
269 warpX = -parentSize.x;
270 }
271
272 if( y < 0 )
273 {
274 warpY = parentSize.y;
275 }
276 else if( y >= parentSize.y )
277 {
278 warpY = -parentSize.y;
279 }
280
281 if( !justWarped )
282 {
283 VECTOR2D d = m_dragStartPoint - mousePos;
284 m_dragStartPoint = mousePos;
285 VECTOR2D delta = m_view->ToWorld( d, false );
287 aEvent.StopPropagation();
288 }
289
290 if( warpX || warpY )
291 {
292 if( !justWarped )
293 {
295 && KIPLATFORM::UI::WarpPointer( m_parentPanel, x + warpX, y + warpY ) )
296 {
297 m_dragStartPoint += VECTOR2D( warpX, warpY );
298 justWarped = true;
299 }
300 }
301 else
302 justWarped = false;
303 }
304 else
305 justWarped = false;
306 }
307 else if( m_state == DRAG_ZOOMING )
308 {
309 static bool justWarped = false;
310 int warpY = 0;
311 wxSize parentSize = m_parentPanel->GetClientSize();
312
313 if( y < 0 )
314 {
315 warpY = parentSize.y;
316 }
317 else if( y >= parentSize.y )
318 {
319 warpY = -parentSize.y;
320 }
321
322 if( !justWarped )
323 {
324 VECTOR2D d = m_dragStartPoint - mousePos;
325 m_dragStartPoint = mousePos;
326
327 double scale = exp( d.y * m_settings.m_zoomSpeed * 0.001 );
328
329 wxLogTrace( traceZoomScroll, wxString::Format( "dy: %f scale: %f", d.y, scale ) );
330
332 aEvent.StopPropagation();
333 }
334
335 if( warpY )
336 {
337 if( !justWarped )
338 {
340 m_dragStartPoint += VECTOR2D( 0, warpY );
341 justWarped = true;
342 }
343 else
344 justWarped = false;
345 }
346 else
347 justWarped = false;
348 }
349 }
350
351 if( m_updateCursor ) // do not update the cursor position if it was explicitly set
352 m_cursorPos = GetClampedCoords( m_view->ToWorld( mousePos ) );
353 else
354 m_updateCursor = true;
355
356 aEvent.Skip();
357}
358
359
360void WX_VIEW_CONTROLS::onWheel( wxMouseEvent& aEvent )
361{
362#ifdef __WXGTK3__
363 if( aEvent.GetTimestamp() == m_lastTimestamp )
364 {
365 aEvent.Skip( false );
366 return;
367 }
368
369 m_lastTimestamp = aEvent.GetTimestamp();
370#endif
371
372 const double wheelPanSpeed = 0.001;
373 const int axis = aEvent.GetWheelAxis();
374
375 if( axis == wxMOUSE_WHEEL_HORIZONTAL && !m_settings.m_horizontalPan )
376 return;
377
378 // Pick the modifier, if any. Shift beats control beats alt, we don't support more than one.
379 int modifiers =
380 aEvent.ShiftDown() ? WXK_SHIFT :
381 ( aEvent.ControlDown() ? WXK_CONTROL : ( aEvent.AltDown() ? WXK_ALT : 0 ) );
382
383 // Restrict zoom handling to the vertical axis, otherwise horizontal
384 // scrolling events (e.g. touchpads and some mice) end up interpreted
385 // as vertical scroll events and confuse the user.
386 if( modifiers == m_settings.m_scrollModifierZoom && axis == wxMOUSE_WHEEL_VERTICAL )
387 {
388 const int rotation = aEvent.GetWheelRotation();
389 const double zoomScale = m_zoomController->GetScaleForRotation( rotation );
390
392 {
394 m_view->SetScale( m_view->GetScale() * zoomScale );
395 }
396 else
397 {
398 const VECTOR2D anchor = m_view->ToWorld( VECTOR2D( aEvent.GetX(), aEvent.GetY() ) );
399 m_view->SetScale( m_view->GetScale() * zoomScale, anchor );
400 }
401
402 // Refresh the zoom level and mouse position on message panel
403 // (mouse position has not changed, only the zoom level has changed):
404 refreshMouse( true );
405 }
406 else
407 {
408 // Scrolling
409 VECTOR2D scrollVec = m_view->ToWorld( m_view->GetScreenPixelSize(), false ) *
410 ( (double) aEvent.GetWheelRotation() * wheelPanSpeed );
411 double scrollX = 0.0;
412 double scrollY = 0.0;
413 bool hReverse = false;
414
415 if( axis != wxMOUSE_WHEEL_HORIZONTAL )
417
418 if( axis == wxMOUSE_WHEEL_HORIZONTAL || modifiers == m_settings.m_scrollModifierPanH )
419 {
420 if( hReverse )
421 scrollX = scrollVec.x;
422 else
423 scrollX = ( axis == wxMOUSE_WHEEL_HORIZONTAL ) ? scrollVec.x : -scrollVec.x;
424 }
425 else
426 {
427 scrollY = -scrollVec.y;
428 }
429
430 VECTOR2D delta( scrollX, scrollY );
431
433 refreshMouse( true );
434 }
435
436 // Do not skip this event, otherwise wxWidgets will fire
437 // 3 wxEVT_SCROLLWIN_LINEUP or wxEVT_SCROLLWIN_LINEDOWN (normal wxWidgets behavior)
438 // and we do not want that.
439}
440
441
442void WX_VIEW_CONTROLS::onMagnify( wxMouseEvent& aEvent )
443{
444 // Scale based on the magnification from our underlying magnification event.
445 VECTOR2D anchor = m_view->ToWorld( VECTOR2D( aEvent.GetX(), aEvent.GetY() ) );
446 m_view->SetScale( m_view->GetScale() * ( aEvent.GetMagnification() + 1.0f ), anchor );
447
448 aEvent.Skip();
449}
450
451
453{
454 m_state = aNewState;
455}
456
457void WX_VIEW_CONTROLS::onButton( wxMouseEvent& aEvent )
458{
459 switch( m_state )
460 {
461 case IDLE:
462 case AUTO_PANNING:
463 if( ( aEvent.MiddleDown() && m_settings.m_dragMiddle == MOUSE_DRAG_ACTION::PAN ) ||
464 ( aEvent.RightDown() && m_settings.m_dragRight == MOUSE_DRAG_ACTION::PAN ) )
465 {
466 m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() );
469
470#if defined USE_MOUSE_CAPTURE
471 if( !m_parentPanel->HasCapture() )
472 m_parentPanel->CaptureMouse();
473#endif
474 }
475 else if( ( aEvent.MiddleDown() && m_settings.m_dragMiddle == MOUSE_DRAG_ACTION::ZOOM ) ||
476 ( aEvent.RightDown() && m_settings.m_dragRight == MOUSE_DRAG_ACTION::ZOOM ) )
477 {
478 m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() );
481
482#if defined USE_MOUSE_CAPTURE
483 if( !m_parentPanel->HasCapture() )
484 m_parentPanel->CaptureMouse();
485#endif
486 }
487
488 if( aEvent.LeftUp() )
489 setState( IDLE ); // Stop autopanning when user release left mouse button
490
491 break;
492
493 case DRAG_ZOOMING:
494 case DRAG_PANNING:
495 if( aEvent.MiddleUp() || aEvent.LeftUp() || aEvent.RightUp() )
496 {
497 setState( IDLE );
499
500#if defined USE_MOUSE_CAPTURE
501 if( !m_settings.m_cursorCaptured && m_parentPanel->HasCapture() )
502 m_parentPanel->ReleaseMouse();
503#endif
504 }
505
506 break;
507 }
508
509 aEvent.Skip();
510}
511
512
513void WX_VIEW_CONTROLS::onEnter( wxMouseEvent& aEvent )
514{
515 // Avoid stealing focus from text controls
516 // This is particularly important for users using On-Screen-Keyboards
517 // They may move the mouse over the canvas to reach the keyboard
519 {
520 return;
521 }
522
523#if defined( _WIN32 ) || defined( __WXGTK__ )
524 // Win32 and some *nix WMs transmit mouse move and wheel events to all controls below the mouse regardless
525 // of focus. Forcing the focus here will cause the EDA FRAMES to immediately become the
526 // top level active window.
527 if( m_parentPanel->GetParent() != nullptr )
528 {
529 // this assumes the parent panel's parent is the eda window
531 {
533 }
534 }
535#else
537#endif
538}
539
540
541void WX_VIEW_CONTROLS::onLeave( wxMouseEvent& aEvent )
542{
543#if !defined USE_MOUSE_CAPTURE
544 onMotion( aEvent );
545#endif
546}
547
548void WX_VIEW_CONTROLS::onCaptureLost( wxMouseEvent& aEvent )
549{
550 // This method must be present to suppress the capture-lost assertion
551
552 // Set the flag to allow calling m_parentPanel->CaptureMouse()
553 // Note: One cannot call m_parentPanel->CaptureMouse() twice, this is not accepted
554 // by wxWidgets (MSW specific) so we need this guard
556}
557
558
559void WX_VIEW_CONTROLS::onTimer( wxTimerEvent& aEvent )
560{
561 switch( m_state )
562 {
563 case AUTO_PANNING:
564 {
566 {
567 setState( IDLE );
568 return;
569 }
570
571 #ifdef __WXMSW__
572 // Hackfix: It's possible for the mouse to leave the canvas
573 // without triggering any leave events on windows
574 // Use a MSW only wx function
575 if( !m_parentPanel->IsMouseInWindow() )
576 {
577 m_panTimer.Stop();
578 setState( IDLE );
579 return;
580 }
581 #endif
582
583 if( !m_parentPanel->HasFocus() && !m_parentPanel->StatusPopupHasFocus() )
584 {
585 setState( IDLE );
586 return;
587 }
588
589 double borderSize = std::min( m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().x,
591
592 // When the mouse cursor is outside the area with no pan,
593 // m_panDirection is the dist to this area limit ( in pixels )
594 // It will be used also as pan value (the pan speed depends on this dist).
596
597 // When the mouse cursor is outside the area with no pan, the pan value
598 // is accelerated depending on the dist between the area and the cursor
599 float accel = 0.5f + ( m_settings.m_autoPanAcceleration / 5.0f );
600
601 // For a small mouse cursor dist to area, just use the distance.
602 // But for a dist > borderSize / 2, use an accelerated pan value
603
604 if( dir.EuclideanNorm() >= borderSize ) // far from area limits
605 dir = dir.Resize( borderSize * accel );
606 else if( dir.EuclideanNorm() > borderSize / 2 ) // Near from area limits
607 dir = dir.Resize( borderSize );
608
609 dir = m_view->ToWorld( dir, false );
610 m_view->SetCenter( m_view->GetCenter() + dir );
611
612 refreshMouse( true );
613
614 m_panTimer.Start();
615 }
616 break;
617
618 case IDLE: // Just remove unnecessary warnings
619 case DRAG_PANNING:
620 case DRAG_ZOOMING:
621 break;
622 }
623}
624
625
626void WX_VIEW_CONTROLS::onZoomGesture( wxZoomGestureEvent& aEvent )
627{
628 if( aEvent.IsGestureStart() )
629 {
631 m_gestureLastPos = VECTOR2D( aEvent.GetPosition().x, aEvent.GetPosition().y );
632 }
633
634 VECTOR2D evtPos( aEvent.GetPosition().x, aEvent.GetPosition().y );
635 VECTOR2D deltaWorld = m_view->ToWorld( evtPos - m_gestureLastPos, false );
636
637 m_view->SetCenter( m_view->GetCenter() - deltaWorld );
638
639 m_view->SetScale( m_view->GetScale() * aEvent.GetZoomFactor() / m_gestureLastZoomFactor,
640 m_view->ToWorld( evtPos ) );
641
642 m_gestureLastZoomFactor = aEvent.GetZoomFactor();
643 m_gestureLastPos = evtPos;
644
645 refreshMouse( true );
646}
647
648
649void WX_VIEW_CONTROLS::onPanGesture( wxPanGestureEvent& aEvent )
650{
651 VECTOR2I screenDelta( aEvent.GetDelta().x, aEvent.GetDelta().y );
652 VECTOR2D deltaWorld = m_view->ToWorld( screenDelta, false );
653
654 m_view->SetCenter( m_view->GetCenter() - deltaWorld );
655
656 refreshMouse( true );
657}
658
659
660void WX_VIEW_CONTROLS::onScroll( wxScrollWinEvent& aEvent )
661{
662 const double linePanDelta = 0.05;
663 const double pagePanDelta = 0.5;
664
665 int type = aEvent.GetEventType();
666 int dir = aEvent.GetOrientation();
667
668 if( type == wxEVT_SCROLLWIN_THUMBTRACK )
669 {
670 auto center = m_view->GetCenter();
671 const auto& boundary = m_view->GetBoundary();
672
673 // Flip scroll direction in flipped view
674 const double xstart = ( m_view->IsMirroredX() ?
675 boundary.GetRight() : boundary.GetLeft() );
676 const double xdelta = ( m_view->IsMirroredX() ? -1 : 1 );
677
678 if( dir == wxHORIZONTAL )
679 center.x = xstart + xdelta * ( aEvent.GetPosition() / m_scrollScale.x );
680 else
681 center.y = boundary.GetTop() + aEvent.GetPosition() / m_scrollScale.y;
682
683 m_view->SetCenter( center );
684 }
685 else if( type == wxEVT_SCROLLWIN_THUMBRELEASE ||
686 type == wxEVT_SCROLLWIN_TOP ||
687 type == wxEVT_SCROLLWIN_BOTTOM )
688 {
689 // Do nothing on thumb release, we don't care about it.
690 // We don't have a concept of top or bottom in our viewport, so ignore those events.
691 }
692 else
693 {
694 double dist = 0;
695
696 if( type == wxEVT_SCROLLWIN_PAGEUP )
697 {
698 dist = pagePanDelta;
699 }
700 else if( type == wxEVT_SCROLLWIN_PAGEDOWN )
701 {
702 dist = -pagePanDelta;
703 }
704 else if( type == wxEVT_SCROLLWIN_LINEUP )
705 {
706 dist = linePanDelta;
707 }
708 else if( type == wxEVT_SCROLLWIN_LINEDOWN )
709 {
710 dist = -linePanDelta;
711 }
712 else
713 {
714 wxCHECK_MSG( false, /* void */, wxT( "Unhandled event type" ) );
715 }
716
717 VECTOR2D scroll = m_view->ToWorld( m_view->GetScreenPixelSize(), false ) * dist;
718
719 double scrollX = 0.0;
720 double scrollY = 0.0;
721
722 if ( dir == wxHORIZONTAL )
723 scrollX = -scroll.x;
724 else
725 scrollY = -scroll.y;
726
727 VECTOR2D delta( scrollX, scrollY );
728
730 }
731
733}
734
735
737{
738#if defined USE_MOUSE_CAPTURE
739 // Note: for some reason, m_parentPanel->HasCapture() can be false even if CaptureMouse()
740 // was called (i.e. mouse was captured, so when need to test m_MouseCapturedLost to be
741 // sure a wxEVT_MOUSE_CAPTURE_LOST event was fired before. Otherwise wxMSW complains
742 // The IsModalDialogFocused is checked because it's possible to start a capture
743 // due to event ordering while a modal dialog was just opened, the mouse capture steels focus
744 // from the modal and causes odd behavior
745 if( aEnabled && !m_parentPanel->HasCapture() && m_parentPanel->m_MouseCapturedLost
747 {
748 m_parentPanel->CaptureMouse();
749
750 // Clear the flag to allow calling m_parentPanel->CaptureMouse()
751 // Calling it without calling ReleaseMouse() is not accepted by wxWidgets (MSW specific)
753 }
754 else if( !aEnabled && m_parentPanel->HasCapture()
756 {
757 m_parentPanel->ReleaseMouse();
758
759 // Mouse is released, calling CaptureMouse() is allowed now:
761 }
762#endif
764}
765
766
768{
770 {
771 setState( IDLE );
772#if defined USE_MOUSE_CAPTURE
773 if( !m_settings.m_cursorCaptured && m_parentPanel->HasCapture() )
774 m_parentPanel->ReleaseMouse();
775#endif
776 }
777}
778
779
780VECTOR2D WX_VIEW_CONTROLS::GetMousePosition( bool aWorldCoordinates ) const
781{
782 wxPoint msp = getMouseScreenPosition();
783 VECTOR2D screenPos( msp.x, msp.y );
784
785 return aWorldCoordinates ? GetClampedCoords( m_view->ToWorld( screenPos ) ) : screenPos;
786}
787
788
790{
791 GAL* gal = m_view->GetGAL();
792
793 if( aEnableSnapping && gal->GetGridSnapping() )
794 {
795 return gal->GetGridPoint( m_cursorPos );
796 }
797 else
798 {
799 return m_cursorPos;
800 }
801}
802
803
805{
807 {
809 }
810 else
811 {
812 return GetClampedCoords( GetRawCursorPosition( aEnableSnapping ) );
813 }
814}
815
816
817void WX_VIEW_CONTROLS::SetCursorPosition( const VECTOR2D& aPosition, bool aWarpView,
818 bool aTriggeredByArrows, long aArrowCommand )
819{
820 m_updateCursor = false;
821
822 VECTOR2D clampedPosition = GetClampedCoords( aPosition );
823
824 if( aTriggeredByArrows )
825 {
829 m_cursorWarped = false;
830 }
831 else
832 {
836 m_cursorWarped = true;
837 }
838
839 WarpMouseCursor( clampedPosition, true, aWarpView );
840 m_cursorPos = clampedPosition;
841}
842
843
845 bool aWarpView = true )
846{
847 m_updateCursor = false;
848
849 VECTOR2D clampedPosition = GetClampedCoords( aPosition );
850
851 const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
852 BOX2I screen( VECTOR2I( 0, 0 ), screenSize );
853 VECTOR2D screenPos = m_view->ToScreen( clampedPosition );
854
855 if( aWarpView && !screen.Contains( screenPos ) )
856 m_view->SetCenter( clampedPosition );
857
858 m_cursorPos = clampedPosition;
859}
860
861
862void WX_VIEW_CONTROLS::WarpMouseCursor( const VECTOR2D& aPosition, bool aWorldCoordinates,
863 bool aWarpView )
864{
865 if( aWorldCoordinates )
866 {
867 const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
868 BOX2I screen( VECTOR2I( 0, 0 ), screenSize );
869 VECTOR2D clampedPosition = GetClampedCoords( aPosition );
870 VECTOR2D screenPos = m_view->ToScreen( clampedPosition );
871
872 if( !screen.Contains( screenPos ) )
873 {
874 if( aWarpView )
875 {
876 m_view->SetCenter( clampedPosition );
877 KIPLATFORM::UI::WarpPointer( m_parentPanel, screenSize.x / 2, screenSize.y / 2 );
878 }
879 }
880 else
881 {
882 KIPLATFORM::UI::WarpPointer( m_parentPanel, screenPos.x, screenPos.y );
883 }
884 }
885 else
886 {
887 KIPLATFORM::UI::WarpPointer( m_parentPanel, aPosition.x, aPosition.y );
888 }
889
890 // If we are not refreshing because of mouse movement, don't set the modifiers
891 // because we are refreshing for keyboard movement, which uses the same modifiers for other actions
893}
894
895
897{
898 const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
899 VECTOR2D screenCenter( screenSize / 2 );
900
901 if( GetMousePosition( false ) != screenCenter )
902 {
903 VECTOR2D newCenter = GetCursorPosition();
904
905 if( KIPLATFORM::UI::WarpPointer( m_parentPanel, screenCenter.x, screenCenter.y ) )
906 {
907 m_view->SetCenter( newCenter );
908 m_dragStartPoint = screenCenter;
909 }
910 }
911}
912
913
915{
916 int border = std::min( m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().x,
918 border += 2;
919
920 VECTOR2D topLeft( border, border );
921 VECTOR2D botRight( m_view->GetScreenPixelSize().x - border,
922 m_view->GetScreenPixelSize().y - border );
923
924 topLeft = m_view->ToWorld( topLeft );
925 botRight = m_view->ToWorld( botRight );
926
927 VECTOR2D pos = GetMousePosition( true );
928
929 if( pos.x < topLeft.x )
930 pos.x = topLeft.x;
931 else if( pos.x > botRight.x )
932 pos.x = botRight.x;
933
934 if( pos.y < topLeft.y )
935 pos.y = topLeft.y;
936 else if( pos.y > botRight.y )
937 pos.y = botRight.y;
938
939 SetCursorPosition( pos, false, false, 0 );
940
941 if( aWarpMouseCursor )
942 WarpMouseCursor( pos, true );
943}
944
945
946bool WX_VIEW_CONTROLS::handleAutoPanning( const wxMouseEvent& aEvent )
947{
948 VECTOR2I p( aEvent.GetX(), aEvent.GetY() );
950
952 {
953 // last cursor move event came from keyboard cursor control. If auto-panning is enabled
954 // and the next position is inside the autopan zone, check if it really came from a mouse
955 // event, otherwise disable autopan temporarily. Also temporarily disable autopan if the
956 // cursor is in the autopan zone because the application warped the cursor.
957
958 m_cursorWarped = false;
959 return true;
960 }
961
962 m_cursorWarped = false;
963
964 // Compute areas where autopanning is active
965 int borderStart = std::min( m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().x,
967 borderStart = std::max( borderStart, 2 );
968 int borderEndX = m_view->GetScreenPixelSize().x - borderStart;
969 int borderEndY = m_view->GetScreenPixelSize().y - borderStart;
970
971 if( p.x < borderStart )
972 m_panDirection.x = -( borderStart - p.x );
973 else if( p.x > borderEndX )
974 m_panDirection.x = ( p.x - borderEndX );
975 else
976 m_panDirection.x = 0;
977
978 if( p.y < borderStart )
979 m_panDirection.y = -( borderStart - p.y );
980 else if( p.y > borderEndY )
981 m_panDirection.y = ( p.y - borderEndY );
982 else
983 m_panDirection.y = 0;
984
985 bool borderHit = ( m_panDirection.x != 0 || m_panDirection.y != 0 );
986
987 switch( m_state )
988 {
989 case AUTO_PANNING:
990 if( !borderHit )
991 {
992 m_panTimer.Stop();
993 setState( IDLE );
994
995 return false;
996 }
997
998 return true;
999
1000 case IDLE:
1001 if( borderHit )
1002 {
1004 m_panTimer.Start( (int) ( 250.0 / 60.0 ), true );
1005
1006 return true;
1007 }
1008
1009 return false;
1010
1011 case DRAG_PANNING:
1012 case DRAG_ZOOMING:
1013 return false;
1014 }
1015
1016 wxCHECK_MSG( false, false, wxT( "This line should never be reached" ) );
1017
1018 return false;
1019}
1020
1021
1023{
1025 {
1026 bool warp = false;
1027 wxSize parentSize = m_parentPanel->GetClientSize();
1028
1029 if( x < 0 )
1030 {
1031 x = 0;
1032 warp = true;
1033 }
1034 else if( x >= parentSize.x )
1035 {
1036 x = parentSize.x - 1;
1037 warp = true;
1038 }
1039
1040 if( y < 0 )
1041 {
1042 y = 0;
1043 warp = true;
1044 }
1045 else if( y >= parentSize.y )
1046 {
1047 y = parentSize.y - 1;
1048 warp = true;
1049 }
1050
1051 if( warp )
1053 }
1054}
1055
1056
1057void WX_VIEW_CONTROLS::refreshMouse( bool aSetModifiers )
1058{
1059 // Notify tools that the cursor position has changed in the world coordinates
1060 wxMouseEvent moveEvent( EVT_REFRESH_MOUSE );
1061 wxPoint msp = getMouseScreenPosition();
1062 moveEvent.SetX( msp.x );
1063 moveEvent.SetY( msp.y );
1064
1065 if( aSetModifiers )
1066 {
1067 // Set the modifiers state
1068 moveEvent.SetControlDown( wxGetKeyState( WXK_CONTROL ) );
1069 moveEvent.SetShiftDown( wxGetKeyState( WXK_SHIFT ) );
1070 moveEvent.SetAltDown( wxGetKeyState( WXK_ALT ) );
1071 }
1072
1073 m_cursorPos = GetClampedCoords( m_view->ToWorld( VECTOR2D( msp.x, msp.y ) ) );
1074 wxPostEvent( m_parentPanel, moveEvent );
1075}
1076
1077
1079{
1080 wxPoint msp = KIPLATFORM::UI::GetMousePosition();
1081 m_parentPanel->ScreenToClient( &msp.x, &msp.y );
1082 return msp;
1083}
1084
1085
1087{
1088 const BOX2D viewport = m_view->GetViewport();
1089 const BOX2D& boundary = m_view->GetBoundary();
1090
1091 m_scrollScale.x = 2e3 / viewport.GetWidth(); // TODO it does not have to be updated so often
1092 m_scrollScale.y = 2e3 / viewport.GetHeight();
1093 VECTOR2I newScroll( ( viewport.Centre().x - boundary.GetLeft() ) * m_scrollScale.x,
1094 ( viewport.Centre().y - boundary.GetTop() ) * m_scrollScale.y );
1095
1096 // We add the width of the scroll bar thumb to the range because the scroll range is given by
1097 // the full bar while the position is given by the left/top position of the thumb
1098 VECTOR2I newRange( m_scrollScale.x * boundary.GetWidth() +
1099 m_parentPanel->GetScrollThumb( wxSB_HORIZONTAL ),
1100 m_scrollScale.y * boundary.GetHeight() +
1101 m_parentPanel->GetScrollThumb( wxSB_VERTICAL ) );
1102
1103 // Flip scroll direction in flipped view
1104 if( m_view->IsMirroredX() )
1105 newScroll.x = ( boundary.GetRight() - viewport.Centre().x ) * m_scrollScale.x;
1106
1107 // Adjust scrollbars only if it is needed. Otherwise there are cases when canvas is continuously
1108 // refreshed (Windows)
1109 if( m_scrollPos != newScroll || newRange.x != m_parentPanel->GetScrollRange( wxSB_HORIZONTAL )
1110 || newRange.y != m_parentPanel->GetScrollRange( wxSB_VERTICAL ) )
1111 {
1112 m_parentPanel->SetScrollbars( 1, 1, newRange.x, newRange.y, newScroll.x, newScroll.y,
1113 true );
1114 m_scrollPos = newScroll;
1115
1116#if !defined( __APPLE__ ) && !defined( WIN32 )
1117 // Trigger a mouse refresh to get the canvas update in GTK (re-draws the scrollbars).
1118 // Note that this causes an infinite loop on OSX and Windows (in certain cases) as it
1119 // generates a paint event.
1120 refreshMouse( false );
1121#endif
1122 }
1123}
1124
1125void WX_VIEW_CONTROLS::ForceCursorPosition( bool aEnabled, const VECTOR2D& aPosition )
1126{
1127 VECTOR2D clampedPosition = GetClampedCoords( aPosition );
1128
1130 m_settings.m_forcedPosition = clampedPosition;
1131}
size_type GetHeight() const
Definition: box2.h:205
coord_type GetTop() const
Definition: box2.h:219
size_type GetWidth() const
Definition: box2.h:204
bool Contains(const Vec &aPoint) const
Definition: box2.h:158
Vec Centre() const
Definition: box2.h:87
coord_type GetRight() const
Definition: box2.h:207
coord_type GetLeft() const
Definition: box2.h:218
The base class for create windows for drawing purpose.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
bool m_MouseCapturedLost
used on wxMSW: true after a wxEVT_MOUSE_CAPTURE_LOST was received false after the mouse is recaptured...
void SetFocus() override
EDA_DRAW_FRAME * GetParentEDAFrame() const
Returns parent EDA_DRAW_FRAME, if available or NULL otherwise.
static constexpr double MAC_SCALE
static constexpr double MSW_SCALE
A suitable (magic) scale factor for Windows systems.
static constexpr double GTK3_SCALE
A suitable (magic) scale factor for Mac systems.
static constexpr double MANUAL_SCALE_FACTOR
Abstract interface for drawing on a 2D-surface.
VECTOR2D GetGridPoint(const VECTOR2D &aPoint) const
For a given point it returns the nearest point belonging to the grid in world coordinates.
bool GetGridSnapping() const
const VECTOR2I & GetScreenPixelSize() const
Return GAL canvas size in pixels.
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
bool m_cursorWarped
Current VIEW_CONTROLS settings.
bool IsCursorWarpingEnabled() const
VC_SETTINGS m_settings
VIEW * m_view
< Pointer to controlled VIEW.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
double GetScale() const
Definition: view.h:277
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:547
const VECTOR2D & GetCenter() const
Return the center point of this VIEW (in world space coordinates).
Definition: view.h:347
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:587
VECTOR2D ToScreen(const VECTOR2D &aCoord, bool aAbsolute=true) const
Convert a world space point/vector to a point/vector in screen space coordinates.
Definition: view.cpp:503
const VECTOR2I & GetScreenPixelSize() const
Return the size of the our rendering area in pixels.
Definition: view.cpp:1227
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:203
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
Definition: view.cpp:484
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:251
const BOX2D & GetBoundary() const
Definition: view.h:306
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition: view.cpp:613
bool m_updateCursor
Flag to indicate if infinite panning works on this platform.
bool m_infinitePanWorks
A #ZOOM_CONTROLLER that determines zoom steps. This is platform-specific.
void SetCrossHairCursorPosition(const VECTOR2D &aPosition, bool aWarpView) override
void LoadSettings() override
Event that forces mouse move event in the dispatcher (eg.
void setState(STATE aNewState)
Sets the interaction state, simply a internal setter to make it easier to debug changes.
STATE m_state
Panel that is affected by VIEW_CONTROLS.
void CaptureCursor(bool aEnabled) override
Force the cursor to stay within the drawing panel area.
void onScroll(wxScrollWinEvent &aEvent)
wxTimer m_panTimer
Ratio used for scaling world coordinates to scrollbar position.
void onButton(wxMouseEvent &aEvent)
void onEnter(wxMouseEvent &WXUNUSED(aEvent))
void onWheel(wxMouseEvent &aEvent)
Handler functions.
VECTOR2I m_scrollPos
The mouse position when a drag zoom started.
void refreshMouse(bool aSetModifiers)
Send an event to refresh mouse position.
WX_VIEW_CONTROLS(VIEW *aView, EDA_DRAW_PANEL_GAL *aParentPanel)
void onZoomGesture(wxZoomGestureEvent &aEvent)
void PinCursorInsideNonAutoscrollArea(bool aWarpMouseCursor) override
Return the current mouse pointer position.
void SetCursorPosition(const VECTOR2D &aPosition, bool warpView, bool aTriggeredByArrows, long aArrowCommand) override
Move the graphic crosshair cursor to the requested position expressed in world coordinates.
VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const override
Return the current mouse pointer position.
void WarpMouseCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false) override
Set the viewport center to the current cursor position and warps the cursor to the screen center.
void onMagnify(wxMouseEvent &aEvent)
VECTOR2D GetRawCursorPosition(bool aSnappingEnabled=true) const override
Return the current cursor position in world coordinates ignoring the cursorUp position force mode.
VECTOR2D m_scrollScale
Current scrollbar position.
bool handleAutoPanning(const wxMouseEvent &aEvent)
Compute new viewport settings while in autopanning mode.
wxPoint getMouseScreenPosition() const
Get the cursor position in the screen coordinates.
void onPanGesture(wxPanGestureEvent &aEvent)
void onTimer(wxTimerEvent &WXUNUSED(aEvent))
std::unique_ptr< ZOOM_CONTROLLER > m_zoomController
Used to track gesture events.
STATE
< Possible states for WX_VIEW_CONTROLS.
@ DRAG_PANNING
Panning with mouse button pressed.
@ AUTO_PANNING
Panning on approaching borders of the frame.
@ DRAG_ZOOMING
Zooming with mouse button pressed.
@ IDLE
Nothing is happening.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
void CenterOnCursor() override
Adjusts the scrollbars position to match the current viewport.
VECTOR2D m_cursorPos
Flag deciding whether the cursor position should be calculated using the mouse position.
void onCaptureLost(wxMouseEvent &WXUNUSED(aEvent))
void onMotion(wxMouseEvent &aEvent)
std::unique_ptr< PROF_COUNTER > m_MotionEventCounter
EDA_DRAW_PANEL_GAL * m_parentPanel
Store information about point where dragging has started.
void UpdateScrollbars()
End any mouse drag action still in progress.
void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0)) override
Applies VIEW_CONTROLS settings from the program COMMON_SETTINGS.
void handleCursorCapture(int x, int y)
Limit the cursor position to within the canvas by warping it.
void onLeave(wxMouseEvent &WXUNUSED(aEvent))
VECTOR2D m_zoomStartPoint
Current cursor position (world coordinates).
static const wxEventType EVT_REFRESH_MOUSE
VECTOR2D m_panDirection
Timer responsible for handling autopanning.
VECTOR2D m_dragStartPoint
Current direction of panning (only autopanning mode).
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:55
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
Definition: kiway_player.h:65
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:406
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition: pgm_base.cpp:678
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:278
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:380
@ FRAME_PCB_EDITOR
Definition: frame_type.h:42
@ FRAME_SCH
Definition: frame_type.h:34
a few functions useful in geometry calculations.
VECTOR2< ret_type > GetClampedCoords(const VECTOR2< in_type > &aCoords, pad_type aPadding=1u)
Clamps a vector to values that can be negated, respecting numeric limits of coordinates data type wit...
const wxChar *const traceZoomScroll
Flag to enable debug output of zoom-scrolling calculations in KIGFX::ZOOM_CONTROLLER and derivatives.
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:247
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: wxgtk/ui.cpp:611
void InfiniteDragReleaseWindow()
On Wayland, allows the cursor to freely move again after a drag (see InfiniteDragPrepareWindow).
Definition: wxgtk/ui.cpp:605
bool WarpPointer(wxWindow *aWindow, int aX, int aY)
Move the mouse cursor to a specific position relative to the window.
Definition: wxgtk/ui.cpp:253
bool IsWindowActive(wxWindow *aWindow)
Check to see if the given window is the currently active window (e.g.
Definition: wxgtk/ui.cpp:73
bool InfiniteDragPrepareWindow(wxWindow *aWindow)
On Wayland, restricts the pointer movement to a rectangle slightly bigger than the given wxWindow.
Definition: wxgtk/ui.cpp:598
KICOMMON_API bool IsInputControlFocused(wxWindow *aFocus=nullptr)
Check if a input control has focus.
Definition: ui_common.cpp:263
KICOMMON_API bool IsModalDialogFocused()
Definition: ui_common.cpp:317
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1059
see class PGM_BASE
const int scale
MOUSE_DRAG_ACTION drag_right
MOUSE_DRAG_ACTION drag_middle
MOUSE_DRAG_ACTION drag_left
float m_autoPanMargin
How fast is panning when in auto mode.
Definition: view_controls.h:80
VECTOR2D m_forcedPosition
Is the forced cursor position enabled.
Definition: view_controls.h:56
MOUSE_DRAG_ACTION m_dragLeft
bool m_horizontalPan
Enable the accelerating zoom controller.
Definition: view_controls.h:92
bool m_autoPanSettingEnabled
Distance from cursor to VIEW edge when panning is active.
Definition: view_controls.h:77
bool m_focusFollowSchPcb
Flag for turning on autopanning.
Definition: view_controls.h:71
float m_autoPanAcceleration
If the cursor is allowed to be warped.
Definition: view_controls.h:86
MOUSE_DRAG_ACTION m_dragMiddle
bool m_cursorCaptured
Should the cursor snap to grid or move freely.
Definition: view_controls.h:62
int m_zoomSpeed
When true, ignore zoom_speed and pick a platform-specific default.
Definition: view_controls.h:98
int m_scrollModifierZoom
What modifier key to enable horizontal pan with the (vertical) scroll wheel.
int m_scrollModifierPanH
What modifier key to enable vertical with the (vertical) scroll wheel.
VECTOR2D m_lastKeyboardCursorPosition
Wether to invert the scroll wheel movement for horizontal pan.
bool m_warpCursor
Enable horizontal panning with the horizontal scroll/trackpad input.
Definition: view_controls.h:89
MOUSE_DRAG_ACTION m_dragRight
Is last cursor motion event coming from keyboard arrow cursor motion action.
bool m_zoomAcceleration
Zoom speed for the non-accelerating zoom controller.
Definition: view_controls.h:95
bool m_lastKeyboardCursorPositionValid
ACTIONS::CURSOR_UP, ACTIONS::CURSOR_DOWN, etc.
bool m_zoomSpeedAuto
What modifier key to enable zoom with the (vertical) scroll wheel.
bool m_autoPanEnabled
Flag for turning on autopanning.
Definition: view_controls.h:74
long m_lastKeyboardCursorCommand
Position of the above event.
bool m_forceCursorPosition
Should the cursor be locked within the parent window area.
Definition: view_controls.h:59
constexpr int delta
wxLogTrace helper definitions.
Functions to provide common constants and other functions to assist in making a consistent UI.
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:673
VECTOR2< double > VECTOR2D
Definition: vector2d.h:672
static std::unique_ptr< ZOOM_CONTROLLER > GetZoomControllerForPlatform(bool aAcceleration)
WX_VIEW_CONTROLS class definition.
ZOOM_CONTROLLER class definition.