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