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