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
470
471 KI_TRACE( traceGalProfile, "Zoom: %.5f\n", m_view->GetScale() * zoomScale );
473 {
475 m_view->SetScale( m_view->GetScale() * zoomScale );
476 }
477 else
478 {
479 const VECTOR2D anchor = m_view->ToWorld( VECTOR2D( aEvent.GetX(), aEvent.GetY() ) );
480 m_view->SetScale( m_view->GetScale() * zoomScale, anchor );
481 }
482
483 aEvent.Skip();
484
485 // Refresh the zoom level and mouse position on message panel
486 // (mouse position has not changed, only the zoom level has changed):
487 refreshMouse( true );
488 }
489 else
490 {
491 // Scrolling
492 VECTOR2D scrollVec = m_view->ToWorld( m_view->GetScreenPixelSize(), false )
493 * ( (double) aEvent.GetWheelRotation() * wheelPanSpeed );
494 double scrollX = 0.0;
495 double scrollY = 0.0;
496 bool hReverse = m_settings.m_scrollReversePanH;
497
498 if( modifiers == m_settings.m_scrollModifierPanH )
499 {
500 scrollX = hReverse ? scrollVec.x : -scrollVec.x;
501 }
502 else
503 {
504 scrollY = -scrollVec.y;
505 }
506
507 VECTOR2D delta( scrollX, scrollY );
508
509 m_view->SetCenter( m_view->GetCenter() + delta );
510 refreshMouse( true );
511 }
512
513 // Do not skip this event, otherwise wxWidgets will fire
514 // 3 wxEVT_SCROLLWIN_LINEUP or wxEVT_SCROLLWIN_LINEDOWN (normal wxWidgets behavior)
515 // and we do not want that.
516 }
517 else
518 {
519 // When we have multiple mods, forward it for tool handling
520 aEvent.Skip();
521 }
522}
523
524
525void WX_VIEW_CONTROLS::onMagnify( wxMouseEvent& aEvent )
526{
527 // Scale based on the magnification from our underlying magnification event.
528 VECTOR2D anchor = m_view->ToWorld( VECTOR2D( aEvent.GetX(), aEvent.GetY() ) );
529 m_view->SetScale( m_view->GetScale() * ( aEvent.GetMagnification() + 1.0f ), anchor );
530
531 aEvent.Skip();
532}
533
534
536{
537 m_state = aNewState;
538}
539
540
541void WX_VIEW_CONTROLS::onButton( wxMouseEvent& aEvent )
542{
543 switch( m_state )
544 {
545 case IDLE:
546 case AUTO_PANNING:
547 if( ( aEvent.MiddleDown() && m_settings.m_dragMiddle == MOUSE_DRAG_ACTION::PAN )
548 || ( aEvent.RightDown() && m_settings.m_dragRight == MOUSE_DRAG_ACTION::PAN ) )
549 {
550 m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() );
553
554#if defined USE_MOUSE_CAPTURE
555 if( !m_parentPanel->HasCapture() )
556 m_parentPanel->CaptureMouse();
557#endif
558 }
559 else if( ( aEvent.MiddleDown() && m_settings.m_dragMiddle == MOUSE_DRAG_ACTION::ZOOM )
560 || ( aEvent.RightDown() && m_settings.m_dragRight == MOUSE_DRAG_ACTION::ZOOM ) )
561 {
562 m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() );
565
566#if defined USE_MOUSE_CAPTURE
567 if( !m_parentPanel->HasCapture() )
568 m_parentPanel->CaptureMouse();
569#endif
570 }
571
572 if( aEvent.LeftUp() )
573 setState( IDLE ); // Stop autopanning when user release left mouse button
574
575 break;
576
577 case DRAG_ZOOMING:
578 case DRAG_PANNING:
579 if( aEvent.MiddleUp() || aEvent.LeftUp() || aEvent.RightUp() )
580 {
581 setState( IDLE );
583
584#if defined USE_MOUSE_CAPTURE
585 if( !m_settings.m_cursorCaptured && m_parentPanel->HasCapture() )
586 m_parentPanel->ReleaseMouse();
587#endif
588 }
589
590 break;
591 }
592
593 aEvent.Skip();
594}
595
596
597void WX_VIEW_CONTROLS::onEnter( wxMouseEvent& aEvent )
598{
599 // Avoid stealing focus from text controls
600 // This is particularly important for users using On-Screen-Keyboards
601 // They may move the mouse over the canvas to reach the keyboard
603 {
604 return;
605 }
606
607#if defined( _WIN32 ) || defined( __WXGTK__ )
608 // Win32 and some *nix WMs transmit mouse move and wheel events to all controls below the
609 // mouse regardless of focus. Forcing the focus here will cause the EDA FRAMES to immediately
610 // become the top level active window.
611 if( m_parentPanel->GetParent() != nullptr )
612 {
613 // this assumes the parent panel's parent is the eda window
615 {
616 m_parentPanel->SetFocus();
617 }
618 }
619#else
620 m_parentPanel->SetFocus();
621#endif
622}
623
624
625void WX_VIEW_CONTROLS::onLeave( wxMouseEvent& aEvent )
626{
627#if !defined USE_MOUSE_CAPTURE
628 onMotion( aEvent );
629#endif
630}
631
632
633void WX_VIEW_CONTROLS::onCaptureLost( wxMouseEvent& aEvent )
634{
635 // This method must be present to suppress the capture-lost assertion
636
637 // Set the flag to allow calling m_parentPanel->CaptureMouse()
638 // Note: One cannot call m_parentPanel->CaptureMouse() twice, this is not accepted
639 // by wxWidgets (MSW specific) so we need this guard
640 m_parentPanel->m_MouseCapturedLost = true;
641}
642
643
644void WX_VIEW_CONTROLS::onTimer( wxTimerEvent& aEvent )
645{
646 switch( m_state )
647 {
648 case AUTO_PANNING:
649 {
650 if( !m_settings.m_autoPanEnabled )
651 {
652 setState( IDLE );
653 return;
654 }
655
656#ifdef __WXMSW__
657 // Hackfix: It's possible for the mouse to leave the canvas
658 // without triggering any leave events on windows
659 // Use a MSW only wx function
660 if( !m_parentPanel->IsMouseInWindow() )
661 {
662 m_panTimer.Stop();
663 setState( IDLE );
664 return;
665 }
666#endif
667
668 if( !m_parentPanel->HasFocus() && !m_parentPanel->StatusPopupHasFocus() )
669 {
670 setState( IDLE );
671 return;
672 }
673
674 double borderSize = std::min( m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().x,
675 m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().y );
676
677 // When the mouse cursor is outside the area with no pan,
678 // m_panDirection is the dist to this area limit ( in pixels )
679 // It will be used also as pan value (the pan speed depends on this dist).
681
682 // When the mouse cursor is outside the area with no pan, the pan value
683 // is accelerated depending on the dist between the area and the cursor
684 float accel = 0.5f + ( m_settings.m_autoPanAcceleration / 5.0f );
685
686 // For a small mouse cursor dist to area, just use the distance.
687 // But for a dist > borderSize / 2, use an accelerated pan value
688
689 if( dir.EuclideanNorm() >= borderSize ) // far from area limits
690 dir = dir.Resize( borderSize * accel );
691 else if( dir.EuclideanNorm() > borderSize / 2 ) // Near from area limits
692 dir = dir.Resize( borderSize );
693
694 dir = m_view->ToWorld( dir, false );
695 m_view->SetCenter( m_view->GetCenter() + dir );
696
697 refreshMouse( true );
698
699 m_panTimer.Start();
700 }
701 break;
702
703 case IDLE: // Just remove unnecessary warnings
704 case DRAG_PANNING:
705 case DRAG_ZOOMING: break;
706 }
707}
708
709
710void WX_VIEW_CONTROLS::onZoomGesture( wxZoomGestureEvent& aEvent )
711{
712 if( aEvent.IsGestureStart() )
713 {
715 m_gestureLastPos = VECTOR2D( aEvent.GetPosition().x, aEvent.GetPosition().y );
716 }
717
718 VECTOR2D evtPos( aEvent.GetPosition().x, aEvent.GetPosition().y );
719 VECTOR2D deltaWorld = m_view->ToWorld( evtPos - m_gestureLastPos, false );
720
721 m_view->SetCenter( m_view->GetCenter() - deltaWorld );
722
723 m_view->SetScale( m_view->GetScale() * aEvent.GetZoomFactor() / m_gestureLastZoomFactor,
724 m_view->ToWorld( evtPos ) );
725
726 m_gestureLastZoomFactor = aEvent.GetZoomFactor();
727 m_gestureLastPos = evtPos;
728
729 refreshMouse( true );
730}
731
732
733void WX_VIEW_CONTROLS::onPanGesture( wxPanGestureEvent& aEvent )
734{
735 VECTOR2I screenDelta( aEvent.GetDelta().x, aEvent.GetDelta().y );
736 VECTOR2D deltaWorld = m_view->ToWorld( screenDelta, false );
737
738 m_view->SetCenter( m_view->GetCenter() - deltaWorld );
739
740 refreshMouse( true );
741}
742
743
744void WX_VIEW_CONTROLS::onScroll( wxScrollWinEvent& aEvent )
745{
746 const double linePanDelta = 0.05;
747 const double pagePanDelta = 0.5;
748
749 int type = aEvent.GetEventType();
750 int dir = aEvent.GetOrientation();
751
752 if( type == wxEVT_SCROLLWIN_THUMBTRACK )
753 {
754 auto center = m_view->GetCenter();
755 const auto& boundary = m_view->GetBoundary();
756
757 // Flip scroll direction in flipped view
758 const double xstart = ( m_view->IsMirroredX() ? boundary.GetRight() : boundary.GetLeft() );
759 const double xdelta = ( m_view->IsMirroredX() ? -1 : 1 );
760
761 if( dir == wxHORIZONTAL )
762 center.x = xstart + xdelta * ( aEvent.GetPosition() / m_scrollScale.x );
763 else
764 center.y = boundary.GetTop() + aEvent.GetPosition() / m_scrollScale.y;
765
766 m_view->SetCenter( center );
767 }
768 else if( type == wxEVT_SCROLLWIN_THUMBRELEASE || type == wxEVT_SCROLLWIN_TOP || type == wxEVT_SCROLLWIN_BOTTOM )
769 {
770 // Do nothing on thumb release, we don't care about it.
771 // We don't have a concept of top or bottom in our viewport, so ignore those events.
772 }
773 else
774 {
775 double dist = 0;
776
777 if( type == wxEVT_SCROLLWIN_PAGEUP )
778 {
779 dist = pagePanDelta;
780 }
781 else if( type == wxEVT_SCROLLWIN_PAGEDOWN )
782 {
783 dist = -pagePanDelta;
784 }
785 else if( type == wxEVT_SCROLLWIN_LINEUP )
786 {
787 dist = linePanDelta;
788 }
789 else if( type == wxEVT_SCROLLWIN_LINEDOWN )
790 {
791 dist = -linePanDelta;
792 }
793 else
794 {
795 wxCHECK_MSG( false, /* void */, wxT( "Unhandled event type" ) );
796 }
797
798 VECTOR2D scroll = m_view->ToWorld( m_view->GetScreenPixelSize(), false ) * dist;
799
800 double scrollX = 0.0;
801 double scrollY = 0.0;
802
803 if( dir == wxHORIZONTAL )
804 scrollX = -scroll.x;
805 else
806 scrollY = -scroll.y;
807
808 VECTOR2D delta( scrollX, scrollY );
809
810 m_view->SetCenter( m_view->GetCenter() + delta );
811 }
812
813 m_parentPanel->Refresh();
814}
815
816
818{
819#if defined USE_MOUSE_CAPTURE
820 // Note: for some reason, m_parentPanel->HasCapture() can be false even if CaptureMouse()
821 // was called (i.e. mouse was captured, so when need to test m_MouseCapturedLost to be
822 // sure a wxEVT_MOUSE_CAPTURE_LOST event was fired before. Otherwise wxMSW complains
823 // The IsModalDialogFocused is checked because it's possible to start a capture
824 // due to event ordering while a modal dialog was just opened, the mouse capture steels focus
825 // from the modal and causes odd behavior
826 if( aEnabled && !m_parentPanel->HasCapture() && m_parentPanel->m_MouseCapturedLost
828 {
829 m_parentPanel->CaptureMouse();
830
831 // Clear the flag to allow calling m_parentPanel->CaptureMouse()
832 // Calling it without calling ReleaseMouse() is not accepted by wxWidgets (MSW specific)
833 m_parentPanel->m_MouseCapturedLost = false;
834 }
835 else if( !aEnabled && m_parentPanel->HasCapture() && m_state != DRAG_PANNING && m_state != DRAG_ZOOMING )
836 {
837 m_parentPanel->ReleaseMouse();
838
839 // Mouse is released, calling CaptureMouse() is allowed now:
840 m_parentPanel->m_MouseCapturedLost = true;
841 }
842#endif
844}
845
846
848{
850 {
851 setState( IDLE );
852
853#if defined USE_MOUSE_CAPTURE
854 if( !m_settings.m_cursorCaptured && m_parentPanel->HasCapture() )
855 m_parentPanel->ReleaseMouse();
856#endif
857 }
858
859 m_metaPanning = false;
860}
861
862
863VECTOR2D WX_VIEW_CONTROLS::GetMousePosition( bool aWorldCoordinates ) const
864{
865 wxPoint msp = getMouseScreenPosition();
866 VECTOR2D screenPos( msp.x, msp.y );
867
868 return aWorldCoordinates ? GetClampedCoords( m_view->ToWorld( screenPos ) ) : screenPos;
869}
870
871
873{
874 GAL* gal = m_view->GetGAL();
875
876 if( aEnableSnapping && gal->GetGridSnapping() )
877 {
878 return gal->GetGridPoint( m_cursorPos );
879 }
880 else
881 {
882 return m_cursorPos;
883 }
884}
885
886
888{
889 if( m_settings.m_forceCursorPosition )
890 {
891 return m_settings.m_forcedPosition;
892 }
893 else
894 {
895 return GetClampedCoords( GetRawCursorPosition( aEnableSnapping ) );
896 }
897}
898
899
900void WX_VIEW_CONTROLS::SetCursorPosition( const VECTOR2D& aPosition, bool aWarpView, bool aTriggeredByArrows,
901 long aArrowCommand )
902{
903 m_updateCursor = false;
904
905 VECTOR2D clampedPosition = GetClampedCoords( aPosition );
906
907 if( aTriggeredByArrows )
908 {
909 m_settings.m_lastKeyboardCursorPositionValid = true;
910 m_settings.m_lastKeyboardCursorPosition = clampedPosition;
911 m_settings.m_lastKeyboardCursorCommand = aArrowCommand;
912 m_cursorWarped = false;
913 }
914 else
915 {
916 m_settings.m_lastKeyboardCursorPositionValid = false;
917 m_settings.m_lastKeyboardCursorPosition = { 0.0, 0.0 };
918 m_settings.m_lastKeyboardCursorCommand = 0;
919 m_cursorWarped = true;
920 }
921
922 WarpMouseCursor( clampedPosition, true, aWarpView );
923 m_cursorPos = clampedPosition;
924}
925
926
927void WX_VIEW_CONTROLS::SetCrossHairCursorPosition( const VECTOR2D& aPosition, bool aWarpView = true )
928{
929 m_updateCursor = false;
930
931 VECTOR2D clampedPosition = GetClampedCoords( aPosition );
932
933 const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
934 BOX2I screen( VECTOR2I( 0, 0 ), screenSize );
935 VECTOR2D screenPos = m_view->ToScreen( clampedPosition );
936
937 if( aWarpView && !screen.Contains( screenPos ) )
938 m_view->SetCenter( clampedPosition );
939
940 m_cursorPos = clampedPosition;
941}
942
943
944void WX_VIEW_CONTROLS::WarpMouseCursor( const VECTOR2D& aPosition, bool aWorldCoordinates, bool aWarpView )
945{
946 if( aWorldCoordinates )
947 {
948 const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
949 BOX2I screen( VECTOR2I( 0, 0 ), screenSize );
950 VECTOR2D clampedPosition = GetClampedCoords( aPosition );
951 VECTOR2D screenPos = m_view->ToScreen( clampedPosition );
952
953 if( !screen.Contains( screenPos ) )
954 {
955 if( aWarpView )
956 {
957 m_view->SetCenter( clampedPosition );
958 KIPLATFORM::UI::WarpPointer( m_parentPanel, screenSize.x / 2, screenSize.y / 2 );
959 }
960 }
961 else
962 {
963 KIPLATFORM::UI::WarpPointer( m_parentPanel, screenPos.x, screenPos.y );
964 }
965 }
966 else
967 {
968 KIPLATFORM::UI::WarpPointer( m_parentPanel, aPosition.x, aPosition.y );
969 }
970
971 // If we are not refreshing because of mouse movement, don't set the modifiers because we
972 // are refreshing for keyboard movement, which uses the same modifiers for other actions
974}
975
976
978{
979 const VECTOR2I& screenSize = m_view->GetGAL()->GetScreenPixelSize();
980 VECTOR2D screenCenter( screenSize / 2 );
981
982 if( GetMousePosition( false ) != screenCenter )
983 {
984 VECTOR2D newCenter = GetCursorPosition();
985
986 if( KIPLATFORM::UI::WarpPointer( m_parentPanel, screenCenter.x, screenCenter.y ) )
987 {
988 m_view->SetCenter( newCenter );
989 m_dragStartPoint = screenCenter;
990 }
991 }
992}
993
994
996{
997 int border = std::min( m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().x,
998 m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().y );
999 border += 2;
1000
1001 VECTOR2D topLeft( border, border );
1002 VECTOR2D botRight( m_view->GetScreenPixelSize().x - border, m_view->GetScreenPixelSize().y - border );
1003
1004 topLeft = m_view->ToWorld( topLeft );
1005 botRight = m_view->ToWorld( botRight );
1006
1007 VECTOR2D pos = GetMousePosition( true );
1008
1009 if( pos.x < topLeft.x )
1010 pos.x = topLeft.x;
1011 else if( pos.x > botRight.x )
1012 pos.x = botRight.x;
1013
1014 if( pos.y < topLeft.y )
1015 pos.y = topLeft.y;
1016 else if( pos.y > botRight.y )
1017 pos.y = botRight.y;
1018
1019 SetCursorPosition( pos, false, false, 0 );
1020
1021 if( aWarpMouseCursor )
1022 WarpMouseCursor( pos, true );
1023}
1024
1025
1026bool WX_VIEW_CONTROLS::handleAutoPanning( const wxMouseEvent& aEvent )
1027{
1028 VECTOR2I p( aEvent.GetX(), aEvent.GetY() );
1029 VECTOR2I pKey( m_view->ToScreen( m_settings.m_lastKeyboardCursorPosition ) );
1030
1031 if( m_cursorWarped || ( m_settings.m_lastKeyboardCursorPositionValid && p == pKey ) )
1032 {
1033 // last cursor move event came from keyboard cursor control. If auto-panning is enabled
1034 // and the next position is inside the autopan zone, check if it really came from a mouse
1035 // event, otherwise disable autopan temporarily. Also temporarily disable autopan if the
1036 // cursor is in the autopan zone because the application warped the cursor.
1037
1038 m_cursorWarped = false;
1039 return true;
1040 }
1041
1042 m_cursorWarped = false;
1043
1044 // Compute areas where autopanning is active
1045 int borderStart = std::min( m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().x,
1046 m_settings.m_autoPanMargin * m_view->GetScreenPixelSize().y );
1047 borderStart = std::max( borderStart, 2 );
1048 int borderEndX = m_view->GetScreenPixelSize().x - borderStart;
1049 int borderEndY = m_view->GetScreenPixelSize().y - borderStart;
1050
1051 if( p.x < borderStart )
1052 m_panDirection.x = -( borderStart - p.x );
1053 else if( p.x > borderEndX )
1054 m_panDirection.x = ( p.x - borderEndX );
1055 else
1056 m_panDirection.x = 0;
1057
1058 if( p.y < borderStart )
1059 m_panDirection.y = -( borderStart - p.y );
1060 else if( p.y > borderEndY )
1061 m_panDirection.y = ( p.y - borderEndY );
1062 else
1063 m_panDirection.y = 0;
1064
1065 bool borderHit = ( m_panDirection.x != 0 || m_panDirection.y != 0 );
1066
1067 switch( m_state )
1068 {
1069 case AUTO_PANNING:
1070 if( !borderHit )
1071 {
1072 m_panTimer.Stop();
1073 setState( IDLE );
1074
1075 return false;
1076 }
1077
1078 return true;
1079
1080 case IDLE:
1081 if( borderHit )
1082 {
1084 m_panTimer.Start( (int) ( 250.0 / 60.0 ), true );
1085
1086 return true;
1087 }
1088
1089 return false;
1090
1091 case DRAG_PANNING:
1092 case DRAG_ZOOMING: return false;
1093 }
1094
1095 wxCHECK_MSG( false, false, wxT( "This line should never be reached" ) );
1096
1097 return false;
1098}
1099
1100
1102{
1103 if( m_settings.m_cursorCaptured )
1104 {
1105 bool warp = false;
1106 wxSize parentSize = m_parentPanel->GetClientSize();
1107
1108 if( x < 0 )
1109 {
1110 x = 0;
1111 warp = true;
1112 }
1113 else if( x >= parentSize.x )
1114 {
1115 x = parentSize.x - 1;
1116 warp = true;
1117 }
1118
1119 if( y < 0 )
1120 {
1121 y = 0;
1122 warp = true;
1123 }
1124 else if( y >= parentSize.y )
1125 {
1126 y = parentSize.y - 1;
1127 warp = true;
1128 }
1129
1130 if( warp )
1132 }
1133}
1134
1135
1136void WX_VIEW_CONTROLS::refreshMouse( bool aSetModifiers )
1137{
1138 // Notify tools that the cursor position has changed in the world coordinates
1139 wxMouseEvent moveEvent( EVT_REFRESH_MOUSE );
1140 wxPoint msp = getMouseScreenPosition();
1141 moveEvent.SetX( msp.x );
1142 moveEvent.SetY( msp.y );
1143
1144 if( aSetModifiers )
1145 {
1146 // Set the modifiers state
1147 moveEvent.SetControlDown( wxGetKeyState( WXK_CONTROL ) );
1148 moveEvent.SetShiftDown( wxGetKeyState( WXK_SHIFT ) );
1149 moveEvent.SetAltDown( wxGetKeyState( WXK_ALT ) );
1150 }
1151
1152 m_cursorPos = GetClampedCoords( m_view->ToWorld( VECTOR2D( msp.x, msp.y ) ) );
1153 wxPostEvent( m_parentPanel, moveEvent );
1154}
1155
1156
1158{
1159 wxPoint msp = KIPLATFORM::UI::GetMousePosition();
1160 m_parentPanel->ScreenToClient( &msp.x, &msp.y );
1161 return msp;
1162}
1163
1164
1166{
1167 const BOX2D viewport = m_view->GetViewport();
1168 const BOX2D& boundary = m_view->GetBoundary();
1169
1170 m_scrollScale.x = 2e3 / viewport.GetWidth(); // TODO it does not have to be updated so often
1171 m_scrollScale.y = 2e3 / viewport.GetHeight();
1172 VECTOR2I newScroll( ( viewport.Centre().x - boundary.GetLeft() ) * m_scrollScale.x,
1173 ( viewport.Centre().y - boundary.GetTop() ) * m_scrollScale.y );
1174
1175 // We add the width of the scroll bar thumb to the range because the scroll range is given by
1176 // the full bar while the position is given by the left/top position of the thumb
1177 VECTOR2I newRange( m_scrollScale.x * boundary.GetWidth() + m_parentPanel->GetScrollThumb( wxSB_HORIZONTAL ),
1178 m_scrollScale.y * boundary.GetHeight() + m_parentPanel->GetScrollThumb( wxSB_VERTICAL ) );
1179
1180 // Flip scroll direction in flipped view
1181 if( m_view->IsMirroredX() )
1182 newScroll.x = ( boundary.GetRight() - viewport.Centre().x ) * m_scrollScale.x;
1183
1184 // Adjust scrollbars only if it is needed. Otherwise there are cases when canvas is continuously
1185 // refreshed (Windows)
1186 if( m_scrollPos != newScroll || newRange.x != m_parentPanel->GetScrollRange( wxSB_HORIZONTAL )
1187 || newRange.y != m_parentPanel->GetScrollRange( wxSB_VERTICAL ) )
1188 {
1189 m_parentPanel->SetScrollbars( 1, 1, newRange.x, newRange.y, newScroll.x, newScroll.y, true );
1190 m_scrollPos = newScroll;
1191
1192#if !defined( __APPLE__ ) && !defined( WIN32 )
1193 // Trigger a mouse refresh to get the canvas update in GTK (re-draws the scrollbars).
1194 // Note that this causes an infinite loop on OSX and Windows (in certain cases) as it
1195 // generates a paint event.
1196 refreshMouse( false );
1197#endif
1198 }
1199}
1200
1201
1202void WX_VIEW_CONTROLS::ForceCursorPosition( bool aEnabled, const VECTOR2D& aPosition )
1203{
1204 VECTOR2D clampedPosition = GetClampedCoords( aPosition );
1205
1206 m_settings.m_forceCursorPosition = aEnabled;
1207 m_settings.m_forcedPosition = clampedPosition;
1208}
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:407
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.
#define KI_TRACE(aWhat,...)
Functions to provide common constants and other functions to assist in making a consistent UI.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694
static std::unique_ptr< ZOOM_CONTROLLER > GetZoomControllerForPlatform(bool aAcceleration)
WX_VIEW_CONTROLS class definition.
ZOOM_CONTROLLER class definition.