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