KiCad PCB EDA Suite
eda_draw_panel.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) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2007 Wayne Stambaugh <stambaughw@gmail.com>
6  * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
30 #include <fctsys.h>
31 #include <wx/timer.h>
32 #include <pgm_base.h>
33 #include <kiface_i.h>
34 #include <gr_basic.h>
35 #include <common.h>
36 #include <macros.h>
37 #include <id.h>
38 #include <class_drawpanel.h>
39 #include <class_draw_panel_gal.h>
40 #include <base_screen.h>
41 #include <draw_frame.h>
42 #include <view/view_controls.h>
44 #include <trace_helpers.h>
45 
46 #include <kicad_device_context.h>
47 
48 static const int CURSOR_SIZE = 12;
49 
50 #define CLIP_BOX_PADDING 2
51 
52 // Definitions for enabling and disabling debugging features in drawpanel.cpp.
53 // Please don't forget to turn these off before making any commits to Launchpad.
54 #define DEBUG_SHOW_CLIP_RECT 0 // Set to 1 to draw clipping rectangle.
55 
56 
57 // Events used by EDA_DRAW_PANEL
58 BEGIN_EVENT_TABLE( EDA_DRAW_PANEL, wxScrolledWindow )
59  EVT_LEAVE_WINDOW( EDA_DRAW_PANEL::OnMouseLeaving )
60  EVT_ENTER_WINDOW( EDA_DRAW_PANEL::OnMouseEntering )
61  EVT_MOUSEWHEEL( EDA_DRAW_PANEL::OnMouseWheel )
62 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
63  EVT_MAGNIFY( EDA_DRAW_PANEL::OnMagnify )
64 #endif
65  EVT_MOUSE_EVENTS( EDA_DRAW_PANEL::OnMouseEvent )
66  EVT_CHAR( EDA_DRAW_PANEL::OnKeyEvent )
67  EVT_CHAR_HOOK( EDA_DRAW_PANEL::OnKeyEvent )
68  EVT_PAINT( EDA_DRAW_PANEL::OnPaint )
69  EVT_ERASE_BACKGROUND( EDA_DRAW_PANEL::OnEraseBackground )
70  EVT_SCROLLWIN( EDA_DRAW_PANEL::OnScroll )
71  EVT_ACTIVATE( EDA_DRAW_PANEL::OnActivate )
74 END_EVENT_TABLE()
75 
76 
77 /***********************************************************************/
78 /* EDA_DRAW_PANEL base functions (EDA_DRAW_PANEL is the main panel)*/
79 /***********************************************************************/
80 
81 #ifdef __WXMAC__
82 const int drawPanelStyle = wxHSCROLL | wxVSCROLL | wxALWAYS_SHOW_SB;
83 #else
84 const int drawPanelStyle = wxHSCROLL | wxVSCROLL;
85 #endif
86 
88  const wxPoint& pos, const wxSize& size ) :
89  wxScrolledWindow( parent, id, pos, size, drawPanelStyle )
90 {
91  wxASSERT( parent );
92 
93  ShowScrollbars( wxSHOW_SB_ALWAYS, wxSHOW_SB_ALWAYS );
94  DisableKeyboardScrolling();
95 
96  m_scrollIncrementX = std::min( size.x / 8, 10 );
97  m_scrollIncrementY = std::min( size.y / 8, 10 );
98 
99  SetLayoutDirection( wxLayout_LeftToRight );
100 
101  SetBackgroundColour( parent->GetDrawBgColor().ToColour() );
102 
103 #if KICAD_USE_BUFFERED_DC || KICAD_USE_BUFFERED_PAINTDC
104  SetBackgroundStyle( wxBG_STYLE_CUSTOM );
105 #endif
106 
107  m_ClipBox.SetSize( size );
108  m_ClipBox.SetX( 0 );
109  m_ClipBox.SetY( 0 );
110  m_canStartBlock = -1; // Command block can start if >= 0
111  m_abortRequest = false;
112  m_enableMousewheelPan = false;
113  m_enableZoomNoCenter = false;
114  m_enableAutoPan = true;
115  m_ignoreMouseEvents = false;
116  // Be sure a mouse release button event will be ignored when creating the canvas
117  // if the mouse click was not made inside the canvas (can happen sometimes, when
118  // launching a editor from a double click made in another frame)
120 
121  m_mouseCaptureCallback = NULL;
123 
127 
128  m_requestAutoPan = false;
129  m_enableBlockCommands = false;
131 
132 #ifdef __WXMAC__
133  m_defaultCursor = m_currentCursor = wxCURSOR_CROSS;
134  m_showCrossHair = false;
135 #else
136  m_defaultCursor = m_currentCursor = wxCURSOR_ARROW;
137  m_showCrossHair = true;
138 #endif
139 
140  m_cursorLevel = 0;
141  m_PrintIsMirrored = false;
142 
143  m_ClickTimer = (wxTimer*) NULL;
144  m_doubleClickInterval = 250;
145 }
146 
147 
149 {
150  wxConfigBase* cfg = Kiface().KifaceSettings();
151 
152  if( cfg )
153  {
156  cfg->Write( ENBL_AUTO_PAN_KEY, m_enableAutoPan );
157  }
158 
159  wxDELETE( m_ClickTimer );
160 }
161 
162 
164 {
165  wxWindow* mom = wxScrolledWindow::GetParent();
166  return (EDA_DRAW_FRAME*) mom;
167 }
168 
169 
171 {
172  return GetParent()->GetDisplayOptions();
173 }
174 
175 
177 {
178  EDA_DRAW_FRAME* parentFrame = GetParent();
179 
180  return parentFrame->GetScreen();
181 }
182 
183 
184 wxPoint EDA_DRAW_PANEL::ToDeviceXY( const wxPoint& pos )
185 {
186  wxPoint ret;
187  INSTALL_UNBUFFERED_DC( dc, this );
188  ret.x = dc.LogicalToDeviceX( pos.x );
189  ret.y = dc.LogicalToDeviceY( pos.y );
190  return ret;
191 }
192 
193 
194 wxPoint EDA_DRAW_PANEL::ToLogicalXY( const wxPoint& pos )
195 {
196  wxPoint ret;
197  INSTALL_UNBUFFERED_DC( dc, this );
198  ret.x = dc.DeviceToLogicalX( pos.x );
199  ret.y = dc.DeviceToLogicalY( pos.y );
200  return ret;
201 }
202 
203 
204 void EDA_DRAW_PANEL::DrawCrossHair( wxDC* aDC, COLOR4D aColor )
205 {
206  if( m_cursorLevel != 0 || aDC == NULL || !m_showCrossHair )
207  return;
208 
209  wxPoint cursor = GetParent()->GetCrossHairPosition();
210 
211 #ifdef USE_WX_GRAPHICS_CONTEXT
212  // Normally cursor color is set to white, so when it is xored with white
213  // background, it is painted black effectively. wxGraphicsContext does not have
214  // xor operation, so we need to invert the color manually.
215  aColor.Invert();
216 #else
217  GRSetDrawMode( aDC, GR_XOR );
218 #endif
219 
220  if( GetParent()->GetGalDisplayOptions().m_fullscreenCursor )
221  {
222  wxSize clientSize = GetClientSize();
223 
224  // Y axis
225  wxPoint lineStart( cursor.x, aDC->DeviceToLogicalY( 0 ) );
226  wxPoint lineEnd( cursor.x, aDC->DeviceToLogicalY( clientSize.y ) );
227 
228  GRLine( &m_ClipBox, aDC, lineStart, lineEnd, 0, aColor );
229 
230  // X axis
231  lineStart = wxPoint( aDC->DeviceToLogicalX( 0 ), cursor.y );
232  lineEnd = wxPoint( aDC->DeviceToLogicalX( clientSize.x ), cursor.y );
233 
234  GRLine( &m_ClipBox, aDC, lineStart, lineEnd, 0, aColor );
235  }
236  else
237  {
238  int len = aDC->DeviceToLogicalXRel( CURSOR_SIZE );
239 
240  GRLine( &m_ClipBox, aDC, cursor.x - len, cursor.y,
241  cursor.x + len, cursor.y, 0, aColor );
242  GRLine( &m_ClipBox, aDC, cursor.x, cursor.y - len,
243  cursor.x, cursor.y + len, 0, aColor );
244  }
245 }
246 
247 
248 void EDA_DRAW_PANEL::CrossHairOff( wxDC* DC )
249 {
250  DrawCrossHair( DC );
251  --m_cursorLevel;
252 }
253 
254 
255 void EDA_DRAW_PANEL::CrossHairOn( wxDC* DC )
256 {
257  ++m_cursorLevel;
258  DrawCrossHair( DC );
259 
260  if( m_cursorLevel > 0 ) // Shouldn't happen, but just in case ..
261  m_cursorLevel = 0;
262 }
263 
264 
266 {
267  return GetScreen()->GetZoom();
268 }
269 
270 
271 void EDA_DRAW_PANEL::SetZoom( double zoom )
272 {
273  GetScreen()->SetZoom( zoom );
274 }
275 
276 
278 {
279  return GetScreen()->GetGridSize();
280 }
281 
282 
283 bool EDA_DRAW_PANEL::IsPointOnDisplay( const wxPoint& aPosition )
284 {
285  wxPoint pos;
286  EDA_RECT display_rect;
287 
288  INSTALL_UNBUFFERED_DC( dc, this ); // Refresh the clip box to the entire screen size.
289  SetClipBox( dc );
290 
291  display_rect = m_ClipBox;
292 
293  // Slightly decreased the size of the useful screen area to avoid drawing limits.
294  #define PIXEL_MARGIN 8
295  display_rect.Inflate( -PIXEL_MARGIN );
296 
297  return display_rect.Contains( aPosition );
298 }
299 
300 
301 void EDA_DRAW_PANEL::RefreshDrawingRect( const EDA_RECT& aRect, bool aEraseBackground )
302 {
303  INSTALL_UNBUFFERED_DC( dc, this );
304 
305  wxRect rect = aRect;
306 
307  rect.x = dc.LogicalToDeviceX( rect.x );
308  rect.y = dc.LogicalToDeviceY( rect.y );
309  rect.width = dc.LogicalToDeviceXRel( rect.width );
310  rect.height = dc.LogicalToDeviceYRel( rect.height );
311 
312  wxLogTrace( kicadTraceCoords,
313  wxT( "Refresh area: drawing (%d, %d, %d, %d), device (%d, %d, %d, %d)" ),
314  aRect.GetX(), aRect.GetY(), aRect.GetWidth(), aRect.GetHeight(),
315  rect.x, rect.y, rect.width, rect.height );
316 
317  RefreshRect( rect, aEraseBackground );
318 }
319 
320 
321 void EDA_DRAW_PANEL::Refresh( bool eraseBackground, const wxRect* rect )
322 {
323  if( GetParent()->IsGalCanvasActive() )
324  {
326  }
327  else
328  {
329  wxScrolledWindow::Refresh( eraseBackground, rect );
330  }
331 }
332 
333 
335 {
336  wxSize size = GetClientSize() / 2;
337  INSTALL_UNBUFFERED_DC( dc, this );
338 
339  return wxPoint( dc.DeviceToLogicalX( size.x ), dc.DeviceToLogicalY( size.y ) );
340 }
341 
342 
344 {
345  MoveCursor( GetParent()->GetCrossHairPosition() );
346 }
347 
348 
349 void EDA_DRAW_PANEL::MoveCursor( const wxPoint& aPosition )
350 {
351  if( GetParent()->IsGalCanvasActive() )
352  return;
353 
354  int x, y, xPpu, yPpu;
355  wxPoint screenPos, drawingPos;
356  wxRect clientRect( wxPoint( 0, 0 ), GetClientSize() );
357 
358  INSTALL_UNBUFFERED_DC( dc, this );
359  screenPos.x = dc.LogicalToDeviceX( aPosition.x );
360  screenPos.y = dc.LogicalToDeviceY( aPosition.y );
361 
362  // Scroll if the requested mouse position cursor is outside the drawing area.
363  if( !clientRect.Contains( screenPos ) )
364  {
365  GetViewStart( &x, &y );
366  GetScrollPixelsPerUnit( &xPpu, &yPpu );
367  CalcUnscrolledPosition( screenPos.x, screenPos.y, &drawingPos.x, &drawingPos.y );
368 
369  wxLogTrace( kicadTraceCoords,
370  wxT( "MoveCursor() initial screen position(%d, %d) " ) \
371  wxT( "rectangle(%d, %d, %d, %d) view(%d, %d)" ),
372  screenPos.x, screenPos.y, clientRect.x, clientRect.y,
373  clientRect.width, clientRect.height, x, y );
374 
375  if( screenPos.y < clientRect.GetTop() )
376  y -= m_scrollIncrementY * yPpu;
377  else if( screenPos.y > clientRect.GetBottom() )
378  y += m_scrollIncrementY * yPpu;
379  else if( clientRect.GetRight() < screenPos.x )
380  x += m_scrollIncrementX * xPpu;
381  else
382  x -= m_scrollIncrementX * xPpu;
383 
384  Scroll( x, y );
385  CalcScrolledPosition( drawingPos.x, drawingPos.y, &screenPos.x, &screenPos.y );
386 
387  wxLogTrace( kicadTraceCoords,
388  wxT( "MoveCursor() scrolled screen position(%d, %d) view(%d, %d)" ),
389  screenPos.x, screenPos.y, x, y );
390  }
391 
392  WarpPointer( screenPos.x, screenPos.y );
393 }
394 
395 
396 void EDA_DRAW_PANEL::OnActivate( wxActivateEvent& event )
397 {
398  m_canStartBlock = -1; // Block Command can't start
399  event.Skip();
400 }
401 
402 
403 void EDA_DRAW_PANEL::OnTimer( wxTimerEvent& event )
404 {
405  INSTALL_UNBUFFERED_DC( DC, this );
406  DC.SetBackground( *wxBLACK_BRUSH );
408 }
409 
410 
411 void EDA_DRAW_PANEL::OnScroll( wxScrollWinEvent& event )
412 {
413  int id = event.GetEventType();
414  int x, y;
415  int ppux, ppuy;
416  int csizeX, csizeY;
417  int unitsX, unitsY;
418 
419  GetViewStart( &x, &y );
420  GetScrollPixelsPerUnit( &ppux, &ppuy );
421  GetClientSize( &csizeX, &csizeY );
422  GetVirtualSize( &unitsX, &unitsY );
423 
424  int tmpX = x;
425  int tmpY = y;
426 
427  csizeX /= ppux;
428  csizeY /= ppuy;
429 
430  unitsX /= ppux;
431  unitsY /= ppuy;
432 
433  int dir = event.GetOrientation(); // wxHORIZONTAL or wxVERTICAL
434 
435  // On windows and on wxWidgets >= 2.9.5 and < 3.1,
436  // there is a bug in mousewheel event which always generates 2 scroll events
437  // (should be the case only for the default mousewheel event)
438  // with id = wxEVT_SCROLLWIN_LINEUP or wxEVT_SCROLLWIN_LINEDOWN
439  // so we skip these events.
440  // Note they are here just in case, because they are not actually used
441  // in Kicad
442 #if wxCHECK_VERSION( 3, 1, 0 ) || !wxCHECK_VERSION( 2, 9, 5 ) || ( !defined (__WINDOWS__) && !defined (__WXMAC__) )
443  int maxX = unitsX - csizeX;
444  int maxY = unitsY - csizeY;
445 
446  if( id == wxEVT_SCROLLWIN_LINEUP )
447  {
448  if( dir == wxHORIZONTAL )
449  {
450  x -= m_scrollIncrementX;
451 
452  if( x < 0 )
453  x = 0;
454  }
455  else
456  {
457  y -= m_scrollIncrementY;
458 
459  if( y < 0 )
460  y = 0;
461  }
462  }
463  else if( id == wxEVT_SCROLLWIN_LINEDOWN )
464  {
465  if( dir == wxHORIZONTAL )
466  {
467  x += m_scrollIncrementX;
468  if( x > maxX )
469  x = maxX;
470  }
471  else
472  {
473  y += m_scrollIncrementY;
474 
475  if( y > maxY )
476  y = maxY;
477  }
478  }
479  else
480 #endif
481  if( id == wxEVT_SCROLLWIN_THUMBTRACK )
482  {
483  if( dir == wxHORIZONTAL )
484  x = event.GetPosition();
485  else
486  y = event.GetPosition();
487  }
488  else
489  {
490  event.Skip();
491  return;
492  }
493 
494  wxLogTrace( kicadTraceCoords,
495  wxT( "Setting scroll bars ppuX=%d, ppuY=%d, unitsX=%d, unitsY=%d, posX=%d, posY=%d" ),
496  ppux, ppuy, unitsX, unitsY, x, y );
497 
498  double scale = GetParent()->GetScreen()->GetScalingFactor();
499 
500  wxPoint center = GetParent()->GetScrollCenterPosition();
501  center.x += KiROUND( (double) ( x - tmpX ) / scale );
502  center.y += KiROUND( (double) ( y - tmpY ) / scale );
503  GetParent()->SetScrollCenterPosition( center );
504 
505  Scroll( x, y );
506  event.Skip();
507 }
508 
509 
510 void EDA_DRAW_PANEL::SetClipBox( wxDC& aDC, const wxRect* aRect )
511 {
512  wxRect clipBox;
513 
514  // Use the entire visible device area if no clip area was defined.
515  if( aRect == NULL )
516  {
517  BASE_SCREEN* Screen = GetScreen();
518 
519  if( !Screen )
520  return;
521 
522  Screen->m_StartVisu = CalcUnscrolledPosition( wxPoint( 0, 0 ) );
523  clipBox.SetSize( GetClientSize() );
524 
525  int scrollX, scrollY;
526 
527  double scalar = Screen->GetScalingFactor();
528  scrollX = KiROUND( Screen->GetGridSize().x * scalar );
529  scrollY = KiROUND( Screen->GetGridSize().y * scalar );
530 
531  m_scrollIncrementX = std::max( GetClientSize().x / 8, scrollX );
532  m_scrollIncrementY = std::max( GetClientSize().y / 8, scrollY );
533  Screen->m_ScrollbarPos.x = GetScrollPos( wxHORIZONTAL );
534  Screen->m_ScrollbarPos.y = GetScrollPos( wxVERTICAL );
535  }
536  else
537  {
538  clipBox = *aRect;
539  }
540 
541  // Pad clip box in device units.
542  clipBox.Inflate( CLIP_BOX_PADDING );
543 
544  // Convert from device units to drawing units.
545  m_ClipBox.SetOrigin( wxPoint( aDC.DeviceToLogicalX( clipBox.x ),
546  aDC.DeviceToLogicalY( clipBox.y ) ) );
547  m_ClipBox.SetSize( wxSize( aDC.DeviceToLogicalXRel( clipBox.width ),
548  aDC.DeviceToLogicalYRel( clipBox.height ) ) );
549 
550  wxLogTrace( kicadTraceCoords,
551  wxT( "Device clip box=(%d, %d, %d, %d), Logical clip box=(%d, %d, %d, %d)" ),
552  clipBox.x, clipBox.y, clipBox.width, clipBox.height,
554 }
555 
556 
557 void EDA_DRAW_PANEL::EraseScreen( wxDC* DC )
558 {
559  GRSetDrawMode( DC, GR_COPY );
560 
561  COLOR4D bgColor = GetParent()->GetDrawBgColor();
562 
563  GRSFilledRect( NULL, DC, m_ClipBox.GetX(), m_ClipBox.GetY(),
565  0, bgColor, bgColor );
566 
567  // Set to one (1) to draw bounding box validate bounding box calculation.
568 #if DEBUG_SHOW_CLIP_RECT
569  EDA_RECT bBox = m_ClipBox;
570  GRRect( NULL, DC, bBox.GetOrigin().x, bBox.GetOrigin().y,
571  bBox.GetEnd().x, bBox.GetEnd().y, 0, LIGHTMAGENTA );
572 #endif
573 }
574 
575 
577 {
578  wxScrolledWindow::DoPrepareDC( dc );
579 
580  if( GetScreen() != NULL )
581  {
582  double scale = GetScreen()->GetScalingFactor();
583  dc.SetUserScale( scale, scale );
584 
585  wxPoint pt = GetScreen()->m_DrawOrg;
586  dc.SetLogicalOrigin( pt.x, pt.y );
587  }
588 
589  SetClipBox( dc ); // Reset the clip box to the entire screen.
590  GRResetPenAndBrush( &dc );
591  dc.SetBackgroundMode( wxTRANSPARENT );
592 }
593 
594 
595 void EDA_DRAW_PANEL::OnPaint( wxPaintEvent& event )
596 {
597  if( GetScreen() == NULL )
598  {
599  event.Skip();
600  return;
601  }
602 
603  INSTALL_PAINTDC( paintDC, this );
604 
605  wxRect region = GetUpdateRegion().GetBox();
606  SetClipBox( paintDC, &region );
607  ReDraw( &paintDC, true );
608 }
609 
610 
611 void EDA_DRAW_PANEL::ReDraw( wxDC* DC, bool erasebg )
612 {
613  BASE_SCREEN* Screen = GetScreen();
614 
615  if( Screen == NULL )
616  return;
617 
618  COLOR4D bgColor = GetParent()->GetDrawBgColor();
619 
620  // TODO(JE): Is this correct?
621  if( bgColor.GetBrightness() > 0.5 )
622  {
623  g_XorMode = GR_NXOR;
625  }
626  else
627  {
628  g_XorMode = GR_XOR;
630  }
631 
632  GRResetPenAndBrush( DC );
633 
634  DC->SetBackground( wxBrush( bgColor.ToColour() ) );
635  DC->SetBackgroundMode( wxSOLID );
636 
637  if( erasebg )
638  EraseScreen( DC );
639 
640  GetParent()->RedrawActiveWindow( DC, erasebg );
641 
642  // Verfies that the clipping is working correctly. If these two sets of numbers are
643  // not the same or really close. The clipping algorithms are broken.
644  wxLogTrace( kicadTraceCoords,
645  wxT( "Clip box: (%d, %d, %d, %d), Draw extents (%d, %d, %d, %d)" ),
647  DC->MinX(), DC->MinY(), DC->MaxX(), DC->MaxY() );
648 }
649 
650 
651 void EDA_DRAW_PANEL::SetEnableMousewheelPan( bool aEnable )
652 {
653  m_enableMousewheelPan = aEnable;
654 
655  if( GetParent()->IsGalCanvasActive() )
657 }
658 
659 void EDA_DRAW_PANEL::SetEnableAutoPan( bool aEnable )
660 {
661  m_enableAutoPan = aEnable;
662 
663  if( GetParent()->IsGalCanvasActive() )
665 }
666 
667 
668 void EDA_DRAW_PANEL::SetEnableZoomNoCenter( bool aEnable )
669 {
670  m_enableZoomNoCenter = aEnable;
671 
672  if( GetParent()->IsGalCanvasActive() )
674 }
675 
676 
677 void EDA_DRAW_PANEL::DrawBackGround( wxDC* DC )
678 {
679  GRSetDrawMode( DC, GR_COPY );
680 
681  if( GetParent()->IsGridVisible() )
682  DrawGrid( DC );
683 
684  // Draw axis
685  if( GetParent()->GetShowAxis() )
686  {
687  COLOR4D axis_color = COLOR4D( BLUE );
688  wxSize pageSize = GetParent()->GetPageSizeIU();
689 
690  // Draw the Y axis
691  GRLine( &m_ClipBox, DC, 0, -pageSize.y, 0, pageSize.y, 0, axis_color );
692 
693  // Draw the X axis
694  GRLine( &m_ClipBox, DC, -pageSize.x, 0, pageSize.x, 0, 0, axis_color );
695  }
696 
697  if( GetParent()->GetShowOriginAxis() )
698  DrawAuxiliaryAxis( DC, GR_COPY );
699 
700  if( GetParent()->GetShowGridAxis() )
701  DrawGridAxis( DC, GR_COPY, GetParent()->GetGridOrigin() );
702 }
703 
704 
705 void EDA_DRAW_PANEL::DrawGrid( wxDC* aDC )
706 {
707  #define MIN_GRID_SIZE 10 // min grid size in pixels to allow drawing
708  BASE_SCREEN* screen = GetScreen();
709  wxRealPoint gridSize;
710  wxSize screenSize;
711  wxPoint org;
712  wxRealPoint screenGridSize;
713 
714  /* The grid must be visible. this is possible only is grid value
715  * and zoom value are sufficient
716  */
717  gridSize = screen->GetGridSize();
718  screen->m_StartVisu = CalcUnscrolledPosition( wxPoint( 0, 0 ) );
719  screenSize = GetClientSize();
720 
721  screenGridSize.x = aDC->LogicalToDeviceXRel( KiROUND( gridSize.x ) );
722  screenGridSize.y = aDC->LogicalToDeviceYRel( KiROUND( gridSize.y ) );
723 
724  org = m_ClipBox.GetPosition();
725 
726  if( screenGridSize.x < MIN_GRID_SIZE || screenGridSize.y < MIN_GRID_SIZE )
727  {
728  screenGridSize.x *= 2.0;
729  screenGridSize.y *= 2.0;
730  gridSize.x *= 2.0;
731  gridSize.y *= 2.0;
732  }
733 
734  if( screenGridSize.x < MIN_GRID_SIZE || screenGridSize.y < MIN_GRID_SIZE )
735  return;
736 
737  org = GetParent()->GetNearestGridPosition( org, &gridSize );
738 
739  // Setting the nearest grid position can select grid points outside the clip box.
740  // Incrementing the start point by one grid step should prevent drawing grid points
741  // outside the clip box.
742  if( org.x < m_ClipBox.GetX() )
743  org.x += KiROUND( gridSize.x );
744 
745  if( org.y < m_ClipBox.GetY() )
746  org.y += KiROUND( gridSize.y );
747 
748  // Use a pixel based draw to display grid. There are a lot of calls, so the cost is
749  // high and grid is slowly drawn on some platforms. Another way using blit transfert was used,
750  // a long time ago, but it did not give very good results.
751  // The better way is highly dependent on the platform and the graphic card.
752  int xpos;
753  double right = ( double ) m_ClipBox.GetRight();
754  double bottom = ( double ) m_ClipBox.GetBottom();
755 
756 #if defined( USE_WX_GRAPHICS_CONTEXT )
757  wxGCDC *gcdc = wxDynamicCast( aDC, wxGCDC );
758 
759  if( gcdc )
760  {
761  // Much faster grid drawing on systems using wxGraphicsContext
762  wxGraphicsContext *gc = gcdc->GetGraphicsContext();
763 
764  // Grid point size
765  const int gsz = 1;
766  const double w = aDC->DeviceToLogicalXRel( gsz );
767  const double h = aDC->DeviceToLogicalYRel( gsz );
768 
769  // Use our own pen
770  wxPen pen( GetParent()->GetGridColor().ToColour(), h );
771  pen.SetCap( wxCAP_BUTT );
772  gc->SetPen( pen );
773 
774  // draw grid
775  wxGraphicsPath path = gc->CreatePath();
776  for( double x = (double) org.x - w/2.0; x <= right - w/2.0; x += gridSize.x )
777  {
778  for( double y = (double) org.y; y <= bottom; y += gridSize.y )
779  {
780  path.MoveToPoint( x, y );
781  path.AddLineToPoint( x+w, y );
782  }
783  }
784  gc->StrokePath( path );
785  }
786  else
787 #endif
788  {
789  GRSetColorPen( aDC, GetParent()->GetGridColor() );
790 
791  for( double x = (double) org.x; x <= right; x += gridSize.x )
792  {
793  xpos = KiROUND( x );
794 
795  for( double y = (double) org.y; y <= bottom; y += gridSize.y )
796  {
797  aDC->DrawPoint( xpos, KiROUND( y ) );
798  }
799  }
800  }
801 }
802 
803 // Set to 1 to draw auxirilary axis as lines, 0 to draw as target (circle with cross)
804 #define DRAW_AXIS_AS_LINES 0
805 // Size in pixels of the target shape
806 #define AXIS_SIZE_IN_PIXELS 15
807 
808 void EDA_DRAW_PANEL::DrawAuxiliaryAxis( wxDC* aDC, GR_DRAWMODE aDrawMode )
809 {
810  wxPoint origin = GetParent()->GetAuxOrigin();
811 
812  if( origin == wxPoint( 0, 0 ) )
813  return;
814 
815  COLOR4D color = COLOR4D( RED );
816 
817  GRSetDrawMode( aDC, aDrawMode );
818 
819 #if DRAW_AXIS_AS_LINES
820  wxSize pageSize = GetParent()->GetPageSizeIU();
821  // Draw the Y axis
822  GRLine( &m_ClipBox, aDC, origin.x, -pageSize.y,
823  origin.x, pageSize.y, 0, color );
824 
825  // Draw the X axis
826  GRLine( &m_ClipBox, aDC, -pageSize.x, origin.y,
827  pageSize.x, origin.y, 0, color );
828 #else
829  int radius = aDC->DeviceToLogicalXRel( AXIS_SIZE_IN_PIXELS );
830  int linewidth = aDC->DeviceToLogicalXRel( 1 );
831 
832  GRSetColorPen( aDC, color, linewidth );
833 
834  GRLine( &m_ClipBox, aDC, origin.x, origin.y-radius,
835  origin.x, origin.y+radius, 0, color );
836 
837  // Draw the + shape
838  GRLine( &m_ClipBox, aDC, origin.x-radius, origin.y,
839  origin.x+radius, origin.y, 0, color );
840 
841  GRCircle( &m_ClipBox, aDC, origin, radius, linewidth, color );
842 #endif
843 }
844 
845 
846 void EDA_DRAW_PANEL::DrawGridAxis( wxDC* aDC, GR_DRAWMODE aDrawMode, const wxPoint& aGridOrigin )
847 {
848  if( !GetParent()->GetShowGridAxis() || ( !aGridOrigin.x && !aGridOrigin.y ) )
849  return;
850 
852 
853  GRSetDrawMode( aDC, aDrawMode );
854 
855 #if DRAW_AXIS_AS_LINES
856  wxSize pageSize = GetParent()->GetPageSizeIU();
857  // Draw the Y axis
858  GRLine( &m_ClipBox, aDC, aGridOrigin.x, -pageSize.y,
859  aGridOrigin.x, pageSize.y, 0, color );
860 
861  // Draw the X axis
862  GRLine( &m_ClipBox, aDC, -pageSize.x, aGridOrigin.y,
863  pageSize.x, aGridOrigin.y, 0, color );
864 #else
865  int radius = aDC->DeviceToLogicalXRel( AXIS_SIZE_IN_PIXELS );
866  int linewidth = aDC->DeviceToLogicalXRel( 1 );
867 
868  GRSetColorPen( aDC, GetParent()->GetGridColor(), linewidth );
869 
870  GRLine( &m_ClipBox, aDC, aGridOrigin.x-radius, aGridOrigin.y-radius,
871  aGridOrigin.x+radius, aGridOrigin.y+radius, 0, color );
872 
873  // Draw the X shape
874  GRLine( &m_ClipBox, aDC, aGridOrigin.x+radius, aGridOrigin.y-radius,
875  aGridOrigin.x-radius, aGridOrigin.y+radius, 0, color );
876 
877  GRCircle( &m_ClipBox, aDC, aGridOrigin, radius, linewidth, color );
878 #endif
879 }
880 
881 
882 bool EDA_DRAW_PANEL::OnRightClick( wxMouseEvent& event )
883 {
884  wxPoint pos;
885  wxMenu MasterMenu;
886 
887  INSTALL_UNBUFFERED_DC( dc, this );
888 
889  pos = event.GetLogicalPosition( dc );
890 
891  if( !GetParent()->OnRightClick( pos, &MasterMenu ) )
892  return false;
893 
894  GetParent()->AddMenuZoomAndGrid( &MasterMenu );
895 
896  pos = event.GetPosition();
897  m_ignoreMouseEvents = true;
898  PopupMenu( &MasterMenu, pos );
899 
900  // The ZoomAndGrid menu is only invoked over empty space so there's no point in warping
901  // the cursor back to the crosshair, and it's very annoying if one clicked out of the menu.
902 
903  m_ignoreMouseEvents = false;
904 
905  return true;
906 }
907 
908 
909 void EDA_DRAW_PANEL::OnMouseEntering( wxMouseEvent& aEvent )
910 {
911  // This is an ugly hack that fixes some cross hair display bugs when the mouse leaves the
912  // canvas area during middle button mouse panning.
913  if( m_cursorLevel != 0 )
914  m_cursorLevel = 0;
915 
916  aEvent.Skip();
917 }
918 
919 
920 void EDA_DRAW_PANEL::OnMouseLeaving( wxMouseEvent& event )
921 {
922  if( m_mouseCaptureCallback == NULL ) // No command in progress.
923  SetAutoPanRequest( false );
924 
926  return;
927 
928  // Auto pan when mouse has left the client window
929  // Ensure the cross_hair position is updated,
930  // because it will be used to center the screen.
931  // We use a position inside the client window
932  wxRect area( wxPoint( 0, 0 ), GetClientSize() );
933  wxPoint cross_hair_pos = event.GetPosition();
934 
935  // Certain window managers (e.g. awesome wm) incorrectly trigger "on leave" event,
936  // therefore test if the cursor has really left the panel area
937  if( !area.Contains( cross_hair_pos ) )
938  {
939  INSTALL_UNBUFFERED_DC( dc, this );
940  cross_hair_pos.x = dc.DeviceToLogicalX( cross_hair_pos.x );
941  cross_hair_pos.y = dc.DeviceToLogicalY( cross_hair_pos.y );
942 
943  GetParent()->SetCrossHairPosition( cross_hair_pos );
944 
945  wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED, ID_POPUP_ZOOM_CENTER );
946  cmd.SetEventObject( this );
947  GetEventHandler()->ProcessEvent( cmd );
948  }
949 
950  event.Skip();
951 }
952 
953 
954 void EDA_DRAW_PANEL::OnMouseWheel( wxMouseEvent& event )
955 {
956  if( m_ignoreMouseEvents )
957  return;
958 
959  wxRect rect = wxRect( wxPoint( 0, 0 ), GetClientSize() );
960 
961  // Ignore scroll events if the cursor is outside the drawing area.
962  if( event.GetWheelRotation() == 0 || !GetParent()->IsEnabled()
963  || !rect.Contains( event.GetPosition() ) )
964  {
965  wxLogTrace( kicadTraceCoords,
966  wxT( "OnMouseWheel() position(%d, %d) rectangle(%d, %d, %d, %d)" ),
967  event.GetPosition().x, event.GetPosition().y,
968  rect.x, rect.y, rect.width, rect.height );
969  event.Skip();
970  return;
971  }
972 
973  INSTALL_UNBUFFERED_DC( dc, this );
974  GetParent()->SetCrossHairPosition( event.GetLogicalPosition( dc ) );
975 
976  wxCommandEvent cmd( wxEVT_COMMAND_MENU_SELECTED );
977  cmd.SetEventObject( this );
978 
979  bool offCenterReq = event.ControlDown() && event.ShiftDown();
980  offCenterReq = offCenterReq || m_enableZoomNoCenter;
981 
982  int axis = event.GetWheelAxis();
983  int wheelRotation = event.GetWheelRotation();
984 
986  {
987  // MousewheelPAN + Ctrl = zooming
988  if( event.ControlDown() && !event.ShiftDown() )
989  {
990  if( wheelRotation > 0 )
991  cmd.SetId( ID_POPUP_ZOOM_IN );
992  else if( wheelRotation < 0)
993  cmd.SetId( ID_POPUP_ZOOM_OUT );
994  }
995  // MousewheelPAN + Shift = horizontal scrolling
996  // Without modifiers MousewheelPAN - just pan
997  else
998  {
999  if( event.ShiftDown() && !event.ControlDown() )
1000  axis = wxMOUSE_WHEEL_HORIZONTAL;
1001 
1002  wxPoint newStart = GetViewStart();
1003  wxPoint center = GetParent()->GetScrollCenterPosition();
1004  double scale = GetParent()->GetScreen()->GetScalingFactor();
1005 
1006  if( axis == wxMOUSE_WHEEL_HORIZONTAL )
1007  {
1008  newStart.x += wheelRotation;
1009  center.x += KiROUND( (double) wheelRotation / scale );
1010  }
1011  else
1012  {
1013  newStart.y -= wheelRotation;
1014  center.y -= KiROUND( (double) wheelRotation / scale );
1015  }
1016  Scroll( newStart );
1017 
1018  GetParent()->SetScrollCenterPosition( center );
1019  GetParent()->SetCrossHairPosition( center, true );
1020  GetParent()->RedrawScreen( center, false );
1021  }
1022  }
1023  else if( wheelRotation > 0 )
1024  {
1025  if( event.ShiftDown() && !event.ControlDown() )
1026  cmd.SetId( ID_PAN_UP );
1027  else if( event.ControlDown() && !event.ShiftDown() )
1028  cmd.SetId( ID_PAN_LEFT );
1029  else if( offCenterReq )
1030  cmd.SetId( ID_OFFCENTER_ZOOM_IN );
1031  else
1032  cmd.SetId( ID_POPUP_ZOOM_IN );
1033  }
1034  else if( wheelRotation < 0 )
1035  {
1036  if( event.ShiftDown() && !event.ControlDown() )
1037  cmd.SetId( ID_PAN_DOWN );
1038  else if( event.ControlDown() && !event.ShiftDown() )
1039  cmd.SetId( ID_PAN_RIGHT );
1040  else if( offCenterReq )
1041  cmd.SetId( ID_OFFCENTER_ZOOM_OUT );
1042  else
1043  cmd.SetId( ID_POPUP_ZOOM_OUT );
1044  }
1045 
1046  if( cmd.GetId() )
1047  GetEventHandler()->ProcessEvent( cmd );
1048  event.Skip();
1049 }
1050 
1051 
1052 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
1053 void EDA_DRAW_PANEL::OnMagnify( wxMouseEvent& event )
1054 {
1055  // Scale the panel around our cursor position.
1056  bool warpCursor = false;
1057 
1058  wxPoint cursorPosition = GetParent()->GetCursorPosition( false );
1059  wxPoint centerPosition = GetParent()->GetScrollCenterPosition();
1060  wxPoint vector = centerPosition - cursorPosition;
1061 
1062  double magnification = ( event.GetMagnification() + 1.0f );
1063  double scaleFactor = GetZoom() / magnification;
1064 
1065  // Scale the vector between the cursor and center point
1066  vector.x /= magnification;
1067  vector.y /= magnification;
1068 
1069  SetZoom(scaleFactor);
1070 
1071  // Recenter the window along our scaled vector such that the
1072  // cursor becomes our scale axis, remaining fixed on screen
1073  GetParent()->RedrawScreen( cursorPosition + vector, warpCursor );
1074 
1075  event.Skip();
1076 }
1077 #endif
1078 
1079 
1080 void EDA_DRAW_PANEL::OnMouseEvent( wxMouseEvent& event )
1081 {
1082  int localbutt = 0;
1083  BASE_SCREEN* screen = GetScreen();
1084 
1085  if( !screen )
1086  return;
1087 
1088  /* Adjust value to filter mouse displacement before consider the drag
1089  * mouse is really a drag command, not just a movement while click
1090  */
1091 #define MIN_DRAG_COUNT_FOR_START_BLOCK_COMMAND 5
1092 
1093  if( event.Leaving() )
1094  m_canStartBlock = -1;
1095 
1096  if( !IsMouseCaptured() ) // No mouse capture in progress.
1097  SetAutoPanRequest( false );
1098 
1099  if( GetParent()->IsActive() )
1100  SetFocus();
1101  else
1102  return;
1103 
1104  if( !event.IsButton() && !event.Moving() && !event.Dragging() )
1105  return;
1106 
1107  if( event.RightDown() )
1108  {
1109  OnRightClick( event );
1110  return;
1111  }
1112 
1113  if( m_ignoreMouseEvents )
1114  return;
1115 
1116  if( event.LeftDown() )
1117  localbutt = GR_M_LEFT_DOWN;
1118 
1119  if( event.ButtonDClick( 1 ) )
1120  localbutt = GR_M_LEFT_DOWN | GR_M_DCLICK;
1121 
1122  if( event.MiddleDown() )
1123  localbutt = GR_M_MIDDLE_DOWN;
1124 
1125  INSTALL_UNBUFFERED_DC( DC, this );
1126  DC.SetBackground( *wxBLACK_BRUSH );
1127 
1128  // Compute the cursor position in drawing (logical) units.
1129  GetParent()->SetMousePosition( event.GetLogicalPosition( DC ) );
1130 
1131  int kbstat = 0;
1132 
1133  if( event.ShiftDown() )
1134  kbstat |= GR_KB_SHIFT;
1135 
1136  if( event.ControlDown() )
1137  kbstat |= GR_KB_CTRL;
1138 
1139  if( event.AltDown() )
1140  kbstat |= GR_KB_ALT;
1141 
1142  // Calling Double Click and Click functions :
1143  if( localbutt == (int) ( GR_M_LEFT_DOWN | GR_M_DCLICK ) )
1144  {
1145  if( m_ClickTimer )
1146  {
1147  m_ClickTimer->Stop();
1148  wxDELETE( m_ClickTimer );
1149  }
1150  GetParent()->OnLeftDClick( &DC, GetParent()->RefPos( true ) );
1151 
1152  // inhibit a response to the mouse left button release,
1153  // because we have a double click, and we do not want a new
1154  // OnLeftClick command at end of this Double Click
1156  }
1157  else if( event.LeftUp() )
1158  {
1159  // A block command is in progress: a left up is the end of block
1160  // or this is the end of a double click, already seen
1161  // Note also m_ignoreNextLeftButtonRelease can be set by
1162  // the call to OnLeftClick(), so do not change it after calling OnLeftClick
1163  bool ignoreEvt = m_ignoreNextLeftButtonRelease;
1165 
1166  if( screen->m_BlockLocate.GetState() == STATE_NO_BLOCK && !ignoreEvt )
1167  {
1168  EDA_ITEM* item = screen->GetCurItem();
1169  m_CursorClickPos = GetParent()->RefPos( true );
1170 
1171  // If we have an item already selected, or we are using a tool,
1172  // we won't use the disambiguation menu so process the click immediately
1173  if( ( item && item->GetFlags() ) || GetParent()->GetToolId() != ID_NO_TOOL_SELECTED )
1175  else
1176  {
1177  wxDELETE( m_ClickTimer );
1178  m_ClickTimer = new wxTimer(this, ID_MOUSE_DOUBLECLICK);
1179  m_ClickTimer->StartOnce( m_doubleClickInterval );
1180  }
1181  }
1182 
1183  }
1184  else if( !event.LeftIsDown() )
1185  {
1186  /* be sure there is a response to a left button release command
1187  * even when a LeftUp event is not seen. This happens when a
1188  * double click opens a dialog box, and the release mouse button
1189  * is made when the dialog box is opened.
1190  */
1192  }
1193 
1194  if( event.ButtonDown( wxMOUSE_BTN_MIDDLE ) )
1195  {
1197  m_PanStartEventPosition = event.GetPosition();
1198 
1199  INSTALL_UNBUFFERED_DC( dc, this );
1200  CrossHairOff( &dc );
1201  SetCursor( wxCURSOR_SIZING );
1202  }
1203 
1204  if( event.ButtonUp( wxMOUSE_BTN_MIDDLE ) )
1205  {
1206  INSTALL_UNBUFFERED_DC( dc, this );
1207  CrossHairOn( &dc );
1208  SetCursor( (wxStockCursor) m_currentCursor );
1209  }
1210 
1211  if( event.MiddleIsDown() )
1212  {
1213  wxPoint currentPosition = event.GetPosition();
1214 
1215  double scale = GetParent()->GetScreen()->GetScalingFactor();
1216  int x = m_PanStartCenter.x +
1217  KiROUND( (double) ( m_PanStartEventPosition.x - currentPosition.x ) / scale );
1218  int y = m_PanStartCenter.y +
1219  KiROUND( (double) ( m_PanStartEventPosition.y - currentPosition.y ) / scale );
1220 
1221  GetParent()->RedrawScreen( wxPoint( x, y ), false );
1222  }
1223 
1224  // Calling the general function on mouse changes (and pseudo key commands)
1225  GetParent()->GeneralControl( &DC, event.GetLogicalPosition( DC ), 0 );
1226 
1227  /*******************************/
1228  /* Control of block commands : */
1229  /*******************************/
1230 
1231  // Command block can't start if mouse is dragging a new panel
1232  static EDA_DRAW_PANEL* lastPanel;
1233  if( lastPanel != this )
1234  {
1235  m_minDragEventCount = 0;
1236  m_canStartBlock = -1;
1237  }
1238 
1239  /* A new command block can start after a release buttons
1240  * and if the drag is enough
1241  * This is to avoid a false start block when a dialog box is dismissed,
1242  * or when changing panels in hierarchy navigation
1243  * or when clicking while and moving mouse
1244  */
1245  if( !event.LeftIsDown() && !event.MiddleIsDown() )
1246  {
1247  m_minDragEventCount = 0;
1248  m_canStartBlock = 0;
1249 
1250  /* Remember the last cursor position when a drag mouse starts
1251  * this is the last position ** before ** clicking a button
1252  * this is useful to start a block command from the point where the
1253  * mouse was clicked first
1254  * (a filter creates a delay for the real block command start, and
1255  * we must remember this point)
1256  */
1258  }
1259 
1260  if( m_enableBlockCommands && !(localbutt & GR_M_DCLICK) )
1261  {
1262  if( !screen->IsBlockActive() )
1263  {
1265  }
1266 
1267  if( event.LeftDown() )
1268  {
1269  if( screen->m_BlockLocate.GetState() == STATE_BLOCK_MOVE )
1270  {
1271  SetAutoPanRequest( false );
1272  GetParent()->HandleBlockPlace( &DC );
1274  }
1275  }
1276  else if( ( m_canStartBlock >= 0 ) && event.LeftIsDown() && !IsMouseCaptured() )
1277  {
1278  // Mouse is dragging: if no block in progress, start a block command.
1279  if( screen->m_BlockLocate.GetState() == STATE_NO_BLOCK )
1280  {
1281  // Start a block command
1282  int cmd_type = kbstat;
1283 
1284  // A block command is started if the drag is enough. A small
1285  // drag is ignored (it is certainly a little mouse move when
1286  // clicking) not really a drag mouse
1289  else
1290  {
1291  auto cmd = (GetParent()->GetToolId() == ID_ZOOM_SELECTION) ? BLOCK_ZOOM : 0;
1292 
1293  if( !GetParent()->HandleBlockBegin( &DC, cmd_type, m_CursorStartPos, cmd ) )
1294  {
1295  // should not occur: error
1297  wxT( "EDA_DRAW_PANEL::OnMouseEvent() Block Error" ) );
1298  }
1299  else
1300  {
1301  SetAutoPanRequest( true );
1302  SetCursor( wxCURSOR_SIZING );
1303  }
1304  }
1305  }
1306  }
1307 
1308  if( event.ButtonUp( wxMOUSE_BTN_LEFT ) )
1309  {
1310  /* Release the mouse button: end of block.
1311  * The command can finish (DELETE) or have a next command (MOVE,
1312  * COPY). However the block command is canceled if the block
1313  * size is small because a block command filtering is already
1314  * made, this case happens, but only when the on grid cursor has
1315  * not moved.
1316  */
1317  #define BLOCK_MINSIZE_LIMIT 1
1318  bool BlockIsSmall =
1320  && ( std::abs( screen->m_BlockLocate.GetHeight() ) < BLOCK_MINSIZE_LIMIT );
1321 
1322  if( (screen->m_BlockLocate.GetState() != STATE_NO_BLOCK) && BlockIsSmall )
1323  {
1325  {
1326  m_endMouseCaptureCallback( this, &DC );
1327  SetAutoPanRequest( false );
1328  }
1329 
1330  SetCursor( (wxStockCursor) m_currentCursor );
1331  }
1332  else if( screen->m_BlockLocate.GetState() == STATE_BLOCK_END )
1333  {
1334  SetAutoPanRequest( false );
1335  GetParent()->HandleBlockEnd( &DC );
1336  SetCursor( (wxStockCursor) m_currentCursor );
1337  if( screen->m_BlockLocate.GetState() == STATE_BLOCK_MOVE )
1338  {
1339  SetAutoPanRequest( true );
1340  SetCursor( wxCURSOR_HAND );
1341  }
1342  }
1343  }
1344  }
1345 
1346  // End of block command on a double click
1347  // To avoid an unwanted block move command if the mouse is moved while double clicking
1348  if( localbutt == (int) ( GR_M_LEFT_DOWN | GR_M_DCLICK ) )
1349  {
1350  if( !screen->IsBlockActive() && IsMouseCaptured() )
1351  {
1352  m_endMouseCaptureCallback( this, &DC );
1353  }
1354  }
1355 
1356  lastPanel = this;
1357 
1358 #ifdef __WXGTK3__
1359  // Screen has to be updated on every operation, otherwise the cursor leaves a trail (when xor
1360  // operation is changed to copy) or is not updated at all.
1361  Refresh();
1362 #endif
1363 }
1364 
1365 
1366 void EDA_DRAW_PANEL::OnCharHook( wxKeyEvent& event )
1367 {
1368  wxLogTrace( kicadTraceKeyEvent, "EDA_DRAW_PANEL::OnCharHook %s", dump( event ) );
1369  event.Skip();
1370 }
1371 
1372 
1373 void EDA_DRAW_PANEL::OnKeyEvent( wxKeyEvent& event )
1374 {
1375  int localkey;
1376  wxPoint pos;
1377 
1378  wxLogTrace( kicadTraceKeyEvent, "EDA_DRAW_PANEL::OnKeyEvent %s", dump( event ) );
1379 
1380  localkey = event.GetKeyCode();
1381  bool keyWasHandled = false;
1382 
1383  switch( localkey )
1384  {
1385  default:
1386  break;
1387 
1388  case WXK_ESCAPE:
1389  m_abortRequest = true;
1390 
1391  if( IsMouseCaptured() )
1392  EndMouseCapture();
1393  else
1395 
1396  keyWasHandled = true; // The key is captured: the key event must not be skipped
1397  break;
1398  }
1399 
1400  /* Normalize keys code to easily handle keys from Ctrl+A to Ctrl+Z
1401  * They have an ascii code from 1 to 27 remapped
1402  * to GR_KB_CTRL + 'A' to GR_KB_CTRL + 'Z'
1403  */
1404  if( event.ControlDown() && localkey >= WXK_CONTROL_A && localkey <= WXK_CONTROL_Z )
1405  localkey += 'A' - 1;
1406 
1407  /* Disallow shift for keys that have two keycodes on them (e.g. number and
1408  * punctuation keys) leaving only the "letter keys" of A-Z.
1409  * Then, you can have, e.g. Ctrl-5 and Ctrl-% (GB layout)
1410  * and Ctrl-( and Ctrl-5 (FR layout).
1411  * Otherwise, you'd have to have to say Ctrl-Shift-5 on a FR layout
1412  */
1413  bool keyIsLetter = ( localkey >= 'A' && localkey <= 'Z' ) ||
1414  ( localkey >= 'a' && localkey <= 'z' );
1415 
1416  if( event.ShiftDown() && ( keyIsLetter || localkey > 256 ) )
1417  localkey |= GR_KB_SHIFT;
1418 
1419  if( event.ControlDown() )
1420  localkey |= GR_KB_CTRL;
1421 
1422  if( event.AltDown() )
1423  localkey |= GR_KB_ALT;
1424 
1425  INSTALL_UNBUFFERED_DC( DC, this );
1426 
1427  // Some key commands use the current mouse position: refresh it.
1428  pos = wxGetMousePosition() - GetScreenPosition();
1429 
1430  // Compute the cursor position in drawing units. Also known as logical units to wxDC.
1431  pos = wxPoint( DC.DeviceToLogicalX( pos.x ), DC.DeviceToLogicalY( pos.y ) );
1432 
1433  GetParent()->SetMousePosition( pos );
1434 
1435  if( !GetParent()->GeneralControl( &DC, pos, localkey ) && !keyWasHandled )
1436  event.Skip(); // Skip this event only when the key was not handled
1437 }
1438 
1439 
1440 void EDA_DRAW_PANEL::OnPan( wxCommandEvent& event )
1441 {
1442  int x, y;
1443  int ppux, ppuy;
1444  int unitsX, unitsY;
1445  int maxX, maxY;
1446  int tmpX, tmpY;
1447 
1448  GetViewStart( &x, &y );
1449  GetScrollPixelsPerUnit( &ppux, &ppuy );
1450  GetVirtualSize( &unitsX, &unitsY );
1451  tmpX = x;
1452  tmpY = y;
1453  maxX = unitsX;
1454  maxY = unitsY;
1455  unitsX /= ppux;
1456  unitsY /= ppuy;
1457 
1458  wxLogTrace( kicadTraceCoords,
1459  wxT( "Scroll center position before pan: (%d, %d)" ), tmpX, tmpY );
1460 
1461  switch( event.GetId() )
1462  {
1463  case ID_PAN_UP:
1464  y -= m_scrollIncrementY;
1465  break;
1466 
1467  case ID_PAN_DOWN:
1468  y += m_scrollIncrementY;
1469  break;
1470 
1471  case ID_PAN_LEFT:
1472  x -= m_scrollIncrementX;
1473  break;
1474 
1475  case ID_PAN_RIGHT:
1476  x += m_scrollIncrementX;
1477  break;
1478 
1479  default:
1480  wxLogDebug( wxT( "Unknown ID %d in EDA_DRAW_PANEL::OnPan()." ), event.GetId() );
1481  }
1482 
1483  bool updateCenterScrollPos = true;
1484 
1485  if( x < 0 )
1486  {
1487  x = 0;
1488  updateCenterScrollPos = false;
1489  }
1490 
1491  if( y < 0 )
1492  {
1493  y = 0;
1494  updateCenterScrollPos = false;
1495  }
1496 
1497  if( x > maxX )
1498  {
1499  x = maxX;
1500  updateCenterScrollPos = false;
1501  }
1502 
1503  if( y > maxY )
1504  {
1505  y = maxY;
1506  updateCenterScrollPos = false;
1507  }
1508 
1509  // Don't update the scroll position beyond the scroll limits.
1510  if( updateCenterScrollPos )
1511  {
1512  double scale = GetParent()->GetScreen()->GetScalingFactor();
1513 
1514  wxPoint center = GetParent()->GetScrollCenterPosition();
1515  center.x += KiROUND( (double) ( x - tmpX ) / scale );
1516  center.y += KiROUND( (double) ( y - tmpY ) / scale );
1517  GetParent()->SetScrollCenterPosition( center );
1518 
1519  wxLogTrace( kicadTraceCoords,
1520  wxT( "Scroll center position after pan: (%d, %d)" ), center.x, center.y );
1521  }
1522 
1523  Scroll( x/ppux, y/ppuy );
1524 }
1525 
1526 
1527 void EDA_DRAW_PANEL::EndMouseCapture( int id, int cursor, const wxString& title,
1528  bool aCallEndFunc )
1529 {
1530  if( m_mouseCaptureCallback && m_endMouseCaptureCallback && aCallEndFunc )
1531  {
1532  INSTALL_UNBUFFERED_DC( dc, this );
1533  m_endMouseCaptureCallback( this, &dc );
1534  }
1535 
1536  m_mouseCaptureCallback = NULL;
1538  SetAutoPanRequest( false );
1539 
1540  if( id != -1 && cursor != -1 )
1541  {
1542  wxASSERT( cursor > wxCURSOR_NONE && cursor < wxCURSOR_MAX );
1543  GetParent()->SetToolID( id, cursor, title );
1544  }
1545 }
1546 
1547 
1548 void EDA_DRAW_PANEL::CallMouseCapture( wxDC* aDC, const wxPoint& aPosition, bool aErase )
1549 {
1550  wxCHECK_RET( aDC != NULL, wxT( "Invalid device context." ) );
1551  wxCHECK_RET( m_mouseCaptureCallback != NULL, wxT( "Mouse capture callback not set." ) );
1552 
1553  m_mouseCaptureCallback( this, aDC, aPosition, aErase );
1554 }
1555 
1556 
1557 void EDA_DRAW_PANEL::CallEndMouseCapture( wxDC* aDC )
1558 {
1559  wxCHECK_RET( aDC != NULL, wxT( "Invalid device context." ) );
1560 
1561  // CallEndMouseCapture is sometimes called with m_endMouseCaptureCallback == NULL
1562  // for instance after an ABORT in block paste.
1564  m_endMouseCaptureCallback( this, aDC );
1565 }
virtual BASE_SCREEN * GetScreen()=0
Definition: colors.h:57
GR_DRAWMODE g_XorMode
Definition: gr_basic.cpp:74
#define GR_KB_ALT
#define GR_M_DCLICK
Definition: gr_basic.h:77
void GRResetPenAndBrush(wxDC *DC)
Definition: gr_basic.cpp:123
bool m_abortRequest
Flag used to abort long commands.
const wxRealPoint & GetGridSize() const
Return the grid size of the currently selected grid.
Definition: base_screen.h:410
int m_canStartBlock
useful to avoid false start block in certain cases (like switch from a sheet to another sheet >= 0 (o...
#define PIXEL_MARGIN
COLOR4D & Invert()
Function Invert Makes the color inverted, alpha remains the same.
Definition: color4d.h:203
BLOCK_STATE_T GetState() const
virtual wxPoint GetScreenCenterLogicalPosition()
Update the board display after modifying it by a python script (note: it is automatically called by a...
BLOCK_SELECTOR m_BlockLocate
Block description for block commands.
Definition: base_screen.h:214
#define GR_M_MIDDLE_DOWN
Definition: gr_basic.h:76
double GetBrightness() const
Function GetBrightness Returns the brightness value of the color ranged from 0.0 to 1....
Definition: color4d.h:277
KIGFX::VIEW_CONTROLS * GetViewControls() const
Function GetViewControls() Returns a pointer to the VIEW_CONTROLS instance used in the panel.
bool IsBlockActive() const
Definition: base_screen.h:499
void GRSetDrawMode(wxDC *DC, GR_DRAWMODE draw_mode)
Definition: gr_basic.cpp:223
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:121
virtual void HandleBlockPlace(wxDC *DC)
Called after HandleBlockEnd, when a block command needs to be executed after the block is moved to it...
virtual wxPoint ToDeviceXY(const wxPoint &pos)
Function ToDeviceXY transforms logical to device coordinates.
void GRSFilledRect(EDA_RECT *aClipBox, wxDC *aDC, int x1, int y1, int x2, int y2, int aWidth, COLOR4D aColor, COLOR4D aBgColor)
Definition: gr_basic.cpp:1078
wxRealPoint GetGrid()
virtual void SetEnableZoomNoCenter(bool aEnable)
bool m_enableZoomNoCenter
True to enable zooming around the crosshair instead of the center.
int GetX() const
Definition: eda_rect.h:109
int m_scrollIncrementX
X axis scroll increment in pixels per unit.
VIEW_CONTROLS class definition.
double GetZoom() const
Function GetZoom returns the current "zoom factor", which is a measure of "internal units per device ...
Definition: base_screen.h:340
bool m_requestAutoPan
true to request an auto pan. Valid only when m_enableAutoPan = true.
EDA_RECT m_ClipBox
The drawing area used to redraw the screen which is usually the visible area of the drawing in intern...
void SetScrollCenterPosition(const wxPoint &aPoint)
EDA_DRAW_PANEL_GAL * GetGalCanvas() const
Return a pointer to GAL-based canvas of given EDA draw frame.
Definition: draw_frame.h:935
int color
Definition: DXF_plotter.cpp:62
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
bool m_PrintIsMirrored
True when drawing in mirror mode.
virtual void DrawGrid(wxDC *aDC)
Function DrawGrid draws a grid to aDC.
int GetWidth() const
Definition: eda_rect.h:117
END_MOUSE_CAPTURE_CALLBACK m_endMouseCaptureCallback
Abort mouse capture callback function.
EVT_MENU_RANGE(ID_LANGUAGE_CHOICE, ID_LANGUAGE_CHOICE_END, KICAD_MANAGER_FRAME::language_change) EVT_UPDATE_UI_RANGE(ID_TO_SCH
virtual void EnableMousewheelPan(bool aEnable)
Function EnableMousewheelPan() Enables or disables mousewheel panning.
virtual void EndMouseCapture(int aId=-1, int aCursorId=-1, const wxString &aTitle=wxEmptyString, bool aCallEndFunc=true)
Function EndMouseCapture ends mouse a capture.
void OnKeyEvent(wxKeyEvent &event)
#define CLIP_BOX_PADDING
#define GR_KB_CTRL
EDA_ITEM * GetCurItem() const
Definition: base_screen.h:233
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:124
#define INSTALL_PAINTDC(name, parent)
virtual void RefreshDrawingRect(const EDA_RECT &aRect, bool aEraseBackground=true)
Function RefreshDrawingRect redraws the contents of aRect in drawing units.
wxPoint m_PanStartEventPosition
Initial position of mouse event when pan started.
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:66
virtual void SetAutoPanRequest(bool aEnable)=0
virtual void MoveCursor(const wxPoint &aPosition)
Function MoveCursor moves the mouse pointer to aPosition in logical (drawing) units.
void OnPan(wxCommandEvent &event)
The base class for create windows for drawing purpose.
Definition: draw_frame.h:81
virtual void MoveCursorToCrossHair()
Function MoveCursorToCrossHair warps the cursor to the current cross hair position.
bool m_enableBlockCommands
True enables block commands.
#define abs(a)
Definition: auxiliary.h:84
bool Contains(const wxPoint &aPoint) const
Function Contains.
virtual void CallEndMouseCapture(wxDC *aDC)
Function CallEndMouseCapture calls the end mouse capture callback.
virtual const wxSize GetPageSizeIU() const =0
Works off of GetPageSettings() to return the size of the paper page in the internal units of this par...
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
void OnMouseEvent(wxMouseEvent &event)
#define ENBL_ZOOM_NO_CENTER_KEY
Definition: pgm_base.h:48
void SetClipBox(const EDA_RECT &aRect)
This file contains miscellaneous commonly used macros and functions.
int GetBottom() const
Definition: eda_rect.h:122
MOUSE_CAPTURE_CALLBACK m_mouseCaptureCallback
Mouse capture move callback function.
virtual void DrawGridAxis(wxDC *aDC, GR_DRAWMODE aDrawMode, const wxPoint &aGridOrigin)
Function DrawGridAxis Draw on auxiliary axis, used in Pcbnew to show grid origin, when the grid origi...
virtual EDA_DRAW_FRAME * GetParent() const =0
virtual wxPoint ToLogicalXY(const wxPoint &pos)
Function ToLogicalXY transforms device to logical coordinates.
virtual bool HandleBlockBegin(wxDC *aDC, EDA_KEY aKey, const wxPoint &aPosition, int aExplicitCommand=0)
Initialize a block command.
void EnableCursorWarping(bool aEnable)
Function EnableCursorWarping() Enables or disables warping the cursor.
wxPoint m_StartVisu
Coordinates in drawing units of the current view position (upper left corner of device)
Definition: base_screen.h:198
void OnTimer(wxTimerEvent &event)
Function OnTimer handle timer events.
void OnPaint(wxPaintEvent &event)
virtual bool IsPointOnDisplay(const wxPoint &aPosition)
Function IsPointOnDisplay.
void GRRect(EDA_RECT *aClipBox, wxDC *aDC, int x1, int y1, int x2, int y2, COLOR4D aColor)
Definition: gr_basic.cpp:1003
#define ENBL_AUTO_PAN_KEY
Definition: pgm_base.h:51
a helper to handle the real device context used in KiCad
const wxPoint & GetScrollCenterPosition() const
void OnEraseBackground(wxEraseEvent &event)
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
GR_DRAWMODE
Drawmode. Compositing mode plus a flag or two.
Definition: gr_basic.h:37
virtual void OnLeftClick(wxDC *DC, const wxPoint &MousePos)=0
void OnMouseLeaving(wxMouseEvent &event)
virtual void CrossHairOn(wxDC *DC=nullptr)
Class BASE_SCREEN handles how to draw a screen (a board, a schematic ...)
Definition: base_screen.h:76
const wxPoint GetPosition() const
Definition: eda_rect.h:113
#define MIN_GRID_SIZE
int GetRight() const
Definition: eda_rect.h:119
bool m_ignoreMouseEvents
Ignore mouse events when true.
virtual void CallMouseCapture(wxDC *aDC, const wxPoint &aPosition, bool aErase)
Function CallMouseCapture calls the mouse capture callback.
virtual void SetZoom(double mode)
#define ENBL_MOUSEWHEEL_PAN_KEY
Definition: pgm_base.h:49
virtual void DrawCrossHair(wxDC *aDC=nullptr, COLOR4D aColor=COLOR4D::WHITE)
Function DrawCrossHair draws the user cross hair.
virtual void CrossHairOff(wxDC *DC=nullptr)
void SetX(int val)
Definition: eda_rect.h:130
wxLogTrace helper definitions.
Definition: colors.h:60
virtual void EnableAutoPan(bool aEnabled)
Function EnableAutoPan Turns on/off auto panning (user setting to disable it entirely).
virtual bool SetZoom(double iu_per_du)
Function SetZoom adjusts the current zoom factor.
virtual void SetToolID(int aId, int aCursor, const wxString &aToolMsg)
Set the tool command ID to aId and sets the cursor to aCursor.
#define GR_KB_SHIFT
void OnMouseEntering(wxMouseEvent &aEvent)
void GRLine(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, COLOR4D Color, wxPenStyle aStyle)
Definition: gr_basic.cpp:285
virtual COLOR4D GetGridColor()
Definition: draw_frame.h:552
VTBL_ENTRY wxConfigBase * CommonSettings() const
Definition: pgm_base.h:189
bool m_ignoreNextLeftButtonRelease
Ignore the next mouse left button release when true.
int GetHeight() const
Definition: eda_rect.h:118
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
wxPoint m_ScrollbarPos
Current scroll bar position in scroll units.
Definition: base_screen.h:196
void SetY(int val)
Definition: eda_rect.h:131
void OnMouseWheel(wxMouseEvent &event)
Function OnMouseWheel handles mouse wheel events.
const int drawPanelStyle
virtual const wxPoint & GetAuxOrigin() const =0
Return the origin of the axis used for plotting and various exports.
virtual bool HandleBlockEnd(wxDC *DC)
Handle the "end" of a block command, i.e.
wxPoint m_PanStartCenter
Initial scroll center position when pan started.
wxPoint GetNearestGridPosition(const wxPoint &aPosition, wxRealPoint *aGridSize=NULL) const
Return the nearest aGridSize location to aPosition.
virtual void RedrawActiveWindow(wxDC *DC, bool EraseBg)=0
bool m_showCrossHair
Indicate if cross hair is to be shown.
virtual void RedrawScreen(const wxPoint &aCenterPoint, bool aWarpPointer)
Redraw the entire screen area by updating the scroll bars and mouse pointer in order to have aCenterP...
#define GR_M_LEFT_DOWN
Definition: gr_basic.h:74
void SetSize(const wxSize &size)
Definition: eda_rect.h:126
wxPoint m_CursorClickPos
Used for maintaining click position.
const int scale
void DisplayToolMsg(const wxString &msg)
see class PGM_BASE
void SetMousePosition(const wxPoint &aPosition)
#define MIN_DRAG_COUNT_FOR_START_BLOCK_COMMAND
virtual void ReDraw(wxDC *aDC, bool aEraseBackground=true)
void OnCharHook(wxKeyEvent &event)
#define max(a, b)
Definition: auxiliary.h:86
#define INSTALL_UNBUFFERED_DC(name, parent)
bool m_enableMousewheelPan
True to enable mousewheel panning by default.
double GetScalingFactor() const
Function GetScalingFactor returns the inverse of the current scale used to draw items on screen.
Definition: base_screen.cpp:95
void OnActivate(wxActivateEvent &event)
Function OnActivate handles window activation events.
int m_currentCursor
Current mouse cursor shape id.
int m_defaultCursor
The default mouse cursor shape id.
void GRCircle(EDA_RECT *ClipBox, wxDC *DC, int xc, int yc, int r, int width, COLOR4D Color)
Definition: gr_basic.cpp:755
void GRSetColorPen(wxDC *DC, COLOR4D Color, int width, wxPenStyle style)
Function GRSetColorPen sets a pen style, width, color, and alpha into the given device context.
Definition: gr_basic.cpp:136
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
wxPoint m_DrawOrg
offsets for drawing the circuit on the screen
Definition: base_screen.h:183
virtual void SetEnableMousewheelPan(bool aEnable)
int GetY() const
Definition: eda_rect.h:110
const wxChar *const kicadTraceKeyEvent
Flag to enable wxKeyEvent debug tracing.
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:154
The common library.
wxPoint RefPos(bool useMouse) const
Return the reference position, coming from either the mouse position or the cursor position.
bool OnRightClick(wxMouseEvent &event)
Function OnRightClick builds and displays a context menu on a right mouse button click.
Definition: colors.h:49
virtual void DrawAuxiliaryAxis(wxDC *aDC, GR_DRAWMODE aDrawMode)
Function DrawAuxiliaryAxis Draw the Auxiliary Axis, used in Pcbnew which as origin coordinates for ge...
int m_minDragEventCount
Count the drag events.
wxPoint m_CursorStartPos
Used for testing the cursor movement.
Definition: id.h:255
virtual bool GeneralControl(wxDC *aDC, const wxPoint &aPosition, EDA_KEY aHotKey=0)
Perform application specific control using aDC at aPosition in logical units.
Definition: draw_frame.h:640
virtual void AddMenuZoomAndGrid(wxMenu *aMasterMenu)
Add standard zoom commands and submenu zoom and grid selection to a popup menu uses zoom hotkeys info...
virtual void DrawBackGround(wxDC *DC)
Function DrawBackGround.
virtual COLOR4D GetDrawBgColor() const
Definition: draw_frame.h:382
bool m_enableAutoPan
True to enable automatic panning.
Definition: colors.h:45
virtual void * GetDisplayOptions()
Function GetDisplayOptions A way to pass info to draw functions.
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL)
#define BLOCK_MINSIZE_LIMIT
void SetCrossHairPosition(const wxPoint &aPosition, bool aSnapToGrid=true)
Set the screen cross hair position to aPosition in logical (drawing) units.
BASE_SCREEN class implementation.
STATUS_FLAGS GetFlags() const
Definition: base_struct.h:258
virtual void EraseScreen(wxDC *DC)
Function OnMouseWheel handles mouse wheel events.
virtual void OnLeftDClick(wxDC *DC, const wxPoint &MousePos)
const wxChar *const kicadTraceCoords
Flag to enable draw panel coordinate debug tracing.
virtual void SetEnableAutoPan(bool aEnable)
#define AXIS_SIZE_IN_PIXELS
virtual BASE_SCREEN * GetScreen() const
Return a pointer to a BASE_SCREEN or one of its derivatives.
Definition: draw_frame.h:404
int m_cursorLevel
Index for cursor redraw in XOR mode.
wxPoint GetCursorPosition(bool aOnGrid, wxRealPoint *aGridSize=NULL) const
Return the current cursor position in logical (drawing) units.
virtual void DoPrepareDC(wxDC &aDC) override
Function DoPrepareDC sets up the device context aDC for drawing.
virtual void * GetDisplayOptions()
A way to pass info to draw functions.
Definition: draw_frame.h:948
void OnScroll(wxScrollWinEvent &event)
COLOR4D g_GhostColor
Global variables definitions.
Definition: common.cpp:57
int GetToolId() const
Definition: draw_frame.h:526
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
static const int CURSOR_SIZE
Cursor size in pixels.
wxPoint GetCrossHairPosition(bool aInvertY=false) const
Return the current cross hair position in logical (drawing) coordinates.
int m_scrollIncrementY
Y axis scroll increment in pixels per unit.
#define min(a, b)
Definition: auxiliary.h:85
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39