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