KiCad PCB EDA Suite
sch_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) 2014-2019 CERN
5  * @author Maciej Suminski <maciej.suminski@cern.ch>
6  * Copyright (C) 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 
26 
27 #include <view/wx_view_controls.h>
28 #include <worksheet_viewitem.h>
29 
31 #include <sch_draw_panel.h>
32 #include <sch_view.h>
33 #include <sch_painter.h>
34 #include <sch_edit_frame.h>
36 #include <tool/tool_manager.h>
37 #include <tool/actions.h>
38 #include <functional>
39 #include <sch_sheet.h>
40 #include <pgm_base.h>
41 #include <tools/ee_actions.h>
43 
44 using namespace std::placeholders;
45 
46 
47 // Events used by EDA_DRAW_PANEL
48 BEGIN_EVENT_TABLE( SCH_DRAW_PANEL, wxScrolledCanvas )
49  EVT_CHAR( SCH_DRAW_PANEL::OnKeyEvent )
50  EVT_CHAR_HOOK( SCH_DRAW_PANEL::OnCharHook )
51  EVT_PAINT( SCH_DRAW_PANEL::onPaint )
52 END_EVENT_TABLE()
53 
54 SCH_DRAW_PANEL::SCH_DRAW_PANEL( wxWindow* aParentWindow, wxWindowID aWindowId,
55  const wxPoint& aPosition, const wxSize& aSize,
56  KIGFX::GAL_DISPLAY_OPTIONS& aOptions, GAL_TYPE aGalType ) :
57  EDA_DRAW_PANEL_GAL( aParentWindow, aWindowId, aPosition, aSize, aOptions, aGalType ),
58  m_parent( aParentWindow )
59 {
60  m_defaultCursor = m_currentCursor = wxCURSOR_ARROW;
61  m_showCrossHair = true;
62  m_view = new KIGFX::SCH_VIEW( true, dynamic_cast<SCH_BASE_FRAME*>( aParentWindow ) );
63  m_view->SetGAL( m_gal );
64 
65  m_gal->SetWorldUnitLength( SCH_WORLD_UNIT );
66 
67  m_painter.reset( new KIGFX::SCH_PAINTER( m_gal ) );
68 
69  m_view->SetPainter( m_painter.get() );
70  m_view->SetScaleLimits( 50.0, 0.05 ); // This fixes the zoom in and zoom out limits
71  m_view->SetMirror( false, false );
72 
73  // Early initialization of the canvas background color,
74  // before any OnPaint event is fired for the canvas using a wrong bg color
75  auto settings = m_painter->GetSettings();
76  m_gal->SetClearColor( settings->GetBackgroundColor() );
77 
78  setDefaultLayerOrder();
79  setDefaultLayerDeps();
80 
81  view()->UpdateAllLayersOrder();
82 
83  // View controls is the first in the event handler chain, so the Tool Framework operates
84  // on updated viewport data.
85  m_viewControls = new KIGFX::WX_VIEW_CONTROLS( m_view, this );
86 
87  Connect( wxEVT_CHAR, wxKeyEventHandler( SCH_DRAW_PANEL::OnKeyEvent ), NULL, this );
88  Connect( wxEVT_CHAR_HOOK, wxKeyEventHandler( SCH_DRAW_PANEL::OnCharHook ), NULL, this );
89 
90  Pgm().CommonSettings()->Read( ENBL_MOUSEWHEEL_PAN_KEY, &m_enableMousewheelPan, false );
91  Pgm().CommonSettings()->Read( ENBL_ZOOM_NO_CENTER_KEY, &m_enableZoomNoCenter, false );
92  Pgm().CommonSettings()->Read( ENBL_AUTO_PAN_KEY, &m_enableAutoPan, true );
93 
94  m_abortRequest = false;
95  m_ignoreMouseEvents = false;
96  // Be sure a mouse release button event will be ignored when creating the canvas
97  // if the mouse click was not made inside the canvas (can happen sometimes, when
98  // launching a editor from a double click made in another frame)
99  m_ignoreNextLeftButtonRelease = true;
100 
101  m_mouseCaptureCallback = NULL;
102  m_endMouseCaptureCallback = NULL;
103 
104  m_enableBlockCommands = false;
105  m_minDragEventCount = 0;
106 
107  m_cursorLevel = 0;
108  m_PrintIsMirrored = false;
109 
110  m_doubleClickInterval = 250;
111 
112  m_viewControls->SetSnapping( true );
113 
114  SetEvtHandlerEnabled( true );
115  SetFocus();
116  Show( true );
117  Raise();
118  StartDrawing();
119 }
120 
121 
123 {
124 }
125 
126 
128 {
129  view()->Clear();
130  view()->DisplayComponent( const_cast<LIB_PART*>(aComponent) );
131 
132 }
133 
134 
136 {
137  view()->Clear();
138 
139  if( aScreen )
140  view()->DisplaySheet( const_cast<SCH_SCREEN*>( aScreen ) );
141 }
142 
143 
145 {
146  for( LAYER_NUM i = 0; (unsigned) i < sizeof( SCH_LAYER_ORDER ) / sizeof( LAYER_NUM ); ++i )
147  {
148  LAYER_NUM layer = SCH_LAYER_ORDER[i];
149  wxASSERT( layer < KIGFX::VIEW::VIEW_MAX_LAYERS );
150 
151  m_view->SetLayerOrder( layer, i );
152  }
153 }
154 
155 
157 {
158  VECTOR2D grid_size = m_gal->GetGridSize();
159  bool rv = EDA_DRAW_PANEL_GAL::SwitchBackend( aGalType );
160  setDefaultLayerDeps();
161  m_gal->SetWorldUnitLength( SCH_WORLD_UNIT );
162 
163  // Keep grid size and grid visibility:
164  m_gal->SetGridSize( grid_size );
165  SCH_BASE_FRAME* frame = dynamic_cast<SCH_BASE_FRAME*>( GetParent() );
166 
167  if( frame )
168  m_gal->SetGridVisibility( frame->IsGridVisible() );
169 
170  Refresh();
171 
172  return rv;
173 }
174 
175 
177 {
178  m_enableMousewheelPan = aEnable;
179 
180  if( GetParent()->IsGalCanvasActive() )
181  GetParent()->GetGalCanvas()->GetViewControls()->EnableMousewheelPan( aEnable );
182 }
183 
184 
186 {
188 
189  if( GetParent()->IsGalCanvasActive() )
190  GetParent()->GetGalCanvas()->GetViewControls()->EnableAutoPan( aEnable );
191 }
192 
193 
195 {
196  wxCHECK( GetParent()->IsGalCanvasActive(), /*void*/ );
197  GetParent()->GetGalCanvas()->GetViewControls()->SetAutoPan( aEnable );
198 }
199 
200 
202 {
203  m_enableZoomNoCenter = aEnable;
204 
205  if( GetParent()->IsGalCanvasActive() )
206  GetParent()->GetGalCanvas()->GetViewControls()->EnableCursorWarping( !aEnable );
207 }
208 
209 
211 {
212  // caching makes no sense for Cairo and other software renderers
213  auto target = m_backend == GAL_TYPE_OPENGL ? KIGFX::TARGET_CACHED : KIGFX::TARGET_NONCACHED;
214 
215  for( int i = 0; i < KIGFX::VIEW::VIEW_MAX_LAYERS; i++ )
216  m_view->SetLayerTarget( i, target );
217 
218  // Bitmaps are draw on a non cached GAL layer:
219  m_view->SetLayerTarget( LAYER_DRAW_BITMAPS , KIGFX::TARGET_NONCACHED );
220 
221  // Some draw layers need specific settings
222  m_view->SetLayerTarget( LAYER_GP_OVERLAY , KIGFX::TARGET_OVERLAY );
223  m_view->SetLayerDisplayOnly( LAYER_GP_OVERLAY ) ;
224 
225  m_view->SetLayerTarget( LAYER_SELECT_OVERLAY , KIGFX::TARGET_OVERLAY );
226  m_view->SetLayerDisplayOnly( LAYER_SELECT_OVERLAY ) ;
227 
228  m_view->SetLayerTarget( LAYER_WORKSHEET , KIGFX::TARGET_NONCACHED );
229  m_view->SetLayerDisplayOnly( LAYER_WORKSHEET ) ;
230 }
231 
232 
234 {
235  return static_cast<KIGFX::SCH_VIEW*>( m_view );
236 }
237 
239 {
240  return GetParent()->GetScreen();
241 }
242 
244 {
245  return static_cast<EDA_DRAW_FRAME*>(m_parent); // static_cast<SCH_EDIT_FRAME*> (m_parent);
246 }
247 
248 
250 {
251  m_viewControls->ShowCursor( false );
252 }
253 
254 
256 {
257  m_viewControls->ShowCursor( true );
258 }
259 
260 
262 {
263  GetViewControls()->WarpCursor( GetParent()->GetCrossHairPosition(), true );
264 }
265 
266 
267 void SCH_DRAW_PANEL::Refresh( bool aEraseBackground, const wxRect* aRect )
268 {
269  EDA_DRAW_PANEL_GAL::Refresh( aEraseBackground, aRect );
270 }
271 
272 
273 void SCH_DRAW_PANEL::OnCharHook( wxKeyEvent& event )
274 {
275  event.Skip();
276 }
277 
278 
279 void SCH_DRAW_PANEL::OnKeyEvent( wxKeyEvent& event )
280 {
281  int localkey = event.GetKeyCode();
282  bool keyWasHandled = false;
283 
284  if( localkey == WXK_ESCAPE )
285  {
286  m_abortRequest = true;
287 
288  EE_SELECTION_TOOL* selTool = GetParent()->GetToolManager()->GetTool<EE_SELECTION_TOOL>();
289 
290  if( EE_CONDITIONS::Idle( selTool->GetSelection() ) )
291  GetParent()->GetToolManager()->RunAction( EE_ACTIONS::selectionActivate, true );
292  else
293  GetParent()->GetToolManager()->RunAction( ACTIONS::cancelInteractive, true );
294 
295  keyWasHandled = true; // The key is captured: the key event will be not skipped
296  }
297 
298  /* Normalize keys code to easily handle keys from Ctrl+A to Ctrl+Z
299  * They have an ascii code from 1 to 27 remapped
300  * to GR_KB_CTRL + 'A' to GR_KB_CTRL + 'Z'
301  */
302  if( event.ControlDown() && localkey >= WXK_CONTROL_A && localkey <= WXK_CONTROL_Z )
303  localkey += 'A' - 1;
304 
305  /* Disallow shift for keys that have two keycodes on them (e.g. number and
306  * punctuation keys) leaving only the "letter keys" of A-Z.
307  * Then, you can have, e.g. Ctrl-5 and Ctrl-% (GB layout)
308  * and Ctrl-( and Ctrl-5 (FR layout).
309  * Otherwise, you'd have to have to say Ctrl-Shift-5 on a FR layout
310  */
311  bool keyIsLetter = ( localkey >= 'A' && localkey <= 'Z' ) ||
312  ( localkey >= 'a' && localkey <= 'z' );
313 
314  if( event.ShiftDown() && ( keyIsLetter || localkey > 256 ) )
315  localkey |= GR_KB_SHIFT;
316 
317  if( event.ControlDown() )
318  localkey |= GR_KB_CTRL;
319 
320  if( event.AltDown() )
321  localkey |= GR_KB_ALT;
322 
323 
324  // Some key commands use the current mouse position: refresh it.
325  //pos = wxGetMousePosition() - GetScreenPosition();
326 
327  // Compute the cursor position in drawing units. Also known as logical units to wxDC.
328  //pos = wxPoint( DC.DeviceToLogicalX( pos.x ), DC.DeviceToLogicalY( pos.y ) );
329 
330  auto p = GetViewControls()->GetCursorPosition( false );
331 
332  wxPoint pos ((int)p.x, (int)p.y);
333 
334  GetParent()->SetMousePosition( pos );
335 
336  // a Key event has to be skipped only if it is not handled:
337  if( !GetParent()->GeneralControl( nullptr, pos, localkey ) && !keyWasHandled )
338  event.Skip();
339 }
340 
341 
342 void SCH_DRAW_PANEL::onPaint( wxPaintEvent& aEvent )
343 {
344  if( !m_gal->IsInitialized() || !m_gal->IsVisible() )
345  // The first wxPaintEvent can be fired at startup before the GAL engine is fully initialized
346  // (depending on platforms). Do nothing in this case
347  return;
348 
349  if( m_painter )
350  static_cast<KIGFX::SCH_PAINTER*>(m_painter.get())->GetSettings()->ImportLegacyColors( nullptr );
351 
352  EDA_DRAW_PANEL_GAL::onPaint( aEvent );
353 }
void DisplaySheet(const SCH_SCREEN *aScreen)
SELECTION & GetSelection()
Function GetSelection()
#define GR_KB_ALT
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: class_module.h:57
virtual EDA_DRAW_FRAME * GetParent() const override
to handle and draw images bitmaps
Class WX_VIEW_CONTROLS is a specific implementation of class VIEW_CONTROLS for wxWidgets library.
constexpr double SCH_WORLD_UNIT
Definition: sch_view.h:42
virtual bool SwitchBackend(GAL_TYPE aGalType)
Function SwitchBackend Switches method of rendering graphics.
virtual bool IsGridVisible() const
Definition: draw_frame.h:533
virtual void MoveCursorToCrossHair() override
Function MoveCursorToCrossHair warps the cursor to the current cross hair position.
static TOOL_ACTION cancelInteractive
Definition: actions.h:45
#define GR_KB_CTRL
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:66
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...
static SELECTION_CONDITION Idle
The base class for create windows for drawing purpose.
Definition: draw_frame.h:82
WX_VIEW_CONTROLS class definition.
static constexpr int VIEW_MAX_LAYERS
maximum number of layers that may be shown
Definition: view.h:712
#define ENBL_ZOOM_NO_CENTER_KEY
Definition: pgm_base.h:49
Auxiliary rendering target (noncached)
Definition: definitions.h:49
static const LAYER_NUM SCH_LAYER_ORDER[]
Definition: sch_view.h:44
Class that handles properties and drawing of worksheet layout.
#define ENBL_AUTO_PAN_KEY
Definition: pgm_base.h:52
virtual void onPaint(wxPaintEvent &WXUNUSED(aEvent))
virtual void CrossHairOff(wxDC *DC=nullptr) override
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
void OnKeyEvent(wxKeyEvent &event)
Class BASE_SCREEN handles how to draw a screen (a board, a schematic ...)
Definition: base_screen.h:76
Class SCH_PAINTER Contains methods for drawing schematic-specific items.
Definition: sch_painter.h:116
void SetEnableAutoPan(bool aEnable) override
KIGFX::SCH_VIEW * view() const
virtual void onPaint(wxPaintEvent &WXUNUSED(aEvent)) override
Define a library symbol object.
#define ENBL_MOUSEWHEEL_PAN_KEY
Definition: pgm_base.h:50
Items that may change while the view stays the same (noncached)
Definition: definitions.h:50
virtual void CrossHairOn(wxDC *DC=nullptr) override
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition: ee_actions.h:47
void setDefaultLayerDeps()
Reassigns layer order to the initial settings.
#define GR_KB_SHIFT
VTBL_ENTRY wxConfigBase * CommonSettings() const
Definition: pgm_base.h:190
bool SwitchBackend(GAL_TYPE aGalType) override
Function SwitchBackend Switches method of rendering graphics.
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...
void SetAutoPanRequest(bool aEnable) override
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
void SetEnableZoomNoCenter(bool aEnable) override
see class PGM_BASE
Main rendering target (cached)
Definition: definitions.h:48
size_t i
Definition: json11.cpp:597
currently selected items overlay
void OnCharHook(wxKeyEvent &event)
BASE_SCREEN * GetScreen() override
A shim class between EDA_DRAW_FRAME and several derived classes: LIB_EDIT_FRAME, LIB_VIEW_FRAME,...
virtual void SetEnableAutoPan(bool aEnable)
void DisplayComponent(const LIB_PART *aComponent)
void setDefaultLayerOrder()
void SetEnableMousewheelPan(bool aEnable) override