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