KiCad PCB EDA Suite
lib_drawing_tools.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 CERN
5  * Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <ee_actions.h>
26 #include <symbol_edit_frame.h>
27 #include <view/view_controls.h>
28 #include <tool/tool_manager.h>
31 #include <tools/lib_pin_tool.h>
32 #include <class_libentry.h>
33 #include <bitmaps.h>
34 #include <lib_text.h>
36 #include <lib_arc.h>
37 #include <lib_circle.h>
38 #include <lib_polyline.h>
39 #include <lib_rectangle.h>
40 #include <pgm_base.h>
43 #include <kicad_string.h>
44 #include "ee_point_editor.h"
45 
46 static void* g_lastPinWeakPtr;
47 
48 
50  EE_TOOL_BASE<SYMBOL_EDIT_FRAME>( "eeschema.SymbolDrawing" ),
51  m_lastTextAngle( 0.0 ),
52  m_lastFillStyle( FILL_TYPE::NO_FILL ),
53  m_drawSpecificConvert( true ),
54  m_drawSpecificUnit( false )
55 {
56 }
57 
58 
60 {
62 
63  auto isDrawingCondition =
64  [] ( const SELECTION& aSel )
65  {
66  LIB_ITEM* item = (LIB_ITEM*) aSel.Front();
67  return item && item->IsNew();
68  };
69 
70  m_menu.GetMenu().AddItem( EE_ACTIONS::finishDrawing, isDrawingCondition, 2 );
71 
72  return true;
73 }
74 
75 
77 {
78  KICAD_T type = aEvent.Parameter<KICAD_T>();
79  auto* settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
80  LIB_PIN_TOOL* pinTool = type == LIB_PIN_T ? m_toolMgr->GetTool<LIB_PIN_TOOL>() : nullptr;
81  VECTOR2I cursorPos;
82  EDA_ITEM* item = nullptr;
83  bool isText = aEvent.IsAction( &EE_ACTIONS::placeSymbolText );
84 
86  getViewControls()->ShowCursor( true );
87 
88  std::string tool = aEvent.GetCommandStr().get();
89  m_frame->PushTool( tool );
90  Activate();
91 
92  // Prime the pump
93  if( aEvent.HasPosition() )
95 
96  auto setCursor =
97  [&]()
98  {
99  if( item )
101  else if( isText )
103  else
105  };
106 
107  // Set initial cursor
108  setCursor();
109 
110  // Main loop: keep receiving events
111  while( TOOL_EVENT* evt = Wait() )
112  {
113  setCursor();
114 
115  cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
116 
117  auto cleanup =
118  [&] ()
119  {
121  m_view->ClearPreview();
122  delete item;
123  item = nullptr;
124  };
125 
126  if( evt->IsCancelInteractive() )
127  {
128  if( item )
129  {
130  cleanup();
131  }
132  else
133  {
134  m_frame->PopTool( tool );
135  break;
136  }
137  }
138  else if( evt->IsActivate() )
139  {
140  if( item )
141  cleanup();
142 
143  if( evt->IsMoveTool() )
144  {
145  // leave ourselves on the stack so we come back after the move
146  break;
147  }
148  else
149  {
150  m_frame->PopTool( tool );
151  break;
152  }
153  }
154  else if( evt->IsClick( BUT_LEFT ) )
155  {
156  LIB_PART* part = m_frame->GetCurPart();
157 
158  if( !part )
159  continue;
160 
161  // First click creates...
162  if( !item )
163  {
165 
166  switch( type )
167  {
168  case LIB_PIN_T:
169  {
170  item = pinTool->CreatePin( wxPoint( cursorPos.x, -cursorPos.y ), part );
171  g_lastPinWeakPtr = item;
172  break;
173  }
174  case LIB_TEXT_T:
175  {
176  LIB_TEXT* text = new LIB_TEXT( part );
177 
178  text->SetPosition( wxPoint( cursorPos.x, -cursorPos.y ) );
179  text->SetTextSize( wxSize( Mils2iu( settings->m_Defaults.text_size ),
180  Mils2iu( settings->m_Defaults.text_size ) ) );
181  text->SetTextAngle( m_lastTextAngle );
182 
183  DIALOG_LIB_EDIT_TEXT dlg( m_frame, text );
184 
185  if( dlg.ShowModal() != wxID_OK || NoPrintableChars( text->GetText() ) )
186  delete text;
187  else
188  item = text;
189 
190  break;
191  }
192  default:
193  wxFAIL_MSG( "TwoClickPlace(): unknown type" );
194  }
195 
196  // Restore cursor after dialog
197  getViewControls()->WarpCursor( getViewControls()->GetCursorPosition(), true );
198 
199  if( item )
200  {
201  item->SetFlags( IS_NEW | IS_MOVED );
202  m_view->ClearPreview();
203  m_view->AddToPreview( item->Clone() );
204  m_selectionTool->AddItemToSel( item );
205 
206  // update the cursor so it looks correct before another event
207  setCursor();
208  }
209 
210  getViewControls()->SetCursorPosition( cursorPos, false );
211  }
212  // ... and second click places:
213  else
214  {
215  m_frame->SaveCopyInUndoList( part );
216 
217  switch( item->Type() )
218  {
219  case LIB_PIN_T:
220  pinTool->PlacePin( (LIB_PIN*) item );
221  break;
222  case LIB_TEXT_T:
223  part->AddDrawItem( (LIB_TEXT*) item );
224  break;
225  default:
226  wxFAIL_MSG( "TwoClickPlace(): unknown type" );
227  }
228 
229  item->ClearEditFlags();
230  item = nullptr;
231  m_view->ClearPreview();
232 
233  m_frame->RebuildView();
234  m_frame->OnModify();
235  }
236  }
237  else if( evt->IsClick( BUT_RIGHT ) )
238  {
239  // Warp after context menu only if dragging...
240  if( !item )
242 
244  }
245  else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
246  {
247  static_cast<LIB_ITEM*>( item )->SetPosition( wxPoint( cursorPos.x, -cursorPos.y ) );
248  m_view->ClearPreview();
249  m_view->AddToPreview( item->Clone() );
250  }
251  else
252  {
253  evt->SetPassEvent();
254  }
255 
256  // Enable autopanning and cursor capture only when there is an item to be placed
257  getViewControls()->SetAutoPan( item != nullptr );
258  getViewControls()->CaptureCursor( item != nullptr );
259  }
260 
262  return 0;
263 }
264 
265 
267 {
268  SYMBOL_EDITOR_SETTINGS* settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
269  KICAD_T type = aEvent.Parameter<KICAD_T>();
270 
271  // We might be running as the same shape in another co-routine. Make sure that one
272  // gets whacked.
274 
276  getViewControls()->ShowCursor( true );
277 
278  std::string tool = aEvent.GetCommandStr().get();
279  m_frame->PushTool( tool );
280  Activate();
281 
282  LIB_PART* part = m_frame->GetCurPart();
283  LIB_ITEM* item = nullptr;
284 
285  // Prime the pump
286  if( aEvent.HasPosition() )
288 
289  auto setCursor =
290  [&]()
291  {
293  };
294 
295  // Set initial cursor
296  setCursor();
297 
298  // Main loop: keep receiving events
299  while( TOOL_EVENT* evt = Wait() )
300  {
301  setCursor();
302 
303  VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
304 
305  auto cleanup =
306  [&] ()
307  {
309  m_view->ClearPreview();
310  delete item;
311  item = nullptr;
312  };
313 
314  if( evt->IsCancelInteractive() )
315  {
316  if( item )
317  cleanup();
318  else
319  {
320  m_frame->PopTool( tool );
321  break;
322  }
323  }
324  else if( evt->IsActivate() )
325  {
326  if( item )
327  cleanup();
328 
329  if( evt->IsPointEditor() )
330  {
331  // don't exit (the point editor runs in the background)
332  }
333  else if( evt->IsMoveTool() )
334  {
335  // leave ourselves on the stack so we come back after the move
336  break;
337  }
338  else
339  {
340  m_frame->PopTool( tool );
341  break;
342  }
343  }
344  else if( evt->IsClick( BUT_LEFT ) && !item )
345  {
346  if( !part )
347  continue;
348 
350 
351  switch( type )
352  {
353  case LIB_ARC_T: item = new LIB_ARC( part ); break;
354  case LIB_CIRCLE_T: item = new LIB_CIRCLE( part ); break;
355  case LIB_POLYLINE_T: item = new LIB_POLYLINE( part ); break;
356  case LIB_RECTANGLE_T: item = new LIB_RECTANGLE( part ); break;
357  default: break; // keep compiler quiet
358  }
359 
360  wxASSERT( item );
361 
362  item->SetWidth( settings->m_Defaults.line_width );
363  item->SetFillMode( m_lastFillStyle );
364  item->SetFlags( IS_NEW );
365  item->BeginEdit( wxPoint( cursorPos.x, -cursorPos.y ) );
366 
367  if( m_drawSpecificUnit )
368  item->SetUnit( m_frame->GetUnit() );
369 
371  item->SetConvert( m_frame->GetConvert() );
372 
373  m_selectionTool->AddItemToSel( item );
374  }
375  else if( item && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
376  || evt->IsAction( &EE_ACTIONS::finishDrawing ) ) )
377  {
378  if( evt->IsDblClick( BUT_LEFT ) || evt->IsAction( &EE_ACTIONS::finishDrawing )
379  || !item->ContinueEdit( wxPoint( cursorPos.x, -cursorPos.y ) ) )
380  {
381  item->EndEdit();
382  item->ClearEditFlags();
383  m_view->ClearPreview();
384 
385  m_frame->SaveCopyInUndoList( part );
386  part->AddDrawItem( item );
387  item = nullptr;
388 
389  m_frame->RebuildView();
390  m_frame->OnModify();
392  }
393  }
394  else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
395  {
396  item->CalcEdit( wxPoint( cursorPos.x, -cursorPos.y) );
397  m_view->ClearPreview();
398  m_view->AddToPreview( item->Clone() );
399  }
400  else if( evt->IsDblClick( BUT_LEFT ) && !item )
401  {
403  }
404  else if( evt->IsClick( BUT_RIGHT ) )
405  {
406  // Warp after context menu only if dragging...
407  if( !item )
409 
411  }
412  else
413  {
414  evt->SetPassEvent();
415  }
416 
417  // Enable autopanning and cursor capture only when there is a shape being drawn
418  getViewControls()->SetAutoPan( item != nullptr );
419  getViewControls()->CaptureCursor( item != nullptr );
420  }
421 
423  return 0;
424 }
425 
426 
428 {
429  getViewControls()->ShowCursor( true );
430 
431  std::string tool = aEvent.GetCommandStr().get();
432  m_frame->PushTool( tool );
433  Activate();
434 
435  auto setCursor =
436  [&]()
437  {
439  };
440 
441  // Set initial cursor
442  setCursor();
443 
444  // Main loop: keep receiving events
445  while( TOOL_EVENT* evt = Wait() )
446  {
447  setCursor();
448 
449  if( evt->IsCancelInteractive() )
450  {
451  m_frame->PopTool( tool );
452  break;
453  }
454  else if( evt->IsActivate() )
455  {
456  m_frame->PopTool( tool );
457  break;
458  }
459  else if( evt->IsClick( BUT_LEFT ) )
460  {
461  LIB_PART* part = m_frame->GetCurPart();
462 
463  if( !part )
464  continue;
465 
466  VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
467  wxPoint offset( -cursorPos.x, cursorPos.y );
468 
469  part->SetOffset( offset );
470 
471  // Refresh the view without changing the viewport
472  auto center = m_view->GetCenter();
473  center.x += offset.x;
474  center.y -= offset.y;
475  m_view->SetCenter( center );
477  m_frame->OnModify();
478  }
479  else if( evt->IsClick( BUT_RIGHT ) )
480  {
482  }
483  else
484  {
485  evt->SetPassEvent();
486  }
487  }
488 
490  return 0;
491 }
492 
493 
495 {
497  LIB_PART* part = m_frame->GetCurPart();
498  LIB_PIN* sourcePin = nullptr;
499 
500  if( !part )
501  return 0;
502 
503  // See if we have a pin matching our weak ptr
504  for( LIB_PIN* test = part->GetNextPin(); test; test = part->GetNextPin( test ) )
505  {
506  if( (void*) test == g_lastPinWeakPtr )
507  sourcePin = test;
508  }
509 
510  if( sourcePin )
511  {
512  LIB_PIN* pin = pinTool->RepeatPin( sourcePin );
513  g_lastPinWeakPtr = pin;
514 
516 
517  if( pin )
519  }
520 
521  return 0;
522 }
523 
524 
526 {
535 }
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current symbol.
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
static TOOL_ACTION properties
Definition: ee_actions.h:121
static TOOL_ACTION placeSymbolText
Definition: ee_actions.h:102
static TOOL_ACTION drawSymbolLines
Definition: ee_actions.h:106
TOOL_MENU m_menu
functions below are not yet implemented - their interface may change
int PlaceAnchor(const TOOL_EVENT &aEvent)
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Function Wait()
FILL_TYPE
Enum class FILL_TYPE is the set of fill types used in plotting or drawing enclosed areas.
Definition: fill_type.h:29
static TOOL_ACTION activatePointEditor
Definition: actions.h:173
Define a symbol library graphical text item.
Definition: lib_text.h:40
const VECTOR2D & GetCenter() const
Function GetCenter() Returns the center point of this VIEW (in world space coordinates)
Definition: view.h:330
void AddToPreview(EDA_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1554
virtual void SetWidth(int aWidth)=0
VIEW_CONTROLS class definition.
CONDITIONAL_MENU & GetMenu()
Function GetMenu.
Definition: tool_menu.cpp:46
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:219
void SetFillMode(FILL_TYPE aFillMode)
Definition: lib_item.h:301
void RecacheAllItems()
Function RecacheAllItems() Rebuilds GAL display lists.
Definition: view.cpp:1377
virtual void PushTool(const std::string &actionName)
NB: the definition of "tool" is different at the user level.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:141
int TwoClickPlace(const TOOL_EVENT &aEvent)
static void * g_lastPinWeakPtr
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Moves cursor to the requested position expressed in world coordinates.
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:244
virtual void CalcEdit(const wxPoint &aPosition)
Calculates the attributes of an item at aPosition when it is being edited.
Definition: lib_item.h:164
int DrawShape(const TOOL_EVENT &aEvent)
void setTransitions() override
Sets up handlers for various events.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:102
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Function Go()
void DeactivateTool()
Function DeactivateTool() Deactivates the currently active tool.
void SetCurrentCursor(KICURSOR cursor)
Function SetCurrentCursor Set the current cursor shape for this panel.
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
virtual EDA_ITEM * Clone() const
Function Clone creates a duplicate of this item with linked list members set to NULL.
Definition: eda_item.cpp:97
The base class for drawable items used by schematic library components.
Definition: lib_item.h:62
bool IsAction(const TOOL_ACTION *aAction) const
Function IsAction() Tests if the event contains an action issued upon activation of the given TOOL_AC...
Definition: tool_event.cpp:67
bool IsNew() const
Definition: eda_item.h:187
void SetOffset(const wxPoint &aOffset)
Move the part aOffset.
static TOOL_ACTION drawSymbolRectangle
Definition: ee_actions.h:103
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:69
void AddDrawItem(LIB_ITEM *aItem)
Add a new draw aItem to the draw object list.
bool Init() override
Function Init() Init() is called once upon a registration of the tool.
EE_SELECTION & GetSelection()
Function GetSelection()
virtual void WarpCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
Function WarpCursor() If enabled (.
static TOOL_ACTION placeSymbolPin
Definition: ee_actions.h:101
void SetCenter(const VECTOR2D &aCenter)
Function SetCenter() Sets the center point of the VIEW (i.e.
Definition: view.cpp:585
void SetFlags(STATUS_FLAGS aMask)
Definition: eda_item.h:220
static TOOL_ACTION addItemToSel
Selects an item (specified as the event parameter).
Definition: ee_actions.h:59
virtual bool ContinueEdit(const wxPoint aPosition)
Continue an edit in progress at aPosition.
Definition: lib_item.h:146
virtual void PopTool(const std::string &actionName)
virtual void CaptureCursor(bool aEnabled)
Function CaptureCursor() Forces the cursor to stay within the drawing panel area.
T Parameter() const
Function Parameter() Returns a non-standard parameter assigned to the event.
Definition: tool_event.h:435
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void SaveCopyInUndoList(EDA_ITEM *aItem, UNDO_REDO aUndoType=UNDO_REDO::LIBEDIT, bool aAppend=false)
Create a copy of the current symbol, and save it in the undo list.
TOOL_EVENT.
Definition: tool_event.h:171
void ClearPreview()
Definition: view.cpp:1535
static TOOL_ACTION repeatDrawItem
Definition: ee_actions.h:116
static TOOL_ACTION drawSymbolCircle
Definition: ee_actions.h:104
Define a library symbol object.
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:181
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
static TOOL_ACTION finishDrawing
Definition: ee_actions.h:108
#define IS_MOVED
Item being moved.
Definition: eda_item.h:105
LIB_PIN * RepeatPin(const LIB_PIN *aSourcePin)
LIB_PART * GetCurPart()
Return the current part being edited or NULL if none selected.
virtual void SetAutoPan(bool aEnabled)
Function SetAutoPan Turns on/off auto panning (this feature is used when there is a tool active (eg.
void SetConvert(int aConvert)
Definition: lib_item.h:298
virtual void BeginEdit(const wxPoint aPosition)
Begin drawing a component library draw item at aPosition.
Definition: lib_item.h:134
OPT< std::string > GetCommandStr() const
Definition: tool_event.h:463
void SetUnit(int aUnit)
Definition: lib_item.h:295
see class PGM_BASE
int AddItemToSel(const TOOL_EVENT &aEvent)
int RepeatDrawItem(const TOOL_EVENT &aEvent)
void VetoContextMenuMouseWarp()
Disables mouse warping after the current context menu is closed.
Definition: tool_manager.h:417
static TOOL_ACTION drawSymbolArc
Definition: ee_actions.h:105
EDA_ITEM is a base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:148
void Activate()
Function Activate() Runs the tool.
void SetPosition(const wxPoint &aPosition) override
Definition: lib_item.h:249
EE_TOOL_BASE.
Definition: ee_tool_base.h:50
bool HasPosition() const
Returns if it this event has a valid position (true for mouse events and context-menu or hotkey-based...
Definition: tool_event.h:260
virtual void SetTextAngle(double aAngle)
Definition: eda_text.h:173
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
Definition: tool_base.cpp:42
bool NoPrintableChars(wxString aString)
Return true if the string is empty or contains only whitespace.
Definition: string.cpp:365
void ClearEditFlags()
Definition: eda_item.h:239
virtual void EndEdit()
End an object editing action.
Definition: lib_item.h:153
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Adds a menu entry to run a TOOL_ACTION on selected items.
void ShowContextMenu(SELECTION &aSelection)
Function ShowContextMenu.
Definition: tool_menu.cpp:59
#define IS_NEW
New item, just created.
Definition: eda_item.h:106
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133
static TOOL_ACTION placeSymbolAnchor
Definition: ee_actions.h:107
static TOOL_ACTION refreshPreview
Definition: actions.h:109
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
static TOOL_ACTION cursorClick
Definition: actions.h:126
KICAD_T Type() const
Function Type()
Definition: eda_item.h:181
The symbol library editor main window.