KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The 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, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <tool/tool_manager.h>
24
25#include <sch_commit.h>
26#include <kidialog.h>
27#include <sch_actions.h>
29#include <increment.h>
32#include <pgm_base.h>
33#include <wx/debug.h>
34
35
39static bool g_LastPinCommonBodyStyle = false;
40static bool g_LastPinCommonUnit = false;
41static bool g_LastPinVisible = true;
42
43// The -1 is a non-valid value to trigger delayed initialization
44static int g_LastPinLength = -1;
45static int g_LastPinNameSize = -1;
46static int g_LastPinNumSize = -1;
47
48static int GetLastPinLength()
49{
50 if( g_LastPinLength == -1 )
51 {
53 g_LastPinLength = schIUScale.MilsToIU( cfg->m_Defaults.pin_length );
54 }
55
56 return g_LastPinLength;
57}
58
60{
61 if( g_LastPinNameSize == -1 )
62 {
64 g_LastPinNameSize = schIUScale.MilsToIU( cfg->m_Defaults.pin_name_size );
65 }
66
67 return g_LastPinNameSize;
68}
69
71{
72 if( g_LastPinNumSize == -1 )
73 {
75 g_LastPinNumSize = schIUScale.MilsToIU( cfg->m_Defaults.pin_num_size );
76 }
77
78 return g_LastPinNumSize;
79}
80
81
86
87
89{
91
92 auto canEdit =
93 [this]( const SELECTION& sel )
94 {
96
97 return editor && editor->IsSymbolGraphicallyEditable();
98 };
99
100 static const std::vector<KICAD_T> pinTypes = { SCH_PIN_T };
101
102 auto singlePinCondition = SCH_CONDITIONS::Count( 1 ) && SCH_CONDITIONS::OnlyTypes( pinTypes );
103
104 CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
105
106 selToolMenu.AddSeparator( 250 );
107 selToolMenu.AddItem( SCH_ACTIONS::pushPinLength, canEdit && singlePinCondition, 250 );
108 selToolMenu.AddItem( SCH_ACTIONS::pushPinNameSize, canEdit && singlePinCondition, 250 );
109 selToolMenu.AddItem( SCH_ACTIONS::pushPinNumSize, canEdit && singlePinCondition, 250 );
110
111 return true;
112}
113
114
116 const SCH_PIN& aOriginalPin )
117{
118 // A pin can have a unit id = 0 (common to all units) to unit count, so we need a buffer
119 // size = GetUnitCount()+1 to store a value in a vector when using the unit id as index.
120 std::vector<bool> got_unit( aSymbol->GetUnitCount() + 1 );
121
122 auto markUnit =
123 [&got_unit]( int aUnit )
124 {
125 if( aUnit >= 0 && static_cast<size_t>( aUnit ) < got_unit.size() )
126 got_unit[static_cast<size_t>( aUnit )] = true;
127 };
128
129 auto unitDone =
130 [&got_unit]( int aUnit )
131 {
132 return aUnit >= 0 && static_cast<size_t>( aUnit ) < got_unit.size()
133 && got_unit[static_cast<size_t>( aUnit )];
134 };
135
136 markUnit( aPin->GetUnit() );
137
138 int removed = 0;
139
140 for( SCH_PIN* other : aSymbol->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES ) )
141 {
142 if( other == aPin )
143 continue;
144
148 if( unitDone( other->GetUnit() ) )
149 continue;
150
151 if( other->GetPosition() != aOriginalPin.GetPosition()
152 || other->GetOrientation() != aOriginalPin.GetOrientation()
153 || other->GetType() != aOriginalPin.GetType()
154 || other->IsVisible() != aOriginalPin.IsVisible()
155 || other->GetName() != aOriginalPin.GetName() )
156 {
157 continue;
158 }
159
160 if( other->GetBodyStyle() == aPin->GetBodyStyle() )
161 {
162 other->ChangeLength( aPin->GetLength() );
163
164 // Must be done after ChangeLength(), which can alter the position
165 other->SetPosition( aPin->GetPosition() );
166
167 other->SetShape( aPin->GetShape() );
168 }
169
170 other->SetOrientation( aPin->GetOrientation() );
171 other->SetType( aPin->GetType() );
172 other->SetVisible( aPin->IsVisible() );
173 other->SetName( aPin->GetName() );
174 other->SetNameTextSize( aPin->GetNameTextSize() );
175 other->SetNumberTextSize( aPin->GetNumberTextSize() );
176
177 markUnit( other->GetUnit() );
178
179 // Unit or body style 0 means aPin applies to all of them, making the matching pin
180 // redundant. Delete last, because RemoveDrawItem() frees the pin.
181 bool coversBodyStyles = aPin->GetBodyStyle() == ALL_BODY_STYLES
182 && ( aPin->GetUnit() == ALL_UNITS || other->GetUnit() == aPin->GetUnit() );
183 bool coversUnits = aPin->GetUnit() == ALL_UNITS
184 && ( aPin->GetBodyStyle() == ALL_BODY_STYLES
185 || other->GetBodyStyle() == aPin->GetBodyStyle() );
186
187 if( coversBodyStyles || coversUnits )
188 {
189 aSymbol->RemoveDrawItem( other );
190 removed++;
191 }
192 }
193
194 return removed;
195}
196
197
198bool SYMBOL_EDITOR_PIN_TOOL::EditPinProperties( SCH_PIN* aPin, bool aFocusPinNumber )
199{
200 SCH_PIN original_pin( *aPin );
201 DIALOG_PIN_PROPERTIES dlg( m_frame, aPin, aFocusPinNumber );
202 SCH_COMMIT commit( m_frame );
203 LIB_SYMBOL* parentSymbol = static_cast<LIB_SYMBOL*>( aPin->GetParentSymbol() );
204
205 if( aPin->GetEditFlags() == 0 )
206 commit.Modify( parentSymbol, m_frame->GetScreen() );
207
208 if( dlg.ShowModal() == wxID_CANCEL )
209 return false;
210
211 int removedPins = 0;
212
213 if( !aPin->IsNew() && m_frame->SynchronizePins() && parentSymbol )
214 removedPins = SynchronizeOtherUnits( parentSymbol, aPin, original_pin );
215
216 commit.Push( _( "Edit Pin Properties" ) );
217
218 // RemoveDrawItem() leaves the freed pins in the view, where hit testing would hand them to
219 // the next edit. RebuildView() empties the selection container without clearing SELECTED,
220 // so drop the selection through the tool.
221 if( removedPins > 0 )
222 {
224 m_frame->RebuildView();
225 }
226
227 std::vector<MSG_PANEL_ITEM> items;
228 aPin->GetMsgPanelInfo( m_frame, items );
229 m_frame->SetMsgPanel( items );
230
231 // Save the pin properties to use for the next new pin.
235 g_LastPinLength = aPin->GetLength();
236 g_LastPinShape = aPin->GetShape();
237 g_LastPinType = aPin->GetType();
240 g_LastPinVisible = aPin->IsVisible();
241
242 return true;
243}
244
245
247{
248 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
249 bool ask_for_pin = true; // Test for another pin in same position in other units
250
251 std::vector<SCH_PIN*> pins = symbol->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES );
252
253 for( SCH_PIN* test : pins )
254 {
255 if( test == aPin || aPin->GetPosition() != test->GetPosition() || test->GetEditFlags() )
256 continue;
257
258 // test for same body style
259 if( test->GetBodyStyle() != ALL_BODY_STYLES && test->GetBodyStyle() != aPin->GetBodyStyle() )
260 continue;
261
262 if( ask_for_pin && m_frame->SynchronizePins() )
263 {
264 wxString msg;
265 msg.Printf( _( "This position is already occupied by another pin, in unit %d." ),
266 test->GetUnit() );
267
268 KIDIALOG dlg( m_frame, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
269 dlg.SetExtendedMessage( _( "Disable the 'Synchronized Pins Mode' option to avoid this message." ) );
270 dlg.SetOKLabel( _( "Place Pin Anyway" ) );
271 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
272
273 bool status = dlg.ShowModal() == wxID_OK;
274
275 if( !status )
276 {
277 if( aPin->IsNew() && !aPin->HasFlag( IS_PASTED ) )
278 delete aPin;
279
280 return false;
281 }
282 else
283 {
284 ask_for_pin = false;
285 }
286 }
287 }
288
289 if( aPin->IsNew() && !aPin->HasFlag( IS_PASTED ) )
290 {
292 g_LastPinType = aPin->GetType();
293 g_LastPinShape = aPin->GetShape();
294
295 if( m_frame->SynchronizePins() )
296 CreateImagePins( aCommit, aPin );
297
298 symbol->AddDrawItem( aPin );
299 aPin->ClearFlags( IS_NEW );
300 }
301
302 // Put linked pins in new position, and clear flags
303 for( SCH_PIN* pin : pins )
304 {
305 if( ( pin->GetEditFlags() & IS_LINKED ) == 0 )
306 continue;
307
308 pin->SetPosition( aPin->GetPosition() );
309 pin->ClearFlags();
310 }
311
312 m_frame->RebuildView();
313 m_frame->OnModify();
314
315 return true;
316}
317
318
319/*
320 * Create a new pin.
321 */
323{
324 aSymbol->ClearTempFlags();
325
326 SCH_PIN* pin = new SCH_PIN( aSymbol );
327
328 pin->SetFlags( IS_NEW );
329
330 // Flag pins to consider
331 if( m_frame->SynchronizePins() )
332 pin->SetFlags( IS_LINKED );
333
334 pin->SetPosition( aPosition );
335 pin->SetLength( GetLastPinLength() );
336 pin->SetOrientation( g_LastPinOrient );
337 pin->SetType( g_LastPinType );
338 pin->SetShape( g_LastPinShape );
339 pin->SetNameTextSize( GetLastPinNameSize() );
340 pin->SetNumberTextSize( GetLastPinNumSize() );
341 pin->SetBodyStyle( g_LastPinCommonBodyStyle ? 0 : m_frame->GetBodyStyle() );
342 pin->SetUnit( g_LastPinCommonUnit ? 0 : m_frame->GetUnit() );
343 pin->SetVisible( g_LastPinVisible );
344
345 if( !EditPinProperties( pin, false ) )
346 {
347 delete pin;
348 pin = nullptr;
349 }
350
351 return pin;
352}
353
354
356{
357 int ii;
358 SCH_PIN* newPin;
359
360 // if "synchronize pins editing" option is off, do not create any similar pin for other
361 // units and/or shapes: each unit is edited regardless other units or body
362 if( !m_frame->SynchronizePins() )
363 return;
364
365 if( aPin->GetUnit() == ALL_UNITS ) // Pin common to all units: no need to create similar pins.
366 return;
367
368 // When units are interchangeable, all units are expected to have similar pins
369 // at the same position
370 // to facilitate pin editing, create pins for all other units for the current body style
371 // at the same position as aPin
372
373 for( ii = 1; ii <= aPin->GetParentSymbol()->GetUnitCount(); ii++ )
374 {
375 if( ii == aPin->GetUnit() )
376 continue;
377
378 // Already called Modify() on parent symbol; no need for Modify() calls on individual items
380 newPin = static_cast<SCH_PIN*>( aPin->Duplicate( true, &dummy ) );
381
382 // To avoid mistakes, gives this pin a new pin number because
383 // it does no have the save pin number as the master pin
384 // Because we do not know the actual number, give it a temporary number
385 wxString unknownNum;
386 unknownNum.Printf( "%s-U%c", aPin->GetNumber(), wxChar( 'A' + ii - 1 ) );
387 newPin->SetNumber( unknownNum );
388
389 newPin->SetUnit( ii );
390
391 try
392 {
393 LIB_SYMBOL* symbol = static_cast<LIB_SYMBOL*>( aPin->GetParentSymbol() );
394 symbol->AddDrawItem( newPin );
395 }
396 catch( const boost::bad_pointer& e )
397 {
398 wxFAIL_MSG( wxString::Format( wxT( "Boost pointer exception occurred: %s" ), e.what() ));
399 delete newPin;
400 return;
401 }
402
403 newPin->ClearFlags( IS_NEW );
404 }
405}
406
407
409{
410 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
411 SCH_SELECTION& selection = m_selectionTool->GetSelection();
412 SCH_PIN* sourcePin = dynamic_cast<SCH_PIN*>( selection.Front() );
413
414 if( !sourcePin )
415 return 0;
416
418
420 {
421 if( pin == sourcePin )
422 continue;
423
424 if( aEvent.IsAction( &SCH_ACTIONS::pushPinLength ) )
425 {
426 if( pin->GetBodyStyle() == ALL_BODY_STYLES || pin->GetBodyStyle() == m_frame->GetBodyStyle() )
427 pin->ChangeLength( sourcePin->GetLength() );
428 }
429 else if( aEvent.IsAction( &SCH_ACTIONS::pushPinNameSize ) )
430 {
431 pin->SetNameTextSize( sourcePin->GetNameTextSize() );
432 }
433 else if( aEvent.IsAction( &SCH_ACTIONS::pushPinNumSize ) )
434 {
435 pin->SetNumberTextSize( sourcePin->GetNumberTextSize() );
436 }
437 }
438
439 m_frame->RebuildView();
440 m_frame->OnModify();
441
442 return 0;
443}
444
445
446// Create a new pin based on the previous pin with an incremented pin number.
448{
449 SCH_COMMIT commit( m_frame );
450 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
451
452 commit.Modify( symbol, m_frame->GetScreen() );
453
454 SCH_PIN* pin = static_cast<SCH_PIN*>( aSourcePin->Duplicate( true, &commit ) );
455
456 pin->ClearFlags();
457 pin->SetFlags( IS_NEW );
458
460 {
461 VECTOR2I step;
462
463 switch( pin->GetOrientation() )
464 {
465 default:
466 case PIN_ORIENTATION::PIN_RIGHT: step.y = schIUScale.MilsToIU( cfg->m_Repeat.pin_step ); break;
467 case PIN_ORIENTATION::PIN_UP: step.x = schIUScale.MilsToIU( cfg->m_Repeat.pin_step ); break;
468 case PIN_ORIENTATION::PIN_DOWN: step.x = schIUScale.MilsToIU( cfg->m_Repeat.pin_step) ; break;
469 case PIN_ORIENTATION::PIN_LEFT: step.y = schIUScale.MilsToIU( cfg->m_Repeat.pin_step ); break;
470 }
471
472 pin->Move( step );
473
474 wxString nextName = pin->GetName();
475 IncrementString( nextName, cfg->m_Repeat.label_delta );
476 pin->SetName( nextName );
477
478 wxString nextNumber = pin->GetNumber();
479 IncrementString( nextNumber, cfg->m_Repeat.label_delta );
480 pin->SetNumber( nextNumber );
481 }
482
483 if( m_frame->SynchronizePins() )
484 pin->SetFlags( IS_LINKED );
485
486 if( PlacePin( &commit, pin ) )
487 {
488 commit.Push( _( "Repeat Pin" ) );
489 return pin;
490 }
491
492 return nullptr;
493}
494
495
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:130
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:102
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.
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
int ShowModal() override
EDA_ITEM_FLAGS GetEditFlags() const
Definition eda_item.h:170
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:160
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:168
bool IsNew() const
Definition eda_item.h:131
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:38
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:51
int ShowModal() override
Definition kidialog.cpp:89
Define a library symbol object.
Definition lib_symbol.h:114
void ClearTempFlags() override
Clears the status flag all draw objects in this symbol.
void RemoveDrawItem(SCH_ITEM *aItem)
Remove draw aItem from list.
int GetUnitCount() const override
std::vector< SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const override
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
static TOOL_ACTION pushPinLength
static TOOL_ACTION pushPinNameSize
static TOOL_ACTION pushPinNumSize
Commit for the schematic and symbol editors.
Definition sch_commit.h:54
void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
SCH_ITEM * Duplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr, bool aDoClone=false) const
Routine to create a new copy of given item.
Definition sch_item.cpp:191
const SYMBOL * GetParentSymbol() const
Definition sch_item.cpp:350
int GetBodyStyle() const
Definition sch_item.h:253
int GetUnit() const
Definition sch_item.h:243
virtual void SetUnit(int aUnit)
Definition sch_item.h:242
int GetNumberTextSize() const
Definition sch_pin.cpp:882
int GetLength() const
Definition sch_pin.cpp:421
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
Definition sch_pin.cpp:1625
void SetNumber(const wxString &aNumber)
Definition sch_pin.cpp:842
bool IsVisible() const
Definition sch_pin.cpp:513
const wxString & GetName() const
Definition sch_pin.cpp:527
PIN_ORIENTATION GetOrientation() const
Definition sch_pin.cpp:386
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:378
int GetNameTextSize() const
Definition sch_pin.cpp:856
const wxString & GetNumber() const
Definition sch_pin.h:144
GRAPHIC_PINSHAPE GetShape() const
Definition sch_pin.cpp:400
ELECTRICAL_PINTYPE GetType() const
Definition sch_pin.cpp:435
void saveCopyInUndoList(EDA_ITEM *aItem, UNDO_REDO aType, bool aAppend=false, bool aDirtyConnectivity=true)
bool Init() override
Init() is called once upon a registration of the tool.
SCH_TOOL_BASE(const std::string &aName)
SCH_SELECTION_TOOL * m_selectionTool
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.
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
EDA_ITEM * Front() const
Definition selection.h:176
void setTransitions() override
Set up handlers for various events.
int PushPinProperties(const TOOL_EVENT &aEvent)
bool EditPinProperties(SCH_PIN *aPin, bool aFocusPinNumber)
void CreateImagePins(SCH_COMMIT *aCommit, SCH_PIN *aPin)
SCH_PIN * RepeatPin(const SCH_PIN *aSourcePin)
bool Init() override
Init() is called once upon a registration of the tool.
SCH_PIN * CreatePin(const VECTOR2I &aPosition, LIB_SYMBOL *aSymbol)
static int SynchronizeOtherUnits(LIB_SYMBOL *aSymbol, SCH_PIN *aPin, const SCH_PIN &aOriginalPin)
Propagate the edits made to aPin to the matching pins of the other units.
bool PlacePin(SCH_COMMIT *aCommit, SCH_PIN *aPin)
The symbol library editor main window.
Generic, UI-independent tool event.
Definition tool_event.h:167
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
void Go(int(SYMBOL_EDIT_FRAME::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
#define _(s)
#define IS_PASTED
Modifier on IS_NEW which indicates it came from clipboard.
#define IS_NEW
New item, just created.
#define IS_LINKED
Used in calculation to mark linked items (temporary use)
KICOMMON_API bool IncrementString(wxString &name, int aIncrement)
Generic string incrementer.
Definition increment.cpp:30
see class PGM_BASE
ELECTRICAL_PINTYPE
The symbol library pin object electrical types used in ERC tests.
Definition pin_type.h:32
@ PT_INPUT
usual pin input: must be connected
Definition pin_type.h:33
PIN_ORIENTATION
The symbol library pin object orientations.
Definition pin_type.h:101
@ PIN_UP
The pin extends upwards from the connection point: Probably on the bottom side of the symbol.
Definition pin_type.h:123
@ PIN_RIGHT
The pin extends rightwards from the connection point.
Definition pin_type.h:107
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
Definition pin_type.h:114
@ PIN_DOWN
The pin extends downwards from the connection: Probably on the top side of the symbol.
Definition pin_type.h:131
GRAPHIC_PINSHAPE
Definition pin_type.h:80
T * GetAppSettings(const char *aFilename)
std::vector< FAB_LAYER_COLOR > dummy
#define ALL_UNITS
Definition symbol.h:150
#define ALL_BODY_STYLES
Definition symbol.h:151
static GRAPHIC_PINSHAPE g_LastPinShape
static bool g_LastPinCommonUnit
static bool g_LastPinVisible
static int GetLastPinNameSize()
static ELECTRICAL_PINTYPE g_LastPinType
static bool g_LastPinCommonBodyStyle
static int GetLastPinLength()
static int g_LastPinLength
static int g_LastPinNameSize
static int g_LastPinNumSize
static int GetLastPinNumSize()
static PIN_ORIENTATION g_LastPinOrient
KIBIS_PIN * pin
@ SCH_PIN_T
Definition typeinfo.h:149
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708