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