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