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 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 #include <ee_actions.h>
25 #include <lib_edit_frame.h>
26 #include <sch_view.h>
27 #include <class_draw_panel_gal.h>
28 #include <project.h>
29 #include <id.h>
30 #include <eeschema_id.h>
31 #include <confirm.h>
32 #include <view/view_group.h>
33 #include <view/view_controls.h>
34 #include <view/view.h>
35 #include <tool/tool_manager.h>
38 #include <tools/lib_pin_tool.h>
39 #include <ee_hotkeys.h>
40 #include <class_libentry.h>
41 #include <bitmaps.h>
42 #include <lib_text.h>
44 #include <lib_arc.h>
45 #include <lib_circle.h>
46 #include <lib_polyline.h>
47 #include <lib_rectangle.h>
48 
49 // Drawing tool actions
50 TOOL_ACTION EE_ACTIONS::placeSymbolPin( "libedit.InteractiveDrawing.placeSymbolPin",
52  _( "Add Pin" ), _( "Add a pin" ),
53  pin_xpm, AF_ACTIVATE );
54 
55 TOOL_ACTION EE_ACTIONS::placeSymbolText( "libedit.InteractiveDrawing.placeSymbolText",
56  AS_GLOBAL, 0,
57  _( "Add Text" ), _( "Add a text item" ),
59 
60 TOOL_ACTION EE_ACTIONS::drawSymbolRectangle( "libedit.InteractiveDrawing.drawSymbolRectangle",
61  AS_GLOBAL, 0,
62  _( "Add Rectangle" ), _( "Add a rectangle" ),
63  add_rectangle_xpm, AF_ACTIVATE );
64 
65 TOOL_ACTION EE_ACTIONS::drawSymbolCircle( "libedit.InteractiveDrawing.drawSymbolCircle",
66  AS_GLOBAL, 0,
67  _( "Add Circle" ), _( "Add a circle" ),
68  add_circle_xpm, AF_ACTIVATE );
69 
70 TOOL_ACTION EE_ACTIONS::drawSymbolArc( "libedit.InteractiveDrawing.drawSymbolArc",
71  AS_GLOBAL, 0,
72  _( "Add Arc" ), _( "Add an arc" ),
73  add_circle_xpm, AF_ACTIVATE );
74 
75 TOOL_ACTION EE_ACTIONS::drawSymbolLines( "libedit.InteractiveDrawing.drawSymbolLines",
76  AS_GLOBAL, 0,
77  _( "Add Lines" ), _( "Add connected graphic lines" ),
78  add_circle_xpm, AF_ACTIVATE );
79 
80 TOOL_ACTION EE_ACTIONS::placeSymbolAnchor( "libedit.InteractiveDrawing.placeSymbolAnchor",
81  AS_GLOBAL, 0,
82  _( "Move Symbol Anchor" ), _( "Specify a new location for the symbol anchor" ),
83  anchor_xpm, AF_ACTIVATE );
84 
85 TOOL_ACTION EE_ACTIONS::finishDrawing( "libedit.InteractiveDrawing.finishDrawing",
86  AS_GLOBAL, 0, _( "Finish Drawing" ), _( "Finish drawing shape" ),
87  checked_ok_xpm, AF_NONE );
88 
89 
90 static void* g_lastPinWeakPtr;
91 
92 
94  EE_TOOL_BASE<LIB_EDIT_FRAME>( "libedit.InteractiveDrawing" )
95 {
96 }
97 
98 
100 {
101 }
102 
103 
105 {
107 
108  auto isDrawingCondition = [] ( const SELECTION& aSel ) {
109  LIB_ITEM* item = (LIB_ITEM*) aSel.Front();
110  return item && item->IsNew();
111  };
112 
113  m_menu.GetMenu().AddItem( EE_ACTIONS::finishDrawing, isDrawingCondition, 2 );
114 
115  return true;
116 }
117 
118 
120 {
121  m_frame->SetToolID( ID_LIBEDIT_PIN_BUTT, wxCURSOR_PENCIL, _( "Add pin" ) );
122  return doTwoClickPlace( LIB_PIN_T );
123 }
124 
125 
127 {
128  m_frame->SetToolID( ID_LIBEDIT_BODY_TEXT_BUTT, wxCURSOR_PENCIL, _( "Add text" ) );
129  return doTwoClickPlace( LIB_TEXT_T );
130 }
131 
132 
134 {
135  LIB_PIN_TOOL* pinTool = aType == LIB_PIN_T ? m_toolMgr->GetTool<LIB_PIN_TOOL>() : nullptr;
136  VECTOR2I cursorPos;
137  EDA_ITEM* item = nullptr;
138 
140  getViewControls()->ShowCursor( true );
141 
142  Activate();
143 
144  // Main loop: keep receiving events
145  while( OPT_TOOL_EVENT evt = Wait() )
146  {
147  cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
148 
149  if( TOOL_EVT_UTILS::IsCancelInteractive( evt.get() ) )
150  {
151  if( item )
152  {
154  m_view->ClearPreview();
155  delete item;
156  item = nullptr;
157 
158  if( !evt->IsActivate() )
159  continue;
160  }
161 
162  break;
163  }
164 
165  else if( evt->IsClick( BUT_LEFT ) )
166  {
167  LIB_PART* part = m_frame->GetCurPart();
168 
169  if( !part )
170  continue;
171 
172  // First click creates...
173  if( !item )
174  {
177 
178  switch( aType )
179  {
180  case LIB_PIN_T:
181  {
182  item = pinTool->CreatePin( wxPoint( cursorPos.x, -cursorPos.y), part );
183  g_lastPinWeakPtr = item;
184  break;
185  }
186  case LIB_TEXT_T:
187  {
188  LIB_TEXT* text = new LIB_TEXT( part );
189  text->SetPosition( wxPoint( cursorPos.x, -cursorPos.y) );
192 
193  DIALOG_LIB_EDIT_TEXT dlg( m_frame, text );
194 
195  if( dlg.ShowModal() != wxID_OK )
196  delete text;
197  else
198  item = text;
199 
200  break;
201  }
202  default:
203  wxFAIL_MSG( "doTwoClickPlace(): unknown type" );
204  }
205 
207 
208  // Restore cursor after dialog
210 
211  if( item )
212  {
213  item->SetFlags( IS_NEW | IS_MOVED );
214  m_view->ClearPreview();
215  m_view->AddToPreview( item->Clone() );
216  m_selectionTool->AddItemToSel( item );
217  }
218 
219  getViewControls()->SetCursorPosition( cursorPos, false );
220  }
221 
222  // ... and second click places:
223  else
224  {
225  m_frame->SaveCopyInUndoList( part );
226 
227  switch( item->Type() )
228  {
229  case LIB_PIN_T:
230  pinTool->PlacePin( (LIB_PIN*) item );
231  break;
232  case LIB_TEXT_T:
233  part->AddDrawItem( (LIB_TEXT*) item );
234  item->ClearEditFlags();
235  break;
236  default:
237  wxFAIL_MSG( "doTwoClickPlace(): unknown type" );
238  }
239 
240  item = nullptr;
241  m_view->ClearPreview();
242 
243  m_frame->RebuildView();
244  m_frame->OnModify();
245  }
246  }
247  else if( evt->IsClick( BUT_RIGHT ) )
248  {
249  // Warp after context menu only if dragging...
250  if( !item )
252 
254  }
255 
256  else if( item && ( evt->IsAction( &EE_ACTIONS::refreshPreview ) || evt->IsMotion() ) )
257  {
258  static_cast<LIB_ITEM*>( item )->SetPosition( wxPoint( cursorPos.x, -cursorPos.y) );
259  m_view->ClearPreview();
260  m_view->AddToPreview( item->Clone() );
261  }
262 
263  // Enable autopanning and cursor capture only when there is an item to be placed
264  getViewControls()->SetAutoPan( !!item );
265  getViewControls()->CaptureCursor( !!item );
266  }
267 
269 
270  return 0;
271 }
272 
273 
275 {
276  // We might be running as the same shape in another co-routine. Make sure that one
277  // gets whacked.
279 
280  if( aEvent.IsAction( &EE_ACTIONS::drawSymbolArc ) )
281  m_frame->SetToolID( ID_LIBEDIT_BODY_ARC_BUTT, wxCURSOR_PENCIL, _( "Draw Arc" ) );
282  else if( aEvent.IsAction( &EE_ACTIONS::drawSymbolCircle ) )
283  m_frame->SetToolID( ID_LIBEDIT_BODY_CIRCLE_BUTT, wxCURSOR_PENCIL, _( "Draw Circle" ) );
284  else if( aEvent.IsAction( &EE_ACTIONS::drawSymbolLines ) )
285  m_frame->SetToolID( ID_LIBEDIT_BODY_LINE_BUTT, wxCURSOR_PENCIL, _( "Draw Lines" ) );
286  else if( aEvent.IsAction( &EE_ACTIONS::drawSymbolRectangle ) )
287  m_frame->SetToolID( ID_LIBEDIT_BODY_RECT_BUTT, wxCURSOR_PENCIL, _( "Draw Rectangle" ) );
288 
290  getViewControls()->ShowCursor( true );
291 
292  Activate();
293 
294  LIB_PART* part = m_frame->GetCurPart();
295  LIB_ITEM* item = nullptr;
296 
297  // Main loop: keep receiving events
298  while( auto evt = Wait() )
299  {
300  VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
301 
302  if( TOOL_EVT_UTILS::IsCancelInteractive( evt.get() ) )
303  {
305  m_view->ClearPreview();
306 
307  if( item )
308  {
309  delete item;
310  item = nullptr;
311 
312  if( !evt->IsActivate() )
313  continue;
314  }
315 
316  break;
317  }
318 
319  else if( evt->IsClick( BUT_LEFT ) && !item )
320  {
321  if( !part )
322  continue;
323 
325 
326  switch( m_frame->GetToolId() )
327  {
328  case ID_LIBEDIT_BODY_ARC_BUTT: item = new LIB_ARC( part ); break;
329  case ID_LIBEDIT_BODY_CIRCLE_BUTT: item = new LIB_CIRCLE( part ); break;
330  case ID_LIBEDIT_BODY_LINE_BUTT: item = new LIB_POLYLINE( part ); break;
331  case ID_LIBEDIT_BODY_RECT_BUTT: item = new LIB_RECTANGLE( part ); break;
332  default: wxFAIL_MSG( "LIB_DRAWING_TOOLS:DrawShape(): unknown tool" );
333  }
334 
337  item->BeginEdit( IS_NEW, wxPoint( cursorPos.x, -cursorPos.y ) );
338 
340  item->SetUnit( m_frame->GetUnit() );
341 
343  item->SetConvert( m_frame->GetConvert() );
344 
345  m_selectionTool->AddItemToSel( item );
346  }
347 
348  else if( item && ( evt->IsClick( BUT_LEFT )
349  || evt->IsDblClick( BUT_LEFT )
350  || evt->IsAction( &EE_ACTIONS::finishDrawing ) ) )
351  {
352  if( evt->IsDblClick( BUT_LEFT )
353  || evt->IsAction( &EE_ACTIONS::finishDrawing )
354  || !item->ContinueEdit( wxPoint( cursorPos.x, -cursorPos.y ) ) )
355  {
356  item->EndEdit( wxPoint( cursorPos.x, -cursorPos.y ) );
357  m_view->ClearPreview();
358 
359  m_frame->SaveCopyInUndoList( part );
360  part->AddDrawItem( item );
361  item = nullptr;
362 
363  m_frame->RebuildView();
364  m_frame->OnModify();
365  }
366  }
367 
368  else if( item && ( evt->IsAction( &EE_ACTIONS::refreshPreview )
369  || evt->IsMotion() ) )
370  {
371  item->CalcEdit( wxPoint( cursorPos.x, -cursorPos.y) );
372  m_view->ClearPreview();
373  m_view->AddToPreview( item->Clone() );
374  }
375 
376  else if( evt->IsDblClick( BUT_LEFT ) && !item )
377  {
379  }
380 
381  else if( evt->IsClick( BUT_RIGHT ) )
382  {
383  // Warp after context menu only if dragging...
384  if( !item )
386 
388  }
389 
390  // Enable autopanning and cursor capture only when there is a shape being drawn
391  getViewControls()->SetAutoPan( !!item );
392  getViewControls()->CaptureCursor( !!item );
393  }
394 
396 
397  return 0;
398 }
399 
400 
402 {
403  m_frame->SetToolID( ID_LIBEDIT_ANCHOR_ITEM_BUTT, wxCURSOR_PENCIL, _( "Move symbol anchor" ) );
404 
405  getViewControls()->ShowCursor( true );
406  getViewControls()->SetSnapping( true );
407 
408  Activate();
409 
410  // Main loop: keep receiving events
411  while( OPT_TOOL_EVENT evt = Wait() )
412  {
413  if( TOOL_EVT_UTILS::IsCancelInteractive( evt.get() ) )
414  {
415  break;
416  }
417  else if( evt->IsClick( BUT_LEFT ) )
418  {
419  LIB_PART* part = m_frame->GetCurPart();
420 
421  if( !part )
422  continue;
423 
424  VECTOR2I cursorPos = getViewControls()->GetCursorPosition( !evt->Modifier( MD_ALT ) );
425  wxPoint offset( -cursorPos.x, cursorPos.y );
426 
427  part->SetOffset( offset );
428 
429  // Refresh the view without changing the viewport
430  auto center = m_view->GetCenter();
431  center.x += offset.x;
432  center.y -= offset.y;
433  m_view->SetCenter( center );
435  m_frame->OnModify();
436  }
437  else if( evt->IsClick( BUT_RIGHT ) )
438  {
440  }
441  }
442 
444 
445  return 0;
446 }
447 
448 
450 {
452  LIB_PART* part = m_frame->GetCurPart();
453  LIB_PIN* sourcePin = nullptr;
454 
455  if( !part )
456  return 0;
457 
458  // See if we have a pin matching our weak ptr
459  for( LIB_PIN* test = part->GetNextPin(); test; test = part->GetNextPin( test ) )
460  {
461  if( (void*) test == g_lastPinWeakPtr )
462  sourcePin = test;
463  }
464 
465  if( sourcePin )
466  {
467  LIB_PIN* pin = pinTool->RepeatPin( sourcePin );
468  g_lastPinWeakPtr = pin;
469 
471 
472  if( pin )
474  }
475 
476  return 0;
477 }
478 
479 
481 {
490 }
void SetTextAngle(double aAngle)
Definition: eda_text.h:173
virtual void ShowCursor(bool aEnabled)
Function ShowCursor() Enables or disables display of cursor.
bool m_DrawSpecificUnit
Specify which component parts the current draw item applies to.
LIB_PART * GetCurPart() const
Return the current part being edited or NULL if none selected.
static TOOL_ACTION properties
Definition: ee_actions.h:124
static TOOL_ACTION placeSymbolText
Definition: ee_actions.h:107
static TOOL_ACTION drawSymbolLines
Definition: ee_actions.h:111
virtual void EndEdit(const wxPoint &aPosition)
End an object editing action.
void AddToPreview(EDA_ITEM *aItem, bool aTakeOwnership=true)
Definition: sch_view.cpp:145
int PlaceAnchor(const TOOL_EVENT &aEvent)
void SetPosition(const wxPoint &aPosition)
This file is part of the common library.
Define a symbol library graphical text item.
Definition: lib_text.h:44
const VECTOR2D & GetCenter() const
Function GetCenter() Returns the center point of this VIEW (in world space coordinates)
Definition: view.h:339
virtual void SetWidth(int aWidth)=0
Set the width of the draw item to aWidth.
VIEW_CONTROLS class definition.
virtual void MoveCursorToCrossHair() override
Function MoveCursorToCrossHair warps the cursor to the current cross hair position.
CONDITIONAL_MENU & GetMenu()
Function GetMenu.
Definition: tool_menu.cpp:46
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:216
void RecacheAllItems()
Function RecacheAllItems() Rebuilds GAL display lists.
Definition: view.cpp:1401
static FILL_T g_LastFillStyle
OPT_TOOL_EVENT Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Function Wait()
virtual void SetSnapping(bool aEnabled)
Function SetSnapping() Enables/disables snapping cursor to grid.
static TOOL_ACTION refreshPreview
Definition: ee_actions.h:168
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:125
static int g_LastLineWidth
static int LegacyHotKey(int aHotKey)
Creates a hot key code that refers to a legacy hot key setting, instead of a particular key.
Definition: tool_action.h:165
static void * g_lastPinWeakPtr
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:231
virtual void CalcEdit(const wxPoint &aPosition)
Calculates the attributes of an item at aPosition when it is being edited.
int DrawShape(const TOOL_EVENT &aEvent)
void setTransitions() override
Sets up handlers for various events.
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.
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.
The base class for drawable items used by schematic library components.
Definition: lib_draw_item.h:67
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:54
bool IsNew() const
Definition: base_struct.h:222
int PlacePin(const TOOL_EVENT &aEvent)
void SetOffset(const wxPoint &aOffset)
Move the part aOffset.
bool m_DrawSpecificConvert
Convert of the item currently being drawn.
static TOOL_ACTION drawSymbolRectangle
Definition: ee_actions.h:108
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.
#define IS_NEW
New item, just created.
Definition: base_struct.h:114
static TOOL_ACTION placeSymbolPin
Definition: ee_actions.h:106
void SetCenter(const VECTOR2D &aCenter)
Function SetCenter() Sets the center point of the VIEW (i.e.
Definition: view.cpp:601
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:259
static TOOL_ACTION addItemToSel
Selects an item (specified as the event parameter).
Definition: ee_actions.h:60
int doTwoClickPlace(KICAD_T aType)
virtual bool ContinueEdit(const wxPoint aPosition)
Continue an edit in progress at aPosition.
virtual void CaptureCursor(bool aEnabled)
Function CaptureCursor() Forces the cursor to stay within the drawing panel area.
Class LIB_ITEM definition.
static double g_LastTextAngle
SCH_DRAW_PANEL * GetCanvas() const override
Class TOOL_EVENT.
Definition: tool_event.h:167
void ClearPreview()
Definition: sch_view.cpp:133
static TOOL_ACTION repeatDrawItem
Definition: ee_actions.h:119
static TOOL_ACTION drawSymbolCircle
Definition: ee_actions.h:109
Define a library symbol object.
VIEW_GROUP extends VIEW_ITEM by possibility of grouping items into a single object.
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:143
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:57
static TOOL_ACTION finishDrawing
Definition: ee_actions.h:113
virtual void SetToolID(int aId, int aCursor, const wxString &aToolMsg)
Set the tool command ID to aId and sets the cursor to aCursor.
bool IsCancelInteractive(const TOOL_EVENT &aEvt)
Function IsCancelInteractive()
Definition: tool_event.cpp:177
All active tools
Definition: tool_event.h:143
LIB_PIN * RepeatPin(const LIB_PIN *aSourcePin)
TOOL_MENU m_menu
Menu model displayed by the tool.
Definition: ee_tool_base.h:147
virtual void SetAutoPan(bool aEnabled)
Function SetAutoPan Turns on/off auto panning (this feature is used when there is a tool active (eg.
void SetFillMode(FILL_T aFillMode)
void SetConvert(int aConvert)
virtual void BeginEdit(STATUS_FLAGS aEditMode, const wxPoint aPosition)
Begin an editing a component library draw item in aEditMode at aPosition.
virtual void SetNoToolSelected()
Select the ID_NO_TOOL_SELECTED id tool (Idle tool)
void SetUnit(int aUnit)
int PlaceText(const TOOL_EVENT &aEvent)
The symbol library editor main window.
int AddItemToSel(const TOOL_EVENT &aEvent)
Class TOOL_ACTION.
Definition: tool_action.h:46
int RepeatDrawItem(const TOOL_EVENT &aEvent)
void SetIgnoreMouseEvents(bool aIgnore)
void VetoContextMenuMouseWarp()
Disables mouse warping after the current context menu is closed.
Definition: tool_manager.h:385
static int g_LastTextSize
static TOOL_ACTION drawSymbolArc
Definition: ee_actions.h:110
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:157
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current symbol.
void Activate()
Function Activate() Runs the tool.
Class EE_TOOL_BASE.
Definition: ee_tool_base.h:49
static const char * text_xpm[]
KIGFX::VIEW_CONTROLS * getViewControls() const
Function getViewControls()
Definition: tool_base.cpp:41
LIB_PIN * CreatePin(const VECTOR2I &aPosition, LIB_PART *aPart)
void ClearEditFlags()
Definition: base_struct.h:276
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Function AddItem()
bool PlacePin(LIB_PIN *aPin)
void ShowContextMenu(SELECTION &aSelection)
Function ShowContextMenu.
Definition: tool_menu.cpp:59
void SaveCopyInUndoList(EDA_ITEM *ItemToCopy, UNDO_REDO_T undoType=UR_LIBEDIT, bool aAppend=false)
Create a copy of the current component, and save it in the undo list.
static TOOL_ACTION placeSymbolAnchor
Definition: ee_actions.h:112
int GetToolId() const
Definition: draw_frame.h:524
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false)=0
Moves cursor to the requested position expressed in world coordinates.
VECTOR2D GetCursorPosition() const
Returns the current cursor position in world coordinates.
OPT< TOOL_EVENT > OPT_TOOL_EVENT
Definition: tool_event.h:486
KICAD_T Type() const
Function Type()
Definition: base_struct.h:204
#define IS_MOVED
Item being moved.
Definition: base_struct.h:113