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