KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_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
25#include <kiway.h>
26#include <tool/action_manager.h>
27#include <tool/picker_tool.h>
28#include <tools/sch_edit_tool.h>
31#include <tools/sch_move_tool.h>
33#include <confirm.h>
34#include <connection_graph.h>
35#include <sch_actions.h>
36#include <sch_tool_utils.h>
37#include <increment.h>
38#include <algorithm>
39#include <set>
40#include <string_utils.h>
41#include <sch_bitmap.h>
42#include <sch_bus_entry.h>
43#include <sch_commit.h>
44#include <sch_group.h>
45#include <sch_label.h>
46#include <sch_junction.h>
47#include <sch_marker.h>
48#include <sch_rule_area.h>
49#include <sch_pin.h>
50#include <sch_sheet_pin.h>
51#include <sch_textbox.h>
52#include <sch_table.h>
53#include <sch_no_connect.h>
55#include <eeschema_id.h>
66#include <dialogs/dialog_text_properties.h>
67#include <dialogs/dialog_tablecell_properties.h>
68#include <dialogs/dialog_table_properties.h>
69#include <pgm_base.h>
72#include <core/kicad_algo.h>
73#include <view/view_controls.h>
74#include <wx/textdlg.h>
75#include <wx/msgdlg.h>
78
79
81{
82public:
84 ACTION_MENU( true )
85 {
87 SetTitle( _( "Symbol Unit" ) );
88 }
89
90protected:
91 ACTION_MENU* create() const override { return new SYMBOL_UNIT_MENU(); }
92
93private:
94 void update() override
95 {
97 SCH_SELECTION& selection = selTool->GetSelection();
98 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( selection.Front() );
99
100 Clear();
101
102 wxCHECK( symbol, /* void */ );
103
104 const int unit = symbol->GetUnit();
105 const int nUnits = symbol->GetLibSymbolRef()->GetUnitCount();
106 const std::set<int> missingUnits = GetUnplacedUnitsForSymbol( *symbol );
107
108 for( int ii = 0; ii < nUnits; ii++ )
109 {
110 wxString unit_text = symbol->GetUnitDisplayName( ii + 1, false );
111
112 if( missingUnits.count( ii + 1 ) == 0 )
113 unit_text += _( " (already placed)" );
114
115 wxMenuItem* item = Append( ID_POPUP_SCH_SELECT_UNIT1 + ii, unit_text, wxEmptyString, wxITEM_CHECK );
116
117 if( unit == ii + 1 )
118 item->Check( true );
119
120 // The ID max for these submenus is ID_POPUP_SCH_SELECT_UNIT_END
121 // See eeschema_id to modify this value.
123 break; // We have used all IDs for these submenus
124 }
125
126 if( !missingUnits.empty() )
127 {
128 AppendSeparator();
129
130 for( int unitNumber : missingUnits )
131 {
132 wxString placeText =
133 wxString::Format( _( "Place unit %s" ), symbol->GetUnitDisplayName( unitNumber, false ) );
134 Append( ID_POPUP_SCH_PLACE_UNIT1 + unitNumber - 1, placeText );
135 }
136 }
137 }
138};
139
140
142{
143public:
145 ACTION_MENU( true )
146 {
148 SetTitle( _( "Body Style" ) );
149 }
150
151protected:
152 ACTION_MENU* create() const override { return new BODY_STYLE_MENU(); }
153
154private:
155 void update() override
156 {
158 SCH_SELECTION& selection = selTool->GetSelection();
159 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( selection.Front() );
160 wxMenuItem* item;
161
162 Clear();
163
164 wxCHECK( symbol, /* void */ );
165
166 if( symbol->HasDeMorganBodyStyles() )
167 {
168 item = Append( ID_POPUP_SCH_SELECT_BODY_STYLE, _( "Standard" ), wxEmptyString, wxITEM_CHECK );
169 item->Check( symbol->GetBodyStyle() == BODY_STYLE::BASE );
170
171 item = Append( ID_POPUP_SCH_SELECT_BODY_STYLE1, _( "Alternate" ), wxEmptyString, wxITEM_CHECK );
172 item->Check( symbol->GetBodyStyle() != BODY_STYLE::BASE );
173 }
174 else if( symbol->IsMultiBodyStyle() )
175 {
176 for( int i = 0; i < symbol->GetBodyStyleCount(); i++ )
177 {
178 item = Append( ID_POPUP_SCH_SELECT_BODY_STYLE + i, symbol->GetBodyStyleDescription( i + 1, true ),
179 wxEmptyString, wxITEM_CHECK );
180 item->Check( symbol->GetBodyStyle() == i + 1 );
181 }
182 }
183 }
184};
185
186
188{
189public:
191 ACTION_MENU( true )
192 {
194 SetTitle( _( "Pin Function" ) );
195 }
196
197protected:
198 ACTION_MENU* create() const override { return new ALT_PIN_FUNCTION_MENU(); }
199
200private:
201 void update() override
202 {
204 SCH_SELECTION& selection = selTool->GetSelection();
205 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( selection.Front() );
206 SCH_PIN* libPin = pin ? pin->GetLibPin() : nullptr;
207
208 Clear();
209
210 wxCHECK( libPin, /* void */ );
211
212 wxMenuItem* item = Append( ID_POPUP_SCH_ALT_PIN_FUNCTION, libPin->GetName(), wxEmptyString, wxITEM_CHECK );
213
214 if( pin->GetAlt().IsEmpty() || ( pin->GetAlt() == libPin->GetName() ) )
215 item->Check( true );
216
217 int ii = 1;
218
219 for( const auto& [name, definition] : libPin->GetAlternates() )
220 {
221 // The default pin name is set above, avoid setting it again.
222 if( name == libPin->GetName() )
223 continue;
224
225 item = Append( ID_POPUP_SCH_ALT_PIN_FUNCTION + ii, name, wxEmptyString, wxITEM_CHECK );
226
227 if( name == pin->GetAlt() )
228 item->Check( true );
229
230 // The ID max for these submenus is ID_POPUP_SCH_ALT_PIN_FUNCTION_END
231 // See eeschema_id to modify this value.
233 break; // We have used all IDs for these submenus
234 }
235 }
236};
237
238
240{
241public:
243 ACTION_MENU( true )
244 {
246 SetTitle( _( "Pin Helpers" ) );
247 }
248
249protected:
250 ACTION_MENU* create() const override { return new PIN_TRICKS_MENU(); }
251
252private:
253 void update() override
254 {
256 SCH_SELECTION& selection = selTool->GetSelection();
257 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( selection.Front() );
258 SCH_SHEET_PIN* sheetPin = dynamic_cast<SCH_SHEET_PIN*>( selection.Front() );
259
260 Clear();
261
262 if( !pin && !sheetPin )
263 return;
264
270 }
271};
272
273
293
294
296 SCH_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveEdit" )
297{
298 m_pickerItem = nullptr;
299}
300
301
303
305{
307
308 SCH_DRAWING_TOOLS* drawingTools = m_toolMgr->GetTool<SCH_DRAWING_TOOLS>();
309 SCH_MOVE_TOOL* moveTool = m_toolMgr->GetTool<SCH_MOVE_TOOL>();
310
311 wxASSERT_MSG( drawingTools, "eeshema.InteractiveDrawing tool is not available" );
312
313 static const std::vector<KICAD_T> attribTypes = { SCH_SYMBOL_T, SCH_SHEET_T, SCH_RULE_AREA_T };
314 static const std::vector<KICAD_T> sheetTypes = { SCH_SHEET_T };
315
316 auto sheetSelection = S_C::Count( 1 ) && S_C::OnlyTypes( sheetTypes );
317
318 auto sheetHasUndefinedPins =
319 []( const SELECTION& aSel )
320 {
321 if( aSel.Size() == 1 && aSel.Front()->Type() == SCH_SHEET_T )
322 return static_cast<SCH_SHEET*>( aSel.Front() )->HasUndefinedPins();
323
324 return false;
325 };
326
327 auto attribDNPCond =
328 [this]( const SELECTION& aSel )
329 {
330 SCH_SHEET_PATH* sheet = &m_frame->GetCurrentSheet();
331 wxString variant = m_frame->Schematic().GetCurrentVariant();
332 int checked = 0;
333 int unchecked = 0;
334
335 for( EDA_ITEM* item : aSel )
336 {
337 switch( item->Type() )
338 {
339 case SCH_SYMBOL_T:
340 if( static_cast<const SCH_SYMBOL*>( item )->GetDNP( sheet, variant ) )
341 checked++;
342 else
343 unchecked++;
344
345 break;
346
347 case SCH_SHEET_T:
348 if( static_cast<const SCH_SHEET*>( item )->GetDNP( sheet, variant ) )
349 checked++;
350 else
351 unchecked++;
352
353 break;
354
355 case SCH_RULE_AREA_T:
356 if( static_cast<const SCH_RULE_AREA*>( item )->GetDNP() )
357 checked++;
358 else
359 unchecked++;
360
361 break;
362
363 default:
364 break;
365 }
366 }
367
368 return checked > 0 && unchecked == 0;
369 };
370
371 auto attribExcludeFromSimCond =
372 [this]( const SELECTION& aSel )
373 {
374 SCH_SHEET_PATH* sheet = &m_frame->GetCurrentSheet();
375 wxString variant = m_frame->Schematic().GetCurrentVariant();
376 int checked = 0;
377 int unchecked = 0;
378
379 for( EDA_ITEM* item : aSel )
380 {
381 switch( item->Type() )
382 {
383 case SCH_SYMBOL_T:
384 if( static_cast<const SCH_SYMBOL*>( item )->GetExcludedFromSim( sheet, variant ) )
385 checked++;
386 else
387 unchecked++;
388
389 break;
390
391 case SCH_SHEET_T:
392 if( static_cast<const SCH_SHEET*>( item )->GetExcludedFromSim( sheet, variant ) )
393 checked++;
394 else
395 unchecked++;
396
397 break;
398
399 case SCH_RULE_AREA_T:
400 if( static_cast<const SCH_RULE_AREA*>( item )->GetExcludedFromSim() )
401 checked++;
402 else
403 unchecked++;
404
405 break;
406
407 default:
408 break;
409 }
410 }
411
412 return checked > 0 && unchecked == 0;
413 };
414
415 auto attribExcludeFromBOMCond =
416 [this]( const SELECTION& aSel )
417 {
418 SCH_SHEET_PATH* sheet = &m_frame->GetCurrentSheet();
419 wxString variant = m_frame->Schematic().GetCurrentVariant();
420 int checked = 0;
421 int unchecked = 0;
422
423 for( EDA_ITEM* item : aSel )
424 {
425 switch( item->Type() )
426 {
427 case SCH_SYMBOL_T:
428 if( static_cast<const SCH_SYMBOL*>( item )->GetExcludedFromBOM( sheet, variant ) )
429 checked++;
430 else
431 unchecked++;
432
433 break;
434
435 case SCH_SHEET_T:
436 if( static_cast<const SCH_SHEET*>( item )->GetExcludedFromBOM( sheet, variant ) )
437 checked++;
438 else
439 unchecked++;
440
441 break;
442
443 case SCH_RULE_AREA_T:
444 if( static_cast<const SCH_RULE_AREA*>( item )->GetExcludedFromBOM() )
445 checked++;
446 else
447 unchecked++;
448
449 break;
450
451 default:
452 break;
453 }
454 }
455
456 return checked > 0 && unchecked == 0;
457 };
458
459
460 auto attribExcludeFromBoardCond =
461 [this]( const SELECTION& aSel )
462 {
463 SCH_SHEET_PATH* sheet = &m_frame->GetCurrentSheet();
464 wxString variant = m_frame->Schematic().GetCurrentVariant();
465 int checked = 0;
466 int unchecked = 0;
467
468 for( EDA_ITEM* item : aSel )
469 {
470 switch( item->Type() )
471 {
472 case SCH_SYMBOL_T:
473 if( static_cast<const SCH_SYMBOL*>( item )->GetExcludedFromBoard( sheet, variant ) )
474 checked++;
475 else
476 unchecked++;
477
478 break;
479
480 case SCH_SHEET_T:
481 if( static_cast<const SCH_SHEET*>( item )->GetExcludedFromBoard( sheet, variant ) )
482 checked++;
483 else
484 unchecked++;
485
486 break;
487
488 case SCH_RULE_AREA_T:
489 if( static_cast<const SCH_RULE_AREA*>( item )->GetExcludedFromBoard() )
490 checked++;
491 else
492 unchecked++;
493
494 break;
495
496 default:
497 break;
498 }
499 }
500
501 return checked > 0 && unchecked == 0;
502 };
503
504 auto haveHighlight =
505 [this]( const SELECTION& sel )
506 {
507 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
508
509 return editFrame && !editFrame->GetHighlightedConnection().IsEmpty();
510 };
511
512 auto anyTextTool =
513 [this]( const SELECTION& aSel )
514 {
515 return ( m_frame->IsCurrentTool( SCH_ACTIONS::placeLabel )
516 || m_frame->IsCurrentTool( SCH_ACTIONS::placeClassLabel )
517 || m_frame->IsCurrentTool( SCH_ACTIONS::placeGlobalLabel )
518 || m_frame->IsCurrentTool( SCH_ACTIONS::placeHierLabel )
519 || m_frame->IsCurrentTool( SCH_ACTIONS::placeSchematicText ) );
520 };
521
522 auto duplicateCondition =
523 []( const SELECTION& aSel )
524 {
526 return false;
527
528 return true;
529 };
530
531 auto orientCondition =
532 []( const SELECTION& aSel )
533 {
535 return false;
536
538 };
539
540 const auto swapSelectionCondition = S_C::OnlyTypes( SwappableItems ) && SELECTION_CONDITIONS::MoreThan( 1 );
541
542 auto propertiesCondition =
543 [this]( const SELECTION& aSel )
544 {
545 if( aSel.GetSize() == 0 )
546 {
547 if( getView()->IsLayerVisible( LAYER_SCHEMATIC_DRAWINGSHEET ) )
548 {
549 DS_PROXY_VIEW_ITEM* ds = m_frame->GetCanvas()->GetView()->GetDrawingSheet();
551
552 if( ds && ds->HitTestDrawingSheetItems( getView(), cursor ) )
553 return true;
554 }
555
556 return false;
557 }
558
559 SCH_ITEM* firstItem = dynamic_cast<SCH_ITEM*>( aSel.Front() );
560 const SCH_SELECTION* eeSelection = dynamic_cast<const SCH_SELECTION*>( &aSel );
561
562 if( !firstItem || !eeSelection )
563 return false;
564
565 switch( firstItem->Type() )
566 {
567 case SCH_SYMBOL_T:
568 case SCH_SHEET_T:
569 case SCH_SHEET_PIN_T:
570 case SCH_TEXT_T:
571 case SCH_TEXTBOX_T:
572 case SCH_TABLE_T:
573 case SCH_TABLECELL_T:
574 case SCH_LABEL_T:
576 case SCH_HIER_LABEL_T:
578 case SCH_RULE_AREA_T:
579 case SCH_FIELD_T:
580 case SCH_SHAPE_T:
581 case SCH_BITMAP_T:
582 case SCH_GROUP_T:
583 return aSel.GetSize() == 1;
584
585 case SCH_LINE_T:
587 case SCH_JUNCTION_T:
588 if( std::all_of( aSel.Items().begin(), aSel.Items().end(),
589 [&]( const EDA_ITEM* item )
590 {
591 return item->Type() == SCH_LINE_T
592 && static_cast<const SCH_LINE*>( item )->IsGraphicLine();
593 } ) )
594 {
595 return true;
596 }
597 else if( std::all_of( aSel.Items().begin(), aSel.Items().end(),
598 [&]( const EDA_ITEM* item )
599 {
600 return item->Type() == SCH_JUNCTION_T;
601 } ) )
602 {
603 return true;
604 }
605 else if( std::all_of( aSel.Items().begin(), aSel.Items().end(),
606 [&]( const EDA_ITEM* item )
607 {
608 const SCH_ITEM* schItem = dynamic_cast<const SCH_ITEM*>( item );
609
610 wxCHECK( schItem, false );
611
612 return ( schItem->HasLineStroke() && schItem->IsConnectable() )
613 || item->Type() == SCH_JUNCTION_T;
614 } ) )
615 {
616 return true;
617 }
618
619 return false;
620
621 default:
622 return false;
623 }
624 };
625
626 auto autoplaceCondition =
627 []( const SELECTION& aSel )
628 {
629 for( const EDA_ITEM* item : aSel )
630 {
631 if( item->IsType( SCH_COLLECTOR::FieldOwners ) )
632 return true;
633 }
634
635 return false;
636 };
637
638 // allTextTypes does not include SCH_SHEET_PIN_T because one cannot convert other
639 // types to/from this type, living only in a SHEET
640 static const std::vector<KICAD_T> allTextTypes = { SCH_LABEL_T,
646
647 auto toChangeCondition = ( S_C::OnlyTypes( allTextTypes ) );
648
649 static const std::vector<KICAD_T> toLabelTypes = { SCH_DIRECTIVE_LABEL_T,
654
655 auto toLabelCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toLabelTypes ) )
656 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
657
658 static const std::vector<KICAD_T> toCLabelTypes = { SCH_LABEL_T,
663
664 auto toCLabelCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toCLabelTypes ) )
665 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
666
667 static const std::vector<KICAD_T> toHLabelTypes = { SCH_LABEL_T,
672
673 auto toHLabelCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toHLabelTypes ) )
674 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
675
676 static const std::vector<KICAD_T> toGLabelTypes = { SCH_LABEL_T,
681
682 auto toGLabelCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toGLabelTypes ) )
683 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
684
685 static const std::vector<KICAD_T> toTextTypes = { SCH_LABEL_T,
690
691 auto toTextCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toTextTypes ) )
692 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
693
694 static const std::vector<KICAD_T> toTextBoxTypes = { SCH_LABEL_T,
698 SCH_TEXT_T };
699
700 auto toTextBoxCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toTextBoxTypes ) )
701 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
702
703 static const std::vector<KICAD_T> busEntryTypes = { SCH_BUS_WIRE_ENTRY_T, SCH_BUS_BUS_ENTRY_T };
704
705 auto entryCondition = S_C::MoreThan( 0 ) && S_C::OnlyTypes( busEntryTypes );
706
707 auto singleSheetCondition = S_C::Count( 1 ) && S_C::OnlyTypes( sheetTypes );
708
709 auto makeSymbolUnitMenu =
710 [&]( TOOL_INTERACTIVE* tool )
711 {
712 std::shared_ptr<SYMBOL_UNIT_MENU> menu = std::make_shared<SYMBOL_UNIT_MENU>();
713 menu->SetTool( tool );
714 tool->GetToolMenu().RegisterSubMenu( menu );
715 return menu.get();
716 };
717
718 auto makeBodyStyleMenu =
719 [&]( TOOL_INTERACTIVE* tool )
720 {
721 std::shared_ptr<BODY_STYLE_MENU> menu = std::make_shared<BODY_STYLE_MENU>();
722 menu->SetTool( tool );
723 tool->GetToolMenu().RegisterSubMenu( menu );
724 return menu.get();
725 };
726
727 auto makePinFunctionMenu =
728 [&]( TOOL_INTERACTIVE* tool )
729 {
730 std::shared_ptr<ALT_PIN_FUNCTION_MENU> menu = std::make_shared<ALT_PIN_FUNCTION_MENU>();
731 menu->SetTool( tool );
732 tool->GetToolMenu().RegisterSubMenu( menu );
733 return menu.get();
734 };
735
736 auto makePinTricksMenu =
737 [&]( TOOL_INTERACTIVE* tool )
738 {
739 std::shared_ptr<PIN_TRICKS_MENU> menu = std::make_shared<PIN_TRICKS_MENU>();
740 menu->SetTool( tool );
741 tool->GetToolMenu().RegisterSubMenu( menu );
742 return menu.get();
743 };
744
745 auto makeTransformMenu =
746 [&]()
747 {
748 CONDITIONAL_MENU* menu = new CONDITIONAL_MENU( moveTool );
749 menu->SetUntranslatedTitle( _HKI( "Transform Selection" ) );
750
751 menu->AddItem( SCH_ACTIONS::rotateCCW, orientCondition );
752 menu->AddItem( SCH_ACTIONS::rotateCW, orientCondition );
753 menu->AddItem( SCH_ACTIONS::mirrorV, orientCondition );
754 menu->AddItem( SCH_ACTIONS::mirrorH, orientCondition );
755
756 return menu;
757 };
758
759 auto makeAttributesMenu =
760 [&]()
761 {
762 CONDITIONAL_MENU* menu = new CONDITIONAL_MENU( moveTool );
763 menu->SetUntranslatedTitle( _HKI( "Attributes" ) );
764
769
770 return menu;
771 };
772
773 auto makeEditFieldsMenu =
774 [&]()
775 {
777 menu->SetUntranslatedTitle( _HKI( "Edit Main Fields" ) );
778
782
783 return menu;
784 };
785
786 auto makeConvertToMenu =
787 [&]()
788 {
790 menu->SetUntranslatedTitle( _HKI( "Change To" ) );
791 menu->SetIcon( BITMAPS::right );
792
793 menu->AddItem( SCH_ACTIONS::toLabel, toLabelCondition );
794 menu->AddItem(SCH_ACTIONS::toDLabel, toCLabelCondition );
795 menu->AddItem( SCH_ACTIONS::toHLabel, toHLabelCondition );
796 menu->AddItem( SCH_ACTIONS::toGLabel, toGLabelCondition );
797 menu->AddItem( SCH_ACTIONS::toText, toTextCondition );
798 menu->AddItem( SCH_ACTIONS::toTextBox, toTextBoxCondition );
799
800 return menu;
801 };
802
803 auto makeLockMenu = [&]( TOOL_INTERACTIVE* tool )
804 {
805 std::shared_ptr<LOCK_CONTEXT_MENU> menu = std::make_shared<LOCK_CONTEXT_MENU>( tool );
806 tool->GetToolMenu().RegisterSubMenu( menu );
807 return menu.get();
808 };
809
810 const auto canCopyText = SCH_CONDITIONS::OnlyTypes( {
819 SCH_PIN_T,
822 } );
823
824 //
825 // Add edit actions to the move tool menu
826 //
827 CONDITIONAL_MENU& moveMenu = moveTool->GetToolMenu().GetMenu();
828
829 moveMenu.AddSeparator();
830 moveMenu.AddMenu( makeSymbolUnitMenu( moveTool ), S_C::SingleMultiUnitSymbol, 1 );
831 moveMenu.AddMenu( makeBodyStyleMenu( moveTool ), S_C::SingleMultiBodyStyleSymbol, 1 );
832
833 moveMenu.AddMenu( makeTransformMenu(), orientCondition, 200 );
834 moveMenu.AddMenu( makeAttributesMenu(), S_C::HasTypes( attribTypes ), 200 );
835 moveMenu.AddItem( SCH_ACTIONS::swap, swapSelectionCondition, 200 );
836 moveMenu.AddItem( SCH_ACTIONS::properties, propertiesCondition, 200 );
837 moveMenu.AddMenu( makeEditFieldsMenu(), S_C::SingleSymbol, 200 );
838
839 moveMenu.AddSeparator();
840 moveMenu.AddItem( ACTIONS::cut, S_C::IdleSelection );
841 moveMenu.AddItem( ACTIONS::copy, S_C::IdleSelection );
842 moveMenu.AddItem( ACTIONS::copyAsText, canCopyText && S_C::IdleSelection );
843 moveMenu.AddItem( ACTIONS::doDelete, S_C::NotEmpty );
844 moveMenu.AddItem( ACTIONS::duplicate, duplicateCondition );
845
846 //
847 // Add editing actions to the drawing tool menu
848 //
849 CONDITIONAL_MENU& drawMenu = drawingTools->GetToolMenu().GetMenu();
850
851 drawMenu.AddItem( SCH_ACTIONS::clearHighlight, haveHighlight && S_C::Idle, 1 );
852 drawMenu.AddSeparator( haveHighlight && S_C::Idle, 1 );
853
854 drawMenu.AddItem( SCH_ACTIONS::enterSheet, sheetSelection && S_C::Idle, 1 );
855 drawMenu.AddSeparator( sheetSelection && S_C::Idle, 1 );
856
857 drawMenu.AddMenu( makeSymbolUnitMenu( drawingTools ), S_C::SingleMultiUnitSymbol, 1 );
858 drawMenu.AddMenu( makeBodyStyleMenu( drawingTools ), S_C::SingleMultiBodyStyleSymbol, 1 );
859
860 drawMenu.AddMenu( makeTransformMenu(), orientCondition, 200 );
861 drawMenu.AddMenu( makeAttributesMenu(), S_C::HasTypes( attribTypes ), 200 );
862 drawMenu.AddItem( SCH_ACTIONS::properties, propertiesCondition, 200 );
863 drawMenu.AddMenu( makeEditFieldsMenu(), S_C::SingleSymbol, 200 );
864 drawMenu.AddItem( SCH_ACTIONS::autoplaceFields, autoplaceCondition, 200 );
865
867
868 drawMenu.AddItem( SCH_ACTIONS::toLabel, anyTextTool && S_C::Idle, 200 );
869 drawMenu.AddItem( SCH_ACTIONS::toHLabel, anyTextTool && S_C::Idle, 200 );
870 drawMenu.AddItem( SCH_ACTIONS::toGLabel, anyTextTool && S_C::Idle, 200 );
871 drawMenu.AddItem( SCH_ACTIONS::toText, anyTextTool && S_C::Idle, 200 );
872 drawMenu.AddItem( SCH_ACTIONS::toTextBox, anyTextTool && S_C::Idle, 200 );
873
874 //
875 // Add editing actions to the selection tool menu
876 //
877 CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
878
879 selToolMenu.AddMenu( makeSymbolUnitMenu( m_selectionTool ), S_C::SingleMultiUnitSymbol, 1 );
880 selToolMenu.AddMenu( makeBodyStyleMenu( m_selectionTool ), S_C::SingleMultiBodyStyleSymbol, 1 );
881 selToolMenu.AddMenu( makePinFunctionMenu( m_selectionTool ), S_C::SingleMultiFunctionPin, 1 );
882 selToolMenu.AddMenu( makePinTricksMenu( m_selectionTool ), S_C::AllPinsOrSheetPins, 1 );
883
884 selToolMenu.AddMenu( makeTransformMenu(), orientCondition, 200 );
885 selToolMenu.AddMenu( makeAttributesMenu(), S_C::HasTypes( attribTypes ), 200 );
886 selToolMenu.AddItem( SCH_ACTIONS::swap, swapSelectionCondition, 200 );
887 selToolMenu.AddItem( SCH_ACTIONS::properties, propertiesCondition, 200 );
888 selToolMenu.AddMenu( makeEditFieldsMenu(), S_C::SingleSymbol, 200 );
889 selToolMenu.AddItem( SCH_ACTIONS::autoplaceFields, autoplaceCondition, 200 );
890
896 selToolMenu.AddMenu( makeConvertToMenu(), toChangeCondition, 200 );
897
898 selToolMenu.AddItem( SCH_ACTIONS::cleanupSheetPins, sheetHasUndefinedPins, 250 );
899 selToolMenu.AddMenu( makeLockMenu( m_selectionTool ), S_C::NotEmpty, 250 );
900
901 selToolMenu.AddSeparator( 300 );
902 selToolMenu.AddItem( ACTIONS::cut, S_C::IdleSelection, 300 );
903 selToolMenu.AddItem( ACTIONS::copy, S_C::IdleSelection, 300 );
904 selToolMenu.AddItem( ACTIONS::copyAsText, canCopyText && S_C::IdleSelection, 300 );
905 selToolMenu.AddItem( ACTIONS::paste, S_C::Idle, 300 );
906 selToolMenu.AddItem( ACTIONS::pasteSpecial, S_C::Idle, 300 );
907 selToolMenu.AddItem( ACTIONS::doDelete, S_C::NotEmpty, 300 );
908 selToolMenu.AddItem( ACTIONS::duplicate, duplicateCondition, 300 );
909
910 selToolMenu.AddSeparator( 400 );
911 selToolMenu.AddItem( ACTIONS::selectAll, S_C::ShowAlways, 400 );
912 selToolMenu.AddItem( ACTIONS::unselectAll, S_C::ShowAlways, 400 );
913
914 ACTION_MANAGER* mgr = m_toolMgr->GetActionManager();
915
916 mgr->SetConditions( SCH_ACTIONS::setDNP, ACTION_CONDITIONS().Check( attribDNPCond ) );
917 mgr->SetConditions( SCH_ACTIONS::setExcludeFromSim, ACTION_CONDITIONS().Check( attribExcludeFromSimCond ) );
918 mgr->SetConditions( SCH_ACTIONS::setExcludeFromBOM, ACTION_CONDITIONS().Check( attribExcludeFromBOMCond ) );
919 mgr->SetConditions( SCH_ACTIONS::setExcludeFromBoard, ACTION_CONDITIONS().Check( attribExcludeFromBoardCond ) );
920
921 return true;
922}
923
924
925const std::vector<KICAD_T> SCH_EDIT_TOOL::RotatableItems = {
931 SCH_TABLECELL_T, // will be promoted to parent table(s)
947};
948
949
950const std::vector<KICAD_T> SCH_EDIT_TOOL::SwappableItems = {
966};
967
968
970{
971 bool clockwise = ( aEvent.Matches( SCH_ACTIONS::rotateCW.MakeEvent() ) );
972 SCH_SELECTION& selection = m_selectionTool->RequestSelection( RotatableItems, true, false );
973
974 m_selectionTool->FilterSelectionForLockedItems();
975
976 wxLogTrace( "KICAD_SCH_MOVE", "SCH_EDIT_TOOL::Rotate: start, clockwise=%d, selection size=%u", clockwise,
977 selection.GetSize() );
978
979 if( selection.GetSize() == 0 )
980 return 0;
981
982 SCH_ITEM* head = nullptr;
983 int principalItemCount = 0; // User-selected items (as opposed to connected wires)
984 VECTOR2I rotPoint;
985 bool moving = false;
986 SCH_COMMIT localCommit( m_toolMgr );
987 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
988 SCH_SCREEN* screen = m_frame->GetScreen();
989
990 std::map<SCH_SHEET_PIN*, SCH_NO_CONNECT*> noConnects;
991
992 if( !commit )
993 commit = &localCommit;
994
995 for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
996 {
997 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
998
999 if( item->HasFlag( SELECTED_BY_DRAG ) )
1000 continue;
1001
1002 principalItemCount++;
1003
1004 if( !head )
1005 head = item;
1006 }
1007
1008 if( head && head->IsMoving() )
1009 moving = true;
1010
1011 if( principalItemCount == 1 )
1012 {
1013 if( moving && selection.HasReferencePoint() )
1014 rotPoint = selection.GetReferencePoint();
1015 else if( head->IsConnectable() )
1016 rotPoint = head->GetPosition();
1017 else
1018 rotPoint = m_frame->GetNearestHalfGridPosition( head->GetBoundingBox().GetCenter() );
1019
1020 if( !moving )
1021 commit->Modify( head, screen, RECURSE_MODE::RECURSE );
1022
1023 switch( head->Type() )
1024 {
1025 case SCH_SYMBOL_T:
1026 {
1027 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( head );
1028
1029 symbol->Rotate( rotPoint, !clockwise );
1030
1031 if( m_frame->eeconfig()->m_AutoplaceFields.enable )
1032 {
1033 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
1034
1035 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
1036 symbol->AutoplaceFields( screen, fieldsAutoplaced );
1037 }
1038
1039 break;
1040 }
1041
1042 case SCH_TEXT_T:
1043 case SCH_LABEL_T:
1044 case SCH_GLOBAL_LABEL_T:
1045 case SCH_HIER_LABEL_T:
1047 {
1048 SCH_TEXT* textItem = static_cast<SCH_TEXT*>( head );
1049 textItem->Rotate90( clockwise );
1050 break;
1051 }
1052
1053 case SCH_SHEET_PIN_T:
1054 {
1055 // Rotate pin within parent sheet
1056 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( head );
1057 SCH_SHEET* sheet = pin->GetParent();
1058
1059 for( SCH_ITEM* ncItem : screen->Items().Overlapping( SCH_NO_CONNECT_T, pin->GetTextPos() ) )
1060 noConnects[pin] = static_cast<SCH_NO_CONNECT*>( ncItem );
1061
1062 pin->Rotate( sheet->GetBoundingBox().GetCenter(), !clockwise );
1063
1064 break;
1065 }
1066
1067 case SCH_LINE_T:
1068 {
1069 SCH_LINE* line = static_cast<SCH_LINE*>( head );
1070
1071 // Equal checks for both and neither. We need this because on undo
1072 // the item will have both flags cleared, but will be selected, so it is possible
1073 // for the user to get a selected line with neither endpoint selected. We
1074 // set flags to make sure Rotate() works when we call it.
1075 if( line->HasFlag( STARTPOINT ) == line->HasFlag( ENDPOINT ) )
1076 {
1077 line->SetFlags( STARTPOINT | ENDPOINT );
1078
1079 // When we allow off grid items, the rotPoint should be set to the midpoint
1080 // of the line to allow rotation around the center, and the next if
1081 // should become an else-if
1082 }
1083
1084 if( line->HasFlag( STARTPOINT ) )
1085 rotPoint = line->GetEndPoint();
1086 else if( line->HasFlag( ENDPOINT ) )
1087 rotPoint = line->GetStartPoint();
1088 }
1089
1091 case SCH_JUNCTION_T:
1092 case SCH_NO_CONNECT_T:
1095 head->Rotate( rotPoint, !clockwise );
1096
1097 break;
1098
1099 case SCH_FIELD_T:
1100 {
1101 SCH_FIELD* field = static_cast<SCH_FIELD*>( head );
1102
1103 if( field->GetTextAngle().IsHorizontal() )
1104 field->SetTextAngle( ANGLE_VERTICAL );
1105 else
1107
1108 // Now that we're moving a field, they're no longer autoplaced.
1109 static_cast<SCH_ITEM*>( head->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
1110
1111 break;
1112 }
1113
1114 case SCH_RULE_AREA_T:
1115 case SCH_SHAPE_T:
1116 case SCH_TEXTBOX_T:
1117 head->Rotate( rotPoint, !clockwise );
1118
1119 break;
1120
1121 case SCH_GROUP_T:
1122 {
1123 // Rotate the group on itself. Groups do not have an anchor point.
1124 SCH_GROUP* group = static_cast<SCH_GROUP*>( head );
1125 rotPoint = m_frame->GetNearestHalfGridPosition( group->GetPosition() );
1126
1127 group->Rotate( rotPoint, !clockwise );
1128
1129 group->Move( rotPoint - m_frame->GetNearestHalfGridPosition( group->GetPosition() ) );
1130
1131 break;
1132 }
1133
1134 case SCH_TABLE_T:
1135 {
1136 // Rotate the table on itself. Tables do not have an anchor point.
1137 SCH_TABLE* table = static_cast<SCH_TABLE*>( head );
1138 rotPoint = m_frame->GetNearestHalfGridPosition( table->GetCenter() );
1139
1140 table->Rotate( rotPoint, !clockwise );
1141
1142 table->Move( rotPoint - m_frame->GetNearestHalfGridPosition( table->GetCenter() ) );
1143
1144 break;
1145 }
1146
1147 case SCH_BITMAP_T:
1148 head->Rotate( rotPoint, clockwise );
1149
1150 // The bitmap is cached in Opengl: clear the cache to redraw
1152 break;
1153
1154 case SCH_SHEET_T:
1155 {
1156 // Rotate the sheet on itself. Sheets do not have an anchor point.
1157 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( head );
1158
1159 noConnects = sheet->GetNoConnects();
1160
1161 rotPoint = m_frame->GetNearestHalfGridPosition( sheet->GetRotationCenter() );
1162 sheet->Rotate( rotPoint, !clockwise );
1163
1164 break;
1165 }
1166
1167 default:
1168 UNIMPLEMENTED_FOR( head->GetClass() );
1169 }
1170
1171 m_frame->UpdateItem( head, false, true );
1172 }
1173 else
1174 {
1175 if( moving && selection.HasReferencePoint() )
1176 rotPoint = selection.GetReferencePoint();
1177 else
1178 rotPoint = m_frame->GetNearestHalfGridPosition( selection.GetCenter() );
1179 }
1180
1181 for( EDA_ITEM* edaItem : selection )
1182 {
1183 SCH_ITEM* item = static_cast<SCH_ITEM*>( edaItem );
1184
1185 // We've already rotated the user selected item if there was only one. We're just
1186 // here to rotate the ends of wires that were attached to it.
1187 if( principalItemCount == 1 && !item->HasFlag( SELECTED_BY_DRAG ) )
1188 continue;
1189
1190 if( !moving )
1191 commit->Modify( item, screen, RECURSE_MODE::RECURSE );
1192
1193 if( item->Type() == SCH_LINE_T )
1194 {
1195 SCH_LINE* line = (SCH_LINE*) item;
1196
1197 line->Rotate( rotPoint, !clockwise );
1198 }
1199 else if( item->Type() == SCH_SHEET_PIN_T )
1200 {
1201 if( item->GetParent()->IsSelected() )
1202 {
1203 // parent will rotate us
1204 }
1205 else
1206 {
1207 // rotate within parent
1208 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
1209 SCH_SHEET* sheet = pin->GetParent();
1210
1211 for( SCH_ITEM* ncItem : screen->Items().Overlapping( SCH_NO_CONNECT_T, pin->GetTextPos() ) )
1212 noConnects[pin] = static_cast<SCH_NO_CONNECT*>( ncItem );
1213
1214 pin->Rotate( sheet->GetBodyBoundingBox().GetCenter(), !clockwise );
1215 }
1216 }
1217 else if( item->Type() == SCH_FIELD_T )
1218 {
1219 if( item->GetParent()->IsSelected() )
1220 {
1221 // parent will rotate us
1222 }
1223 else
1224 {
1225 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
1226
1227 field->Rotate( rotPoint, !clockwise );
1228
1229 // Now that we're moving a field, they're no longer autoplaced.
1230 static_cast<SCH_ITEM*>( field->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
1231 }
1232 }
1233 else if( item->Type() == SCH_TABLE_T )
1234 {
1235 SCH_TABLE* table = static_cast<SCH_TABLE*>( item );
1236 VECTOR2I beforeCenter = table->GetCenter();
1237
1238 table->Rotate( rotPoint, !clockwise );
1239 RotatePoint( beforeCenter, rotPoint, clockwise ? -ANGLE_90 : ANGLE_90 );
1240
1241 table->Move( beforeCenter - table->GetCenter() );
1242 }
1243 else if( item->Type() == SCH_SHEET_T )
1244 {
1245 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1246
1247 noConnects = sheet->GetNoConnects();
1248
1249 sheet->Rotate( rotPoint, !clockwise );
1250 }
1251 else
1252 {
1253 VECTOR2I posBefore = item->GetPosition();
1254 item->Rotate( rotPoint, !clockwise );
1255 VECTOR2I posAfter = item->GetPosition();
1256 wxLogTrace( "KICAD_SCH_MOVE", " SCH_EDIT_TOOL::Rotate: item type=%d rotated, pos (%d,%d) -> (%d,%d)",
1257 item->Type(), posBefore.x, posBefore.y, posAfter.x, posAfter.y );
1258 }
1259
1260 m_frame->UpdateItem( item, false, true );
1261 updateItem( item, true );
1262 }
1263
1264 wxLogTrace( "KICAD_SCH_MOVE", "SCH_EDIT_TOOL::Rotate: complete, moving=%d", moving );
1265
1266 if( moving )
1267 {
1268 wxLogTrace( "KICAD_SCH_MOVE", "SCH_EDIT_TOOL::Rotate: posting refreshPreview" );
1269 m_toolMgr->PostAction( ACTIONS::refreshPreview );
1270 }
1271 else
1272 {
1273 for( auto& [sheetPin, noConnect] : noConnects )
1274 {
1275 if( noConnect->GetPosition() != sheetPin->GetTextPos() )
1276 {
1277 commit->Modify( noConnect, screen );
1278 noConnect->SetPosition( sheetPin->GetTextPos() );
1279 updateItem( noConnect, true );
1280 }
1281 }
1282
1283 SCH_SELECTION selectionCopy = selection;
1284
1285 if( selection.IsHover() )
1286 m_toolMgr->RunAction( ACTIONS::selectionClear );
1287
1289 lwbTool->TrimOverLappingWires( commit, &selectionCopy );
1290 lwbTool->AddJunctionsIfNeeded( commit, &selectionCopy );
1291
1292 m_frame->Schematic().CleanUp( commit );
1293
1294 if( !localCommit.Empty() )
1295 localCommit.Push( _( "Rotate" ) );
1296 }
1297
1298 return 0;
1299}
1300
1301
1303{
1304 SCH_SELECTION& selection = m_selectionTool->RequestSelection( RotatableItems, false, false );
1305
1306 m_selectionTool->FilterSelectionForLockedItems();
1307
1308 if( selection.GetSize() == 0 )
1309 return 0;
1310
1311 bool vertical = ( aEvent.Matches( SCH_ACTIONS::mirrorV.MakeEvent() ) );
1312 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
1313 bool connections = false;
1314 bool moving = item->IsMoving();
1315 SCH_COMMIT localCommit( m_toolMgr );
1316 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
1317 SCH_SCREEN* screen = m_frame->GetScreen();
1318
1319 std::map<SCH_SHEET_PIN*, SCH_NO_CONNECT*> noConnects;
1320
1321 if( !commit )
1322 commit = &localCommit;
1323
1324 if( selection.GetSize() == 1 )
1325 {
1326 if( !moving )
1327 commit->Modify( item, screen, RECURSE_MODE::RECURSE );
1328
1329 switch( item->Type() )
1330 {
1331 case SCH_SYMBOL_T:
1332 {
1333 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1334
1335 if( vertical )
1336 symbol->SetOrientation( SYM_MIRROR_X );
1337 else
1338 symbol->SetOrientation( SYM_MIRROR_Y );
1339
1341 break;
1342 }
1343
1344 case SCH_TEXT_T:
1345 case SCH_LABEL_T:
1346 case SCH_GLOBAL_LABEL_T:
1347 case SCH_HIER_LABEL_T:
1349 {
1350 SCH_TEXT* textItem = static_cast<SCH_TEXT*>( item );
1351 textItem->MirrorSpinStyle( !vertical );
1352 break;
1353 }
1354
1355 case SCH_SHEET_PIN_T:
1356 {
1357 // mirror within parent sheet
1358 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
1359 SCH_SHEET* sheet = pin->GetParent();
1360
1361 for( SCH_ITEM* ncItem : screen->Items().Overlapping( SCH_NO_CONNECT_T, pin->GetTextPos() ) )
1362 noConnects[pin] = static_cast<SCH_NO_CONNECT*>( ncItem );
1363
1364 if( vertical )
1365 pin->MirrorVertically( sheet->GetBoundingBox().GetCenter().y );
1366 else
1367 pin->MirrorHorizontally( sheet->GetBoundingBox().GetCenter().x );
1368
1369 break;
1370 }
1371
1372 case SCH_FIELD_T:
1373 {
1374 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
1375
1376 if( vertical )
1378 else
1380
1381 // Now that we're re-justifying a field, they're no longer autoplaced.
1382 static_cast<SCH_ITEM*>( field->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
1383
1384 break;
1385 }
1386
1387 case SCH_BITMAP_T:
1388 if( vertical )
1389 item->MirrorVertically( item->GetPosition().y );
1390 else
1391 item->MirrorHorizontally( item->GetPosition().x );
1392
1393 // The bitmap is cached in Opengl: clear the cache to redraw
1395 break;
1396
1397 case SCH_SHEET_T:
1398 {
1399 noConnects = static_cast<SCH_SHEET*>( item )->GetNoConnects();
1400
1401 // Mirror the sheet on itself. Sheets do not have a anchor point.
1402 VECTOR2I mirrorPoint = m_frame->GetNearestHalfGridPosition( item->GetBoundingBox().Centre() );
1403
1404 if( vertical )
1405 item->MirrorVertically( mirrorPoint.y );
1406 else
1407 item->MirrorHorizontally( mirrorPoint.x );
1408
1409 break;
1410 }
1411
1412 default:
1413 if( vertical )
1414 item->MirrorVertically( item->GetPosition().y );
1415 else
1416 item->MirrorHorizontally( item->GetPosition().x );
1417
1418 break;
1419 }
1420
1421 connections = item->IsConnectable();
1422 m_frame->UpdateItem( item, false, true );
1423 }
1424 else if( selection.GetSize() > 1 )
1425 {
1426 VECTOR2I mirrorPoint = m_frame->GetNearestHalfGridPosition( selection.GetCenter() );
1427
1428 for( EDA_ITEM* edaItem : selection )
1429 {
1430 item = static_cast<SCH_ITEM*>( edaItem );
1431
1432 if( !moving )
1433 commit->Modify( item, screen, RECURSE_MODE::RECURSE );
1434
1435 if( item->Type() == SCH_SHEET_PIN_T )
1436 {
1437 if( item->GetParent()->IsSelected() )
1438 {
1439 // parent will mirror us
1440 }
1441 else
1442 {
1443 // mirror within parent sheet
1444 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
1445 SCH_SHEET* sheet = pin->GetParent();
1446
1447 if( vertical )
1448 pin->MirrorVertically( sheet->GetBoundingBox().GetCenter().y );
1449 else
1450 pin->MirrorHorizontally( sheet->GetBoundingBox().GetCenter().x );
1451 }
1452 }
1453 else if( item->Type() == SCH_FIELD_T )
1454 {
1455 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
1456
1457 if( vertical )
1459 else
1461
1462 // Now that we're re-justifying a field, they're no longer autoplaced.
1463 static_cast<SCH_ITEM*>( field->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
1464 }
1465 else
1466 {
1467 if( vertical )
1468 item->MirrorVertically( mirrorPoint.y );
1469 else
1470 item->MirrorHorizontally( mirrorPoint.x );
1471 }
1472
1473 connections |= item->IsConnectable();
1474 m_frame->UpdateItem( item, false, true );
1475 }
1476 }
1477
1478 // Update R-Tree for modified items
1479 for( EDA_ITEM* selected : selection )
1480 updateItem( selected, true );
1481
1482 if( item->IsMoving() )
1483 {
1484 m_toolMgr->RunAction( ACTIONS::refreshPreview );
1485 }
1486 else
1487 {
1488 for( auto& [sheetPin, noConnect] : noConnects )
1489 {
1490 if( noConnect->GetPosition() != sheetPin->GetTextPos() )
1491 {
1492 commit->Modify( noConnect, screen );
1493 noConnect->SetPosition( sheetPin->GetTextPos() );
1494 updateItem( noConnect, true );
1495 }
1496 }
1497
1498 SCH_SELECTION selectionCopy = selection;
1499
1500 if( selection.IsHover() )
1501 m_toolMgr->RunAction( ACTIONS::selectionClear );
1502
1503 if( connections )
1504 {
1506 lwbTool->TrimOverLappingWires( commit, &selectionCopy );
1507 lwbTool->AddJunctionsIfNeeded( commit, &selectionCopy );
1508
1509 m_frame->Schematic().CleanUp( commit );
1510 }
1511
1512 if( !localCommit.Empty() )
1513 localCommit.Push( _( "Mirror" ) );
1514 }
1515
1516 return 0;
1517}
1518
1528static void swapFieldPositionsWithMatching( std::vector<SCH_FIELD>& aAFields, std::vector<SCH_FIELD>& aBFields,
1529 unsigned aFallbackRotationsCCW )
1530{
1531 std::set<wxString> handledKeys;
1532
1533 const auto swapFieldTextProps = []( SCH_FIELD& aField, SCH_FIELD& bField )
1534 {
1535 const VECTOR2I aRelPos = aField.GetPosition() - aField.GetParentPosition();
1536 const GR_TEXT_H_ALIGN_T aTextJustifyH = aField.GetHorizJustify();
1537 const GR_TEXT_V_ALIGN_T aTextJustifyV = aField.GetVertJustify();
1538 const EDA_ANGLE aTextAngle = aField.GetTextAngle();
1539
1540 const VECTOR2I bRelPos = bField.GetPosition() - bField.GetParentPosition();
1541 const GR_TEXT_H_ALIGN_T bTextJustifyH = bField.GetHorizJustify();
1542 const GR_TEXT_V_ALIGN_T bTextJustifyV = bField.GetVertJustify();
1543 const EDA_ANGLE bTextAngle = bField.GetTextAngle();
1544
1545 aField.SetPosition( aField.GetParentPosition() + bRelPos );
1546 aField.SetHorizJustify( bTextJustifyH );
1547 aField.SetVertJustify( bTextJustifyV );
1548 aField.SetTextAngle( bTextAngle );
1549
1550 bField.SetPosition( bField.GetParentPosition() + aRelPos );
1551 bField.SetHorizJustify( aTextJustifyH );
1552 bField.SetVertJustify( aTextJustifyV );
1553 bField.SetTextAngle( aTextAngle );
1554 };
1555
1556 for( SCH_FIELD& aField : aAFields )
1557 {
1558 const wxString name = aField.GetCanonicalName();
1559
1560 auto it = std::find_if( aBFields.begin(), aBFields.end(),
1561 [name]( const SCH_FIELD& bField )
1562 {
1563 return bField.GetCanonicalName() == name;
1564 } );
1565
1566 if( it != aBFields.end() )
1567 {
1568 // We have a field with the same key in both labels
1569 SCH_FIELD& bField = *it;
1570 swapFieldTextProps( aField, bField );
1571 }
1572 else
1573 {
1574 // We only have this field in A, so just rotate it
1575 for( unsigned ii = 0; ii < aFallbackRotationsCCW; ii++ )
1576 {
1577 aField.Rotate( aField.GetParentPosition(), true );
1578 }
1579 }
1580
1581 // And keep track that we did this one
1582 handledKeys.insert( name );
1583 }
1584
1585 // Any fields in B that weren't in A weren't handled and need to be rotated
1586 // in reverse
1587 for( SCH_FIELD& bField : aBFields )
1588 {
1589 const wxString bName = bField.GetCanonicalName();
1590 if( handledKeys.find( bName ) == handledKeys.end() )
1591 {
1592 for( unsigned ii = 0; ii < aFallbackRotationsCCW; ii++ )
1593 {
1594 bField.Rotate( bField.GetParentPosition(), false );
1595 }
1596 }
1597 }
1598}
1599
1600
1602{
1603 SCH_SELECTION& selection = m_selectionTool->RequestSelection( SwappableItems );
1604
1605 m_selectionTool->FilterSelectionForLockedItems();
1606
1607 std::vector<EDA_ITEM*> sorted = selection.GetItemsSortedBySelectionOrder();
1608
1609 if( selection.Size() < 2 )
1610 return 0;
1611
1612 // Sheet pins are special, we need to make sure if we have any sheet pins,
1613 // that we only have sheet pins, and that they have the same parent
1614 if( selection.CountType( SCH_SHEET_PIN_T ) > 0 )
1615 {
1616 if( !selection.OnlyContains( { SCH_SHEET_PIN_T } ) )
1617 return 0;
1618
1619 EDA_ITEM* parent = selection.Front()->GetParent();
1620
1621 for( EDA_ITEM* item : selection )
1622 {
1623 if( item->GetParent() != parent )
1624 return 0;
1625 }
1626 }
1627
1628 bool moving = selection.Front()->IsMoving();
1629 bool connections = false;
1630
1631 SCH_COMMIT localCommit( m_toolMgr );
1632 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
1633
1634 if( !commit )
1635 commit = &localCommit;
1636
1637 for( size_t i = 0; i < sorted.size() - 1; i++ )
1638 {
1639 SCH_ITEM* a = static_cast<SCH_ITEM*>( sorted[i] );
1640 SCH_ITEM* b = static_cast<SCH_ITEM*>( sorted[( i + 1 ) % sorted.size()] );
1641
1642 if( !moving )
1643 {
1644 commit->Modify( a, m_frame->GetScreen(), RECURSE_MODE::RECURSE );
1645 commit->Modify( b, m_frame->GetScreen(), RECURSE_MODE::RECURSE );
1646 }
1647
1648 VECTOR2I aPos = a->GetPosition(), bPos = b->GetPosition();
1649 std::swap( aPos, bPos );
1650
1651 // Sheet pins need to have their sides swapped before we change their
1652 // positions
1653 if( a->Type() == SCH_SHEET_PIN_T )
1654 {
1655 SCH_SHEET_PIN* aPin = static_cast<SCH_SHEET_PIN*>( a );
1656 SCH_SHEET_PIN* bPin = static_cast<SCH_SHEET_PIN*>( b );
1657 SHEET_SIDE aSide = aPin->GetSide(), bSide = bPin->GetSide();
1658 std::swap( aSide, bSide );
1659 aPin->SetSide( aSide );
1660 bPin->SetSide( bSide );
1661 }
1662
1663 a->SetPosition( aPos );
1664 b->SetPosition( bPos );
1665
1666 if( a->Type() == b->Type() )
1667 {
1668 switch( a->Type() )
1669 {
1670 case SCH_LABEL_T:
1671 case SCH_GLOBAL_LABEL_T:
1672 case SCH_HIER_LABEL_T:
1674 {
1675 SCH_LABEL_BASE& aLabelBase = static_cast<SCH_LABEL_BASE&>( *a );
1676 SCH_LABEL_BASE& bLabelBase = static_cast<SCH_LABEL_BASE&>( *b );
1677
1678 const SPIN_STYLE aSpinStyle = aLabelBase.GetSpinStyle();
1679 const SPIN_STYLE bSpinStyle = bLabelBase.GetSpinStyle();
1680 const GR_TEXT_V_ALIGN_T aVertJustify = aLabelBase.GetVertJustify();
1681 const GR_TEXT_V_ALIGN_T bVertJustify = bLabelBase.GetVertJustify();
1682
1683 // First, swap the label orientations
1684 aLabelBase.SetSpinStyle( bSpinStyle );
1685 bLabelBase.SetSpinStyle( aSpinStyle );
1686 aLabelBase.SetVertJustify( bVertJustify );
1687 bLabelBase.SetVertJustify( aVertJustify );
1688
1689 // And swap the fields as best we can
1690 std::vector<SCH_FIELD>& aFields = aLabelBase.GetFields();
1691 std::vector<SCH_FIELD>& bFields = bLabelBase.GetFields();
1692
1693 const unsigned rotationsAtoB = aSpinStyle.CCWRotationsTo( bSpinStyle );
1694
1695 swapFieldPositionsWithMatching( aFields, bFields, rotationsAtoB );
1696 break;
1697 }
1698 case SCH_TEXT_T:
1699 case SCH_TEXTBOX_T:
1700 {
1701 EDA_TEXT* aText = dynamic_cast<EDA_TEXT*>( a );
1702 EDA_TEXT* bText = dynamic_cast<EDA_TEXT*>( b );
1703
1704 if( !aText || !bText )
1705 break;
1706
1707 const GR_TEXT_H_ALIGN_T aHorizJustify = aText->GetHorizJustify();
1708 const GR_TEXT_V_ALIGN_T aVertJustify = aText->GetVertJustify();
1709 const GR_TEXT_H_ALIGN_T bHorizJustify = bText->GetHorizJustify();
1710 const GR_TEXT_V_ALIGN_T bVertJustify = bText->GetVertJustify();
1711
1712 aText->SetHorizJustify( bHorizJustify );
1713 aText->SetVertJustify( bVertJustify );
1714 bText->SetHorizJustify( aHorizJustify );
1715 bText->SetVertJustify( aVertJustify );
1716 break;
1717 }
1718 case SCH_SYMBOL_T:
1719 {
1720 SCH_SYMBOL* aSymbol = static_cast<SCH_SYMBOL*>( a );
1721 SCH_SYMBOL* bSymbol = static_cast<SCH_SYMBOL*>( b );
1722
1723 // Only swap orientations when both symbols are the same library symbol.
1724 // Different symbols (e.g. LED vs resistor) have different default orientations,
1725 // so swapping their orientations leads to unexpected visual results.
1726 if( aSymbol->GetLibId() == bSymbol->GetLibId() )
1727 {
1728 int aOrient = aSymbol->GetOrientation();
1729 int bOrient = bSymbol->GetOrientation();
1730 std::swap( aOrient, bOrient );
1731 aSymbol->SetOrientation( aOrient );
1732 bSymbol->SetOrientation( bOrient );
1733 }
1734
1735 break;
1736 }
1737 default: break;
1738 }
1739 }
1740
1741 connections |= a->IsConnectable();
1742 connections |= b->IsConnectable();
1743 m_frame->UpdateItem( a, false, true );
1744 m_frame->UpdateItem( b, false, true );
1745 }
1746
1747 if( moving )
1748 {
1749 m_toolMgr->PostAction( ACTIONS::refreshPreview );
1750 }
1751 else
1752 {
1753 if( selection.IsHover() )
1754 m_toolMgr->RunAction( ACTIONS::selectionClear );
1755
1756 if( connections )
1757 m_frame->TestDanglingEnds();
1758 m_frame->OnModify();
1759
1760 if( !localCommit.Empty() )
1761 localCommit.Push( _( "Swap" ) );
1762 }
1763
1764 return 0;
1765}
1766
1767
1768/*
1769 * This command always works on the instance owned by the schematic, never directly on the
1770 * external library file. Pins that still reference their library definition are swapped by
1771 * touching that shared lib pin first; afterwards we call UpdatePins() so the schematic now owns a
1772 * cached copy with the new geometry. Pins that already have an instance-local copy simply swap in
1773 * place. In both cases the undo stack captures the modified pins (and the parent symbol) so the
1774 * user can revert the change. Saving the schematic writes the updated pin order into the sheet,
1775 * while the global symbol library remains untouched unless the user explicitly pushes it later.
1776 */
1778{
1779 wxCHECK( m_frame, 0 );
1780
1781 if( !m_frame->eeconfig()->m_Input.allow_unconstrained_pin_swaps )
1782 return 0;
1783
1784 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_PIN_T } );
1785 std::vector<EDA_ITEM*> sorted = selection.GetItemsSortedBySelectionOrder();
1786
1787 if( selection.Size() < 2 )
1788 return 0;
1789
1790 EDA_ITEM* parent = selection.Front()->GetParent();
1791
1792 if( !parent || parent->Type() != SCH_SYMBOL_T )
1793 return 0;
1794
1795 SCH_SYMBOL* parentSymbol = static_cast<SCH_SYMBOL*>( parent );
1796
1797 // All pins need to be on the same symbol
1798 for( EDA_ITEM* item : selection )
1799 {
1800 if( item->GetParent() != parent )
1801 return 0;
1802 }
1803
1804 std::set<wxString> sharedSheetPaths;
1805 std::set<wxString> sharedProjectNames;
1806
1807 if( SymbolHasSheetInstances( *parentSymbol, m_frame->Prj().GetProjectName(), &sharedSheetPaths,
1808 &sharedProjectNames ) )
1809 {
1810 // This will give us nice names for our project, but not when the sheet is shared across
1811 // multiple projects. But, in that case we bail early and just list the project names so it isn't an issue.
1812 std::set<wxString> friendlySheets;
1813
1814 if( !sharedSheetPaths.empty() )
1815 friendlySheets = GetSheetNamesFromPaths( sharedSheetPaths, m_frame->Schematic() );
1816
1817 if( !sharedProjectNames.empty() )
1818 {
1819 wxString projects = AccumulateDescriptions( sharedProjectNames );
1820
1821 if( projects.IsEmpty() )
1822 {
1823 m_frame->ShowInfoBarError( _( "Pin swaps are disabled for symbols shared across other projects. "
1824 "Duplicate the sheet to edit pins independently." ) );
1825 }
1826 else
1827 {
1828 m_frame->ShowInfoBarError(
1829 wxString::Format( _( "Pin swaps are disabled for symbols shared across other projects (%s). "
1830 "Duplicate the sheet to edit pins independently." ),
1831 projects ) );
1832 }
1833 }
1834 else if( !friendlySheets.empty() )
1835 {
1836 wxString sheets = AccumulateDescriptions( friendlySheets );
1837
1838 m_frame->ShowInfoBarError(
1839 wxString::Format( _( "Pin swaps are disabled for symbols used by multiple sheet instances (%s). "
1840 "Duplicate the sheet to edit pins independently." ),
1841 sheets ) );
1842 }
1843 else
1844 {
1845 m_frame->ShowInfoBarError(
1846 _( "Pin swaps are disabled for shared symbols. Duplicate the sheet to edit pins independently." ) );
1847 }
1848
1849 return 0;
1850 }
1851
1852 bool connections = false;
1853
1854 SCH_COMMIT localCommit( m_toolMgr );
1855 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
1856
1857 if( !commit )
1858 commit = &localCommit;
1859
1860 // Stage the parent symbol so undo/redo captures the cache copy that UpdatePins() may rebuild
1861 // after we touch any shared library pins.
1862 commit->Modify( parentSymbol, m_frame->GetScreen(), RECURSE_MODE::RECURSE ); // RECURSE is harmless here
1863
1864 bool swappedLibPins = false;
1865
1866 for( size_t i = 0; i < sorted.size() - 1; i++ )
1867 {
1868 SCH_PIN* aPin = static_cast<SCH_PIN*>( sorted[i] );
1869 SCH_PIN* bPin = static_cast<SCH_PIN*>( sorted[( i + 1 ) % sorted.size()] );
1870
1871 // Record both pins in the commit and swap their geometry. SwapPinGeometry returns true if
1872 // it had to operate on the shared library pins (meaning the schematic instance still
1873 // referenced them), in which case UpdatePins() below promotes the symbol to an instance
1874 // copy that reflects the new pin order.
1875 commit->Modify( aPin, m_frame->GetScreen(), RECURSE_MODE::RECURSE );
1876 commit->Modify( bPin, m_frame->GetScreen(), RECURSE_MODE::RECURSE );
1877
1878 swappedLibPins |= SwapPinGeometry( aPin, bPin );
1879
1880 connections |= aPin->IsConnectable();
1881 connections |= bPin->IsConnectable();
1882 m_frame->UpdateItem( aPin, false, true );
1883 m_frame->UpdateItem( bPin, false, true );
1884 }
1885
1886 if( swappedLibPins )
1887 parentSymbol->UpdatePins(); // clone the library data into the schematic cache with new geometry
1888
1889 // Refresh changed symbol in screen R-Tree / lib caches
1890 m_frame->UpdateItem( parentSymbol, false, true );
1891
1892 SCH_SELECTION selectionCopy = selection;
1893
1894 if( selection.IsHover() )
1895 m_toolMgr->RunAction( ACTIONS::selectionClear );
1896
1897 // Reconcile any wiring that was connected to the swapped pins so the schematic stays tidy and
1898 // the undo stack captures the resulting edits to wires and junctions.
1900 lwbTool->TrimOverLappingWires( commit, &selectionCopy );
1901 lwbTool->AddJunctionsIfNeeded( commit, &selectionCopy );
1902
1903 m_frame->Schematic().CleanUp( commit );
1904
1905 if( connections )
1906 m_frame->TestDanglingEnds();
1907
1908 m_frame->OnModify();
1909
1910 if( !localCommit.Empty() )
1911 localCommit.Push( _( "Swap Pins" ) );
1912
1913 return 0;
1914}
1915
1916
1917// Used by SwapPinLabels() and SwapUnitLabels() to find the single net label connected to a pin
1919 const SCH_SHEET_PATH& aSheetPath )
1920{
1921 if( !aGraph || !aPin )
1922 return nullptr;
1923
1924 CONNECTION_SUBGRAPH* sg = aGraph->GetSubgraphForItem( aPin );
1925
1926 if( !sg )
1927 return nullptr;
1928
1929 const std::set<SCH_ITEM*>& items = sg->GetItems();
1930
1931 size_t pinCount = 0;
1932 SCH_LABEL_BASE* label = nullptr;
1933
1934 for( SCH_ITEM* item : items )
1935 {
1936 if( item->Type() == SCH_PIN_T )
1937 pinCount++;
1938
1939 switch( item->Type() )
1940 {
1941 case SCH_LABEL_T:
1942 case SCH_GLOBAL_LABEL_T:
1943 case SCH_HIER_LABEL_T:
1944 {
1945 SCH_CONNECTION* conn = item->Connection( &aSheetPath );
1946
1947 if( conn && conn->IsNet() )
1948 {
1949 if( label )
1950 return nullptr; // more than one label
1951
1952 label = static_cast<SCH_LABEL_BASE*>( item );
1953 }
1954
1955 break;
1956 }
1957 default: break;
1958 }
1959 }
1960
1961 if( pinCount != 1 )
1962 return nullptr;
1963
1964 return label;
1965}
1966
1967
1969{
1970 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_PIN_T } );
1971 std::vector<EDA_ITEM*> orderedPins = selection.GetItemsSortedBySelectionOrder();
1972
1973 if( orderedPins.size() < 2 )
1974 return 0;
1975
1976 CONNECTION_GRAPH* connectionGraph = m_frame->Schematic().ConnectionGraph();
1977
1978 const SCH_SHEET_PATH& sheetPath = m_frame->GetCurrentSheet();
1979
1980 std::vector<SCH_LABEL_BASE*> labels;
1981
1982 for( EDA_ITEM* item : orderedPins )
1983 {
1984 SCH_PIN* pin = static_cast<SCH_PIN*>( item );
1985 SCH_LABEL_BASE* label = findSingleNetLabelForPin( pin, connectionGraph, sheetPath );
1986
1987 if( !label )
1988 {
1989 m_frame->ShowInfoBarError(
1990 _( "Each selected pin must have exactly one attached net label and no other pin connections." ) );
1991 return 0;
1992 }
1993
1994 labels.push_back( label );
1995 }
1996
1997 if( labels.size() >= 2 )
1998 {
1999 SCH_COMMIT commit( m_frame );
2000
2001 for( SCH_LABEL_BASE* lb : labels )
2002 commit.Modify( lb, m_frame->GetScreen() );
2003
2004 for( size_t i = 0; i < labels.size() - 1; ++i )
2005 {
2006 SCH_LABEL_BASE* a = labels[i];
2007 SCH_LABEL_BASE* b = labels[( i + 1 ) % labels.size()];
2008 wxString aText = a->GetText();
2009 wxString bText = b->GetText();
2010 a->SetText( bText );
2011 b->SetText( aText );
2012 }
2013
2014 commit.Push( _( "Swap Pin Labels" ) );
2015 }
2016
2017 return 0;
2018}
2019
2020
2022{
2023 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_SYMBOL_T } );
2024 std::vector<SCH_SYMBOL*> selectedUnits = GetSameSymbolMultiUnitSelection( selection );
2025
2026 if( selectedUnits.size() < 2 )
2027 return 0;
2028
2029 CONNECTION_GRAPH* connectionGraph = m_frame->Schematic().ConnectionGraph();
2030
2031 const SCH_SHEET_PATH& sheetPath = m_frame->GetCurrentSheet();
2032
2033 // Build ordered label vectors (sorted by pin X/Y) for each selected unit
2034 std::vector<std::vector<SCH_LABEL_BASE*>> symbolLabelVectors;
2035
2036 for( SCH_SYMBOL* symbol : selectedUnits )
2037 {
2038 std::vector<std::pair<VECTOR2I, SCH_LABEL_BASE*>> byPos;
2039
2040 for( SCH_PIN* pin : symbol->GetPins( &sheetPath ) )
2041 {
2042 SCH_LABEL_BASE* label = findSingleNetLabelForPin( pin, connectionGraph, sheetPath );
2043
2044 if( !label )
2045 {
2046 m_frame->ShowInfoBarError( _( "Each pin of selected units must have exactly one attached net label and "
2047 "no other pin connections." ) );
2048 return 0;
2049 }
2050
2051 byPos.emplace_back( pin->GetPosition(), label );
2052 }
2053
2054 // Sort labels by pin position (X, then Y)
2055 std::sort( byPos.begin(), byPos.end(),
2056 []( const auto& a, const auto& b )
2057 {
2058 if( a.first.x != b.first.x )
2059 return a.first.x < b.first.x;
2060
2061 return a.first.y < b.first.y;
2062 } );
2063
2064 // Discard position, just keep the order
2065 std::vector<SCH_LABEL_BASE*> labels;
2066
2067 for( const auto& pr : byPos )
2068 labels.push_back( pr.second );
2069
2070 symbolLabelVectors.push_back( labels );
2071 }
2072
2073 // All selected units are guaranteed to have identical pin counts by GetSameSymbolMultiUnitSelection()
2074 const size_t pinCount = symbolLabelVectors.front().size();
2075
2076 // Perform cyclic swap of labels across all selected symbols, per pin index
2077 SCH_COMMIT commit( m_frame );
2078
2079 for( size_t pin = 0; pin < pinCount; pin++ )
2080 {
2081 for( auto& vec : symbolLabelVectors )
2082 commit.Modify( vec[pin], m_frame->GetScreen() );
2083
2084 wxString carry = symbolLabelVectors.back()[pin]->GetText();
2085
2086 for( size_t i = 0; i < symbolLabelVectors.size(); i++ )
2087 {
2088 SCH_LABEL_BASE* lbl = symbolLabelVectors[i][pin];
2089 wxString next = lbl->GetText();
2090 lbl->SetText( carry );
2091 carry = next;
2092 }
2093 }
2094
2095 if( !commit.Empty() )
2096 commit.Push( _( "Swap Unit Labels" ) );
2097
2098 return 0;
2099}
2100
2101
2103{
2104 const std::vector<std::unique_ptr<SCH_ITEM>>& sourceItems = m_frame->GetRepeatItems();
2105
2106 if( sourceItems.empty() )
2107 return 0;
2108
2109 m_toolMgr->RunAction( ACTIONS::selectionClear );
2110
2111 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
2112 SCH_COMMIT commit( m_toolMgr );
2113 SCH_SELECTION newItems;
2114
2115 for( const std::unique_ptr<SCH_ITEM>& item : sourceItems )
2116 {
2117 SCH_ITEM* newItem = item->Duplicate( IGNORE_PARENT_GROUP );
2118 bool restore_state = false;
2119
2120 // Ensure newItem has a suitable parent: the current screen, because an item from
2121 // a list of items to repeat must be attached to this current screen
2122 newItem->SetParent( m_frame->GetScreen() );
2123
2124 if( SCH_GROUP* enteredGroup = selectionTool->GetEnteredGroup() )
2125 {
2126 if( newItem->IsGroupableType() )
2127 {
2128 commit.Modify( enteredGroup, m_frame->GetScreen(), RECURSE_MODE::NO_RECURSE );
2129 enteredGroup->AddItem( newItem );
2130 }
2131 }
2132
2133 if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( newItem ) )
2134 {
2135 // If incrementing tries to go below zero, tell user why the value is repeated
2136 if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
2137 {
2138 if( !label->IncrementLabel( cfg->m_Drawing.repeat_label_increment ) )
2139 m_frame->ShowInfoBarWarning( _( "Label value cannot go below zero" ), true );
2140 }
2141 }
2142
2143 // If cloning a symbol then put into 'move' mode.
2144 if( newItem->Type() == SCH_SYMBOL_T )
2145 {
2146 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( true );
2147 newItem->Move( cursorPos - newItem->GetPosition() );
2148 }
2149 else if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
2150 {
2151 newItem->Move( VECTOR2I( schIUScale.MilsToIU( cfg->m_Drawing.default_repeat_offset_x ),
2152 schIUScale.MilsToIU( cfg->m_Drawing.default_repeat_offset_y ) ) );
2153 }
2154
2155 // If cloning a sheet, check that we aren't going to create recursion
2156 if( newItem->Type() == SCH_SHEET_T )
2157 {
2158 SCH_SHEET_PATH* currentSheet = &m_frame->GetCurrentSheet();
2159 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( newItem );
2160
2161 if( m_frame->CheckSheetForRecursion( sheet, currentSheet ) )
2162 {
2163 // Clear out the filename so that the user can pick a new one
2164 const wxString originalFileName = sheet->GetFileName();
2165 const wxString originalScreenFileName = sheet->GetScreen()->GetFileName();
2166
2167 sheet->SetFileName( wxEmptyString );
2168 sheet->GetScreen()->SetFileName( wxEmptyString );
2169 restore_state = !m_frame->EditSheetProperties( sheet, currentSheet );
2170
2171 if( restore_state )
2172 {
2173 sheet->SetFileName( originalFileName );
2174 sheet->GetScreen()->SetFileName( originalScreenFileName );
2175 }
2176 }
2177 }
2178
2179 m_toolMgr->RunAction<EDA_ITEM*>( ACTIONS::selectItem, newItem );
2180 newItem->SetFlags( IS_NEW );
2181 m_frame->AddToScreen( newItem, m_frame->GetScreen() );
2182 commit.Added( newItem, m_frame->GetScreen() );
2183
2184 if( newItem->Type() == SCH_SYMBOL_T )
2185 {
2186 SCHEMATIC_SETTINGS& projSettings = m_frame->Schematic().Settings();
2187 int annotateStartNum = projSettings.m_AnnotateStartNum;
2188 ANNOTATE_ORDER_T annotateOrder = static_cast<ANNOTATE_ORDER_T>( projSettings.m_AnnotateSortOrder );
2189 ANNOTATE_ALGO_T annotateAlgo = static_cast<ANNOTATE_ALGO_T>( projSettings.m_AnnotateMethod );
2190
2191 if( m_frame->eeconfig()->m_AnnotatePanel.automatic )
2192 {
2193 static_cast<SCH_SYMBOL*>( newItem )->ClearAnnotation( nullptr, false );
2194 NULL_REPORTER reporter;
2195 m_frame->AnnotateSymbols( &commit, ANNOTATE_SELECTION, annotateOrder, annotateAlgo,
2196 true /* recursive */, annotateStartNum, false, false, false,
2197 reporter );
2198 }
2199
2200 // Annotation clears the selection so re-add the item
2201 m_toolMgr->RunAction<EDA_ITEM*>( ACTIONS::selectItem, newItem );
2202
2203 restore_state = !m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit );
2204 }
2205
2206 if( restore_state )
2207 {
2208 commit.Revert();
2209 }
2210 else
2211 {
2212 newItems.Add( newItem );
2213
2215 lwbTool->TrimOverLappingWires( &commit, &newItems );
2216 lwbTool->AddJunctionsIfNeeded( &commit, &newItems );
2217
2218 m_frame->Schematic().CleanUp( &commit );
2219 commit.Push( _( "Repeat Item" ) );
2220 }
2221 }
2222
2223 if( !newItems.Empty() )
2224 m_frame->SaveCopyForRepeatItem( static_cast<SCH_ITEM*>( newItems[0] ) );
2225
2226 for( size_t ii = 1; ii < newItems.GetSize(); ++ii )
2227 m_frame->AddCopyForRepeatItem( static_cast<SCH_ITEM*>( newItems[ii] ) );
2228
2229 return 0;
2230}
2231
2232
2234{
2235 SCH_SCREEN* screen = m_frame->GetScreen();
2236
2238 m_selectionTool->FilterSelectionForLockedItems();
2239
2240 std::deque<EDA_ITEM*> items = m_selectionTool->GetSelection().GetItems();
2241 SCH_COMMIT commit( m_toolMgr );
2242 std::vector<VECTOR2I> pts;
2243 bool updateHierarchy = false;
2244
2245 if( items.empty() )
2246 return 0;
2247
2248 // Don't leave a freed pointer in the selection
2249 m_toolMgr->RunAction( ACTIONS::selectionClear );
2250
2251 for( EDA_ITEM* item : items )
2252 item->ClearFlags( STRUCT_DELETED );
2253
2254 for( EDA_ITEM* item : items )
2255 {
2256 SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item );
2257
2258 if( !sch_item )
2259 continue;
2260
2261 if( sch_item->IsConnectable() )
2262 {
2263 std::vector<VECTOR2I> tmp_pts = sch_item->GetConnectionPoints();
2264 pts.insert( pts.end(), tmp_pts.begin(), tmp_pts.end() );
2265 }
2266
2267 if( sch_item->Type() == SCH_JUNCTION_T )
2268 {
2269 sch_item->SetFlags( STRUCT_DELETED );
2270 // clean up junctions at the end
2271 }
2272 else if( sch_item->Type() == SCH_SHEET_PIN_T )
2273 {
2274 SCH_SHEET_PIN* pin = (SCH_SHEET_PIN*) sch_item;
2275 SCH_SHEET* sheet = pin->GetParent();
2276
2277 if( !alg::contains( items, sheet ) )
2278 {
2279 commit.Modify( sheet, m_frame->GetScreen() );
2280 sheet->RemovePin( pin );
2281 }
2282 }
2283 else if( sch_item->Type() == SCH_FIELD_T )
2284 {
2285 // Hide field
2286 commit.Modify( item, m_frame->GetScreen() );
2287 static_cast<SCH_FIELD*>( sch_item )->SetVisible( false );
2288 }
2289 else if( sch_item->Type() == SCH_TABLECELL_T )
2290 {
2291 // Clear contents of table cell
2292 commit.Modify( item, m_frame->GetScreen() );
2293 static_cast<SCH_TABLECELL*>( sch_item )->SetText( wxEmptyString );
2294 }
2295 else if( sch_item->Type() == SCH_RULE_AREA_T )
2296 {
2297 sch_item->SetFlags( STRUCT_DELETED );
2298 commit.Remove( item, m_frame->GetScreen() );
2299 }
2300 else if( sch_item->Type() == SCH_GROUP_T )
2301 {
2302 // Groups need to delete their children
2303 sch_item->RunOnChildren(
2304 [&]( SCH_ITEM* aChild )
2305 {
2306 aChild->SetFlags( STRUCT_DELETED );
2307 commit.Remove( aChild, m_frame->GetScreen() );
2308 },
2310
2311 sch_item->SetFlags( STRUCT_DELETED );
2312 commit.Remove( sch_item, m_frame->GetScreen() );
2313 }
2314 else
2315 {
2316 sch_item->SetFlags( STRUCT_DELETED );
2317 commit.Remove( item, m_frame->GetScreen() );
2318 updateHierarchy |= ( sch_item->Type() == SCH_SHEET_T );
2319 }
2320 }
2321
2322 for( const VECTOR2I& point : pts )
2323 {
2324 SCH_ITEM* junction = screen->GetItem( point, 0, SCH_JUNCTION_T );
2325
2326 if( !junction )
2327 continue;
2328
2329 if( junction->HasFlag( STRUCT_DELETED ) || !screen->IsExplicitJunction( point ) )
2330 m_frame->DeleteJunction( &commit, junction );
2331 }
2332
2333 commit.Push( _( "Delete" ) );
2334
2335 if( updateHierarchy )
2336 m_frame->UpdateHierarchyNavigator();
2337
2338 return 0;
2339}
2340
2341
2343{
2344 KICAD_T parentType = aField->GetParent() ? aField->GetParent()->Type() : SCHEMATIC_T;
2345 SCH_COMMIT commit( m_toolMgr );
2346
2347 // Save old symbol in undo list if not already in edit, or moving.
2348 if( aField->GetEditFlags() == 0 ) // i.e. not edited, or moved
2349 commit.Modify( aField, m_frame->GetScreen() );
2350
2351 if( parentType == SCH_SYMBOL_T && aField->GetId() == FIELD_T::REFERENCE )
2352 static_cast<SCH_ITEM*>( aField->GetParent() )->SetConnectivityDirty();
2353
2354 wxString caption;
2355
2356 // Use title caps for mandatory fields. "Edit Sheet name Field" looks dorky.
2357 if( aField->IsMandatory() )
2358 {
2359 wxString fieldName = GetDefaultFieldName( aField->GetId(), DO_TRANSLATE );
2360 caption.Printf( _( "Edit %s Field" ), TitleCaps( fieldName ) );
2361 }
2362 else
2363 {
2364 caption.Printf( _( "Edit '%s' Field" ), aField->GetName() );
2365 }
2366
2367 DIALOG_FIELD_PROPERTIES dlg( m_frame, caption, aField );
2368
2369 // The footprint field dialog can invoke a KIWAY_PLAYER so we must use a quasi-modal
2370 if( dlg.ShowQuasiModal() != wxID_OK )
2371 return;
2372
2373 dlg.UpdateField( &commit, aField, &m_frame->GetCurrentSheet() );
2374
2375 if( m_frame->eeconfig()->m_AutoplaceFields.enable || parentType == SCH_SHEET_T )
2376 {
2377 SCH_ITEM* parent = static_cast<SCH_ITEM*>( aField->GetParent() );
2378 AUTOPLACE_ALGO fieldsAutoplaced = parent->GetFieldsAutoplaced();
2379
2380 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
2381 parent->AutoplaceFields( m_frame->GetScreen(), fieldsAutoplaced );
2382 }
2383
2384 if( !commit.Empty() )
2385 commit.Push( caption );
2386}
2387
2388
2390{
2391 SCH_SELECTION sel = m_selectionTool->RequestSelection( { SCH_FIELD_T, SCH_SYMBOL_T, SCH_PIN_T } );
2392
2393 if( sel.Size() != 1 )
2394 return 0;
2395
2396 bool clearSelection = sel.IsHover();
2397 EDA_ITEM* item = sel.Front();
2398
2399 if( item->Type() == SCH_FIELD_T )
2400 {
2401 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
2402
2403 if( ( aEvent.IsAction( &SCH_ACTIONS::editReference ) && field->GetId() != FIELD_T::REFERENCE )
2404 || ( aEvent.IsAction( &SCH_ACTIONS::editValue ) && field->GetId() != FIELD_T::VALUE )
2405 || ( aEvent.IsAction( &SCH_ACTIONS::editFootprint ) && field->GetId() != FIELD_T::FOOTPRINT ) )
2406 {
2407 item = field->GetParentSymbol();
2408
2409 m_selectionTool->ClearSelection( true );
2410
2411 // If the field to edit is not a symbol field, we cannot edit the ref, value or footprint
2412 if( item == nullptr )
2413 return 0;
2414
2415 m_selectionTool->AddItemToSel( item );
2416 }
2417 }
2418
2419 if( item->Type() == SCH_SYMBOL_T )
2420 {
2421 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2422
2423 if( aEvent.IsAction( &SCH_ACTIONS::editReference ) )
2424 {
2426 }
2427 else if( aEvent.IsAction( &SCH_ACTIONS::editValue ) )
2428 {
2430 }
2431 else if( aEvent.IsAction( &SCH_ACTIONS::editFootprint ) )
2432 {
2433 if( !symbol->IsPower() )
2435 }
2436 }
2437 else if( item->Type() == SCH_FIELD_T )
2438 {
2439 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
2440
2441 editFieldText( field );
2442
2443 if( !field->IsVisible() )
2444 clearSelection = true;
2445 }
2446 else if( item->Type() == SCH_PIN_T )
2447 {
2448 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item->GetParent() );
2449
2450 if( symbol )
2451 {
2452 if( aEvent.IsAction( &SCH_ACTIONS::editReference ) )
2453 {
2455 }
2456 else if( aEvent.IsAction( &SCH_ACTIONS::editValue ) )
2457 {
2459 }
2460 else if( aEvent.IsAction( &SCH_ACTIONS::editFootprint ) )
2461 {
2462 if( !symbol->IsPower() )
2464 }
2465 }
2466 }
2467
2468 if( clearSelection )
2469 m_toolMgr->RunAction( ACTIONS::selectionClear );
2470
2471 return 0;
2472}
2473
2474
2476{
2477 SCH_SELECTION& selection = m_selectionTool->RequestSelection( RotatableItems );
2478 SCH_COMMIT commit( m_toolMgr );
2479 SCH_ITEM* head = static_cast<SCH_ITEM*>( selection.Front() );
2480 bool moving = head && head->IsMoving();
2481
2482 if( selection.Empty() )
2483 return 0;
2484
2485 std::vector<SCH_ITEM*> autoplaceItems;
2486
2487 for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
2488 {
2489 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
2490
2491 if( item->IsType( SCH_COLLECTOR::FieldOwners ) )
2492 autoplaceItems.push_back( item );
2493 else if( item->GetParent() && item->GetParent()->IsType( SCH_COLLECTOR::FieldOwners ) )
2494 autoplaceItems.push_back( static_cast<SCH_ITEM*>( item->GetParent() ) );
2495 }
2496
2497 for( SCH_ITEM* sch_item : autoplaceItems )
2498 {
2499 if( !moving && !sch_item->IsNew() )
2500 commit.Modify( sch_item, m_frame->GetScreen() );
2501
2502 sch_item->AutoplaceFields( m_frame->GetScreen(), AUTOPLACE_MANUAL );
2503
2504 updateItem( sch_item, true );
2505 }
2506
2507 if( moving )
2508 {
2509 m_toolMgr->PostAction( ACTIONS::refreshPreview );
2510 }
2511 else
2512 {
2513 if( !commit.Empty() )
2514 commit.Push( _( "Autoplace Fields" ) );
2515
2516 if( selection.IsHover() )
2517 m_toolMgr->RunAction( ACTIONS::selectionClear );
2518 }
2519
2520 return 0;
2521}
2522
2523
2525{
2526 SCH_SYMBOL* selectedSymbol = nullptr;
2527 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_SYMBOL_T } );
2528
2529 if( !selection.Empty() )
2530 selectedSymbol = dynamic_cast<SCH_SYMBOL*>( selection.Front() );
2531
2533
2536
2537 DIALOG_CHANGE_SYMBOLS dlg( m_frame, selectedSymbol, mode );
2538
2539 // QuasiModal required to invoke symbol browser
2540 dlg.ShowQuasiModal();
2541
2542 if( selection.IsHover() )
2543 m_toolMgr->RunAction( ACTIONS::selectionClear );
2544
2545 return 0;
2546}
2547
2548
2550{
2551 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_SYMBOL_T } );
2552
2553 if( selection.Empty() )
2554 return 0;
2555
2556 SCH_SYMBOL* symbol = (SCH_SYMBOL*) selection.Front();
2557 SCH_COMMIT commit( m_toolMgr );
2558
2559 if( !symbol->IsNew() )
2560 commit.Modify( symbol, m_frame->GetScreen() );
2561
2562 int nextBodyStyle = symbol->GetBodyStyle() + 1;
2563
2564 if( nextBodyStyle > symbol->GetBodyStyleCount() )
2565 nextBodyStyle = 1;
2566
2567 m_frame->SelectBodyStyle( symbol, nextBodyStyle );
2568
2569 if( symbol->IsNew() )
2570 m_toolMgr->PostAction( ACTIONS::refreshPreview );
2571
2572 if( !commit.Empty() )
2573 commit.Push( _( "Change Body Style" ) );
2574
2575 if( selection.IsHover() )
2576 m_toolMgr->RunAction( ACTIONS::selectionClear );
2577
2578 return 0;
2579}
2580
2581
2583{
2584 SCH_SELECTION& selection = m_selectionTool->RequestSelection();
2585 bool clearSelection = selection.IsHover();
2586
2587 if( selection.Empty() )
2588 {
2589 if( getView()->IsLayerVisible( LAYER_SCHEMATIC_DRAWINGSHEET ) )
2590 {
2591 DS_PROXY_VIEW_ITEM* ds = m_frame->GetCanvas()->GetView()->GetDrawingSheet();
2592 VECTOR2D cursorPos = getViewControls()->GetCursorPosition( false );
2593
2594 if( ds && ds->HitTestDrawingSheetItems( getView(), cursorPos ) )
2595 m_toolMgr->PostAction( ACTIONS::pageSettings );
2596 }
2597
2598 return 0;
2599 }
2600
2601 EDA_ITEM* curr_item = selection.Front();
2602
2603 // If a single pin is selected, promote to its parent symbol
2604 if( ( selection.GetSize() == 1 ) && ( curr_item->Type() == SCH_PIN_T ) )
2605 {
2606 EDA_ITEM* parent = curr_item->GetParent();
2607
2608 if( parent->Type() == SCH_SYMBOL_T )
2609 curr_item = parent;
2610 }
2611
2612 switch( curr_item->Type() )
2613 {
2614 case SCH_LINE_T:
2616 case SCH_JUNCTION_T:
2618 {
2619 std::deque<SCH_LINE*> lines;
2620
2621 for( EDA_ITEM* selItem : selection.Items() )
2622 lines.push_back( static_cast<SCH_LINE*>( selItem ) );
2623
2624 DIALOG_LINE_PROPERTIES dlg( m_frame, lines );
2625
2626 dlg.ShowModal();
2627 }
2628 else if( SELECTION_CONDITIONS::OnlyTypes( { SCH_JUNCTION_T } )( selection ) )
2629 {
2630 std::deque<SCH_JUNCTION*> junctions;
2631
2632 for( EDA_ITEM* selItem : selection.Items() )
2633 junctions.push_back( static_cast<SCH_JUNCTION*>( selItem ) );
2634
2635 DIALOG_JUNCTION_PROPS dlg( m_frame, junctions );
2636
2637 dlg.ShowModal();
2638 }
2642 SCH_JUNCTION_T } )( selection ) )
2643 {
2644 std::deque<SCH_ITEM*> items;
2645
2646 for( EDA_ITEM* selItem : selection.Items() )
2647 items.push_back( static_cast<SCH_ITEM*>( selItem ) );
2648
2649 DIALOG_WIRE_BUS_PROPERTIES dlg( m_frame, items );
2650
2651 dlg.ShowModal();
2652 }
2653 else
2654 {
2655 return 0;
2656 }
2657
2658 break;
2659
2660 case SCH_MARKER_T:
2661 if( SELECTION_CONDITIONS::OnlyTypes( { SCH_MARKER_T } )( selection ) )
2662 {
2663 SCH_INSPECTION_TOOL* inspectionTool = m_toolMgr->GetTool<SCH_INSPECTION_TOOL>();
2664
2665 if( inspectionTool )
2666 inspectionTool->CrossProbe( static_cast<SCH_MARKER*>( selection.Front() ) );
2667 }
2668 break;
2669
2670 case SCH_TABLECELL_T:
2671 if( SELECTION_CONDITIONS::OnlyTypes( { SCH_TABLECELL_T } )( selection ) )
2672 {
2673 std::vector<SCH_TABLECELL*> cells;
2674
2675 for( EDA_ITEM* item : selection.Items() )
2676 cells.push_back( static_cast<SCH_TABLECELL*>( item ) );
2677
2679
2680 // QuasiModal required for syntax help and Scintilla auto-complete
2681 dlg.ShowQuasiModal();
2682
2684 {
2685 SCH_TABLE* table = static_cast<SCH_TABLE*>( cells[0]->GetParent() );
2687
2688 tableDlg.ShowModal();
2689 }
2690 }
2691
2692 break;
2693
2694 default:
2695 if( selection.Size() > 1 )
2696 return 0;
2697
2698 EditProperties( curr_item );
2699 }
2700
2701 if( clearSelection )
2702 m_toolMgr->RunAction( ACTIONS::selectionClear );
2703
2704 return 0;
2705}
2706
2707
2709{
2710 switch( aItem->Type() )
2711 {
2712 case SCH_SYMBOL_T:
2713 {
2714 int retval;
2715 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( aItem );
2716
2717 // This needs to be scoped so the dialog destructor removes blocking status
2718 // before we launch the next dialog.
2719 {
2720 DIALOG_SYMBOL_PROPERTIES symbolPropsDialog( m_frame, symbol );
2721
2722 // This dialog itself subsequently can invoke a KIWAY_PLAYER as a quasimodal
2723 // frame. Therefore this dialog as a modal frame parent, MUST be run under
2724 // quasimodal mode for the quasimodal frame support to work. So don't use
2725 // the QUASIMODAL macros here.
2726 retval = symbolPropsDialog.ShowQuasiModal();
2727 }
2728
2729 if( retval == SYMBOL_PROPS_EDIT_OK )
2730 {
2731 if( m_frame->eeconfig()->m_AutoplaceFields.enable )
2732 {
2733 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
2734
2735 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
2736 symbol->AutoplaceFields( m_frame->GetScreen(), fieldsAutoplaced );
2737 }
2738
2739 m_frame->OnModify();
2740 }
2741 else if( retval == SYMBOL_PROPS_EDIT_SCHEMATIC_SYMBOL )
2742 {
2743 if( KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR, true ) )
2744 {
2745 SYMBOL_EDIT_FRAME* editor = static_cast<SYMBOL_EDIT_FRAME*>( frame );
2746
2747 if( wxWindow* blocking_win = editor->Kiway().GetBlockingDialog() )
2748 blocking_win->Close( true );
2749
2750 // The broken library symbol link indicator cannot be edited.
2751 if( symbol->IsMissingLibSymbol() )
2752 return;
2753
2754 editor->LoadSymbolFromSchematic( symbol );
2755 editor->Show( true );
2756 editor->Raise();
2757 }
2758 }
2759 else if( retval == SYMBOL_PROPS_EDIT_LIBRARY_SYMBOL )
2760 {
2761 if( KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR, true ) )
2762 {
2763 SYMBOL_EDIT_FRAME* editor = static_cast<SYMBOL_EDIT_FRAME*>( frame );
2764
2765 if( wxWindow* blocking_win = editor->Kiway().GetBlockingDialog() )
2766 blocking_win->Close( true );
2767
2768 editor->LoadSymbol( symbol->GetLibId(), symbol->GetUnit(), symbol->GetBodyStyle() );
2769 editor->Show( true );
2770 editor->Raise();
2771 }
2772 }
2773 else if( retval == SYMBOL_PROPS_WANT_UPDATE_SYMBOL )
2774 {
2776 dlg.ShowQuasiModal();
2777 }
2778 else if( retval == SYMBOL_PROPS_WANT_EXCHANGE_SYMBOL )
2779 {
2781 dlg.ShowQuasiModal();
2782 }
2783
2784 break;
2785 }
2786
2787 case SCH_SHEET_T:
2788 {
2789 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
2790 bool isUndoable = false;
2791 bool doClearAnnotation = false;
2792 bool okPressed = false;
2793 bool updateHierarchyNavigator = false;
2794
2795 // Keep track of existing sheet paths. EditSheet() can modify this list.
2796 // Note that we use the validity checking/repairing version here just to make sure
2797 // we've got a valid hierarchy to begin with.
2798 SCH_SHEET_LIST originalHierarchy;
2799 originalHierarchy.BuildSheetList( &m_frame->Schematic().Root(), true );
2800
2801 SCH_COMMIT commit( m_toolMgr );
2802 commit.Modify( sheet, m_frame->GetScreen() );
2803 okPressed = m_frame->EditSheetProperties( sheet, &m_frame->GetCurrentSheet(), &isUndoable, &doClearAnnotation,
2804 &updateHierarchyNavigator );
2805
2806 if( okPressed )
2807 {
2808 if( isUndoable )
2809 {
2810 commit.Push( _( "Edit Sheet Properties" ) );
2811 }
2812 else
2813 {
2814 std::vector<SCH_ITEM*> items;
2815
2816 items.emplace_back( sheet );
2817 m_frame->Schematic().OnItemsRemoved( items );
2818 m_frame->Schematic().OnItemsAdded( items );
2819 m_frame->OnModify();
2820 m_frame->Schematic().RefreshHierarchy();
2821 m_frame->UpdateHierarchyNavigator();
2822 }
2823 }
2824 else
2825 {
2826 // If we are renaming files, the undo/redo list becomes invalid and must be cleared.
2827 m_frame->ClearUndoRedoList();
2828 m_frame->OnModify();
2829 }
2830
2831 // If the sheet file is changed and new sheet contents are loaded then we have to
2832 // clear the annotations on the new content (as it may have been set from some other
2833 // sheet path reference)
2834 if( doClearAnnotation )
2835 {
2836 SCH_SCREENS screensList( &m_frame->Schematic().Root() );
2837
2838 // We clear annotation of new sheet paths here:
2839 screensList.ClearAnnotationOfNewSheetPaths( originalHierarchy );
2840
2841 // Clear annotation of g_CurrentSheet itself, because its sheetpath is not a new
2842 // path, but symbols managed by its sheet path must have their annotation cleared
2843 // because they are new:
2844 sheet->GetScreen()->ClearAnnotation( &m_frame->GetCurrentSheet(), false );
2845 }
2846
2847 if( okPressed )
2848 m_frame->GetCanvas()->Refresh();
2849
2850 if( updateHierarchyNavigator )
2851 m_frame->UpdateHierarchyNavigator();
2852
2853 break;
2854 }
2855
2856 case SCH_SHEET_PIN_T:
2857 {
2858 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( aItem );
2860
2861 // QuasiModal required for help dialog
2862 dlg.ShowQuasiModal();
2863 break;
2864 }
2865
2866 case SCH_TEXT_T:
2867 case SCH_TEXTBOX_T:
2868 {
2869 DIALOG_TEXT_PROPERTIES dlg( m_frame, static_cast<SCH_ITEM*>( aItem ) );
2870
2871 // QuasiModal required for syntax help and Scintilla auto-complete
2872 dlg.ShowQuasiModal();
2873 break;
2874 }
2875
2876 case SCH_TABLE_T:
2877 {
2878 DIALOG_TABLE_PROPERTIES dlg( m_frame, static_cast<SCH_TABLE*>( aItem ) );
2879
2880 // QuasiModal required for Scintilla auto-complete
2881 dlg.ShowQuasiModal();
2882 break;
2883 }
2884
2885 case SCH_LABEL_T:
2886 case SCH_GLOBAL_LABEL_T:
2887 case SCH_HIER_LABEL_T:
2889 {
2890 DIALOG_LABEL_PROPERTIES dlg( m_frame, static_cast<SCH_LABEL_BASE*>( aItem ), false );
2891
2892 // QuasiModal for syntax help and Scintilla auto-complete
2893 dlg.ShowQuasiModal();
2894 break;
2895 }
2896
2897 case SCH_FIELD_T:
2898 {
2899 SCH_FIELD* field = static_cast<SCH_FIELD*>( aItem );
2900
2901 editFieldText( field );
2902
2903 if( !field->IsVisible() )
2904 m_toolMgr->RunAction( ACTIONS::selectionClear );
2905
2906 break;
2907 }
2908
2909 case SCH_SHAPE_T:
2910 {
2911 DIALOG_SHAPE_PROPERTIES dlg( m_frame, static_cast<SCH_SHAPE*>( aItem ) );
2912
2913 dlg.ShowModal();
2914 break;
2915 }
2916
2917 case SCH_BITMAP_T:
2918 {
2919 SCH_BITMAP& bitmap = static_cast<SCH_BITMAP&>( *aItem );
2920 DIALOG_IMAGE_PROPERTIES dlg( m_frame, bitmap );
2921
2922 if( dlg.ShowModal() == wxID_OK )
2923 {
2924 // The bitmap is cached in Opengl: clear the cache in case it has become invalid
2926 }
2927
2928 break;
2929 }
2930
2931 case SCH_RULE_AREA_T:
2932 {
2933 DIALOG_SHAPE_PROPERTIES dlg( m_frame, static_cast<SCH_SHAPE*>( aItem ) );
2934 dlg.SetTitle( _( "Rule Area Properties" ) );
2935
2936 dlg.ShowModal();
2937 break;
2938 }
2939
2940 case SCH_NO_CONNECT_T:
2941 case SCH_PIN_T:
2942 break;
2943
2944 case SCH_GROUP_T:
2945 m_toolMgr->RunAction( ACTIONS::groupProperties, static_cast<EDA_GROUP*>( static_cast<SCH_GROUP*>( aItem ) ) );
2946
2947 break;
2948
2949 default: // Unexpected item
2950 wxFAIL_MSG( wxString( "Cannot edit schematic item type " ) + aItem->GetClass() );
2951 }
2952
2953 updateItem( aItem, true );
2954}
2955
2956
2958{
2959 KICAD_T convertTo = aEvent.Parameter<KICAD_T>();
2960 SCH_SELECTION selection = m_selectionTool->RequestSelection( { SCH_LABEL_LOCATE_ANY_T,
2961 SCH_TEXT_T,
2962 SCH_TEXTBOX_T } );
2963 SCH_COMMIT localCommit( m_toolMgr );
2964 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
2965
2966 if( !commit )
2967 commit = &localCommit;
2968
2969 for( unsigned int i = 0; i < selection.GetSize(); ++i )
2970 {
2971 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( selection.GetItem( i ) );
2972
2973 if( item && item->Type() != convertTo )
2974 {
2975 EDA_TEXT* sourceText = dynamic_cast<EDA_TEXT*>( item );
2976 bool selected = item->IsSelected();
2977 SCH_ITEM* newtext = nullptr;
2978 VECTOR2I position = item->GetPosition();
2979 wxString txt;
2980 wxString href;
2983
2984 wxCHECK2( sourceText, continue );
2985
2986 switch( item->Type() )
2987 {
2988 case SCH_LABEL_T:
2989 case SCH_GLOBAL_LABEL_T:
2990 case SCH_HIER_LABEL_T:
2991 {
2992 SCH_LABEL_BASE* label = static_cast<SCH_LABEL_BASE*>( item );
2993
2994 txt = UnescapeString( label->GetText() );
2995 spinStyle = label->GetSpinStyle();
2996 shape = label->GetShape();
2997 href = label->GetHyperlink();
2998 break;
2999 }
3000
3002 {
3003 SCH_DIRECTIVE_LABEL* dirlabel = static_cast<SCH_DIRECTIVE_LABEL*>( item );
3004
3005 // a SCH_DIRECTIVE_LABEL has no text
3006 txt = _( "<empty>" );
3007
3008 spinStyle = dirlabel->GetSpinStyle();
3009 href = dirlabel->GetHyperlink();
3010 break;
3011 }
3012
3013 case SCH_TEXT_T:
3014 {
3015 SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
3016
3017 txt = text->GetText();
3018 href = text->GetHyperlink();
3019 break;
3020 }
3021
3022 case SCH_TEXTBOX_T:
3023 {
3024 SCH_TEXTBOX* textbox = static_cast<SCH_TEXTBOX*>( item );
3025 BOX2I bbox = textbox->GetBoundingBox();
3026
3027 bbox.SetOrigin( bbox.GetLeft() + textbox->GetMarginLeft(), bbox.GetTop() + textbox->GetMarginTop() );
3028 bbox.SetEnd( bbox.GetRight() - textbox->GetMarginRight(),
3029 bbox.GetBottom() - textbox->GetMarginBottom() );
3030
3031 if( convertTo == SCH_LABEL_T || convertTo == SCH_HIER_LABEL_T || convertTo == SCH_GLOBAL_LABEL_T )
3032 {
3033 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
3034 wxCHECK( text, 0 );
3035 int textSize = text->GetTextSize().y;
3036 bbox.Inflate( KiROUND( item->Schematic()->Settings().m_LabelSizeRatio * textSize ) );
3037 }
3038
3039 txt = textbox->GetText();
3040
3041 if( textbox->GetTextAngle().IsVertical() )
3042 {
3043 if( textbox->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
3044 {
3045 spinStyle = SPIN_STYLE::SPIN::BOTTOM;
3046 position = VECTOR2I( bbox.Centre().x, bbox.GetOrigin().y );
3047 }
3048 else
3049 {
3050 spinStyle = SPIN_STYLE::SPIN::UP;
3051 position = VECTOR2I( bbox.Centre().x, bbox.GetEnd().y );
3052 }
3053 }
3054 else
3055 {
3056 if( textbox->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
3057 {
3058 spinStyle = SPIN_STYLE::SPIN::LEFT;
3059 position = VECTOR2I( bbox.GetEnd().x, bbox.Centre().y );
3060 }
3061 else
3062 {
3063 spinStyle = SPIN_STYLE::SPIN::RIGHT;
3064 position = VECTOR2I( bbox.GetOrigin().x, bbox.Centre().y );
3065 }
3066 }
3067
3068 position = m_frame->GetNearestGridPosition( position );
3069 href = textbox->GetHyperlink();
3070 break;
3071 }
3072
3073 default:
3074 UNIMPLEMENTED_FOR( item->GetClass() );
3075 break;
3076 }
3077
3078 auto getValidNetname =
3079 []( const wxString& aText )
3080 {
3081 wxString local_txt = aText;
3082 local_txt.Replace( "\n", "_" );
3083 local_txt.Replace( "\r", "_" );
3084 local_txt.Replace( "\t", "_" );
3085
3086 // Bus groups can have spaces; bus vectors and signal names cannot
3087 if( !NET_SETTINGS::ParseBusGroup( aText, nullptr, nullptr ) )
3088 local_txt.Replace( " ", "_" );
3089
3090 // label strings are "escaped" i.e. a '/' is replaced by "{slash}"
3091 local_txt = EscapeString( local_txt, CTX_NETNAME );
3092
3093 if( local_txt.IsEmpty() )
3094 return _( "<empty>" );
3095 else
3096 return local_txt;
3097 };
3098
3099 switch( convertTo )
3100 {
3101 case SCH_LABEL_T:
3102 {
3103 SCH_LABEL_BASE* new_label = new SCH_LABEL( position, getValidNetname( txt ) );
3104
3105 new_label->SetShape( shape );
3106 new_label->SetAttributes( *sourceText, false );
3107 new_label->SetSpinStyle( spinStyle );
3108 new_label->SetHyperlink( href );
3109
3110 if( item->Type() == SCH_GLOBAL_LABEL_T || item->Type() == SCH_HIER_LABEL_T )
3111 {
3112 if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::UP )
3113 new_label->MirrorVertically( position.y );
3114 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::BOTTOM )
3115 new_label->MirrorVertically( position.y );
3116 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::LEFT )
3117 new_label->MirrorHorizontally( position.x );
3118 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::RIGHT )
3119 new_label->MirrorHorizontally( position.x );
3120 }
3121
3122 newtext = new_label;
3123 break;
3124 }
3125
3126 case SCH_GLOBAL_LABEL_T:
3127 {
3128 SCH_LABEL_BASE* new_label = new SCH_GLOBALLABEL( position, getValidNetname( txt ) );
3129
3130 new_label->SetShape( shape );
3131 new_label->SetAttributes( *sourceText, false );
3132 new_label->SetSpinStyle( spinStyle );
3133 new_label->SetHyperlink( href );
3134
3135 if( item->Type() == SCH_LABEL_T )
3136 {
3137 if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::UP )
3138 new_label->MirrorVertically( position.y );
3139 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::BOTTOM )
3140 new_label->MirrorVertically( position.y );
3141 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::LEFT )
3142 new_label->MirrorHorizontally( position.x );
3143 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::RIGHT )
3144 new_label->MirrorHorizontally( position.x );
3145 }
3146
3147 newtext = new_label;
3148 break;
3149 }
3150
3151 case SCH_HIER_LABEL_T:
3152 {
3153 SCH_LABEL_BASE* new_label = new SCH_HIERLABEL( position, getValidNetname( txt ) );
3154
3155 new_label->SetShape( shape );
3156 new_label->SetAttributes( *sourceText, false );
3157 new_label->SetSpinStyle( spinStyle );
3158 new_label->SetHyperlink( href );
3159
3160 if( item->Type() == SCH_LABEL_T )
3161 {
3162 if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::UP )
3163 new_label->MirrorVertically( position.y );
3164 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::BOTTOM )
3165 new_label->MirrorVertically( position.y );
3166 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::LEFT )
3167 new_label->MirrorHorizontally( position.x );
3168 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::RIGHT )
3169 new_label->MirrorHorizontally( position.x );
3170 }
3171
3172 newtext = new_label;
3173 break;
3174 }
3175
3177 {
3178 SCH_LABEL_BASE* new_label = new SCH_DIRECTIVE_LABEL( position );
3179
3180 // A SCH_DIRECTIVE_LABEL usually has at least one field containing the net class
3181 // name. If we're copying from a text object assume the text is the netclass
3182 // name. Otherwise, we'll just copy the fields which will either have a netclass
3183 // or not.
3184 if( !dynamic_cast<SCH_LABEL_BASE*>( item ) )
3185 {
3186 SCH_FIELD netclass( new_label, FIELD_T::USER, wxT( "Netclass" ) );
3187 netclass.SetText( txt );
3188 netclass.SetTextPos( position );
3189 new_label->GetFields().push_back( netclass );
3190 }
3191
3192 new_label->SetShape( LABEL_FLAG_SHAPE::F_ROUND );
3193 new_label->SetAttributes( *sourceText, false );
3194 new_label->SetSpinStyle( spinStyle );
3195 new_label->SetHyperlink( href );
3196 newtext = new_label;
3197 break;
3198 }
3199
3200 case SCH_TEXT_T:
3201 {
3202 SCH_TEXT* new_text = new SCH_TEXT( position, txt );
3203
3204 new_text->SetAttributes( *sourceText, false );
3205 new_text->SetHyperlink( href );
3206 newtext = new_text;
3207 break;
3208 }
3209
3210 case SCH_TEXTBOX_T:
3211 {
3212 SCH_TEXTBOX* new_textbox = new SCH_TEXTBOX( LAYER_NOTES, 0, FILL_T::NO_FILL, txt );
3213 BOX2I bbox = item->GetBoundingBox();
3214
3215 if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( item ) )
3216 bbox.Inflate( -label->GetLabelBoxExpansion() );
3217
3218 new_textbox->SetAttributes( *sourceText, false );
3219
3220 bbox.SetOrigin( bbox.GetLeft() - new_textbox->GetMarginLeft(),
3221 bbox.GetTop() - new_textbox->GetMarginTop() );
3222 bbox.SetEnd( bbox.GetRight() + new_textbox->GetMarginRight(),
3223 bbox.GetBottom() + new_textbox->GetMarginBottom() );
3224
3225 VECTOR2I topLeft = bbox.GetPosition();
3226 VECTOR2I botRight = bbox.GetEnd();
3227
3228 // Add 1/20 of the margin at the end to reduce line-breaking changes.
3229 int slop = new_textbox->GetLegacyTextMargin() / 20;
3230
3231 if( sourceText->GetTextAngle() == ANGLE_VERTICAL )
3232 {
3233 if( sourceText->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
3234 botRight.y += slop;
3235 else
3236 topLeft.y -= slop;
3237 }
3238 else
3239 {
3240 if( sourceText->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
3241 topLeft.x -= slop;
3242 else
3243 botRight.x += slop;
3244 }
3245
3246 new_textbox->SetPosition( topLeft );
3247 new_textbox->SetEnd( botRight );
3248
3249 new_textbox->SetHyperlink( href );
3250 newtext = new_textbox;
3251 break;
3252 }
3253
3254 default:
3255 UNIMPLEMENTED_FOR( wxString::Format( "%d.", convertTo ) );
3256 break;
3257 }
3258
3259 wxCHECK2( newtext, continue );
3260
3261 // Copy the old text item settings to the new one. Justifications are not copied
3262 // because they are not used in labels. Justifications will be set to default value
3263 // in the new text item type.
3264 //
3265 newtext->SetFlags( item->GetEditFlags() );
3266
3267 EDA_TEXT* eda_text = dynamic_cast<EDA_TEXT*>( item );
3268 EDA_TEXT* new_eda_text = dynamic_cast<EDA_TEXT*>( newtext );
3269
3270 wxCHECK2( eda_text && new_eda_text, continue );
3271
3272 new_eda_text->SetFont( eda_text->GetFont() );
3273 new_eda_text->SetTextSize( eda_text->GetTextSize() );
3274 new_eda_text->SetTextThickness( eda_text->GetTextThickness() );
3275
3276 // Must be after SetTextSize()
3277 new_eda_text->SetBold( eda_text->IsBold() );
3278 new_eda_text->SetItalic( eda_text->IsItalic() );
3279
3280 newtext->AutoplaceFields( m_frame->GetScreen(), AUTOPLACE_AUTO );
3281
3282 SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( item );
3283 SCH_LABEL_BASE* new_label = dynamic_cast<SCH_LABEL_BASE*>( newtext );
3284
3285 if( label && new_label )
3286 {
3287 new_label->AddFields( label->GetFields() );
3288
3289 // A SCH_GLOBALLABEL has a specific field for intersheet references that has
3290 // no meaning for other labels
3291 std::erase_if( new_label->GetFields(),
3292 [&]( SCH_FIELD& field )
3293 {
3294 return field.GetId() == FIELD_T::INTERSHEET_REFS
3295 && new_label->Type() != SCH_GLOBAL_LABEL_T;
3296 } );
3297 }
3298
3299 if( selected )
3300 m_toolMgr->RunAction<EDA_ITEM*>( ACTIONS::unselectItem, item );
3301
3302 m_frame->RemoveFromScreen( item, m_frame->GetScreen() );
3303
3304 if( commit->GetStatus( item, m_frame->GetScreen() ) == CHT_ADD )
3305 commit->Unstage( item, m_frame->GetScreen() );
3306 else
3307 commit->Removed( item, m_frame->GetScreen() );
3308
3309 m_frame->AddToScreen( newtext, m_frame->GetScreen() );
3310 commit->Added( newtext, m_frame->GetScreen() );
3311
3312 if( selected )
3313 m_toolMgr->RunAction<EDA_ITEM*>( ACTIONS::selectItem, newtext );
3314 }
3315 }
3316
3317 if( !localCommit.Empty() )
3318 localCommit.Push( _( "Change To" ) );
3319
3320 if( selection.IsHover() )
3321 m_toolMgr->RunAction( ACTIONS::selectionClear );
3322
3323 return 0;
3324}
3325
3326
3328{
3329 static std::vector<KICAD_T> justifiableItems = { SCH_FIELD_T, SCH_TEXT_T, SCH_TEXTBOX_T, SCH_LABEL_T };
3330
3331 SCH_SELECTION& selection = m_selectionTool->RequestSelection( justifiableItems );
3332
3333 if( selection.GetSize() == 0 )
3334 return 0;
3335
3336 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
3337 bool moving = item->IsMoving();
3338 SCH_COMMIT localCommit( m_toolMgr );
3339 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
3340
3341 if( !commit )
3342 commit = &localCommit;
3343
3344 auto setJustify =
3345 [&]( EDA_TEXT* aTextItem )
3346 {
3347 if( aEvent.Matches( ACTIONS::leftJustify.MakeEvent() ) )
3348 aTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
3349 else if( aEvent.Matches( ACTIONS::centerJustify.MakeEvent() ) )
3350 aTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
3351 else
3352 aTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
3353 };
3354
3355 for( EDA_ITEM* edaItem : selection )
3356 {
3357 item = static_cast<SCH_ITEM*>( edaItem );
3358
3359 if( !moving )
3360 commit->Modify( item, m_frame->GetScreen() );
3361
3362 if( item->Type() == SCH_FIELD_T )
3363 {
3364 setJustify( static_cast<SCH_FIELD*>( item ) );
3365
3366 // Now that we're re-justifying a field, they're no longer autoplaced.
3367 static_cast<SCH_ITEM*>( item->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
3368 }
3369 else if( item->Type() == SCH_TEXT_T )
3370 {
3371 setJustify( static_cast<SCH_TEXT*>( item ) );
3372 }
3373 else if( item->Type() == SCH_TEXTBOX_T )
3374 {
3375 setJustify( static_cast<SCH_TEXTBOX*>( item ) );
3376 }
3377 else if( item->Type() == SCH_LABEL_T )
3378 {
3379 SCH_LABEL* label = static_cast<SCH_LABEL*>( item );
3380
3381 if( label->GetTextAngle() == ANGLE_HORIZONTAL )
3382 setJustify( label );
3383 }
3384
3385 m_frame->UpdateItem( item, false, true );
3386 }
3387
3388 // Update R-Tree for modified items
3389 for( EDA_ITEM* selected : selection )
3390 updateItem( selected, true );
3391
3392 if( item->IsMoving() )
3393 {
3394 m_toolMgr->RunAction( ACTIONS::refreshPreview );
3395 }
3396 else
3397 {
3398 SCH_SELECTION selectionCopy = selection;
3399
3400 if( selection.IsHover() )
3401 m_toolMgr->RunAction( ACTIONS::selectionClear );
3402
3403 if( !localCommit.Empty() )
3404 {
3405 if( aEvent.Matches( ACTIONS::leftJustify.MakeEvent() ) )
3406 localCommit.Push( _( "Left Justify" ) );
3407 else if( aEvent.Matches( ACTIONS::centerJustify.MakeEvent() ) )
3408 localCommit.Push( _( "Center Justify" ) );
3409 else
3410 localCommit.Push( _( "Right Justify" ) );
3411 }
3412 }
3413
3414 return 0;
3415}
3416
3417
3419{
3420 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_SHEET_T } );
3421 SCH_SHEET* sheet = (SCH_SHEET*) selection.Front();
3422 SCH_COMMIT commit( m_toolMgr );
3423
3424 if( !sheet || !sheet->HasUndefinedPins() )
3425 return 0;
3426
3427 if( !IsOK( m_frame, _( "Do you wish to delete the unreferenced pins from this sheet?" ) ) )
3428 return 0;
3429
3430 commit.Modify( sheet, m_frame->GetScreen() );
3431
3432 sheet->CleanupSheet();
3433
3434 updateItem( sheet, true );
3435
3436 commit.Push( _( "Cleanup Sheet Pins" ) );
3437
3438 if( selection.IsHover() )
3439 m_toolMgr->RunAction( ACTIONS::selectionClear );
3440
3441 return 0;
3442}
3443
3444
3446{
3447 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_SHEET_T } );
3448
3449 if( selection.GetSize() > 1 )
3450 return 0;
3451
3452 SCH_SHEET* sheet = (SCH_SHEET*) selection.Front();
3453
3454 SCH_SHEET_PATH instance = m_frame->GetCurrentSheet();
3455
3456 SCH_SCREEN* screen;
3457
3458 if( sheet )
3459 {
3460 // When changing the page number of a selected sheet, the current screen owns the sheet.
3461 screen = m_frame->GetScreen();
3462
3463 instance.push_back( sheet );
3464 }
3465 else
3466 {
3467 SCH_SHEET_PATH prevInstance = instance;
3468
3469 // When change the page number in the screen, the previous screen owns the sheet.
3470 if( prevInstance.size() )
3471 {
3472 prevInstance.pop_back();
3473 screen = prevInstance.LastScreen();
3474 }
3475 else
3476 {
3477 // The root sheet and root screen are effectively the same thing.
3478 screen = m_frame->GetScreen();
3479 }
3480
3481 sheet = m_frame->GetCurrentSheet().Last();
3482 }
3483
3484 wxString msg;
3485 wxString sheetPath = instance.PathHumanReadable( false );
3486 wxString pageNumber = instance.GetPageNumber();
3487
3488 msg.Printf( _( "Enter page number for sheet path%s" ),
3489 ( sheetPath.Length() > 20 ) ? "\n" + sheetPath : " " + sheetPath );
3490
3491 wxTextEntryDialog dlg( m_frame, msg, _( "Edit Sheet Page Number" ), pageNumber );
3492
3493 dlg.SetTextValidator( wxFILTER_ALPHANUMERIC ); // No white space.
3494
3495 if( dlg.ShowModal() == wxID_CANCEL || dlg.GetValue() == instance.GetPageNumber() )
3496 return 0;
3497
3498 SCH_COMMIT commit( m_frame );
3499
3500 commit.Modify( sheet, screen );
3501
3502 instance.SetPageNumber( dlg.GetValue() );
3503
3504 if( instance == m_frame->GetCurrentSheet() )
3505 {
3506 m_frame->GetScreen()->SetPageNumber( dlg.GetValue() );
3507 m_frame->OnPageSettingsChange();
3508 }
3509
3510 commit.Push( wxS( "Change Sheet Page Number" ) );
3511
3512 if( selection.IsHover() )
3513 m_toolMgr->RunAction( ACTIONS::selectionClear );
3514
3515 return 0;
3516}
3517
3518
3520{
3521 return m_toolMgr->RunAction( SCH_ACTIONS::importSheet, aEvent.Parameter<wxString*>() );
3522}
3523
3524
3526{
3527 wxString* filename = aEvent.Parameter<wxString*>();
3528
3529 if( !filename )
3530 return 0;
3531
3532 SCH_BITMAP* image = new SCH_BITMAP( VECTOR2I( 0, 0 ) );
3533
3534 if( !image->GetReferenceImage().ReadImageFile( *filename ) )
3535 {
3536 wxMessageBox( wxString::Format( _( "Could not load image from '%s'." ), *filename ) );
3537 delete image;
3538 return 0;
3539 }
3540
3541 return m_toolMgr->RunAction( SCH_ACTIONS::placeImage, image );
3542}
3543
3544
3546{
3547 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_SYMBOL_T, SCH_SHEET_T, SCH_RULE_AREA_T } );
3548 std::set<std::pair<SCH_ITEM*, SCH_SCREEN*>> collectedItems;
3549
3550 for( EDA_ITEM* item : selection )
3551 {
3552 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item) )
3553 {
3554 collectedItems.insert( { symbol, m_frame->GetScreen() } );
3555
3556 // The attributes should be kept in sync in multi-unit parts.
3557 // Of course the symbol must be annotated to collect other units.
3558 if( symbol->IsAnnotated( &m_frame->GetCurrentSheet() ) )
3559 {
3560 wxString ref = symbol->GetRef( &m_frame->GetCurrentSheet() );
3561 int unit = symbol->GetUnit();
3562 LIB_ID libId = symbol->GetLibId();
3563
3564 for( SCH_SHEET_PATH& sheet : m_frame->Schematic().Hierarchy() )
3565 {
3566 SCH_SCREEN* screen = sheet.LastScreen();
3567 std::vector<SCH_SYMBOL*> otherUnits;
3568
3569 CollectOtherUnits( ref, unit, libId, sheet, &otherUnits );
3570
3571 for( SCH_SYMBOL* otherUnit : otherUnits )
3572 collectedItems.insert( { otherUnit, screen } );
3573 }
3574 }
3575 }
3576 else if( SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( item ) )
3577 {
3578 collectedItems.insert( { sheet, m_frame->GetScreen() } );
3579 }
3580 else if( SCH_RULE_AREA* ruleArea = dynamic_cast<SCH_RULE_AREA*>( item ) )
3581 {
3582 collectedItems.insert( { ruleArea, m_frame->GetScreen() } );
3583 }
3584 }
3585
3586 SCH_COMMIT commit( m_toolMgr );
3587 SCH_SHEET_PATH* sheet = &m_frame->GetCurrentSheet();
3588 wxString variant = m_frame->Schematic().GetCurrentVariant();
3589 bool new_state = false;
3590
3591 for( const auto& [item, _] : collectedItems )
3592 {
3593 if( ( aEvent.IsAction( &SCH_ACTIONS::setDNP ) && !item->GetDNP( sheet, variant ) )
3594 || ( aEvent.IsAction( &SCH_ACTIONS::setExcludeFromSim ) && !item->GetExcludedFromSim( sheet, variant ) )
3595 || ( aEvent.IsAction( &SCH_ACTIONS::setExcludeFromBOM ) && !item->GetExcludedFromBOM( sheet, variant ) )
3596 || ( aEvent.IsAction( &SCH_ACTIONS::setExcludeFromBoard ) && !item->GetExcludedFromBoard( sheet, variant ) ) )
3597 {
3598 new_state = true;
3599 break;
3600 }
3601 }
3602
3603 for( const auto& [item, screen] : collectedItems )
3604 {
3605 commit.Modify( item, screen );
3606
3607 if( aEvent.IsAction( &SCH_ACTIONS::setDNP ) )
3608 item->SetDNP( new_state, sheet, variant );
3609
3611 item->SetExcludedFromSim( new_state, sheet, variant );
3612
3614 item->SetExcludedFromBOM( new_state, sheet, variant );
3615
3617 item->SetExcludedFromBoard( new_state, sheet, variant );
3618 }
3619
3620 if( !commit.Empty() )
3621 commit.Push( _( "Toggle Attribute" ) );
3622
3623 if( selection.IsHover() )
3624 m_toolMgr->RunAction( ACTIONS::selectionClear );
3625
3626 return 0;
3627}
3628
3629
3630wxString SCH_EDIT_TOOL::FixERCErrorMenuText( const std::shared_ptr<RC_ITEM>& aERCItem )
3631{
3632 if( aERCItem->GetErrorCode() == ERCE_SIMULATION_MODEL
3633 || aERCItem->GetErrorCode() == ERCE_FOOTPRINT_FILTERS
3634 || aERCItem->GetErrorCode() == ERCE_FOOTPRINT_LINK_ISSUES )
3635 {
3636 return _( "Edit Symbol Properties..." );
3637 }
3638 else if( aERCItem->GetErrorCode() == ERCE_LIB_SYMBOL_ISSUES )
3639 {
3640 return m_frame->GetRunMenuCommandDescription( SCH_ACTIONS::showSymbolLibTable );
3641 }
3642 else if( aERCItem->GetErrorCode() == ERCE_LIB_SYMBOL_MISMATCH )
3643 {
3644 return m_frame->GetRunMenuCommandDescription( SCH_ACTIONS::updateSymbol );
3645 }
3646 else if( aERCItem->GetErrorCode() == ERCE_UNANNOTATED
3647 || aERCItem->GetErrorCode() == ERCE_DUPLICATE_REFERENCE )
3648 {
3649 return m_frame->GetRunMenuCommandDescription( SCH_ACTIONS::annotate );
3650 }
3651 else if( aERCItem->GetErrorCode() == ERCE_UNDEFINED_NETCLASS )
3652 {
3653 return _( "Edit Netclasses..." );
3654 }
3655
3656 return wxEmptyString;
3657}
3658
3659
3660void SCH_EDIT_TOOL::FixERCError( const std::shared_ptr<RC_ITEM>& aERCItem )
3661{
3662 SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3663
3664 wxCHECK( frame, /* void */ );
3665
3666 if( aERCItem->GetErrorCode() == ERCE_SIMULATION_MODEL
3667 || aERCItem->GetErrorCode() == ERCE_FOOTPRINT_FILTERS
3668 || aERCItem->GetErrorCode() == ERCE_FOOTPRINT_LINK_ISSUES )
3669 {
3670 if( EDA_ITEM* item = frame->ResolveItem( aERCItem->GetMainItemID() ) )
3671 EditProperties( item );
3672 }
3673 else if( aERCItem->GetErrorCode() == ERCE_LIB_SYMBOL_ISSUES )
3674 {
3676 }
3677 else if( aERCItem->GetErrorCode() == ERCE_LIB_SYMBOL_MISMATCH )
3678 {
3679 EDA_ITEM* item = frame->ResolveItem( aERCItem->GetMainItemID() );
3680
3681 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item ) )
3682 {
3684 dlg.ShowQuasiModal();
3685 }
3686 }
3687 else if( aERCItem->GetErrorCode() == ERCE_UNANNOTATED
3688 || aERCItem->GetErrorCode() == ERCE_DUPLICATE_REFERENCE )
3689 {
3690 m_toolMgr->RunAction( SCH_ACTIONS::annotate );
3691 }
3692 else if( aERCItem->GetErrorCode() == ERCE_UNDEFINED_NETCLASS )
3693 {
3694 frame->ShowSchematicSetupDialog( _( "Net Classes" ) );
3695 }
3696}
3697
3698
3700{
3701 return modifyLockSelected( TOGGLE );
3702}
3703
3704
3706{
3707 return modifyLockSelected( ON );
3708}
3709
3710
3712{
3713 return modifyLockSelected( OFF );
3714}
3715
3716
3718{
3719 SCH_SELECTION& selection = m_selectionTool->RequestSelection();
3720
3721 if( selection.Empty() )
3722 m_toolMgr->RunAction( ACTIONS::cursorClick );
3723
3724 if( selection.Empty() )
3725 return 0;
3726
3727 if( aMode == TOGGLE )
3728 {
3729 aMode = ON;
3730
3731 for( EDA_ITEM* item : selection )
3732 {
3733 if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( item ) )
3734 {
3735 if( schItem->IsLocked() )
3736 {
3737 aMode = OFF;
3738 break;
3739 }
3740 }
3741 }
3742 }
3743
3744 wxString commitMsg = ( aMode == ON ) ? _( "Lock" ) : _( "Unlock" );
3745 SCH_COMMIT commit( m_toolMgr );
3746
3747 for( EDA_ITEM* item : selection )
3748 {
3749 if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( item ) )
3750 {
3751 // Don't lock/unlock pins, fields, or sheet pins - they inherit from parent
3752 if( schItem->Type() == SCH_PIN_T || schItem->Type() == SCH_FIELD_T
3753 || schItem->Type() == SCH_SHEET_PIN_T )
3754 continue;
3755
3756 commit.Modify( schItem, m_frame->GetScreen() );
3757 schItem->SetLocked( aMode == ON );
3758 }
3759 }
3760
3761 if( !commit.Empty() )
3762 {
3763 commit.Push( commitMsg );
3764 m_toolMgr->PostEvent( EVENTS::SelectedEvent );
3765 }
3766
3767 return 0;
3768}
3769
3770
3772{
3773 // clang-format off
3779 Go( &SCH_EDIT_TOOL::Swap, SCH_ACTIONS::swap.MakeEvent() );
3785
3791
3811
3812
3817
3819 Go( &SCH_EDIT_TOOL::Lock, SCH_ACTIONS::lock.MakeEvent() );
3821
3825
3828 // clang-format on
3829}
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
@ add_hierarchical_label
@ component_select_unit
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
static TOOL_ACTION decrementPrimary
Definition actions.h:96
static TOOL_ACTION paste
Definition actions.h:80
static TOOL_ACTION unselectAll
Definition actions.h:83
static TOOL_ACTION decrementSecondary
Definition actions.h:98
static TOOL_ACTION selectItem
Select an item (specified as the event parameter).
Definition actions.h:227
static TOOL_ACTION unselectItem
Definition actions.h:228
static TOOL_ACTION copy
Definition actions.h:78
static TOOL_ACTION showSymbolLibTable
Definition actions.h:282
static TOOL_ACTION pasteSpecial
Definition actions.h:81
static TOOL_ACTION groupProperties
Definition actions.h:247
static TOOL_ACTION rightJustify
Definition actions.h:89
static TOOL_ACTION pageSettings
Definition actions.h:63
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 cursorClick
Definition actions.h:180
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:224
static TOOL_ACTION leftJustify
Definition actions.h:87
static TOOL_ACTION cut
Definition actions.h:77
static TOOL_ACTION copyAsText
Definition actions.h:79
static TOOL_ACTION refreshPreview
Definition actions.h:159
static TOOL_ACTION selectAll
Definition actions.h:82
static TOOL_ACTION centerJustify
Definition actions.h:88
Manage TOOL_ACTION objects.
void SetConditions(const TOOL_ACTION &aAction, const ACTION_CONDITIONS &aConditions)
Set the conditions the UI elements for activating a specific tool action should use for determining t...
ACTION_MENU(bool isContextMenu, TOOL_INTERACTIVE *aTool=nullptr)
Default constructor.
TOOL_MANAGER * getToolManager() const
Return an instance of TOOL_MANAGER class.
void SetUntranslatedTitle(const wxString &aTitle)
Definition action_menu.h:64
void Clear()
Remove all the entries from the menu (as well as its title).
void SetTitle(const wxString &aTitle) override
Set title for the menu.
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
wxMenuItem * Add(const wxString &aLabel, int aId, BITMAPS aIcon)
Add a wxWidgets-style entry to the menu.
friend class TOOL_INTERACTIVE
TOOL_INTERACTIVE * m_tool
Creator of the menu.
ACTION_MENU * create() const override
Return an instance of this class. It has to be overridden in inheriting classes.
void update() override
Update menu state stub.
void update() override
Update menu state stub.
ACTION_MENU * create() const override
Return an instance of this class. It has to be overridden in inheriting classes.
constexpr const Vec & GetPosition() const
Definition box2.h:211
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:558
constexpr const Vec GetEnd() const
Definition box2.h:212
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:237
constexpr Vec Centre() const
Definition box2.h:97
constexpr const Vec GetCenter() const
Definition box2.h:230
constexpr coord_type GetLeft() const
Definition box2.h:228
constexpr const Vec & GetOrigin() const
Definition box2.h:210
constexpr coord_type GetRight() const
Definition box2.h:217
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:297
constexpr coord_type GetTop() const
Definition box2.h:229
constexpr coord_type GetBottom() const
Definition box2.h:222
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition commit.h:90
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition commit.h:84
void Unstage(EDA_ITEM *aItem, BASE_SCREEN *aScreen)
Definition commit.cpp:140
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
COMMIT & Removed(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Definition commit.h:96
int GetStatus(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Returns status of an item.
Definition commit.cpp:171
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.
void AddCheckItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a checked menu entry to run a TOOL_ACTION on selected items.
void AddMenu(ACTION_MENU *aMenu, const SELECTION_CONDITION &aCondition=SELECTION_CONDITIONS::ShowAlways, int aOrder=ANY_ORDER)
Add a submenu to the menu.
CONDITIONAL_MENU(TOOL_INTERACTIVE *aTool)
Calculate the connectivity of a schematic and generates netlists.
CONNECTION_SUBGRAPH * GetSubgraphForItem(SCH_ITEM *aItem) const
A subgraph is a set of items that are electrically connected on a single sheet.
const std::set< SCH_ITEM * > & GetItems() const
Provide a read-only reference to the items in the subgraph.
Dialog to update or change schematic library symbols.
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 used to edit SCH_SYMBOL objects in a schematic.
bool HitTestDrawingSheetItems(KIGFX::VIEW *aView, const VECTOR2I &aPosition)
bool IsHorizontal() const
Definition eda_angle.h:142
bool IsVertical() const
Definition eda_angle.h:148
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:46
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:100
virtual VECTOR2I GetPosition() const
Definition eda_item.h:279
virtual void SetPosition(const VECTOR2I &aPos)
Definition eda_item.h:280
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:120
EDA_ITEM_FLAGS GetEditFlags() const
Definition eda_item.h:155
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:149
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
bool IsSelected() const
Definition eda_item.h:129
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:199
EDA_ITEM * GetParent() const
Definition eda_item.h:114
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:153
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:93
bool IsMoving() const
Definition eda_item.h:127
bool IsNew() const
Definition eda_item.h:126
void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:232
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:91
bool IsItalic() const
Definition eda_text.h:180
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:158
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:516
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:109
virtual bool IsVisible() const
Definition eda_text.h:198
void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:560
KIFONT::FONT * GetFont() const
Definition eda_text.h:258
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition eda_text.cpp:417
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:401
wxString GetHyperlink() const
Definition eda_text.h:414
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:211
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition eda_text.cpp:268
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition eda_text.cpp:319
bool IsBold() const
Definition eda_text.h:195
void SetHyperlink(wxString aLink)
Definition eda_text.h:415
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:214
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:254
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:283
int GetTextThickness() const
Definition eda_text.h:139
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:291
void SetFont(KIFONT::FONT *aFont)
Definition eda_text.cpp:483
VECTOR2I GetTextSize() const
Definition eda_text.h:272
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:393
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition sch_rtree.h:230
static const TOOL_EVENT SelectedEvent
Definition actions.h:345
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual wxString GetClass() const =0
Return the class name.
void RecacheAllItems()
Rebuild GAL display lists.
Definition view.cpp:1538
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
int GetUnitCount() const override
ACTION_MENU * create() const override
Return an instance of this class. It has to be overridden in inheriting classes.
LOCK_CONTEXT_MENU(TOOL_INTERACTIVE *aTool)
static bool ParseBusGroup(const wxString &aGroup, wxString *name, std::vector< wxString > *aMemberList)
Parse a bus group label into the name and a list of components.
A singleton reporter that reports to nowhere.
Definition reporter.h:218
void update() override
Update menu state stub.
ACTION_MENU * create() const override
Return an instance of this class. It has to be overridden in inheriting classes.
These are loaded from Eeschema settings but then overwritten by the project settings.
SCHEMATIC_SETTINGS & Settings() const
static TOOL_ACTION rotateCCW
static TOOL_ACTION placeClassLabel
Definition sch_actions.h:79
static TOOL_ACTION swapPins
static TOOL_ACTION editValue
static TOOL_ACTION setExcludeFromBOM
static TOOL_ACTION mirrorV
static TOOL_ACTION clearHighlight
static TOOL_ACTION swap
static TOOL_ACTION placeGlobalLabel
Definition sch_actions.h:80
static TOOL_ACTION changeSymbols
static TOOL_ACTION updateSymbol
static TOOL_ACTION autoplaceFields
static TOOL_ACTION changeSymbol
static TOOL_ACTION ddAddImage
static TOOL_ACTION properties
static TOOL_ACTION editReference
static TOOL_ACTION placeHierLabel
Definition sch_actions.h:81
static TOOL_ACTION placeLabel
Definition sch_actions.h:78
static TOOL_ACTION toText
static TOOL_ACTION toHLabel
static TOOL_ACTION rotateCW
static TOOL_ACTION importSheet
Definition sch_actions.h:87
static TOOL_ACTION setExcludeFromSim
static TOOL_ACTION toLabel
static TOOL_ACTION setDNP
static TOOL_ACTION swapUnitLabels
static TOOL_ACTION placeImage
static TOOL_ACTION editWithLibEdit
static TOOL_ACTION cleanupSheetPins
static TOOL_ACTION toDLabel
static TOOL_ACTION cycleBodyStyle
static TOOL_ACTION mirrorH
static TOOL_ACTION ddAppendFile
static TOOL_ACTION placeSchematicText
Definition sch_actions.h:92
static TOOL_ACTION toTextBox
static TOOL_ACTION unlock
Definition sch_actions.h:62
static TOOL_ACTION lock
Definition sch_actions.h:61
static TOOL_ACTION annotate
static TOOL_ACTION updateSymbols
static TOOL_ACTION swapPinLabels
static TOOL_ACTION enterSheet
static TOOL_ACTION editFootprint
static TOOL_ACTION repeatDrawItem
static TOOL_ACTION editTextAndGraphics
static TOOL_ACTION editPageNumber
static TOOL_ACTION toGLabel
static TOOL_ACTION setExcludeFromBoard
static TOOL_ACTION move
static TOOL_ACTION toggleLock
Definition sch_actions.h:60
Object to handle a bitmap image that can be inserted in a schematic.
Definition sch_bitmap.h:40
static const std::vector< KICAD_T > FieldOwners
static const std::vector< KICAD_T > DeletableItems
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
static SELECTION_CONDITION SingleMultiFunctionPin
static SELECTION_CONDITION SingleSymbol
static SELECTION_CONDITION MultipleSymbolsOrPower
static SELECTION_CONDITION HasLockedItems
static SELECTION_CONDITION AllPinsOrSheetPins
static SELECTION_CONDITION SingleSymbolOrPower
static SELECTION_CONDITION HasUnlockedItems
static SELECTION_CONDITION SingleMultiUnitSymbol
static SELECTION_CONDITION SingleMultiBodyStyleSymbol
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
bool IsNet() const
Tool responsible for drawing/placing items (symbols, wires, buses, labels, etc.).
Schematic editor (Eeschema) main window.
void ShowSchematicSetupDialog(const wxString &aInitialPage=wxEmptyString)
EDA_ITEM * ResolveItem(const KIID &aId, bool aAllowNullptrReturn=false) const override
Fetch an item by KIID.
const wxString & GetHighlightedConnection() const
wxString FixERCErrorMenuText(const std::shared_ptr< RC_ITEM > &aERCItem)
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
static const std::vector< KICAD_T > RotatableItems
int SwapUnitLabels(const TOOL_EVENT &aEvent)
int EditField(const TOOL_EVENT &aEvent)
int EditPageNumber(const TOOL_EVENT &aEvent)
int DoDelete(const TOOL_EVENT &aEvent)
bool Init() override
Init() is called once upon a registration of the tool.
int CleanupSheetPins(const TOOL_EVENT &aEvent)
int Unlock(const TOOL_EVENT &aEvent)
Delete the selected items, or the item under the cursor.
void EditProperties(EDA_ITEM *aItem)
void editFieldText(SCH_FIELD *aField)
int SwapPins(const TOOL_EVENT &aEvent)
int Mirror(const TOOL_EVENT &aEvent)
int GlobalEdit(const TOOL_EVENT &aEvent)
Lock/unlock selected items.
int SetAttribute(const TOOL_EVENT &aEvent)
Modify Attributes (DNP, Exclude, etc.) All attributes are set to true unless all symbols already have...
int Properties(const TOOL_EVENT &aEvent)
int Rotate(const TOOL_EVENT &aEvent)
int Lock(const TOOL_EVENT &aEvent)
int DdAppendFile(const TOOL_EVENT &aEvent)
Drag and drop.
int JustifyText(const TOOL_EVENT &aEvent)
int modifyLockSelected(MODIFY_MODE aMode)
Set up handlers for various events.
static const std::vector< KICAD_T > SwappableItems
void FixERCError(const std::shared_ptr< RC_ITEM > &aERCItem)
int SwapPinLabels(const TOOL_EVENT &aEvent)
int AutoplaceFields(const TOOL_EVENT &aEvent)
int CycleBodyStyle(const TOOL_EVENT &aEvent)
int Swap(const TOOL_EVENT &aEvent)
int ChangeSymbols(const TOOL_EVENT &aEvent)
int ChangeTextType(const TOOL_EVENT &aEvent)
Change a text type to another one.
int ToggleLock(const TOOL_EVENT &aEvent)
int DdAddImage(const TOOL_EVENT &aEvent)
int RepeatDrawItem(const TOOL_EVENT &aEvent)
bool IsMandatory() const
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
VECTOR2I GetPosition() const override
FIELD_T GetId() const
Definition sch_field.h:127
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
void SetPosition(const VECTOR2I &aPosition) override
void SetText(const wxString &aText) override
VECTOR2I GetParentPosition() const
A set of SCH_ITEMs (i.e., without duplicates).
Definition sch_group.h:52
int CrossProbe(const TOOL_EVENT &aEvent)
Called when clicking on a item:
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
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:161
virtual bool IsConnectable() const
Definition sch_item.h:530
virtual void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo)
Definition sch_item.h:632
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode)
Definition sch_item.h:634
const SYMBOL * GetParentSymbol() const
Definition sch_item.cpp:275
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:269
int GetBodyStyle() const
Definition sch_item.h:248
virtual void MirrorHorizontally(int aCenter)
Mirror item horizontally about aCenter.
Definition sch_item.h:410
virtual void Move(const VECTOR2I &aMoveVector)
Move the item by aMoveVector to a new position.
Definition sch_item.h:402
int GetUnit() const
Definition sch_item.h:239
void SetConnectivityDirty(bool aDirty=true)
Definition sch_item.h:593
void SetFieldsAutoplaced(AUTOPLACE_ALGO aAlgo)
Definition sch_item.h:630
virtual void Rotate(const VECTOR2I &aCenter, bool aRotateCCW)
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition sch_item.h:426
AUTOPLACE_ALGO GetFieldsAutoplaced() const
Return whether the fields have been automatically placed.
Definition sch_item.h:629
wxString GetClass() const override
Return the class name.
Definition sch_item.h:178
bool IsGroupableType() const
Definition sch_item.cpp:117
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition sch_item.h:545
bool IsType(const std::vector< KICAD_T > &aScanTypes) const override
Check whether the item is one of the listed types.
Definition sch_item.h:183
virtual void MirrorVertically(int aCenter)
Mirror item vertically about aCenter.
Definition sch_item.h:418
void AddFields(const std::vector< SCH_FIELD > &aFields)
Definition sch_label.h:225
void MirrorHorizontally(int aCenter) override
Mirror item horizontally about aCenter.
SPIN_STYLE GetSpinStyle() const
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition sch_label.h:181
LABEL_FLAG_SHAPE GetShape() const
Definition sch_label.h:180
void MirrorVertically(int aCenter) override
Mirror item vertically about aCenter.
std::vector< SCH_FIELD > & GetFields()
Definition sch_label.h:212
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Tool responsible for drawing/placing items (symbols, wires, buses, labels, etc.)
int AddJunctionsIfNeeded(SCH_COMMIT *aCommit, SCH_SELECTION *aSelection)
Handle the addition of junctions to a selection of objects.
int TrimOverLappingWires(SCH_COMMIT *aCommit, SCH_SELECTION *aSelection)
Logic to remove wires when overlapping correct items.
static bool IsDrawingLineWireOrBus(const SELECTION &aSelection)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:42
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition sch_line.cpp:408
VECTOR2I GetEndPoint() const
Definition sch_line.h:148
VECTOR2I GetStartPoint() const
Definition sch_line.h:139
const std::map< wxString, ALT > & GetAlternates() const
Definition sch_pin.h:160
bool IsConnectable() const override
Definition sch_pin.h:313
const wxString & GetName() const
Definition sch_pin.cpp:403
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:749
void ClearAnnotationOfNewSheetPaths(SCH_SHEET_LIST &aInitialSheetPathList)
Clear the annotation for the symbols inside new sheetpaths when a complex hierarchy is modified and n...
bool IsExplicitJunction(const VECTOR2I &aPosition) const
Indicate that a junction dot is necessary at the given location.
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:119
const wxString & GetFileName() const
Definition sch_screen.h:154
SCH_ITEM * GetItem(const VECTOR2I &aPosition, int aAccuracy=0, KICAD_T aType=SCH_LOCATE_ANY_T) const
Check aPosition within a distance of aAccuracy for items of type aFilter.
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
void ClearAnnotation(SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear the annotation for the symbols in aSheetPath on the screen.
SCH_SELECTION & GetSelection()
SCH_GROUP * GetEnteredGroup()
void SetPosition(const VECTOR2I &aPos) override
Definition sch_shape.h:86
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void BuildSheetList(SCH_SHEET *aSheet, bool aCheckIntegrity)
Build the list of sheets and their sheet path from aSheet.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_SCREEN * LastScreen()
wxString GetPageNumber() const
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false, bool aEscapeSheetNames=false) const
Return the sheet path in a human readable form made from the sheet names.
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
size_t size() const
Forwarded method from std::vector.
void pop_back()
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
SHEET_SIDE GetSide() const
void SetSide(SHEET_SIDE aEdge)
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:377
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:371
std::map< SCH_SHEET_PIN *, SCH_NO_CONNECT * > GetNoConnects() const
VECTOR2I GetRotationCenter() const
Rotating around the boundingBox's center can cause walking when the sheetname or filename is longer t...
void CleanupSheet()
Delete sheet label which do not have a corresponding hierarchical label.
void RemovePin(const SCH_SHEET_PIN *aSheetPin)
Remove aSheetPin from the sheet.
bool HasUndefinedPins() const
Check all sheet labels against schematic for undefined hierarchical labels.
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:140
const BOX2I GetBodyBoundingBox() const
Return a bounding box for the sheet body but not the fields.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
Schematic symbol object.
Definition sch_symbol.h:76
wxString GetUnitDisplayName(int aUnit, bool aLabel) const override
Return the display name for a given unit aUnit.
bool IsMultiBodyStyle() const override
Definition sch_symbol.h:264
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
Automatically orient all the fields in the symbol.
wxString GetBodyStyleDescription(int aBodyStyle, bool aLabel) const override
void UpdatePins()
Updates the cache of SCH_PIN objects for each pin.
bool HasDeMorganBodyStyles() const override
int GetBodyStyleCount() const override
Return the number of body styles of the symbol.
void SetOrientation(int aOrientation)
Compute the new transform matrix based on aOrientation for the symbol which is applied to the current...
bool IsMissingLibSymbol() const
Check to see if the library symbol is set to the dummy library symbol.
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:165
int GetOrientation() const override
Get the display symbol orientation.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:184
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
bool IsPower() const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
int GetMarginBottom() const
Definition sch_textbox.h:73
int GetLegacyTextMargin() const
int GetMarginLeft() const
Definition sch_textbox.h:70
int GetMarginRight() const
Definition sch_textbox.h:72
int GetMarginTop() const
Definition sch_textbox.h:71
virtual void Rotate90(bool aClockwise)
Definition sch_text.cpp:213
virtual void MirrorSpinStyle(bool aLeftRight)
Definition sch_text.cpp:224
void updateItem(EDA_ITEM *aItem, bool aUpdateRTree) const
int Increment(const TOOL_EVENT &aEvent)
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 SELECTION_CONDITION HasTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if among the selected items there is at least one of a given types.
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 bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
virtual void Add(EDA_ITEM *aItem)
Definition selection.cpp:42
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition selection.cpp:75
VECTOR2I GetReferencePoint() const
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
int Size() const
Returns the number of selected parts.
Definition selection.h:121
std::deque< EDA_ITEM * > & Items()
Definition selection.h:182
std::vector< EDA_ITEM * > GetItemsSortedBySelectionOrder() const
bool OnlyContains(std::vector< KICAD_T > aList) const
Checks if all items in the selection have a type in aList.
bool Empty() const
Checks if there is anything selected.
Definition selection.h:115
bool HasReferencePoint() const
Definition selection.h:216
size_t CountType(KICAD_T aType) const
unsigned CCWRotationsTo(const SPIN_STYLE &aOther) const
Get CCW rotation needed to get to the given spin style.
The symbol library editor main window.
void update() override
Update menu state stub.
ACTION_MENU * create() const override
Return an instance of this class. It has to be overridden in inheriting classes.
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.
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:473
void Go(int(SCH_EDIT_FRAME::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
TOOL_MENU & GetToolMenu()
TOOL_INTERACTIVE(TOOL_ID aId, const std::string &aName)
Create a tool with given id & name.
CONDITIONAL_MENU & GetMenu()
Definition tool_menu.cpp:44
@ CHT_ADD
Definition commit.h:42
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:259
This file is part of the common library.
@ SYMBOL_PROPS_EDIT_SCHEMATIC_SYMBOL
@ SYMBOL_PROPS_WANT_EXCHANGE_SYMBOL
@ SYMBOL_PROPS_WANT_UPDATE_SYMBOL
@ SYMBOL_PROPS_EDIT_LIBRARY_SYMBOL
@ SYMBOL_PROPS_EDIT_OK
#define _(s)
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
@ RECURSE
Definition eda_item.h:53
@ NO_RECURSE
Definition eda_item.h:54
#define IGNORE_PARENT_GROUP
Definition eda_item.h:57
#define IS_NEW
New item, just created.
#define SELECTED_BY_DRAG
Item was algorithmically selected as a dragged item.
#define STRUCT_DELETED
flag indication structures to be erased
#define ENDPOINT
ends. (Used to support dragging.)
#define STARTPOINT
When a line is selected, these flags indicate which.
@ NO_FILL
Definition eda_shape.h:59
@ ID_POPUP_SCH_PIN_TRICKS_HIER_LABEL
@ ID_POPUP_SCH_PIN_TRICKS_WIRE
@ ID_POPUP_SCH_ALT_PIN_FUNCTION
@ ID_POPUP_SCH_SELECT_UNIT1
Definition eeschema_id.h:88
@ ID_POPUP_SCH_SELECT_UNIT
Definition eeschema_id.h:87
@ ID_POPUP_SCH_SELECT_BODY_STYLE
Definition eeschema_id.h:97
@ ID_POPUP_SCH_PLACE_UNIT1
Definition eeschema_id.h:94
@ ID_POPUP_SCH_SELECT_BODY_STYLE1
Definition eeschema_id.h:98
@ ID_POPUP_SCH_PIN_TRICKS_NET_LABEL
@ ID_POPUP_SCH_PIN_TRICKS_NO_CONNECT
@ ID_POPUP_SCH_SELECT_UNIT_END
Definition eeschema_id.h:91
@ ID_POPUP_SCH_ALT_PIN_FUNCTION_END
@ ID_POPUP_SCH_PIN_TRICKS_GLOBAL_LABEL
@ ERCE_UNANNOTATED
Symbol has not been annotated.
@ ERCE_DUPLICATE_REFERENCE
More than one symbol with the same reference.
@ ERCE_FOOTPRINT_LINK_ISSUES
The footprint link is invalid, or points to a missing (or inactive) footprint or library.
@ ERCE_UNDEFINED_NETCLASS
A netclass was referenced but not defined.
@ ERCE_SIMULATION_MODEL
An error was found in the simulation model.
@ ERCE_LIB_SYMBOL_MISMATCH
Symbol doesn't match copy in library.
@ ERCE_LIB_SYMBOL_ISSUES
Symbol not found in active libraries.
@ ERCE_FOOTPRINT_FILTERS
The assigned footprint doesn't match the footprint filters.
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:35
@ LAYER_NOTES
Definition layer_ids.h:469
@ LAYER_SCHEMATIC_DRAWINGSHEET
Definition layer_ids.h:498
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition macros.h:83
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:96
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
#define _HKI(x)
Definition page_info.cpp:44
see class PGM_BASE
CITER next(CITER it)
Definition ptree.cpp:124
void CollectOtherUnits(const wxString &aRef, int aUnit, const LIB_ID &aLibId, SCH_SHEET_PATH &aSheet, std::vector< SCH_SYMBOL * > *otherUnits)
static SCH_LABEL_BASE * findSingleNetLabelForPin(SCH_PIN *aPin, CONNECTION_GRAPH *aGraph, const SCH_SHEET_PATH &aSheetPath)
static void swapFieldPositionsWithMatching(std::vector< SCH_FIELD > &aAFields, std::vector< SCH_FIELD > &aBFields, unsigned aFallbackRotationsCCW)
Swap the positions of the fields in the two lists, aAFields and aBFields, relative to their parent po...
SCH_CONDITIONS S_C
Class to handle a set of SCH_ITEMs.
AUTOPLACE_ALGO
Definition sch_item.h:69
@ AUTOPLACE_MANUAL
Definition sch_item.h:72
@ AUTOPLACE_NONE
Definition sch_item.h:70
@ AUTOPLACE_AUTO
Definition sch_item.h:71
@ BASE
Definition sch_item.h:60
LABEL_FLAG_SHAPE
Definition sch_label.h:99
@ L_UNSPECIFIED
Definition sch_label.h:104
@ F_ROUND
Definition sch_label.h:108
ANNOTATE_ORDER_T
Schematic annotation order options.
@ ANNOTATE_SELECTION
Annotate the selection.
ANNOTATE_ALGO_T
Schematic annotation type options.
static std::vector< KICAD_T > sheetTypes
SHEET_SIDE
Define the edge of the sheet that the sheet pin is positioned.
std::set< wxString > GetSheetNamesFromPaths(const std::set< wxString > &aSheetPaths, const SCHEMATIC &aSchematic)
Get human-readable sheet names from a set of sheet paths, e.g.
bool SwapPinGeometry(SCH_PIN *aFirst, SCH_PIN *aSecond)
Swap the positions/lengths/etc.
std::set< int > GetUnplacedUnitsForSymbol(const SCH_SYMBOL &aSym)
Get a list of unplaced (i.e.
bool SymbolHasSheetInstances(const SCH_SYMBOL &aSymbol, const wxString &aCurrentProject, std::set< wxString > *aSheetPaths, std::set< wxString > *aProjectNames)
Returns true when the given symbol has instances, e.g.
std::vector< SCH_SYMBOL * > GetSameSymbolMultiUnitSelection(const SELECTION &aSel)
Validates and gathers a selection containing multiple symbol units that all belong to the same refere...
T * GetAppSettings(const char *aFilename)
wxString UnescapeString(const wxString &aSource)
wxString TitleCaps(const wxString &aString)
Capitalize the first letter in each word.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_NETNAME
void AccumulateDescriptions(wxString &aDesc, const T &aItemCollection)
Build a comma-separated list from a collection of wxStrings.
Functors that can be used to figure out how the action controls should be displayed in the UI and if ...
@ SYM_MIRROR_Y
Definition symbol.h:44
@ SYM_MIRROR_X
Definition symbol.h:43
wxString GetDefaultFieldName(FIELD_T aFieldId, bool aTranslateForHI)
Return a default symbol field name for a mandatory field type.
#define DO_TRANSLATE
@ USER
The field ID hasn't been set yet; field is invalid.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
KIBIS_PIN * pin
std::vector< std::vector< std::string > > table
GR_TEXT_H_ALIGN_T
This is API surface mapped to common.types.HorizontalAlignment.
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
GR_TEXT_V_ALIGN_T
This is API surface mapped to common.types.VertialAlignment.
constexpr GR_TEXT_H_ALIGN_T GetFlippedAlignment(GR_TEXT_H_ALIGN_T aAlign)
Get the reverse alignment: left-right are swapped, others are unchanged.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:229
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:75
@ SCH_GROUP_T
Definition typeinfo.h:174
@ SCH_TABLE_T
Definition typeinfo.h:166
@ SCH_LINE_T
Definition typeinfo.h:164
@ SCH_NO_CONNECT_T
Definition typeinfo.h:161
@ SCH_SYMBOL_T
Definition typeinfo.h:173
@ SCH_TABLECELL_T
Definition typeinfo.h:167
@ SCH_ITEM_LOCATE_WIRE_T
Definition typeinfo.h:187
@ SCH_FIELD_T
Definition typeinfo.h:151
@ SCH_DIRECTIVE_LABEL_T
Definition typeinfo.h:172
@ SCH_LABEL_T
Definition typeinfo.h:168
@ SCH_SHEET_T
Definition typeinfo.h:176
@ SCH_ITEM_LOCATE_BUS_T
Definition typeinfo.h:188
@ SCH_MARKER_T
Definition typeinfo.h:159
@ SCH_SHAPE_T
Definition typeinfo.h:150
@ SCH_RULE_AREA_T
Definition typeinfo.h:171
@ SCH_HIER_LABEL_T
Definition typeinfo.h:170
@ SCH_BUS_BUS_ENTRY_T
Definition typeinfo.h:163
@ SCH_LABEL_LOCATE_ANY_T
Definition typeinfo.h:192
@ SCH_ITEM_LOCATE_GRAPHIC_LINE_T
Definition typeinfo.h:189
@ SCHEMATIC_T
Definition typeinfo.h:205
@ SCH_SHEET_PIN_T
Definition typeinfo.h:175
@ SCH_TEXT_T
Definition typeinfo.h:152
@ SCH_BUS_WIRE_ENTRY_T
Definition typeinfo.h:162
@ SCH_BITMAP_T
Definition typeinfo.h:165
@ SCH_TEXTBOX_T
Definition typeinfo.h:153
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:169
@ SCH_JUNCTION_T
Definition typeinfo.h:160
@ SCH_PIN_T
Definition typeinfo.h:154
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
VECTOR2< double > VECTOR2D
Definition vector2d.h:686