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