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#include <cmath>
44
45#ifdef __WXMSW__
46#define USE_MOUSE_CAPTURE
47#endif
48
49#ifdef KICAD_GAL_PROFILE
50#include <trace_helpers.h>
51#endif
52
53using namespace KIGFX;
54
55const wxEventType WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE = wxNewEventType();
56
57
58static std::unique_ptr<ZOOM_CONTROLLER> GetZoomControllerForPlatform( bool aAcceleration )
59{
60#ifdef __WXMAC__
61 // On Apple pointer devices, wheel events occur frequently and with
62 // smaller rotation values. For those devices, let's handle zoom
63 // based on the rotation amount rather than the time difference.
64 return std::make_unique<CONSTANT_ZOOM_CONTROLLER>( CONSTANT_ZOOM_CONTROLLER::MAC_SCALE );
65#elif __WXGTK3__
66 // GTK3 is similar, but the scale constant is smaller
67 return std::make_unique<CONSTANT_ZOOM_CONTROLLER>( CONSTANT_ZOOM_CONTROLLER::GTK3_SCALE );
68#else
69 if( aAcceleration )
70 return std::make_unique<ACCELERATING_ZOOM_CONTROLLER>();
71 else
72 return std::make_unique<CONSTANT_ZOOM_CONTROLLER>( CONSTANT_ZOOM_CONTROLLER::MSW_SCALE );
73#endif
74}
75
76
78 VIEW_CONTROLS( aView ),
79 m_state( IDLE ),
80 m_parentPanel( aParentPanel ),
81 m_dragStartPoint( 0, 0 ),
82 m_panDirection( 0, 0 ),
83 m_scrollScale( 1.0, 1.0 ),
84 m_scrollPos( 0, 0 ),
85 m_zoomStartPoint( 0, 0 ),
86 m_cursorPos( 0, 0 ),
87 m_updateCursor( true ),
88 m_metaPanning( false ),
89 m_metaPanStart( 0, 0 ),
90 m_infinitePanWorks( false ),
92 m_gestureLastPos( 0, 0 )
93{
95
96 m_MotionEventCounter = std::make_unique<PROF_COUNTER>( "Mouse motion events" );
97
98 m_parentPanel->Connect( wxEVT_MOTION,
99 wxMouseEventHandler( WX_VIEW_CONTROLS::onMotion ), nullptr, this );
100 m_parentPanel->Connect( wxEVT_MAGNIFY,
101 wxMouseEventHandler( WX_VIEW_CONTROLS::onMagnify ), nullptr, this );
102 m_parentPanel->Connect( wxEVT_MOUSEWHEEL,
103 wxMouseEventHandler( WX_VIEW_CONTROLS::onWheel ), nullptr, this );
104 m_parentPanel->Connect( wxEVT_MIDDLE_UP,
105 wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), nullptr, this );
106 m_parentPanel->Connect( wxEVT_MIDDLE_DOWN,
107 wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), nullptr, this );
108 m_parentPanel->Connect( wxEVT_LEFT_UP,
109 wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), nullptr, this );
110 m_parentPanel->Connect( wxEVT_LEFT_DOWN,
111 wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), nullptr, this );
112 m_parentPanel->Connect( wxEVT_RIGHT_UP,
113 wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), nullptr, this );
114 m_parentPanel->Connect( wxEVT_RIGHT_DOWN,
115 wxMouseEventHandler( WX_VIEW_CONTROLS::onButton ), nullptr, this );
116#if defined __WXMSW__
117 m_parentPanel->Connect( wxEVT_ENTER_WINDOW,
118 wxMouseEventHandler( WX_VIEW_CONTROLS::onEnter ), nullptr, this );
119#endif
120 m_parentPanel->Connect( wxEVT_LEAVE_WINDOW,
121 wxMouseEventHandler( WX_VIEW_CONTROLS::onLeave ), nullptr, this );
122 m_parentPanel->Connect( wxEVT_SCROLLWIN_THUMBTRACK,
123 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
124 m_parentPanel->Connect( wxEVT_SCROLLWIN_PAGEUP,
125 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
126 m_parentPanel->Connect( wxEVT_SCROLLWIN_PAGEDOWN,
127 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
128
129 m_parentPanel->Connect( wxEVT_SCROLLWIN_BOTTOM,
130 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
131 m_parentPanel->Connect( wxEVT_SCROLLWIN_TOP,
132 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
133 m_parentPanel->Connect( wxEVT_SCROLLWIN_LINEUP,
134 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
135 m_parentPanel->Connect( wxEVT_SCROLLWIN_LINEDOWN,
136 wxScrollWinEventHandler( WX_VIEW_CONTROLS::onScroll ), nullptr, this );
137#if defined USE_MOUSE_CAPTURE
138 m_parentPanel->Connect( wxEVT_MOUSE_CAPTURE_LOST,
139 wxMouseEventHandler( WX_VIEW_CONTROLS::onCaptureLost ), nullptr, this );
140#endif
141
142#ifndef __WXOSX__
143 if( m_parentPanel->EnableTouchEvents( wxTOUCH_ZOOM_GESTURE | wxTOUCH_PAN_GESTURES ) )
144 {
145 m_parentPanel->Connect( wxEVT_GESTURE_ZOOM,
146 wxZoomGestureEventHandler( WX_VIEW_CONTROLS::onZoomGesture ),
147 nullptr, this );
148
149 m_parentPanel->Connect( wxEVT_GESTURE_PAN,
150 wxPanGestureEventHandler( WX_VIEW_CONTROLS::onPanGesture ), nullptr,
151 this );
152 }
153#endif
154
155 m_cursorWarped = false;
156
157 m_panTimer.SetOwner( this );
158 Connect( wxEVT_TIMER, wxTimerEventHandler( WX_VIEW_CONTROLS::onTimer ), nullptr, this );
159
160 m_settings.m_lastKeyboardCursorPositionValid = false;
161 m_settings.m_lastKeyboardCursorPosition = { 0.0, 0.0 };
162 m_settings.m_lastKeyboardCursorCommand = 0;
163}
164
165
167{
168#if defined USE_MOUSE_CAPTURE
169 if( m_parentPanel->HasCapture() )
170 m_parentPanel->ReleaseMouse();
171#endif
172}
173
174
176{
178
179 m_settings.m_warpCursor = cfg->m_Input.center_on_zoom;
180 m_settings.m_focusFollowSchPcb = cfg->m_Input.focus_follow_sch_pcb;
181 m_settings.m_autoPanSettingEnabled = cfg->m_Input.auto_pan;
182 m_settings.m_autoPanAcceleration = cfg->m_Input.auto_pan_acceleration;
183 m_settings.m_horizontalPan = cfg->m_Input.horizontal_pan;
184 m_settings.m_zoomAcceleration = cfg->m_Input.zoom_acceleration;
185 m_settings.m_zoomSpeed = cfg->m_Input.zoom_speed;
186 m_settings.m_zoomSpeedAuto = cfg->m_Input.zoom_speed_auto;
187 m_settings.m_scrollModifierZoom = cfg->m_Input.scroll_modifier_zoom;
188 m_settings.m_scrollModifierPanH = cfg->m_Input.scroll_modifier_pan_h;
189 m_settings.m_scrollModifierPanV = cfg->m_Input.scroll_modifier_pan_v;
190 m_settings.m_dragLeft = cfg->m_Input.drag_left;
191 m_settings.m_dragMiddle = cfg->m_Input.drag_middle;
192 m_settings.m_dragRight = cfg->m_Input.drag_right;
193 m_settings.m_scrollReverseZoom = cfg->m_Input.reverse_scroll_zoom;
194 m_settings.m_scrollReversePanH = cfg->m_Input.reverse_scroll_pan_h;
195 m_settings.m_motionPanModifier = cfg->m_Input.motion_pan_modifier;
196
197 m_zoomController.reset();
198
199 if( cfg->m_Input.zoom_speed_auto )
200 {
202 }
203 else
204 {
205 if( cfg->m_Input.zoom_acceleration )
206 {
208 std::make_unique<ACCELERATING_ZOOM_CONTROLLER>( cfg->m_Input.zoom_speed );
209 }
210 else
211 {
213
214 m_zoomController = std::make_unique<CONSTANT_ZOOM_CONTROLLER>( scale );
215 }
216 }
217}
218
219
220void WX_VIEW_CONTROLS::onMotion( wxMouseEvent& aEvent )
221{
222#ifdef KICAD_GAL_PROFILE
223 latencyProbeRepaintToMotion.Checkpoint("motion-event");
224 wxLogTrace( traceGalProfile, "%s", latencyProbeRepaintToMotion.to_string() );
225 latencyProbeZoomToRender.Reset();
226#endif
227
228 ( *m_MotionEventCounter )++;
229
230 // Because Weston sends a motion event to previous location after warping the pointer
231 wxPoint mouseRel = m_parentPanel->ScreenToClient( KIPLATFORM::UI::GetMousePosition() );
232
233 bool isAutoPanning = false;
234 int x = mouseRel.x;
235 int y = mouseRel.y;
236 VECTOR2D mousePos( x, y );
237
238 // Clear keyboard cursor position flag when actual mouse motion is detected
239 // (i.e., not from cursor warping and position has changed)
240 if( !m_cursorWarped && m_settings.m_lastKeyboardCursorPositionValid )
241 {
242 VECTOR2I screenPos( x, y );
243 VECTOR2I keyboardScreenPos = m_view->ToScreen( m_settings.m_lastKeyboardCursorPosition );
244
245 // If mouse has moved to a different position than the keyboard cursor position,
246 // clear the keyboard position flag to allow mouse control
247 if( screenPos != keyboardScreenPos )
248 {
249 m_settings.m_lastKeyboardCursorPositionValid = false;
250 m_settings.m_lastKeyboardCursorPosition = { 0.0, 0.0 };
251 }
252 }
253
254 // Automatic focus switching between SCH and PCB windows on canvas mouse motion
255 if( m_settings.m_focusFollowSchPcb )
256 {
257 if( EDA_DRAW_FRAME* frame = m_parentPanel->GetParentEDAFrame() )
258 {
259 KIWAY_PLAYER* otherFrame = nullptr;
260
261 if( frame->IsType( FRAME_PCB_EDITOR ) )
262 {
263 otherFrame = frame->Kiway().Player( FRAME_SCH, false );
264 }
265 else if( frame->IsType( FRAME_SCH ) )
266 {
267 otherFrame = frame->Kiway().Player( FRAME_PCB_EDITOR, false );
268 }
269
270 if( otherFrame && KIPLATFORM::UI::IsWindowActive( otherFrame )
271 && !KIPLATFORM::UI::IsWindowActive( frame ) )
272 {
273 frame->Raise();
274 }
275 }
276 }
277
278 if( m_settings.m_motionPanModifier != WXK_NONE
279 && wxGetKeyState( static_cast<wxKeyCode>( m_settings.m_motionPanModifier ) ) )
280 {
281 if( !m_metaPanning )
282 {
283 m_metaPanning = true;
284 m_metaPanStart = mousePos;
285 aEvent.StopPropagation();
286 }
287 else
288 {
289 VECTOR2D d = m_metaPanStart - mousePos;
290 m_metaPanStart = mousePos;
291 VECTOR2D delta = m_view->ToWorld( d, false );
292 m_view->SetCenter( m_view->GetCenter() + delta );
293 aEvent.StopPropagation();
294 }
295
296 if( m_updateCursor )
297 m_cursorPos = GetClampedCoords( m_view->ToWorld( mousePos ) );
298 else
299 m_updateCursor = true;
300
301 aEvent.Skip();
302 return;
303 }
304 else
305 {
306 m_metaPanning = false;
307 }
308
310 handleCursorCapture( x, y );
311
312 if( m_settings.m_autoPanEnabled && m_settings.m_autoPanSettingEnabled )
313 isAutoPanning = handleAutoPanning( aEvent );
314
315 if( !isAutoPanning && aEvent.Dragging() )
316 {
317 if( m_state == DRAG_PANNING )
318 {
319 static bool justWarped = false;
320 int warpX = 0;
321 int warpY = 0;
322 wxSize parentSize = m_parentPanel->GetClientSize();
323
324 if( x < 0 )
325 {
326 warpX = parentSize.x;
327 }
328 else if( x >= parentSize.x )
329 {
330 warpX = -parentSize.x;
331 }
332
333 if( y < 0 )
334 {
335 warpY = parentSize.y;
336 }
337 else if( y >= parentSize.y )
338 {
339 warpY = -parentSize.y;
340 }
341
342 if( !justWarped )
343 {
344 VECTOR2D d = m_dragStartPoint - mousePos;
345 m_dragStartPoint = mousePos;
346 VECTOR2D delta = m_view->ToWorld( d, false );
347#ifdef KICAD_GAL_PROFILE
348 latencyProbeZoomToRender.Checkpoint("mouse-mb-pan");
349#endif
350 m_view->SetCenter( m_view->GetCenter() + delta );
351 aEvent.StopPropagation();
352 }
353
354 if( warpX || warpY )
355 {
356 if( !justWarped )
357 {
358 if( m_infinitePanWorks && KIPLATFORM::UI::WarpPointer( m_parentPanel, x + warpX, y + warpY ) )
359 {
360 m_dragStartPoint += VECTOR2D( warpX, warpY );
361 justWarped = true;
362 }
363 }
364 else
365 {
366 justWarped = false;
367 }
368 }
369 else
370 {
371 justWarped = false;
372 }
373 }
374 else if( m_state == DRAG_ZOOMING )
375 {
376 static bool justWarped = false;
377 int warpY = 0;
378 wxSize parentSize = m_parentPanel->GetClientSize();
379
380 if( y < 0 )
381 {
382 warpY = parentSize.y;
383 }
384 else if( y >= parentSize.y )
385 {
386 warpY = -parentSize.y;
387 }
388
389 if( !justWarped )
390 {
391 VECTOR2D d = m_dragStartPoint - mousePos;
392 m_dragStartPoint = mousePos;
393
394 double scale = exp( d.y * m_settings.m_zoomSpeed * 0.001 );
395
396 wxLogTrace( traceZoomScroll, wxString::Format( "dy: %f scale: %f", d.y, scale ) );
397
398 m_view->SetScale( m_view->GetScale() * scale, m_view->ToWorld( m_zoomStartPoint ) );
399 aEvent.StopPropagation();
400 }
401
402 if( warpY )
403 {
404 if( !justWarped )
405 {
407 m_dragStartPoint += VECTOR2D( 0, warpY );
408 justWarped = true;
409 }
410 else
411 justWarped = false;
412 }
413 else
414 {
415 justWarped = false;
416 }
417 }
418 }
419
420 if( m_updateCursor ) // do not update the cursor position if it was explicitly set
421 m_cursorPos = GetClampedCoords( m_view->ToWorld( mousePos ) );
422 else
423 m_updateCursor = true;
424
425 aEvent.Skip();
426}
427
428
429void WX_VIEW_CONTROLS::onWheel( wxMouseEvent& aEvent )
430{
431 const double wheelPanSpeed = 0.001;
432 const int axis = aEvent.GetWheelAxis();
433
434#ifdef KICAD_GAL_PROFILE
435 latencyProbeZoomToRender.Reset();
436#endif
437
438 // Native horizontal wheel events (tilt wheels, side-button scroll combos, touchpads) pan the
439 // view when "Pan left/right with horizontal movement" is enabled, otherwise they are ignored
440 if( axis == wxMOUSE_WHEEL_HORIZONTAL )
441 {
442 if( !m_settings.m_horizontalPan )
443 return;
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 );
740 aEvent.GetZoomFactor() / m_gestureLastZoomFactor, evtPos );
741
742 m_gestureLastZoomFactor = aEvent.GetZoomFactor();
743 m_gestureLastPos = evtPos;
744}
745
746
747void WX_VIEW_CONTROLS::onPanGesture( wxPanGestureEvent& aEvent )
748{
749 VECTOR2I screenDelta( aEvent.GetDelta().x, aEvent.GetDelta().y );
750
751 ApplyPanAndZoomGesture( screenDelta, 1.0, VECTOR2D() );
752}
753
754
755void WX_VIEW_CONTROLS::ApplyPanAndZoomGesture( const VECTOR2D& aPanDelta, double aZoomFactor,
756 const VECTOR2D& aZoomAnchor )
757{
758 VECTOR2D deltaWorld = m_view->ToWorld( aPanDelta, false );
759
760 m_view->SetCenter( m_view->GetCenter() - deltaWorld );
761
762 if( std::isfinite( aZoomFactor ) && aZoomFactor > 0.0 && aZoomFactor != 1.0 )
763 m_view->SetScale( m_view->GetScale() * aZoomFactor, m_view->ToWorld( aZoomAnchor ) );
764
765 refreshMouse( true );
766}
767
768
769void WX_VIEW_CONTROLS::onScroll( wxScrollWinEvent& aEvent )
770{
771 const double linePanDelta = 0.05;
772 const double pagePanDelta = 0.5;
773
774 int type = aEvent.GetEventType();
775 int dir = aEvent.GetOrientation();
776
777 if( type == wxEVT_SCROLLWIN_THUMBTRACK )
778 {
779 auto center = m_view->GetCenter();
780 const auto& boundary = m_view->GetBoundary();
781
782 // Flip scroll direction in flipped view
783 const double xstart = ( m_view->IsMirroredX() ? boundary.GetRight() : boundary.GetLeft() );
784 const double xdelta = ( m_view->IsMirroredX() ? -1 : 1 );
785
786 if( dir == wxHORIZONTAL )
787 center.x = xstart + xdelta * ( aEvent.GetPosition() / m_scrollScale.x );
788 else
789 center.y = boundary.GetTop() + aEvent.GetPosition() / m_scrollScale.y;
790
791 m_view->SetCenter( center );
792 }
793 else if( type == wxEVT_SCROLLWIN_THUMBRELEASE || type == wxEVT_SCROLLWIN_TOP || type == wxEVT_SCROLLWIN_BOTTOM )
794 {
795 // Do nothing on thumb release, we don't care about it.
796 // We don't have a concept of top or bottom in our viewport, so ignore those events.
797 }
798 else
799 {
800 double dist = 0;
801
802 if( type == wxEVT_SCROLLWIN_PAGEUP )
803 {
804 dist = pagePanDelta;
805 }
806 else if( type == wxEVT_SCROLLWIN_PAGEDOWN )
807 {
808 dist = -pagePanDelta;
809 }
810 else if( type == wxEVT_SCROLLWIN_LINEUP )
811 {
812 dist = linePanDelta;
813 }
814 else if( type == wxEVT_SCROLLWIN_LINEDOWN )
815 {
816 dist = -linePanDelta;
817 }
818 else
819 {
820 wxCHECK_MSG( false, /* void */, wxT( "Unhandled event type" ) );
821 }
822
823 VECTOR2D scroll = m_view->ToWorld( m_view->GetScreenPixelSize(), false ) * dist;
824
825 double scrollX = 0.0;
826 double scrollY = 0.0;
827
828 if( dir == wxHORIZONTAL )
829 scrollX = -scroll.x;
830 else
831 scrollY = -scroll.y;
832
833 VECTOR2D delta( scrollX, scrollY );
834
835 m_view->SetCenter( m_view->GetCenter() + delta );
836 }
837
838 m_parentPanel->Refresh();
839}
840
841
843{
844#if defined USE_MOUSE_CAPTURE
845 // Note: for some reason, m_parentPanel->HasCapture() can be false even if CaptureMouse()
846 // was called (i.e. mouse was captured, so when need to test m_MouseCapturedLost to be
847 // sure a wxEVT_MOUSE_CAPTURE_LOST event was fired before. Otherwise wxMSW complains
848 // The IsModalDialogFocused is checked because it's possible to start a capture
849 // due to event ordering while a modal dialog was just opened, the mouse capture steels focus
850 // from the modal and causes odd behavior
851 if( aEnabled && !m_parentPanel->HasCapture() && m_parentPanel->m_MouseCapturedLost
853 {
854 m_parentPanel->CaptureMouse();
855
856 // Clear the flag to allow calling m_parentPanel->CaptureMouse()
857 // Calling it without calling ReleaseMouse() is not accepted by wxWidgets (MSW specific)
858 m_parentPanel->m_MouseCapturedLost = false;
859 }
860 else if( !aEnabled && m_parentPanel->HasCapture() && m_state != DRAG_PANNING && m_state != DRAG_ZOOMING )
861 {
862 m_parentPanel->ReleaseMouse();
863
864 // Mouse is released, calling CaptureMouse() is allowed now:
865 m_parentPanel->m_MouseCapturedLost = true;
866 }
867#endif
869}
870
871
873{
875 {
876 setState( IDLE );
877
878#if defined USE_MOUSE_CAPTURE
879 if( !m_settings.m_cursorCaptured && m_parentPanel->HasCapture() )
880 m_parentPanel->ReleaseMouse();
881#endif
882 }
883
884 m_metaPanning = false;
885}
886
887
888VECTOR2D WX_VIEW_CONTROLS::GetMousePosition( bool aWorldCoordinates ) const
889{
890 wxPoint msp = getMouseScreenPosition();
891 VECTOR2D screenPos( msp.x, msp.y );
892
893 return aWorldCoordinates ? GetClampedCoords( m_view->ToWorld( screenPos ) ) : screenPos;
894}
895
896
898{
899 GAL* gal = m_view->GetGAL();
900
901 if( aEnableSnapping && gal->GetGridSnapping() )
902 {
903 return gal->GetGridPoint( m_cursorPos );
904 }
905 else
906 {
907 return m_cursorPos;
908 }
909}
910
911
913{
914 if( m_settings.m_forceCursorPosition )
915 {
916 return m_settings.m_forcedPosition;
917 }
918 else
919 {
920 return GetClampedCoords( GetRawCursorPosition( aEnableSnapping ) );
921 }
922}
923
924
925void WX_VIEW_CONTROLS::SetCursorPosition( const VECTOR2D& aPosition, bool aWarpView, bool aTriggeredByArrows,
926 long aArrowCommand )
927{
928 m_updateCursor = false;
929
930 VECTOR2D clampedPosition = GetClampedCoords( aPosition );
931
932 if( aTriggeredByArrows )
933 {
934 m_settings.m_lastKeyboardCursorPositionValid = true;
935 m_settings.m_lastKeyboardCursorPosition = clampedPosition;
936 m_settings.m_lastKeyboardCursorCommand = aArrowCommand;
937 m_cursorWarped = false;
938 }
939 else
940 {
941 m_settings.m_lastKeyboardCursorPositionValid = false;
942 m_settings.m_lastKeyboardCursorPosition = { 0.0, 0.0 };
943 m_settings.m_lastKeyboardCursorCommand = 0;
944 m_cursorWarped = true;
945 }
946
947 WarpMouseCursor( clampedPosition, true, aWarpView );
948 m_cursorPos = clampedPosition;
949}
950
951
952void WX_VIEW_CONTROLS::SetCrossHairCursorPosition( const VECTOR2D& aPosition, bool aWarpView = true )
953{
954 m_updateCursor = false;
955
956 VECTOR2D clampedPosition = GetClampedCoords( aPosition );
957
958 const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
959 BOX2I screen( VECTOR2I( 0, 0 ), screenSize );
960 VECTOR2D screenPos = m_view->ToScreen( clampedPosition );
961
962 if( aWarpView && !screen.Contains( screenPos ) )
963 m_view->SetCenter( clampedPosition );
964
965 m_cursorPos = clampedPosition;
966}
967
968
969void WX_VIEW_CONTROLS::WarpMouseCursor( const VECTOR2D& aPosition, bool aWorldCoordinates, bool aWarpView )
970{
971 if( aWorldCoordinates )
972 {
973 const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
974 BOX2I screen( VECTOR2I( 0, 0 ), screenSize );
975 VECTOR2D clampedPosition = GetClampedCoords( aPosition );
976 VECTOR2D screenPos = m_view->ToScreen( clampedPosition );
977
978 if( !screen.Contains( screenPos ) )
979 {
980 if( aWarpView )
981 {
982 m_view->SetCenter( clampedPosition );
983 KIPLATFORM::UI::WarpPointer( m_parentPanel, screenSize.x / 2, screenSize.y / 2 );
984 }
985 }
986 else
987 {
988 KIPLATFORM::UI::WarpPointer( m_parentPanel, screenPos.x, screenPos.y );
989 }
990 }
991 else
992 {
993 KIPLATFORM::UI::WarpPointer( m_parentPanel, aPosition.x, aPosition.y );
994 }
995
996 // If we are not refreshing because of mouse movement, don't set the modifiers because we
997 // are refreshing for keyboard movement, which uses the same modifiers for other actions
999}
1000
1001
1003{
1004 const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
1005 VECTOR2D screenCenter( screenSize / 2 );
1006
1007 if( GetMousePosition( false ) != screenCenter )
1008 {
1009 VECTOR2D newCenter = GetCursorPosition();
1010
1011 if( KIPLATFORM::UI::WarpPointer( m_parentPanel, screenCenter.x, screenCenter.y ) )
1012 {
1013 m_view->SetCenter( newCenter );
1014 m_dragStartPoint = screenCenter;
1015 }
1016 }
1017}
1018
1019
1021{
1022 int border = std::min( m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().x,
1023 m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().y );
1024 border += 2;
1025
1026 VECTOR2D topLeft( border, border );
1027 VECTOR2D botRight( m_view->GetScreenPixelSize().x - border, m_view->GetScreenPixelSize().y - border );
1028
1029 topLeft = m_view->ToWorld( topLeft );
1030 botRight = m_view->ToWorld( botRight );
1031
1032 VECTOR2D pos = GetMousePosition( true );
1033
1034 if( pos.x < topLeft.x )
1035 pos.x = topLeft.x;
1036 else if( pos.x > botRight.x )
1037 pos.x = botRight.x;
1038
1039 if( pos.y < topLeft.y )
1040 pos.y = topLeft.y;
1041 else if( pos.y > botRight.y )
1042 pos.y = botRight.y;
1043
1044 SetCursorPosition( pos, false, false, 0 );
1045
1046 if( aWarpMouseCursor )
1047 WarpMouseCursor( pos, true );
1048}
1049
1050
1051bool WX_VIEW_CONTROLS::handleAutoPanning( const wxMouseEvent& aEvent )
1052{
1053 VECTOR2I p( aEvent.GetX(), aEvent.GetY() );
1054 VECTOR2I pKey( m_view->ToScreen( m_settings.m_lastKeyboardCursorPosition ) );
1055
1056 if( m_cursorWarped || ( m_settings.m_lastKeyboardCursorPositionValid && p == pKey ) )
1057 {
1058 // last cursor move event came from keyboard cursor control. If auto-panning is enabled
1059 // and the next position is inside the autopan zone, check if it really came from a mouse
1060 // event, otherwise disable autopan temporarily. Also temporarily disable autopan if the
1061 // cursor is in the autopan zone because the application warped the cursor.
1062
1063 m_cursorWarped = false;
1064 return true;
1065 }
1066
1067 m_cursorWarped = false;
1068
1069 // Compute areas where autopanning is active
1070 int borderStart = std::min( m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().x,
1071 m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().y );
1072 borderStart = std::max( borderStart, 2 );
1073 int borderEndX = m_view->GetScreenPixelSize().x - borderStart;
1074 int borderEndY = m_view->GetScreenPixelSize().y - borderStart;
1075
1076 if( p.x < borderStart )
1077 m_panDirection.x = -( borderStart - p.x );
1078 else if( p.x > borderEndX )
1079 m_panDirection.x = ( p.x - borderEndX );
1080 else
1081 m_panDirection.x = 0;
1082
1083 if( p.y < borderStart )
1084 m_panDirection.y = -( borderStart - p.y );
1085 else if( p.y > borderEndY )
1086 m_panDirection.y = ( p.y - borderEndY );
1087 else
1088 m_panDirection.y = 0;
1089
1090 bool borderHit = ( m_panDirection.x != 0 || m_panDirection.y != 0 );
1091
1092 switch( m_state )
1093 {
1094 case AUTO_PANNING:
1095 if( !borderHit )
1096 {
1097 m_panTimer.Stop();
1098 setState( IDLE );
1099
1100 return false;
1101 }
1102
1103 return true;
1104
1105 case IDLE:
1106 if( borderHit )
1107 {
1109 m_panTimer.Start( (int) ( 250.0 / 60.0 ), true );
1110
1111 return true;
1112 }
1113
1114 return false;
1115
1116 case DRAG_PANNING:
1117 case DRAG_ZOOMING: return false;
1118 }
1119
1120 wxCHECK_MSG( false, false, wxT( "This line should never be reached" ) );
1121
1122 return false;
1123}
1124
1125
1127{
1128 if( m_settings.m_cursorCaptured )
1129 {
1130 bool warp = false;
1131 wxSize parentSize = m_parentPanel->GetClientSize();
1132
1133 if( x < 0 )
1134 {
1135 x = 0;
1136 warp = true;
1137 }
1138 else if( x >= parentSize.x )
1139 {
1140 x = parentSize.x - 1;
1141 warp = true;
1142 }
1143
1144 if( y < 0 )
1145 {
1146 y = 0;
1147 warp = true;
1148 }
1149 else if( y >= parentSize.y )
1150 {
1151 y = parentSize.y - 1;
1152 warp = true;
1153 }
1154
1155 if( warp )
1157 }
1158}
1159
1160
1161void WX_VIEW_CONTROLS::refreshMouse( bool aSetModifiers )
1162{
1163 // Notify tools that the cursor position has changed in the world coordinates
1164 wxMouseEvent moveEvent( EVT_REFRESH_MOUSE );
1165 wxPoint msp = getMouseScreenPosition();
1166 moveEvent.SetX( msp.x );
1167 moveEvent.SetY( msp.y );
1168
1169 if( aSetModifiers )
1170 {
1171 // Set the modifiers state
1172 moveEvent.SetControlDown( wxGetKeyState( WXK_CONTROL ) );
1173 moveEvent.SetShiftDown( wxGetKeyState( WXK_SHIFT ) );
1174 moveEvent.SetAltDown( wxGetKeyState( WXK_ALT ) );
1175 }
1176
1177 m_cursorPos = GetClampedCoords( m_view->ToWorld( VECTOR2D( msp.x, msp.y ) ) );
1178 wxPostEvent( m_parentPanel, moveEvent );
1179}
1180
1181
1183{
1184 wxPoint msp = KIPLATFORM::UI::GetMousePosition();
1185 m_parentPanel->ScreenToClient( &msp.x, &msp.y );
1186 return msp;
1187}
1188
1189
1191{
1192 const BOX2D viewport = m_view->GetViewport();
1193 const BOX2D& boundary = m_view->GetBoundary();
1194
1195 m_scrollScale.x = 2e3 / viewport.GetWidth(); // TODO it does not have to be updated so often
1196 m_scrollScale.y = 2e3 / viewport.GetHeight();
1197 VECTOR2I newScroll( ( viewport.Centre().x - boundary.GetLeft() ) * m_scrollScale.x,
1198 ( viewport.Centre().y - boundary.GetTop() ) * m_scrollScale.y );
1199
1200 // We add the width of the scroll bar thumb to the range because the scroll range is given by
1201 // the full bar while the position is given by the left/top position of the thumb
1202 VECTOR2I newRange( m_scrollScale.x * boundary.GetWidth() + m_parentPanel->GetScrollThumb( wxSB_HORIZONTAL ),
1203 m_scrollScale.y * boundary.GetHeight() + m_parentPanel->GetScrollThumb( wxSB_VERTICAL ) );
1204
1205 // Flip scroll direction in flipped view
1206 if( m_view->IsMirroredX() )
1207 newScroll.x = ( boundary.GetRight() - viewport.Centre().x ) * m_scrollScale.x;
1208
1209 // Adjust scrollbars only if it is needed. Otherwise there are cases when canvas is continuously
1210 // refreshed (Windows)
1211 if( m_scrollPos != newScroll || newRange.x != m_parentPanel->GetScrollRange( wxSB_HORIZONTAL )
1212 || newRange.y != m_parentPanel->GetScrollRange( wxSB_VERTICAL ) )
1213 {
1214 m_parentPanel->SetScrollbars( 1, 1, newRange.x, newRange.y, newScroll.x, newScroll.y, true );
1215 m_scrollPos = newScroll;
1216
1217#if !defined( __APPLE__ ) && !defined( WIN32 )
1218 // Trigger a mouse refresh to get the canvas update in GTK (re-draws the scrollbars).
1219 // Note that this causes an infinite loop on OSX and Windows (in certain cases) as it
1220 // generates a paint event.
1221 refreshMouse( false );
1222#endif
1223 }
1224}
1225
1226
1227void WX_VIEW_CONTROLS::ForceCursorPosition( bool aEnabled, const VECTOR2D& aPosition )
1228{
1229 VECTOR2D clampedPosition = GetClampedCoords( aPosition );
1230
1231 m_settings.m_forceCursorPosition = aEnabled;
1232 m_settings.m_forcedPosition = clampedPosition;
1233}
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
BOX2< VECTOR2D > BOX2D
Definition box2.h:928
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr Vec Centre() const
Definition box2.h:94
constexpr size_type GetHeight() const
Definition box2.h:212
constexpr coord_type GetLeft() const
Definition box2.h:225
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:165
constexpr coord_type GetRight() const
Definition box2.h:214
constexpr coord_type GetTop() const
Definition box2.h:226
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 ApplyPanAndZoomGesture(const VECTOR2D &aPanDelta, double aZoomFactor, const VECTOR2D &aZoomAnchor)
Apply a platform gesture expressed in canvas pixel 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:388
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:546
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:30
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition wxgtk/ui.cpp:839
void InfiniteDragReleaseWindow()
On Wayland, allows the cursor to freely move again after a drag (see InfiniteDragPrepareWindow).
Definition wxgtk/ui.cpp:833
bool WarpPointer(wxWindow *aWindow, int aX, int aY)
Move the mouse cursor to a specific position relative to the window.
Definition wxgtk/ui.cpp:425
bool IsWindowActive(wxWindow *aWindow)
Check to see if the given window is the currently active window (e.g.
Definition wxgtk/ui.cpp:149
bool InfiniteDragPrepareWindow(wxWindow *aWindow)
On Wayland, restricts the pointer movement to a rectangle slightly bigger than the given wxWindow.
Definition wxgtk/ui.cpp:826
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.