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