KiCad PCB EDA Suite
symbol_editor_pin_tool.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-2021 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 <tool/tool_manager.h>
27 #include <symbol_edit_frame.h>
28 #include <confirm.h>
29 #include <ee_actions.h>
33 #include <pgm_base.h>
34 #include "symbol_editor_pin_tool.h"
35 
36 
40 static bool g_LastPinCommonConvert = false;
41 static bool g_LastPinCommonUnit = false;
42 static bool g_LastPinVisible = true;
43 
44 // The -1 is a non-valid value to trigger delayed initialization
45 static int g_LastPinLength = -1;
46 static int g_LastPinNameSize = -1;
47 static int g_LastPinNumSize = -1;
48 
49 static int GetLastPinLength()
50 {
51  if( g_LastPinLength == -1 )
52  {
53  auto* settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
54  g_LastPinLength = Mils2iu( settings->m_Defaults.pin_length );
55  }
56 
57  return g_LastPinLength;
58 }
59 
60 static int GetLastPinNameSize()
61 {
62  if( g_LastPinNameSize == -1 )
63  {
64  auto* settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
65  g_LastPinNameSize = Mils2iu( settings->m_Defaults.pin_name_size );
66  }
67 
68  return g_LastPinNameSize;
69 }
70 
71 static int GetLastPinNumSize()
72 {
73  if( g_LastPinNumSize == -1 )
74  {
75  auto* settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
76  g_LastPinNumSize = Mils2iu( settings->m_Defaults.pin_num_size );
77  }
78 
79  return g_LastPinNumSize;
80 }
81 
82 
83 extern bool IncrementLabelMember( wxString& name, int aIncrement );
84 
85 
87  EE_TOOL_BASE<SYMBOL_EDIT_FRAME>( "eeschema.PinEditing" )
88 {
89 }
90 
91 
93 {
95 
96  auto canEdit =
97  [&]( const SELECTION& sel )
98  {
99  SYMBOL_EDIT_FRAME* editor = static_cast<SYMBOL_EDIT_FRAME*>( m_frame );
100  wxCHECK( editor, false );
101 
102  return editor->IsSymbolEditable() && !editor->IsSymbolAlias();
103  };
104 
105  auto singlePinCondition = EE_CONDITIONS::Count( 1 ) && EE_CONDITIONS::OnlyType( LIB_PIN_T );
106 
108 
109  selToolMenu.AddSeparator( 250 );
110  selToolMenu.AddItem( EE_ACTIONS::pushPinLength, canEdit && singlePinCondition, 250 );
111  selToolMenu.AddItem( EE_ACTIONS::pushPinNameSize, canEdit && singlePinCondition, 250 );
112  selToolMenu.AddItem( EE_ACTIONS::pushPinNumSize, canEdit && singlePinCondition, 250 );
113 
114  return true;
115 }
116 
117 
119 {
120  LIB_PIN original_pin( *aPin );
121  DIALOG_PIN_PROPERTIES dlg( m_frame, aPin );
122 
123  if( aPin->GetEditFlags() == 0 )
125 
126  if( dlg.ShowModal() == wxID_CANCEL )
127  {
128  if( aPin->GetEditFlags() == 0 )
130 
131  return false;
132  }
133 
134  aPin->SetModified();
135 
136  if( !aPin->IsNew() && m_frame->SynchronizePins() && aPin->GetParent() )
137  {
138  LIB_PINS pinList;
139  aPin->GetParent()->GetPins( pinList );
140  std::vector<bool> got_unit( aPin->GetParent()->GetUnitCount() );
141 
142  got_unit[aPin->GetUnit()] = true;
143 
144  for( LIB_PIN* other : pinList )
145  {
146  if( other == aPin )
147  continue;
148 
152  if( got_unit[other->GetUnit()] )
153  continue;
154 
155  if( other->GetPosition() == original_pin.GetPosition()
156  && other->GetOrientation() == original_pin.GetOrientation()
157  && other->GetType() == original_pin.GetType()
158  && other->IsVisible() == original_pin.IsVisible()
159  && other->GetName() == original_pin.GetName() )
160  {
161  if( aPin->GetConvert() == 0 )
162  {
163  if( !aPin->GetUnit() || other->GetUnit() == aPin->GetUnit() )
164  aPin->GetParent()->RemoveDrawItem( other );
165  }
166  else if( other->GetConvert() == aPin->GetConvert() )
167  {
168  other->SetPosition( aPin->GetPosition() );
169  other->SetLength( aPin->GetLength() );
170  other->SetShape( aPin->GetShape() );
171  }
172 
173  if( aPin->GetUnit() == 0 )
174  {
175  if( !aPin->GetConvert() || other->GetConvert() == aPin->GetConvert() )
176  aPin->GetParent()->RemoveDrawItem( other );
177  }
178 
179  other->SetOrientation( aPin->GetOrientation() );
180  other->SetType( aPin->GetType() );
181  other->SetVisible( aPin->IsVisible() );
182  other->SetName( aPin->GetName() );
183  other->SetNameTextSize( aPin->GetNameTextSize() );
184  other->SetNumberTextSize( aPin->GetNumberTextSize() );
185 
186  other->SetModified();
187  got_unit[other->GetUnit()] = true;
188  }
189  }
190  }
191 
192  m_frame->UpdateItem( aPin );
193  m_frame->OnModify( );
194 
195  MSG_PANEL_ITEMS items;
196  aPin->GetMsgPanelInfo( m_frame, items );
197  m_frame->SetMsgPanel( items );
198 
199  // Save the pin properties to use for the next new pin.
203  g_LastPinLength = aPin->GetLength();
204  g_LastPinShape = aPin->GetShape();
205  g_LastPinType = aPin->GetType();
206  g_LastPinCommonConvert = aPin->GetConvert() == 0;
207  g_LastPinCommonUnit = aPin->GetUnit() == 0;
208  g_LastPinVisible = aPin->IsVisible();
209 
210  return true;
211 }
212 
213 
215 {
216  LIB_PART* part = m_frame->GetCurPart();
217  bool ask_for_pin = true; // Test for another pin in same position in other units
218 
219  for( LIB_PIN* test = part->GetNextPin(); test; test = part->GetNextPin( test ) )
220  {
221  if( test == aPin || aPin->GetPosition() != test->GetPosition() || test->GetEditFlags() )
222  continue;
223 
224  // test for same body style
225  if( test->GetConvert() && test->GetConvert() != aPin->GetConvert() )
226  continue;
227 
228  if( ask_for_pin && m_frame->SynchronizePins() )
229  {
230  wxString msg;
231  msg.Printf( _( "This position is already occupied by another pin, in unit %d." ),
232  test->GetUnit() );
233 
234  KIDIALOG dlg( m_frame, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
235  dlg.SetOKLabel( _( "Place Pin Anyway" ) );
236  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
237 
238  bool status = dlg.ShowModal() == wxID_OK;
239 
240  if( !status )
241  {
242  if( aPin->IsNew() )
243  delete aPin;
244 
245  return false;
246  }
247  else
248  {
249  ask_for_pin = false;
250  }
251  }
252  }
253 
254  if( aPin->IsNew() && !aPin->HasFlag( IS_PASTED ) )
255  {
257  g_LastPinType = aPin->GetType();
258  g_LastPinShape = aPin->GetShape();
259 
260  if( m_frame->SynchronizePins() )
261  CreateImagePins( aPin );
262 
263  part->AddDrawItem( aPin );
264  aPin->ClearFlags( IS_NEW );
265  }
266 
267  // Put linked pins in new position, and clear flags
268  for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) )
269  {
270  if( ( pin->GetEditFlags() & IS_LINKED ) == 0 )
271  continue;
272 
273  pin->MoveTo( aPin->GetPosition() );
274  pin->ClearFlags();
275  }
276 
277  m_frame->RebuildView();
278  m_frame->OnModify();
279 
280  return true;
281 }
282 
283 
284 /*
285  * Create a new pin.
286  */
288 {
289  aPart->ClearTempFlags();
290 
291  LIB_PIN* pin = new LIB_PIN( aPart );
292 
293  pin->SetFlags( IS_NEW );
294 
295  // Flag pins to consider
296  if( m_frame->SynchronizePins() )
297  pin->SetFlags( IS_LINKED );
298 
299  pin->MoveTo((wxPoint) aPosition );
300  pin->SetLength( GetLastPinLength() );
302  pin->SetType( g_LastPinType );
303  pin->SetShape( g_LastPinShape );
307  pin->SetUnit( g_LastPinCommonUnit ? 0 : m_frame->GetUnit() );
309 
310  if( !EditPinProperties( pin ) )
311  {
312  delete pin;
313  pin = nullptr;
314  }
315 
316  return pin;
317 }
318 
319 
321 {
322  int ii;
323  LIB_PIN* newPin;
324 
325  // if "synchronize pins editing" option is off, do not create any similar pin for other
326  // units and/or shapes: each unit is edited regardless other units or body
327  if( !m_frame->SynchronizePins() )
328  return;
329 
330  if( aPin->GetUnit() == 0 ) // Pin common to all units: no need to create similar pins.
331  return;
332 
333  // When units are interchangeable, all units are expected to have similar pins
334  // at the same position
335  // to facilitate pin editing, create pins for all other units for the current body style
336  // at the same position as aPin
337 
338  for( ii = 1; ii <= aPin->GetParent()->GetUnitCount(); ii++ )
339  {
340  if( ii == aPin->GetUnit() )
341  continue;
342 
343  newPin = (LIB_PIN*) aPin->Clone();
344 
345  // To avoid mistakes, gives this pin a new pin number because
346  // it does no have the save pin number as the master pin
347  // Because we do not know the actual number, give it a temporary number
348  wxString unknownNum;
349  unknownNum.Printf( "%s-U%c", aPin->GetNumber(), wxChar( 'A' + ii - 1 ) );
350  newPin->SetNumber( unknownNum );
351 
352  newPin->SetUnit( ii );
353 
354  try
355  {
356  aPin->GetParent()->AddDrawItem( newPin );
357  }
358  catch( const boost::bad_pointer& e )
359  {
360  wxLogError( "Cannot add new pin to symbol. Boost pointer error %s occurred.",
361  e.what() );
362  delete newPin;
363  return;
364  }
365 
366  newPin->ClearFlags( IS_NEW );
367  }
368 }
369 
370 
372 {
373  LIB_PART* part = m_frame->GetCurPart();
374  EE_SELECTION& selection = m_selectionTool->GetSelection();
375  LIB_PIN* sourcePin = dynamic_cast<LIB_PIN*>( selection.Front() );
376 
377  if( !sourcePin )
378  return 0;
379 
381 
382  for( LIB_PIN* pin = part->GetNextPin(); pin; pin = part->GetNextPin( pin ) )
383  {
384  if( pin == sourcePin )
385  continue;
386 
387  if( aEvent.IsAction( &EE_ACTIONS::pushPinLength ) )
388  {
389  if( !pin->GetConvert() || pin->GetConvert() == m_frame->GetConvert() )
390  pin->SetLength( sourcePin->GetLength() );
391  }
392  else if( aEvent.IsAction( &EE_ACTIONS::pushPinNameSize ) )
393  {
394  pin->SetNameTextSize( sourcePin->GetNameTextSize() );
395  }
396  else if( aEvent.IsAction( &EE_ACTIONS::pushPinNumSize ) )
397  {
398  pin->SetNumberTextSize( sourcePin->GetNumberTextSize() );
399  }
400  }
401 
402  m_frame->RebuildView();
403  m_frame->OnModify();
404 
405  return 0;
406 }
407 
408 
409 // Create a new pin based on the previous pin with an incremented pin number.
411 {
412  LIB_PIN* pin = (LIB_PIN*) aSourcePin->Clone();
413  wxPoint step;
414 
415  pin->ClearFlags();
416  pin->SetFlags( IS_NEW );
417 
418  auto* settings = Pgm().GetSettingsManager().GetAppSettings<SYMBOL_EDITOR_SETTINGS>();
419 
420  switch( pin->GetOrientation() )
421  {
422  case PIN_UP: step.x = Mils2iu(settings->m_Repeat.pin_step); break;
423  case PIN_DOWN: step.x = Mils2iu(settings->m_Repeat.pin_step); break;
424  case PIN_LEFT: step.y = Mils2iu(-settings->m_Repeat.pin_step); break;
425  case PIN_RIGHT: step.y = Mils2iu(-settings->m_Repeat.pin_step); break;
426  }
427 
428  pin->Offset( step );
429 
430  wxString nextName = pin->GetName();
431  IncrementLabelMember( nextName, settings->m_Repeat.label_delta );
432  pin->SetName( nextName );
433 
434  wxString nextNumber = pin->GetNumber();
435  IncrementLabelMember( nextNumber, settings->m_Repeat.label_delta );
436  pin->SetNumber( nextNumber );
437 
438  if( m_frame->SynchronizePins() )
439  pin->SetFlags( IS_LINKED );
440 
441  if( PlacePin( pin ) )
442  return pin;
443 
444  return nullptr;
445 }
446 
447 
449 {
453 }
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current symbol.
void SetNumberTextSize(int aSize)
Definition: lib_pin.h:178
LIB_PIN * RepeatPin(const LIB_PIN *aSourcePin)
void SetModified()
Definition: eda_item.cpp:79
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: lib_pin.cpp:825
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
Definition: confirm.cpp:56
static bool g_LastPinCommonConvert
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false)
Mark an item for refresh.
void SetOrientation(int aOrientation)
Definition: lib_pin.h:126
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:45
void MoveTo(const wxPoint &aNewPosition) override
Move a draw object to aPosition.
Definition: lib_pin.cpp:915
This file is part of the common library.
int GetOrientation() const
Definition: lib_pin.h:125
LIB_PART * GetParent() const
Definition: lib_item.h:149
std::vector< LIB_PIN * > LIB_PINS
Helper for defining a list of pin object pointers.
Definition: lib_item.h:56
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition: lib_pin.h:129
static int g_LastPinNameSize
GRAPHIC_PINSHAPE GetShape() const
Definition: lib_pin.h:128
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:46
static int g_LastPinOrient
LIB_PIN * CreatePin(const VECTOR2I &aPosition, LIB_PART *aPart)
TOOL_MENU & GetToolMenu()
static bool g_LastPinVisible
void SetLength(int aLength)
Definition: lib_pin.h:132
int PushPinProperties(const TOOL_EVENT &aEvent)
Definition: lib_pin.h:50
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
GRAPHIC_PINSHAPE
Definition: pin_type.h:54
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:106
static TOOL_ACTION pushPinNameSize
Definition: ee_actions.h:198
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
void ClearTempFlags()
Clears the status flag all draw objects in this part.
static GRAPHIC_PINSHAPE g_LastPinShape
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:70
bool IsNew() const
Definition: eda_item.h:168
bool Init() override
Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:65
void AddDrawItem(LIB_ITEM *aItem)
Add a new draw aItem to the draw object list.
Definition: lib_symbol.cpp:648
EE_SELECTION & GetSelection()
Return the set of currently selected items.
void SetNumber(const wxString &aNumber)
Definition: lib_pin.h:166
void GetPins(LIB_PINS &aList, int aUnit=0, int aConvert=0)
Return a list of pin object pointers from the draw item list.
Definition: lib_symbol.cpp:686
int GetUnit() const
Definition: lib_item.h:262
#define IS_LINKED
Used in calculation to mark linked items (temporary use)
Definition: eda_item.h:103
void SetType(ELECTRICAL_PINTYPE aType)
Definition: lib_pin.h:135
void SetFlags(STATUS_FLAGS aMask)
Definition: eda_item.h:202
int GetUnitCount() const override
For items with units, return the number of units.
bool IsSymbolAlias() const
Restore the empty editor screen, without any part or library selected.
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void saveCopyInUndoList(EDA_ITEM *aItem, UNDO_REDO aType, bool aAppend=false)
Definition: ee_tool_base.h:133
STATUS_FLAGS GetEditFlags() const
Definition: eda_item.h:207
static ELECTRICAL_PINTYPE g_LastPinType
const wxString & GetName() const
Definition: lib_pin.h:156
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.
Generic, UI-independent tool event.
Definition: tool_event.h:173
static int g_LastPinLength
Define a library symbol object.
Definition: lib_symbol.h:93
void SetVisible(bool aVisible)
Definition: lib_pin.h:148
virtual PICKED_ITEMS_LIST * PopCommandFromUndoList()
Return the last command to undo and remove it from list, nothing is deleted.
static TOOL_ACTION pushPinLength
Definition: ee_actions.h:197
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:176
static int GetLastPinNumSize()
bool IsVisible() const
Definition: lib_pin.h:147
int GetNameTextSize() const
Definition: lib_pin.h:174
Implementing DIALOG_LIB_EDIT_PIN_BASE.
int GetConvert() const
Definition: lib_item.h:265
LIB_PART * GetCurPart()
Return the current part being edited or NULL if none selected.
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Display basic info (type, part and convert) about the current item in message panel.
Definition: lib_pin.cpp:995
static int GetLastPinLength()
bool IncrementLabelMember(wxString &name, int aIncrement)
Definition: sch_text.cpp:54
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
void SetConvert(int aConvert)
Definition: lib_item.h:264
wxPoint GetPosition() const override
Definition: lib_pin.h:258
LIB_PIN * GetNextPin(LIB_PIN *aItem=NULL)
Return the next pin object from the draw list.
Definition: lib_symbol.h:365
#define IS_PASTED
Modifier on IS_NEW which indicates it came from clipboard.
Definition: eda_item.h:119
const wxString & GetNumber() const
Definition: lib_pin.h:165
ELECTRICAL_PINTYPE GetType() const
Definition: lib_pin.h:134
void SetUnit(int aUnit)
Definition: lib_item.h:261
int GetNumberTextSize() const
Definition: lib_pin.h:177
void setTransitions() override
< Set up handlers for various events.
see class PGM_BASE
void SetName(const wxString &aName)
Definition: lib_pin.h:157
bool IsSymbolEditable() const
Test if a symbol is loaded and can be edited.
const char * name
Definition: DXF_plotter.cpp:59
void SetNameTextSize(int aSize)
Definition: lib_pin.h:175
ELECTRICAL_PINTYPE
The component library pin object electrical types used in ERC tests.
Definition: pin_type.h:34
int GetLength() const
Definition: lib_pin.h:131
#define _(s)
Definition: 3d_actions.cpp:33
usual pin input: must be connected
static SELECTION_CONDITION OnlyType(KICAD_T aType)
Create a functor that tests if the selected items are only of given type.
std::vector< MSG_PANEL_ITEM > MSG_PANEL_ITEMS
Definition: msgpanel.h:97
static int g_LastPinNumSize
int ShowModal() override
Definition: confirm.cpp:100
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:203
static TOOL_ACTION pushPinNumSize
Definition: ee_actions.h:199
void CreateImagePins(LIB_PIN *aPin)
A foundation class for a tool operating on a schematic or symbol.
Definition: ee_tool_base.h:48
static bool g_LastPinCommonUnit
bool Init() override
Init() is called once upon a registration of the tool.
void Offset(const wxPoint &aOffset) override
Set the drawing object by aOffset from the current position.
Definition: lib_pin.cpp:909
bool EditPinProperties(LIB_PIN *aPin)
static int GetLastPinNameSize()
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
#define IS_NEW
New item, just created.
Definition: eda_item.h:106
bool HasFlag(STATUS_FLAGS aFlag) const
Definition: eda_item.h:205
EDA_ITEM * Front() const
Definition: selection.h:203
void RemoveDrawItem(LIB_ITEM *aItem)
Remove draw aItem from list.
Definition: lib_symbol.cpp:622
The symbol library editor main window.