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