KiCad PCB EDA Suite
Loading...
Searching...
No Matches
symbol_editor_edit_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, 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
26
27#include <tool/picker_tool.h>
33#include <clipboard.h>
34#include <sch_actions.h>
35#include <increment.h>
36#include <pin_layout_cache.h>
37#include <string_utils.h>
38#include <symbol_edit_frame.h>
39#include <sch_commit.h>
41#include <dialogs/dialog_text_properties.h>
46#include <view/view_controls.h>
47#include <richio.h>
49#include <sch_textbox.h>
50#include <wx/textdlg.h> // for wxTextEntryDialog
51#include <math/util.h> // for KiROUND
53
55 SCH_TOOL_BASE( "eeschema.SymbolEditTool" )
56{
57}
58
59
61{
63
66
67 wxASSERT_MSG( drawingTools, "eeschema.SymbolDrawing tool is not available" );
68
69 auto haveSymbolCondition =
70 [&]( const SELECTION& sel )
71 {
72 return m_isSymbolEditor && m_frame->GetCurSymbol();
73 };
74
75 auto canEdit =
76 [&]( const SELECTION& sel )
77 {
78 if( !m_frame->IsSymbolEditable() )
79 return false;
80
81 if( m_frame->IsSymbolAlias() )
82 {
83 for( EDA_ITEM* item : sel )
84 {
85 if( item->Type() != SCH_FIELD_T )
86 return false;
87 }
88 }
89
90 return true;
91 };
92
93 const auto canCopyText = SCH_CONDITIONS::OnlyTypes( {
100 } );
101
102 const auto canConvertStackedPins =
103 [&]( const SELECTION& sel )
104 {
105 // If multiple pins are selected, check they are all at same location
106 if( sel.Size() >= 2 )
107 {
108 std::vector<SCH_PIN*> pins;
109 for( EDA_ITEM* item : sel )
110 {
111 if( item->Type() != SCH_PIN_T )
112 return false;
113 pins.push_back( static_cast<SCH_PIN*>( item ) );
114 }
115
116 // Check that all pins are at the same location
117 VECTOR2I pos = pins[0]->GetPosition();
118 for( size_t i = 1; i < pins.size(); ++i )
119 {
120 if( pins[i]->GetPosition() != pos )
121 return false;
122 }
123 return true;
124 }
125
126 // If single pin is selected, check if there are other pins at same location
127 if( sel.Size() == 1 && sel.Front()->Type() == SCH_PIN_T )
128 {
129 SCH_PIN* selectedPin = static_cast<SCH_PIN*>( sel.Front() );
130 VECTOR2I pos = selectedPin->GetPosition();
131
132 // Get the symbol and check for other pins at same location
133 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
134 if( !symbol )
135 return false;
136
137 int coLocatedCount = 0;
138
139 for( SCH_PIN* pin : symbol->GetPins() )
140 {
141 if( pin->GetPosition() == pos )
142 {
143 coLocatedCount++;
144
145 if( coLocatedCount >= 2 )
146 return true;
147 }
148 }
149 }
150
151 return false;
152 };
153
154 const auto canExplodeStackedPin =
155 [&]( const SELECTION& sel )
156 {
157 if( sel.Size() != 1 || sel.Front()->Type() != SCH_PIN_T )
158 return false;
159
160 SCH_PIN* pin = static_cast<SCH_PIN*>( sel.Front() );
161 bool isValid;
162 std::vector<wxString> stackedNumbers = pin->GetStackedPinNumbers( &isValid );
163 return isValid && stackedNumbers.size() > 1;
164 };
165
166 // clang-format off
167 // Add edit actions to the move tool menu
168 if( moveTool )
169 {
170 CONDITIONAL_MENU& moveMenu = moveTool->GetToolMenu().GetMenu();
171
172 moveMenu.AddSeparator( 200 );
173 moveMenu.AddItem( SCH_ACTIONS::rotateCCW, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
174 moveMenu.AddItem( SCH_ACTIONS::rotateCW, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
175 moveMenu.AddItem( SCH_ACTIONS::mirrorV, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
176 moveMenu.AddItem( SCH_ACTIONS::mirrorH, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
177
178 moveMenu.AddItem( SCH_ACTIONS::swap, canEdit && SELECTION_CONDITIONS::MoreThan( 1 ), 200);
179 moveMenu.AddItem( SCH_ACTIONS::properties, canEdit && SCH_CONDITIONS::Count( 1 ), 200 );
180
181 moveMenu.AddSeparator( 300 );
184 moveMenu.AddItem( ACTIONS::copyAsText, canCopyText && SCH_CONDITIONS::IdleSelection, 300 );
185 moveMenu.AddItem( ACTIONS::duplicate, canEdit && SCH_CONDITIONS::NotEmpty, 300 );
186 moveMenu.AddItem( ACTIONS::doDelete, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
187
188 moveMenu.AddSeparator( 400 );
189 moveMenu.AddItem( ACTIONS::selectAll, haveSymbolCondition, 400 );
190 moveMenu.AddItem( ACTIONS::unselectAll, haveSymbolCondition, 400 );
191 }
192
193 // Add editing actions to the drawing tool menu
194 CONDITIONAL_MENU& drawMenu = drawingTools->GetToolMenu().GetMenu();
195
196 drawMenu.AddSeparator( 200 );
201
202 drawMenu.AddItem( SCH_ACTIONS::properties, canEdit && SCH_CONDITIONS::Count( 1 ), 200 );
203
204 // Add editing actions to the selection tool menu
205 CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
206
207 selToolMenu.AddItem( SCH_ACTIONS::rotateCCW, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
208 selToolMenu.AddItem( SCH_ACTIONS::rotateCW, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
209 selToolMenu.AddItem( SCH_ACTIONS::mirrorV, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
210 selToolMenu.AddItem( SCH_ACTIONS::mirrorH, canEdit && SCH_CONDITIONS::NotEmpty, 200 );
211
212 selToolMenu.AddItem( SCH_ACTIONS::swap, canEdit && SELECTION_CONDITIONS::MoreThan( 1 ), 200 );
213 selToolMenu.AddItem( SCH_ACTIONS::properties, canEdit && SCH_CONDITIONS::Count( 1 ), 200 );
214
215 selToolMenu.AddSeparator( 250 );
216 selToolMenu.AddItem( SCH_ACTIONS::convertStackedPins, canEdit && canConvertStackedPins, 250 );
217 selToolMenu.AddItem( SCH_ACTIONS::explodeStackedPin, canEdit && canExplodeStackedPin, 250 );
218
219 selToolMenu.AddSeparator( 300 );
222 selToolMenu.AddItem( ACTIONS::copyAsText, canCopyText && SCH_CONDITIONS::IdleSelection, 300 );
223 selToolMenu.AddItem( ACTIONS::paste, canEdit && SCH_CONDITIONS::Idle, 300 );
224 selToolMenu.AddItem( ACTIONS::duplicate, canEdit && SCH_CONDITIONS::NotEmpty, 300 );
225 selToolMenu.AddItem( ACTIONS::doDelete, canEdit && SCH_CONDITIONS::NotEmpty, 300 );
226
227 selToolMenu.AddSeparator( 400 );
228 selToolMenu.AddItem( ACTIONS::selectAll, haveSymbolCondition, 400 );
229 selToolMenu.AddItem( ACTIONS::unselectAll, haveSymbolCondition, 400 );
230 // clang-format on
231
232 return true;
233}
234
235
237{
238 SCH_SELECTION& selection = m_selectionTool->RequestSelection();
239
240 if( selection.GetSize() == 0 )
241 return 0;
242
243 VECTOR2I rotPoint;
244 bool ccw = ( aEvent.Matches( SCH_ACTIONS::rotateCCW.MakeEvent() ) );
245 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
246 SCH_COMMIT localCommit( m_toolMgr );
247 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
248
249 if( !commit )
250 commit = &localCommit;
251
252 if( !item->IsMoving() )
253 commit->Modify( m_frame->GetCurSymbol(), m_frame->GetScreen(), RECURSE_MODE::RECURSE );
254
255 if( selection.GetSize() == 1 )
256 rotPoint = item->GetPosition();
257 else
258 rotPoint = m_frame->GetNearestHalfGridPosition( selection.GetCenter() );
259
260 for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
261 {
262 item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
263 item->Rotate( rotPoint, ccw );
264 m_frame->UpdateItem( item, false, true );
265 }
266
267 if( item->IsMoving() )
268 {
270 }
271 else
272 {
273 if( selection.IsHover() )
275
276 if( !localCommit.Empty() )
277 localCommit.Push( _( "Rotate" ) );
278 }
279
280 return 0;
281}
282
283
285{
286 SCH_SELECTION& selection = m_selectionTool->RequestSelection();
287
288 if( selection.GetSize() == 0 )
289 return 0;
290
291 VECTOR2I mirrorPoint;
292 bool xAxis = ( aEvent.Matches( SCH_ACTIONS::mirrorV.MakeEvent() ) );
293 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
294
295 if( !item->IsMoving() )
297
298 if( selection.GetSize() == 1 )
299 {
300 mirrorPoint = item->GetPosition();
301
302 switch( item->Type() )
303 {
304 case SCH_FIELD_T:
305 {
306 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
307
308 if( xAxis )
310 else
312
313 break;
314 }
315
316 default:
317 if( xAxis )
318 item->MirrorVertically( mirrorPoint.y );
319 else
320 item->MirrorHorizontally( mirrorPoint.x );
321
322 break;
323 }
324
325
326 m_frame->UpdateItem( item, false, true );
327 }
328 else
329 {
330 mirrorPoint = m_frame->GetNearestHalfGridPosition( selection.GetCenter() );
331
332 for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
333 {
334 item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
335
336 if( xAxis )
337 item->MirrorVertically( mirrorPoint.y );
338 else
339 item->MirrorHorizontally( mirrorPoint.x );
340
341 m_frame->UpdateItem( item, false, true );
342 }
343 }
344
345 if( item->IsMoving() )
346 {
348 }
349 else
350 {
351 if( selection.IsHover() )
353
354 m_frame->OnModify();
355 }
356
357 return 0;
358}
359
360
361const std::vector<KICAD_T> swappableItems = {
362 LIB_SYMBOL_T, // Allows swapping the anchor
363 SCH_PIN_T,
368};
369
370
372{
373 SCH_SELECTION& selection = m_selectionTool->RequestSelection( swappableItems );
374 std::vector<EDA_ITEM*> sorted = selection.GetItemsSortedBySelectionOrder();
375
376 if( selection.Size() < 2 )
377 return 0;
378
379 EDA_ITEM* front = selection.Front();
380 bool isMoving = front->IsMoving();
381
382 // Save copy for undo if not in edit (edit command already handle the save copy)
383 if( front->GetEditFlags() == 0 )
385
386 for( size_t i = 0; i < sorted.size() - 1; i++ )
387 {
388 SCH_ITEM* a = static_cast<SCH_ITEM*>( sorted[i] );
389 SCH_ITEM* b = static_cast<SCH_ITEM*>( sorted[( i + 1 ) % sorted.size()] );
390
391 VECTOR2I aPos = a->GetPosition(), bPos = b->GetPosition();
392 std::swap( aPos, bPos );
393
394 a->SetPosition( aPos );
395 b->SetPosition( bPos );
396
397 // Special case some common swaps
398 if( a->Type() == b->Type() )
399 {
400 switch( a->Type() )
401 {
402 case SCH_PIN_T:
403 {
404 SCH_PIN* aPin = static_cast<SCH_PIN*>( a );
405 SCH_PIN* bBpin = static_cast<SCH_PIN*>( b );
406
407 PIN_ORIENTATION aOrient = aPin->GetOrientation();
408 PIN_ORIENTATION bOrient = bBpin->GetOrientation();
409
410 aPin->SetOrientation( bOrient );
411 bBpin->SetOrientation( aOrient );
412
413 break;
414 }
415 default: break;
416 }
417 }
418
419 m_frame->UpdateItem( a, false, true );
420 m_frame->UpdateItem( b, false, true );
421 }
422
423 // Update R-Tree for modified items
424 for( EDA_ITEM* selected : selection )
425 updateItem( selected, true );
426
427 if( isMoving )
428 {
429 m_toolMgr->PostAction( ACTIONS::refreshPreview );
430 }
431 else
432 {
433 if( selection.IsHover() )
435
436 m_frame->OnModify();
437 }
438
439 return 0;
440}
441
442
443static std::vector<KICAD_T> nonFields =
444{
450};
451
452
454{
455 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
456 std::deque<EDA_ITEM*> items = m_selectionTool->RequestSelection().GetItems();
457 SCH_COMMIT commit( m_frame );
458
459 if( items.empty() )
460 return 0;
461
462 // Don't leave a freed pointer in the selection
464
465 commit.Modify( symbol, m_frame->GetScreen() );
466
467 std::set<SCH_ITEM*> toDelete;
468 int fieldsHidden = 0;
469 int fieldsAlreadyHidden = 0;
470
471 for( EDA_ITEM* item : items )
472 {
473 if( item->Type() == SCH_PIN_T )
474 {
475 SCH_PIN* curr_pin = static_cast<SCH_PIN*>( item );
476 VECTOR2I pos = curr_pin->GetPosition();
477
478 toDelete.insert( curr_pin );
479
480 // when pin editing is synchronized, pins in the same position, with the same name
481 // in different units are also removed. But only one pin per unit (matching)
482 if( m_frame->SynchronizePins() )
483 {
484 std::vector<bool> got_unit( symbol->GetUnitCount() + 1 );
485
486 got_unit[curr_pin->GetUnit()] = true;
487
488 for( SCH_PIN* pin : symbol->GetPins() )
489 {
490 if( got_unit[pin->GetUnit()] )
491 continue;
492
493 if( pin->GetPosition() != pos )
494 continue;
495
496 if( pin->GetBodyStyle() != curr_pin->GetBodyStyle() )
497 continue;
498
499 if( pin->GetType() != curr_pin->GetType() )
500 continue;
501
502 if( pin->GetName() != curr_pin->GetName() )
503 continue;
504
505 toDelete.insert( pin );
506 got_unit[pin->GetUnit()] = true;
507 }
508 }
509 }
510 else if( item->Type() == SCH_FIELD_T )
511 {
512 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
513
514 // Hide "deleted" fields
515 if( field->IsVisible() )
516 {
517 field->SetVisible( false );
518 fieldsHidden++;
519 }
520 else
521 {
522 fieldsAlreadyHidden++;
523 }
524 }
525 else if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( item ) )
526 {
527 toDelete.insert( schItem );
528 }
529 }
530
531 for( SCH_ITEM* item : toDelete )
532 symbol->RemoveDrawItem( item );
533
534 if( toDelete.size() == 0 )
535 {
536 if( fieldsHidden == 1 )
537 commit.Push( _( "Hide Field" ) );
538 else if( fieldsHidden > 1 )
539 commit.Push( _( "Hide Fields" ) );
540 else if( fieldsAlreadyHidden > 0 )
541 m_frame->ShowInfoBarError( _( "Use the Symbol Properties dialog to remove fields." ) );
542 }
543 else
544 {
545 commit.Push( _( "Delete" ) );
546 }
547
548 m_frame->RebuildView();
549 return 0;
550}
551
552
554{
555 SCH_SELECTION& selection = m_selectionTool->RequestSelection();
556
557 if( selection.Empty() || aEvent.IsAction( &SCH_ACTIONS::symbolProperties ) )
558 {
559 if( m_frame->GetCurSymbol() )
561 }
562 else if( selection.Size() == 1 )
563 {
564 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
565
566 // Save copy for undo if not in edit (edit command already handle the save copy)
567 if( item->GetEditFlags() == 0 )
569
570 switch( item->Type() )
571 {
572 case SCH_PIN_T:
573 {
574 SCH_PIN& pin = static_cast<SCH_PIN&>( *item );
575
576 // Mouse, not cursor, as grid points may well not be under any text
577 const VECTOR2I& mousePos = m_toolMgr->GetMousePosition();
578 PIN_LAYOUT_CACHE& layout = pin.GetLayoutCache();
579
580 bool mouseOverNumber = false;
581 if( OPT_BOX2I numberBox = layout.GetPinNumberBBox() )
582 {
583 mouseOverNumber = numberBox->Contains( mousePos );
584 }
585
586 if( SYMBOL_EDITOR_PIN_TOOL* pinTool = m_toolMgr->GetTool<SYMBOL_EDITOR_PIN_TOOL>() )
587 pinTool->EditPinProperties( &pin, mouseOverNumber );
588
589 break;
590 }
591 case SCH_SHAPE_T:
592 editShapeProperties( static_cast<SCH_SHAPE*>( item ) );
593 break;
594
595 case SCH_TEXT_T:
596 editTextProperties( item );
597 break;
598
599 case SCH_TEXTBOX_T:
600 editTextBoxProperties( item );
601 break;
602
603 case SCH_FIELD_T:
604 editFieldProperties( static_cast<SCH_FIELD*>( item ) );
605 break;
606
607 default:
608 wxFAIL_MSG( wxT( "Unhandled item <" ) + item->GetClass() + wxT( ">" ) );
609 break;
610 }
611 }
612
613 if( selection.IsHover() )
615
616 return 0;
617}
618
619
621{
622 DIALOG_SHAPE_PROPERTIES dlg( m_frame, aShape );
623
624 if( dlg.ShowModal() != wxID_OK )
625 return;
626
627 updateItem( aShape, true );
628 m_frame->GetCanvas()->Refresh();
629 m_frame->OnModify();
630
633 drawingTools->SetDrawSpecificUnit( !dlg.GetApplyToAllUnits() );
634
635 std::vector<MSG_PANEL_ITEM> items;
636 aShape->GetMsgPanelInfo( m_frame, items );
637 m_frame->SetMsgPanel( items );
638}
639
640
642{
643 if ( aItem->Type() != SCH_TEXT_T )
644 return;
645
646 DIALOG_TEXT_PROPERTIES dlg( m_frame, static_cast<SCH_TEXT*>( aItem ) );
647
648 if( dlg.ShowModal() != wxID_OK )
649 return;
650
651 updateItem( aItem, true );
652 m_frame->GetCanvas()->Refresh();
653 m_frame->OnModify( );
654}
655
656
658{
659 if ( aItem->Type() != SCH_TEXTBOX_T )
660 return;
661
662 DIALOG_TEXT_PROPERTIES dlg( m_frame, static_cast<SCH_TEXTBOX*>( aItem ) );
663
664 if( dlg.ShowModal() != wxID_OK )
665 return;
666
667 updateItem( aItem, true );
668 m_frame->GetCanvas()->Refresh();
669 m_frame->OnModify( );
670}
671
672
674{
675 if( aField == nullptr )
676 return;
677
678 wxString caption;
679
680 if( aField->IsMandatory() )
681 caption.Printf( _( "Edit %s Field" ), TitleCaps( aField->GetName() ) );
682 else
683 caption.Printf( _( "Edit '%s' Field" ), aField->GetName() );
684
685 DIALOG_FIELD_PROPERTIES dlg( m_frame, caption, aField );
686
687 // The dialog may invoke a kiway player for footprint fields
688 // so we must use a quasimodal dialog.
689 if( dlg.ShowQuasiModal() != wxID_OK )
690 return;
691
692 SCH_COMMIT commit( m_toolMgr );
693 commit.Modify( aField, m_frame->GetScreen() );
694
695 dlg.UpdateField( aField );
696
697 commit.Push( caption );
698
699 m_frame->GetCanvas()->Refresh();
700 m_frame->UpdateSymbolMsgPanelInfo();
701}
702
703
705{
706 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
707 bool partLocked = symbol->UnitsLocked();
708
711
713
714 // This dialog itself subsequently can invoke a KIWAY_PLAYER as a quasimodal
715 // frame. Therefore this dialog as a modal frame parent, MUST be run under
716 // quasimodal mode for the quasimodal frame support to work. So don't use
717 // the QUASIMODAL macros here.
718 if( dlg.ShowQuasiModal() != wxID_OK )
719 return;
720
721 m_frame->RebuildSymbolUnitAndBodyStyleLists();
722 m_frame->OnModify();
723
724 // if m_UnitSelectionLocked has changed, set some edit options or defaults
725 // to the best value
726 if( partLocked != symbol->UnitsLocked() )
727 {
729
730 // Enable synchronized pin edit mode for symbols with interchangeable units
731 m_frame->m_SyncPinEdit = !symbol->UnitsLocked();
732
733 // also set default edit options to the better value
734 // Usually if units are locked, graphic items are specific to each unit
735 // and if units are interchangeable, graphic items are common to units
736 tools->SetDrawSpecificUnit( symbol->UnitsLocked() );
737 }
738}
739
740
742{
743 SCH_COMMIT commit( m_frame );
744 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
745
746 if( !symbol )
747 return 0;
748
749 commit.Modify( symbol, m_frame->GetScreen() );
750
751 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
752 wxCHECK( selTool, -1 );
753
754 std::vector<SCH_PIN*> selectedPins;
755
756 SCH_SELECTION& selection = selTool->GetSelection();
757
758 for( EDA_ITEM* item : selection )
759 {
760 if( item->Type() == SCH_PIN_T )
761 {
762 SCH_PIN* pinItem = static_cast<SCH_PIN*>( item );
763 selectedPins.push_back( pinItem );
764 }
765 }
766
767 // And now clear the selection so if we change the pins we don't have dangling pointers
768 // in the selection.
770
771 DIALOG_LIB_EDIT_PIN_TABLE dlg( m_frame, symbol, selectedPins );
772
773 if( dlg.ShowModal() == wxID_CANCEL )
774 return -1;
775
776 commit.Push( _( "Edit Pins" ) );
777 m_frame->RebuildView();
778
779 return 0;
780}
781
782
784{
785 SCH_COMMIT commit( m_frame );
786 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
787
788 if( !symbol )
789 return 0;
790
791 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
792 wxCHECK( selTool, -1 );
793
794 SCH_SELECTION& selection = selTool->GetSelection();
795
796 // Collect pins to convert - accept pins with any number format
797 std::vector<SCH_PIN*> pinsToConvert;
798
799 if( selection.Size() == 1 && selection.Front()->Type() == SCH_PIN_T )
800 {
801 // Single pin selected - find all pins at the same location
802 SCH_PIN* selectedPin = static_cast<SCH_PIN*>( selection.Front() );
803 VECTOR2I pos = selectedPin->GetPosition();
804
805 for( SCH_PIN* pin : symbol->GetPins() )
806 {
807 if( pin->GetPosition() == pos )
808 pinsToConvert.push_back( pin );
809 }
810 }
811 else
812 {
813 // Multiple pins selected - use them directly, accepting any pin numbers
814 for( EDA_ITEM* item : selection )
815 {
816 if( item->Type() == SCH_PIN_T )
817 pinsToConvert.push_back( static_cast<SCH_PIN*>( item ) );
818 }
819 }
820
821 if( pinsToConvert.size() < 2 )
822 {
823 m_frame->ShowInfoBarError( _( "At least two pins are needed to convert to stacked pins" ) );
824 return 0;
825 }
826
827 // Check that all pins are at the same location
828 VECTOR2I pos = pinsToConvert[0]->GetPosition();
829 for( size_t i = 1; i < pinsToConvert.size(); ++i )
830 {
831 if( pinsToConvert[i]->GetPosition() != pos )
832 {
833 m_frame->ShowInfoBarError( _( "All pins must be at the same location" ) );
834 return 0;
835 }
836 }
837
838 commit.Modify( symbol, m_frame->GetScreen() );
839
840 // Clear selection before modifying pins, like the Delete command does
842
843 // Sort pins for consistent ordering - handle arbitrary pin number formats
844 std::sort( pinsToConvert.begin(), pinsToConvert.end(),
845 []( SCH_PIN* a, SCH_PIN* b )
846 {
847 wxString numA = a->GetNumber();
848 wxString numB = b->GetNumber();
849
850 // Try to convert to integers for proper numeric sorting
851 long longA, longB;
852 bool aIsNumeric = numA.ToLong( &longA );
853 bool bIsNumeric = numB.ToLong( &longB );
854
855 // Both are purely numeric - sort numerically
856 if( aIsNumeric && bIsNumeric )
857 return longA < longB;
858
859 // Mixed numeric/non-numeric - numeric pins come first
860 if( aIsNumeric && !bIsNumeric )
861 return true;
862 if( !aIsNumeric && bIsNumeric )
863 return false;
864
865 // Both non-numeric or mixed alphanumeric - use lexicographic sorting
866 return numA < numB;
867 });
868
869 // Build the stacked notation string with range collapsing
870 wxString stackedNotation = wxT("[");
871
872 // Helper function to collapse consecutive numbers into ranges - handles arbitrary pin formats
873 auto collapseRanges = [&]() -> wxString
874 {
875 if( pinsToConvert.empty() )
876 return wxT("");
877
878 wxString result;
879
880 // Group pins by their alphanumeric prefix for range collapsing
881 std::map<wxString, std::vector<long>> prefixGroups;
882 std::vector<wxString> nonNumericPins;
883
884 // Parse each pin number to separate prefix from numeric suffix
885 for( SCH_PIN* pin : pinsToConvert )
886 {
887 wxString pinNumber = pin->GetNumber();
888
889 // Skip empty pin numbers (shouldn't happen, but be defensive)
890 if( pinNumber.IsEmpty() )
891 {
892 nonNumericPins.push_back( wxT("(empty)") );
893 continue;
894 }
895
896 wxString prefix;
897 wxString numericPart;
898
899 // Find where numeric part starts (scan from end)
900 size_t numStart = pinNumber.length();
901 for( int i = pinNumber.length() - 1; i >= 0; i-- )
902 {
903 if( !wxIsdigit( pinNumber[i] ) )
904 {
905 numStart = i + 1;
906 break;
907 }
908 if( i == 0 ) // All digits
909 numStart = 0;
910 }
911
912 if( numStart < pinNumber.length() ) // Has numeric suffix
913 {
914 prefix = pinNumber.Left( numStart );
915 numericPart = pinNumber.Mid( numStart );
916
917 long numValue;
918 if( numericPart.ToLong( &numValue ) && numValue >= 0 ) // Valid non-negative number
919 {
920 prefixGroups[prefix].push_back( numValue );
921 }
922 else
923 {
924 // Numeric part couldn't be parsed or is negative - treat as non-numeric
925 nonNumericPins.push_back( pinNumber );
926 }
927 }
928 else // No numeric suffix - consolidate as individual value
929 {
930 nonNumericPins.push_back( pinNumber );
931 }
932 }
933
934 // Process each prefix group
935 for( auto& [prefix, numbers] : prefixGroups )
936 {
937 if( !result.IsEmpty() )
938 result += wxT(",");
939
940 // Sort numeric values for this prefix
941 std::sort( numbers.begin(), numbers.end() );
942
943 // Collapse consecutive ranges within this prefix
944 size_t i = 0;
945 while( i < numbers.size() )
946 {
947 if( i > 0 ) // Not first number in this prefix group
948 result += wxT(",");
949
950 long start = numbers[i];
951 long end = start;
952
953 // Find the end of consecutive sequence
954 while( i + 1 < numbers.size() && numbers[i + 1] == numbers[i] + 1 )
955 {
956 i++;
957 end = numbers[i];
958 }
959
960 // Add range or single number with prefix
961 if( end > start + 1 ) // Range of 3+ numbers
962 result += wxString::Format( wxT("%s%ld-%s%ld"), prefix, start, prefix, end );
963 else if( end == start + 1 ) // Two consecutive numbers
964 result += wxString::Format( wxT("%s%ld,%s%ld"), prefix, start, prefix, end );
965 else // Single number
966 result += wxString::Format( wxT("%s%ld"), prefix, start );
967
968 i++;
969 }
970 }
971
972 // Add non-numeric pin numbers as individual comma-separated values
973 for( const wxString& nonNum : nonNumericPins )
974 {
975 if( !result.IsEmpty() )
976 result += wxT(",");
977 result += nonNum;
978 }
979
980 return result;
981 };
982
983 stackedNotation += collapseRanges();
984 stackedNotation += wxT("]");
985
986 // Keep the first pin and give it the stacked notation
987 SCH_PIN* masterPin = pinsToConvert[0];
988 masterPin->SetNumber( stackedNotation );
989
990 // Log information about pins being removed before we remove them
991 wxLogTrace( "KICAD_STACKED_PINS",
992 wxString::Format( "Converting %zu pins to stacked notation '%s'",
993 pinsToConvert.size(), stackedNotation ) );
994
995 // Remove all other pins from the symbol that were consolidated into the stacked notation
996 // Collect pins to remove first, then remove them all at once like the Delete command
997 std::vector<SCH_PIN*> pinsToRemove;
998 for( size_t i = 1; i < pinsToConvert.size(); ++i )
999 {
1000 SCH_PIN* pinToRemove = pinsToConvert[i];
1001
1002 // Log the pin before removing it
1003 wxLogTrace( "KICAD_STACKED_PINS",
1004 wxString::Format( "Will remove pin '%s' at position (%d, %d)",
1005 pinToRemove->GetNumber(),
1006 pinToRemove->GetPosition().x,
1007 pinToRemove->GetPosition().y ) );
1008
1009 pinsToRemove.push_back( pinToRemove );
1010 }
1011
1012 // Remove all pins at once, like the Delete command does
1013 for( SCH_PIN* pin : pinsToRemove )
1014 {
1015 symbol->RemoveDrawItem( pin );
1016 }
1017
1018 commit.Push( wxString::Format( _( "Convert %zu Stacked Pins to '%s'" ),
1019 pinsToConvert.size(), stackedNotation ) );
1020 m_frame->RebuildView();
1021 return 0;
1022}
1023
1024
1026{
1027 SCH_COMMIT commit( m_frame );
1028 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1029
1030 if( !symbol )
1031 return 0;
1032
1033 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1034 wxCHECK( selTool, -1 );
1035
1036 SCH_SELECTION& selection = selTool->GetSelection();
1037
1038 if( selection.GetSize() != 1 || selection.Front()->Type() != SCH_PIN_T )
1039 {
1040 m_frame->ShowInfoBarError( _( "Select a single pin with stacked notation to explode" ) );
1041 return 0;
1042 }
1043
1044 SCH_PIN* pin = static_cast<SCH_PIN*>( selection.Front() );
1045
1046 // Check if the pin has stacked notation
1047 bool isValid;
1048 std::vector<wxString> stackedNumbers = pin->GetStackedPinNumbers( &isValid );
1049
1050 if( !isValid || stackedNumbers.size() <= 1 )
1051 {
1052 m_frame->ShowInfoBarError( _( "Selected pin does not have valid stacked notation" ) );
1053 return 0;
1054 }
1055
1056 commit.Modify( symbol, m_frame->GetScreen() );
1057
1058 // Clear selection before modifying pins
1059 m_toolMgr->RunAction( ACTIONS::selectionClear );
1060
1061 // Sort the stacked numbers to find the smallest one
1062 std::sort( stackedNumbers.begin(), stackedNumbers.end(),
1063 []( const wxString& a, const wxString& b )
1064 {
1065 // Try to convert to integers for proper numeric sorting
1066 long numA, numB;
1067 if( a.ToLong( &numA ) && b.ToLong( &numB ) )
1068 return numA < numB;
1069
1070 // Fall back to string comparison if not numeric
1071 return a < b;
1072 });
1073
1074 // Change the original pin to use the first (smallest) number and make it visible
1075 pin->SetNumber( stackedNumbers[0] );
1076 pin->SetVisible( true );
1077
1078 // Create additional pins for the remaining numbers and make them invisible
1079 for( size_t i = 1; i < stackedNumbers.size(); ++i )
1080 {
1081 SCH_PIN* newPin = new SCH_PIN( symbol );
1082
1083 // Copy all properties from the original pin
1084 newPin->SetPosition( pin->GetPosition() );
1085 newPin->SetOrientation( pin->GetOrientation() );
1086 newPin->SetShape( pin->GetShape() );
1087 newPin->SetLength( pin->GetLength() );
1088 newPin->SetType( pin->GetType() );
1089 newPin->SetName( pin->GetName() );
1090 newPin->SetNumber( stackedNumbers[i] );
1091 newPin->SetNameTextSize( pin->GetNameTextSize() );
1092 newPin->SetNumberTextSize( pin->GetNumberTextSize() );
1093 newPin->SetUnit( pin->GetUnit() );
1094 newPin->SetBodyStyle( pin->GetBodyStyle() );
1095 newPin->SetVisible( false ); // Make all other pins invisible
1096
1097 // Add the new pin to the symbol
1098 symbol->AddDrawItem( newPin );
1099 }
1100
1101 commit.Push( _( "Explode Stacked Pin" ) );
1102 m_frame->RebuildView();
1103 return 0;
1104}
1105
1106
1108{
1109 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1110
1111 if( !symbol )
1112 return 0;
1113
1114 if( !symbol->IsDerived() )
1115 {
1116 m_frame->ShowInfoBarError( _( "Symbol is not derived from another symbol." ) );
1117 }
1118 else
1119 {
1120 DIALOG_UPDATE_SYMBOL_FIELDS dlg( m_frame, symbol );
1121
1122 if( dlg.ShowModal() == wxID_CANCEL )
1123 return -1;
1124 }
1125
1126 return 0;
1127}
1128
1129
1131{
1132 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1133
1134 // Nuke the selection for later rebuilding. This does *not* clear the flags on any items;
1135 // it just clears the SELECTION's reference to them.
1136 selTool->GetSelection().Clear();
1137 {
1138 m_frame->GetSymbolFromUndoList();
1139 }
1140 selTool->RebuildSelection();
1141
1142 return 0;
1143}
1144
1145
1147{
1148 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1149
1150 // Nuke the selection for later rebuilding. This does *not* clear the flags on any items;
1151 // it just clears the SELECTION's reference to them.
1152 selTool->GetSelection().Clear();
1153 {
1154 m_frame->GetSymbolFromRedoList();
1155 }
1156 selTool->RebuildSelection();
1157
1158 return 0;
1159}
1160
1161
1163{
1164 int retVal = Copy( aEvent );
1165
1166 if( retVal == 0 )
1167 retVal = DoDelete( aEvent );
1168
1169 return retVal;
1170}
1171
1172
1174{
1175 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1176 SCH_SELECTION& selection = m_selectionTool->RequestSelection( nonFields );
1177
1178 if( !symbol || !selection.GetSize() )
1179 return 0;
1180
1181 for( SCH_ITEM& item : symbol->GetDrawItems() )
1182 {
1183 if( item.Type() == SCH_FIELD_T )
1184 continue;
1185
1186 wxASSERT( !item.HasFlag( STRUCT_DELETED ) );
1187
1188 if( !item.IsSelected() )
1189 item.SetFlags( STRUCT_DELETED );
1190 }
1191
1192 LIB_SYMBOL* partCopy = new LIB_SYMBOL( *symbol );
1193
1194 STRING_FORMATTER formatter;
1195 SCH_IO_KICAD_SEXPR::FormatLibSymbol( partCopy, formatter );
1196
1197 delete partCopy;
1198
1199 for( SCH_ITEM& item : symbol->GetDrawItems() )
1200 item.ClearFlags( STRUCT_DELETED );
1201
1202 std::string prettyData = formatter.GetString();
1203 KICAD_FORMAT::Prettify( prettyData, true );
1204
1205 if( SaveClipboard( prettyData ) )
1206 return 0;
1207 else
1208 return -1;
1209}
1210
1211
1213{
1214 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1215 SCH_SELECTION& selection = selTool->RequestSelection();
1216
1217 if( selection.Empty() )
1218 return 0;
1219
1220 wxString itemsAsText = GetSelectedItemsAsText( selection );
1221
1222 if( selection.IsHover() )
1223 m_toolMgr->RunAction( ACTIONS::selectionClear );
1224
1225 return SaveClipboard( itemsAsText.ToStdString() );
1226}
1227
1228
1230{
1231 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1232 LIB_SYMBOL* newPart = nullptr;
1233
1234 if( !symbol || symbol->IsDerived() )
1235 return 0;
1236
1237 std::string clipboardData = GetClipboardUTF8();
1238
1239 try
1240 {
1241 std::vector<LIB_SYMBOL*> newParts = SCH_IO_KICAD_SEXPR::ParseLibSymbols( clipboardData, "Clipboard" );
1242
1243 if( newParts.empty() || !newParts[0] )
1244 return -1;
1245
1246 newPart = newParts[0];
1247 }
1248 catch( IO_ERROR& )
1249 {
1250 // If it's not a symbol then paste as text
1251 newPart = new LIB_SYMBOL( "dummy_part" );
1252
1253 wxString pasteText( clipboardData );
1254
1255 // Limit of 5000 is totally arbitrary. Without a limit, pasting a bitmap image from
1256 // eeschema makes KiCad appear to hang.
1257 if( pasteText.Length() > 5000 )
1258 pasteText = pasteText.Left( 5000 ) + wxT( "..." );
1259
1260 SCH_TEXT* newText = new SCH_TEXT( { 0, 0 }, pasteText, LAYER_DEVICE );
1261 newPart->AddDrawItem( newText );
1262 }
1263
1264 SCH_COMMIT commit( m_toolMgr );
1265
1266 commit.Modify( symbol, m_frame->GetScreen() );
1267 m_selectionTool->ClearSelection();
1268
1269 for( SCH_ITEM& item : symbol->GetDrawItems() )
1270 item.ClearFlags( IS_NEW | IS_PASTED | SELECTED );
1271
1272 for( SCH_ITEM& item : newPart->GetDrawItems() )
1273 {
1274 if( item.Type() == SCH_FIELD_T )
1275 continue;
1276
1277 SCH_ITEM* newItem = item.Duplicate( true, &commit );
1278 newItem->SetParent( symbol );
1279 newItem->SetFlags( IS_NEW | IS_PASTED | SELECTED );
1280
1281 newItem->SetUnit( newItem->GetUnit() ? m_frame->GetUnit() : 0 );
1282 newItem->SetBodyStyle( newItem->GetBodyStyle() ? m_frame->GetBodyStyle() : 0 );
1283
1284 symbol->AddDrawItem( newItem );
1285 getView()->Add( newItem );
1286 }
1287
1288 delete newPart;
1289
1290 m_selectionTool->RebuildSelection();
1291
1292 SCH_SELECTION& selection = m_selectionTool->GetSelection();
1293
1294 if( !selection.Empty() )
1295 {
1296 selection.SetReferencePoint( getViewControls()->GetCursorPosition( true ) );
1297
1298 if( m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit ) )
1299 commit.Push( _( "Paste" ) );
1300 else
1301 commit.Revert();
1302 }
1303
1304 return 0;
1305}
1306
1307
1309{
1310 LIB_SYMBOL* symbol = m_frame->GetCurSymbol();
1311 SCH_SELECTION& selection = m_selectionTool->RequestSelection( nonFields );
1312 SCH_COMMIT commit( m_toolMgr );
1313
1314 if( selection.GetSize() == 0 )
1315 return 0;
1316
1317 commit.Modify( symbol, m_frame->GetScreen() );
1318
1319 std::vector<EDA_ITEM*> oldItems;
1320 std::vector<EDA_ITEM*> newItems;
1321
1322 std::copy( selection.begin(), selection.end(), std::back_inserter( oldItems ) );
1323 std::sort( oldItems.begin(), oldItems.end(), []( EDA_ITEM* a, EDA_ITEM* b )
1324 {
1325 int cmp;
1326
1327 if( a->Type() != b->Type() )
1328 return a->Type() < b->Type();
1329
1330 // Create the new pins in the same order as the old pins
1331 if( a->Type() == SCH_PIN_T )
1332 {
1333 const wxString& aNum = static_cast<SCH_PIN*>( a )->GetNumber();
1334 const wxString& bNum = static_cast<SCH_PIN*>( b )->GetNumber();
1335
1336 cmp = StrNumCmp( aNum, bNum );
1337
1338 // If the pin numbers are not numeric, then just number them by their position
1339 // on the screen.
1340 if( aNum.IsNumber() && bNum.IsNumber() && cmp != 0 )
1341 return cmp < 0;
1342 }
1343
1345
1346 if( cmp != 0 )
1347 return cmp < 0;
1348
1349 return a->m_Uuid < b->m_Uuid;
1350 } );
1351
1352 for( EDA_ITEM* item : oldItems )
1353 {
1354 SCH_ITEM* oldItem = static_cast<SCH_ITEM*>( item );
1355 SCH_ITEM* newItem = oldItem->Duplicate( true, &commit );
1356
1357 if( newItem->Type() == SCH_PIN_T )
1358 {
1359 SCH_PIN* newPin = static_cast<SCH_PIN*>( newItem );
1360
1361 if( !newPin->GetNumber().IsEmpty() )
1362 newPin->SetNumber( wxString::Format( wxT( "%i" ), symbol->GetMaxPinNumber() + 1 ) );
1363 }
1364
1365 oldItem->ClearFlags( IS_NEW | IS_PASTED | SELECTED );
1366 newItem->SetFlags( IS_NEW | IS_PASTED | SELECTED );
1367 newItem->SetParent( symbol );
1368 newItems.push_back( newItem );
1369
1370 symbol->AddDrawItem( newItem );
1371 getView()->Add( newItem );
1372 }
1373
1374 m_toolMgr->RunAction( ACTIONS::selectionClear );
1375 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &newItems );
1376
1377 selection.SetReferencePoint( getViewControls()->GetCursorPosition( true ) );
1378
1379 if( m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit ) )
1380 commit.Push( _( "Duplicate" ) );
1381 else
1382 commit.Revert();
1383
1384 return 0;
1385}
1386
1387
1389{
1390 // clang-format off
1398
1406
1412
1419 // clang-format on
1420}
std::optional< BOX2I > OPT_BOX2I
Definition box2.h:926
static TOOL_ACTION decrementPrimary
Definition actions.h:96
static TOOL_ACTION paste
Definition actions.h:80
static TOOL_ACTION cancelInteractive
Definition actions.h:72
static TOOL_ACTION unselectAll
Definition actions.h:83
static TOOL_ACTION decrementSecondary
Definition actions.h:98
static TOOL_ACTION copy
Definition actions.h:78
static TOOL_ACTION undo
Definition actions.h:75
static TOOL_ACTION incrementSecondary
Definition actions.h:97
static TOOL_ACTION duplicate
Definition actions.h:84
static TOOL_ACTION incrementPrimary
Definition actions.h:95
static TOOL_ACTION doDelete
Definition actions.h:85
static TOOL_ACTION redo
Definition actions.h:76
static TOOL_ACTION deleteTool
Definition actions.h:86
static TOOL_ACTION increment
Definition actions.h:94
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:223
static TOOL_ACTION cut
Definition actions.h:77
static TOOL_ACTION copyAsText
Definition actions.h:79
static TOOL_ACTION refreshPreview
Definition actions.h:158
static TOOL_ACTION selectAll
Definition actions.h:82
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:231
bool Empty() const
Definition commit.h:137
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:106
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.
This class is setup in expectation of its children possibly using Kiway player so DIALOG_SHIM::ShowQu...
void UpdateField(SCH_FIELD *aField)
int ShowModal() override
Dialog to update or change schematic library symbols.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
virtual VECTOR2I GetPosition() const
Definition eda_item.h:272
virtual void SetPosition(const VECTOR2I &aPos)
Definition eda_item.h:273
EDA_ITEM_FLAGS GetEditFlags() const
Definition eda_item.h:148
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:142
const KIID m_Uuid
Definition eda_item.h:516
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:144
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.h:113
EDA_ITEM * GetParent() const
Definition eda_item.h:112
bool IsMoving() const
Definition eda_item.h:125
virtual bool IsVisible() const
Definition eda_text.h:186
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:418
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:199
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:387
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:202
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:410
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:298
Define a library symbol object.
Definition lib_symbol.h:85
bool UnitsLocked() const
Check whether symbol units are interchangeable.
Definition lib_symbol.h:291
bool IsDerived() const
Definition lib_symbol.h:206
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:532
void RemoveDrawItem(SCH_ITEM *aItem)
Remove draw aItem from list.
std::vector< SCH_PIN * > GetPins() const override
int GetUnitCount() const override
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
A pin layout helper is a class that manages the layout of the parts of a pin on a schematic symbol:
OPT_BOX2I GetPinNumberBBox()
Get the bounding box of the pin number, if there is one.
static TOOL_ACTION rotateCCW
static TOOL_ACTION mirrorV
static TOOL_ACTION swap
static TOOL_ACTION convertStackedPins
static TOOL_ACTION pinTable
static TOOL_ACTION properties
static TOOL_ACTION rotateCW
static TOOL_ACTION mirrorH
static TOOL_ACTION symbolProperties
static TOOL_ACTION explodeStackedPin
static TOOL_ACTION updateSymbolFields
static TOOL_ACTION move
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
virtual void Revert() override
Revert the commit by restoring the modified items state.
bool IsMandatory() const
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
static void FormatLibSymbol(LIB_SYMBOL *aPart, OUTPUTFORMATTER &aFormatter)
static std::vector< LIB_SYMBOL * > ParseLibSymbols(std::string &aSymbolText, std::string aSource, int aFileVersion=SEXPR_SCHEMATIC_FILE_VERSION)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
SCH_ITEM * Duplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr, bool doClone=false) const
Routine to create a new copy of given item.
Definition sch_item.cpp:137
virtual void SetBodyStyle(int aBodyStyle)
Definition sch_item.h:243
int GetBodyStyle() const
Definition sch_item.h:244
virtual void MirrorHorizontally(int aCenter)
Mirror item horizontally about aCenter.
Definition sch_item.h:373
int GetUnit() const
Definition sch_item.h:238
virtual void Rotate(const VECTOR2I &aCenter, bool aRotateCCW)
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition sch_item.h:389
virtual void SetUnit(int aUnit)
Definition sch_item.h:237
wxString GetClass() const override
Return the class name.
Definition sch_item.h:177
virtual void MirrorVertically(int aCenter)
Mirror item vertically about aCenter.
Definition sch_item.h:381
void SetNumber(const wxString &aNumber)
Definition sch_pin.cpp:633
void SetVisible(bool aVisible)
Definition sch_pin.h:114
void SetOrientation(PIN_ORIENTATION aOrientation)
Definition sch_pin.h:93
void SetName(const wxString &aName)
Definition sch_pin.cpp:418
void SetPosition(const VECTOR2I &aPos) override
Definition sch_pin.h:238
const wxString & GetName() const
Definition sch_pin.cpp:400
void SetLength(int aLength)
Definition sch_pin.h:99
PIN_ORIENTATION GetOrientation() const
Definition sch_pin.cpp:263
void SetNumberTextSize(int aSize)
Definition sch_pin.cpp:684
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition sch_pin.h:96
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:255
void SetType(ELECTRICAL_PINTYPE aType)
Definition sch_pin.cpp:332
const wxString & GetNumber() const
Definition sch_pin.h:124
ELECTRICAL_PINTYPE GetType() const
Definition sch_pin.cpp:312
void SetNameTextSize(int aSize)
Definition sch_pin.cpp:660
void RebuildSelection()
Rebuild the selection from the EDA_ITEMs' selection flags.
SCH_SELECTION & GetSelection()
SCH_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, bool aPromoteCellSelections=false, bool aPromoteGroups=false)
Return either an existing selection (filtered), or the selection at the current cursor position if th...
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.
void updateItem(EDA_ITEM *aItem, bool aUpdateRTree) const
int Increment(const TOOL_EVENT &aEvent)
void saveCopyInUndoList(EDA_ITEM *aItem, UNDO_REDO aType, bool aAppend=false, bool aDirtyConnectivity=true)
int InteractiveDelete(const TOOL_EVENT &aEvent)
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 bool NotEmpty(const SELECTION &aSelection)
Test if there are any items selected.
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
static bool IdleSelection(const SELECTION &aSelection)
Test if all selected items are not being edited.
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.
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition selection.cpp:75
ITER end()
Definition selection.h:80
ITER begin()
Definition selection.h:79
virtual VECTOR2I GetCenter() const
Returns the center point of the selection area bounding box.
Definition selection.cpp:92
bool IsHover() const
Definition selection.h:89
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition selection.h:105
EDA_ITEM * Front() const
Definition selection.h:177
virtual void Clear() override
Remove all the stored items from the group.
Definition selection.h:98
int Size() const
Returns the number of selected parts.
Definition selection.h:121
std::vector< EDA_ITEM * > GetItemsSortedBySelectionOrder() const
void SetReferencePoint(const VECTOR2I &aP)
bool Empty() const
Checks if there is anything selected.
Definition selection.h:115
Implement an OUTPUTFORMATTER to a memory buffer.
Definition richio.h:449
const std::string & GetString()
Definition richio.h:472
int Undo(const TOOL_EVENT &aEvent)
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
void editTextBoxProperties(SCH_ITEM *aItem)
int PinTable(const TOOL_EVENT &aEvent)
int Copy(const TOOL_EVENT &aEvent)
int CopyAsText(const TOOL_EVENT &aEvent)
int Paste(const TOOL_EVENT &aEvent)
int Cut(const TOOL_EVENT &aEvent)
bool Init() override
Init() is called once upon a registration of the tool.
int Redo(const TOOL_EVENT &aEvent)
void editTextProperties(SCH_ITEM *aItem)
int Swap(const TOOL_EVENT &aEvent)
void editFieldProperties(SCH_FIELD *aField)
void editShapeProperties(SCH_SHAPE *aShape)
int Duplicate(const TOOL_EVENT &aEvent)
int Mirror(const TOOL_EVENT &aEvent)
int Rotate(const TOOL_EVENT &aEvent)
int Properties(const TOOL_EVENT &aEvent)
int ExplodeStackedPin(const TOOL_EVENT &aEvent)
int ConvertStackedPins(const TOOL_EVENT &aEvent)
void editSymbolProperties()
Set up handlers for various events.
int UpdateSymbolFields(const TOOL_EVENT &aEvent)
int DoDelete(const TOOL_EVENT &aEvent)
Delete the selected items, or the item under the cursor.
KIGFX::VIEW_CONTROLS * getViewControls() const
Definition tool_base.cpp:44
KIGFX::VIEW * getView() const
Definition tool_base.cpp:38
Generic, UI-independent tool event.
Definition tool_event.h:171
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition tool_event.h:392
COMMIT * Commit() const
Definition tool_event.h:283
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))
TOOL_MENU & GetToolMenu()
CONDITIONAL_MENU & GetMenu()
Definition tool_menu.cpp:44
bool SaveClipboard(const std::string &aTextUTF8)
Store information to the system clipboard.
Definition clipboard.cpp:38
std::string GetClipboardUTF8()
Return the information currently stored in the system clipboard.
Definition clipboard.cpp:58
#define _(s)
@ RECURSE
Definition eda_item.h:51
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition eda_item.h:566
#define IS_PASTED
Modifier on IS_NEW which indicates it came from clipboard.
#define IS_NEW
New item, just created.
#define SELECTED
Item was manually selected by the user.
#define STRUCT_DELETED
flag indication structures to be erased
@ LAYER_DEVICE
Definition layer_ids.h:465
void Prettify(std::string &aSource, bool aCompactSave)
PIN_ORIENTATION
The symbol library pin object orientations.
Definition pin_type.h:105
const std::vector< KICAD_T > swappableItems
wxString GetSelectedItemsAsText(const SELECTION &aSel)
wxString TitleCaps(const wxString &aString)
Capitalize the first letter in each word.
static std::vector< KICAD_T > nonFields
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.
constexpr GR_TEXT_H_ALIGN_T GetFlippedAlignment(GR_TEXT_H_ALIGN_T aAlign)
Get the reverse alignment: left-right are swapped, others are unchanged.
@ SCH_TABLE_T
Definition typeinfo.h:167
@ LIB_SYMBOL_T
Definition typeinfo.h:150
@ SCH_TABLECELL_T
Definition typeinfo.h:168
@ SCH_FIELD_T
Definition typeinfo.h:152
@ SCH_SHAPE_T
Definition typeinfo.h:151
@ SCH_TEXT_T
Definition typeinfo.h:153
@ SCH_TEXTBOX_T
Definition typeinfo.h:154
@ SCH_PIN_T
Definition typeinfo.h:155
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
constexpr int LexicographicalCompare(const VECTOR2< T > &aA, const VECTOR2< T > &aB)
Definition vector2d.h:644