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