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 auto hasElements = [this]( const SELECTION& aSel )
293 {
294 return !m_frame->GetScreen()->Items().empty();
295 };
296
297 auto sheetHasUndefinedPins = []( const SELECTION& aSel )
298 {
299 if( aSel.Size() == 1 && aSel.Front()->Type() == SCH_SHEET_T )
300 return static_cast<SCH_SHEET*>( aSel.Front() )->HasUndefinedPins();
301
302 return false;
303 };
304
305 auto attribDNPCond = []( const SELECTION& aSel )
306 {
307 return std::all_of( aSel.Items().begin(), aSel.Items().end(),
308 []( const EDA_ITEM* item )
309 {
310 return !item->IsType( { SCH_SYMBOL_T } )
311 || static_cast<const SCH_SYMBOL*>( item )->GetDNP();
312 } );
313 };
314
315 auto attribExcludeFromSimCond = []( const SELECTION& aSel )
316 {
317 return std::all_of( aSel.Items().begin(), aSel.Items().end(),
318 []( const EDA_ITEM* item )
319 {
320 return !item->IsType( { SCH_SYMBOL_T } )
321 || static_cast<const SCH_SYMBOL*>( item )->GetExcludedFromSim();
322 } );
323 };
324
325 auto attribExcludeFromBOMCond = []( const SELECTION& aSel )
326 {
327 return std::all_of( aSel.Items().begin(), aSel.Items().end(),
328 []( const EDA_ITEM* item )
329 {
330 return !item->IsType( { SCH_SYMBOL_T } )
331 || static_cast<const SCH_SYMBOL*>( item )->GetExcludedFromBOM();
332 } );
333 };
334
335
336 auto attribExcludeFromBoardCond = []( const SELECTION& aSel )
337 {
338 return std::all_of( aSel.Items().begin(), aSel.Items().end(),
339 []( const EDA_ITEM* item )
340 {
341 return !item->IsType( { SCH_SYMBOL_T } )
342 || static_cast<const SCH_SYMBOL*>( item )->GetExcludedFromBoard();
343 } );
344 };
345
346 static const std::vector<KICAD_T> sheetTypes = { SCH_SHEET_T };
347
348 auto sheetSelection = S_C::Count( 1 ) && S_C::OnlyTypes( sheetTypes );
349
350 auto haveHighlight = [this]( const SELECTION& sel )
351 {
352 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
353
354 return editFrame && !editFrame->GetHighlightedConnection().IsEmpty();
355 };
356
357 auto anyTextTool = [this]( const SELECTION& aSel )
358 {
359 return ( m_frame->IsCurrentTool( SCH_ACTIONS::placeLabel )
360 || m_frame->IsCurrentTool( SCH_ACTIONS::placeClassLabel )
361 || m_frame->IsCurrentTool( SCH_ACTIONS::placeGlobalLabel )
362 || m_frame->IsCurrentTool( SCH_ACTIONS::placeHierLabel )
363 || m_frame->IsCurrentTool( SCH_ACTIONS::placeSchematicText ) );
364 };
365
366 auto duplicateCondition = []( const SELECTION& aSel )
367 {
369 return false;
370
371 return true;
372 };
373
374 auto orientCondition = []( const SELECTION& aSel )
375 {
377 return false;
378
380 };
381
382 const auto swapSelectionCondition = S_C::OnlyTypes( SwappableItems ) && SELECTION_CONDITIONS::MoreThan( 1 );
383
384 auto propertiesCondition = [this]( const SELECTION& aSel )
385 {
386 if( aSel.GetSize() == 0 )
387 {
388 if( getView()->IsLayerVisible( LAYER_SCHEMATIC_DRAWINGSHEET ) )
389 {
390 DS_PROXY_VIEW_ITEM* ds = m_frame->GetCanvas()->GetView()->GetDrawingSheet();
391 VECTOR2D cursor = getViewControls()->GetCursorPosition( false );
392
393 if( ds && ds->HitTestDrawingSheetItems( getView(), cursor ) )
394 return true;
395 }
396
397 return false;
398 }
399
400 SCH_ITEM* firstItem = dynamic_cast<SCH_ITEM*>( aSel.Front() );
401 const SCH_SELECTION* eeSelection = dynamic_cast<const SCH_SELECTION*>( &aSel );
402
403 if( !firstItem || !eeSelection )
404 return false;
405
406 switch( firstItem->Type() )
407 {
408 case SCH_SYMBOL_T:
409 case SCH_SHEET_T:
410 case SCH_SHEET_PIN_T:
411 case SCH_TEXT_T:
412 case SCH_TEXTBOX_T:
413 case SCH_TABLE_T:
414 case SCH_TABLECELL_T:
415 case SCH_LABEL_T:
417 case SCH_HIER_LABEL_T:
419 case SCH_RULE_AREA_T:
420 case SCH_FIELD_T:
421 case SCH_SHAPE_T:
422 case SCH_BITMAP_T:
423 case SCH_GROUP_T: return aSel.GetSize() == 1;
424
425 case SCH_LINE_T:
427 case SCH_JUNCTION_T:
428 if( std::all_of( aSel.Items().begin(), aSel.Items().end(),
429 [&]( const EDA_ITEM* item )
430 {
431 return item->Type() == SCH_LINE_T
432 && static_cast<const SCH_LINE*>( item )->IsGraphicLine();
433 } ) )
434 {
435 return true;
436 }
437 else if( std::all_of( aSel.Items().begin(), aSel.Items().end(),
438 [&]( const EDA_ITEM* item )
439 {
440 return item->Type() == SCH_JUNCTION_T;
441 } ) )
442 {
443 return true;
444 }
445 else if( std::all_of( aSel.Items().begin(), aSel.Items().end(),
446 [&]( const EDA_ITEM* item )
447 {
448 const SCH_ITEM* schItem = dynamic_cast<const SCH_ITEM*>( item );
449
450 wxCHECK( schItem, false );
451
452 return ( schItem->HasLineStroke() && schItem->IsConnectable() )
453 || item->Type() == SCH_JUNCTION_T;
454 } ) )
455 {
456 return true;
457 }
458
459 return false;
460
461 default: return false;
462 }
463 };
464
465 auto autoplaceCondition = []( const SELECTION& aSel )
466 {
467 for( const EDA_ITEM* item : aSel )
468 {
470 return true;
471 }
472
473 return false;
474 };
475
476 // allTextTypes does not include SCH_SHEET_PIN_T because one cannot convert other
477 // types to/from this type, living only in a SHEET
478 static const std::vector<KICAD_T> allTextTypes = { SCH_LABEL_T, SCH_DIRECTIVE_LABEL_T,
481
482 auto toChangeCondition = ( S_C::OnlyTypes( allTextTypes ) );
483
484 static const std::vector<KICAD_T> toLabelTypes = { SCH_DIRECTIVE_LABEL_T, SCH_GLOBAL_LABEL_T, SCH_HIER_LABEL_T,
486
487 auto toLabelCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toLabelTypes ) )
488 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
489
490 static const std::vector<KICAD_T> toCLabelTypes = { SCH_LABEL_T, SCH_HIER_LABEL_T, SCH_GLOBAL_LABEL_T, SCH_TEXT_T,
492
493 auto toCLabelCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toCLabelTypes ) )
494 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
495
496 static const std::vector<KICAD_T> toHLabelTypes = { SCH_LABEL_T, SCH_DIRECTIVE_LABEL_T, SCH_GLOBAL_LABEL_T,
498
499 auto toHLabelCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toHLabelTypes ) )
500 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
501
502 static const std::vector<KICAD_T> toGLabelTypes = { SCH_LABEL_T, SCH_DIRECTIVE_LABEL_T, SCH_HIER_LABEL_T,
504
505 auto toGLabelCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toGLabelTypes ) )
506 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
507
508 static const std::vector<KICAD_T> toTextTypes = { SCH_LABEL_T, SCH_DIRECTIVE_LABEL_T, SCH_GLOBAL_LABEL_T,
510
511 auto toTextCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toTextTypes ) )
512 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
513
514 static const std::vector<KICAD_T> toTextBoxTypes = { SCH_LABEL_T, SCH_DIRECTIVE_LABEL_T, SCH_GLOBAL_LABEL_T,
516
517 auto toTextBoxCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toTextBoxTypes ) )
518 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
519
520 static const std::vector<KICAD_T> busEntryTypes = { SCH_BUS_WIRE_ENTRY_T, SCH_BUS_BUS_ENTRY_T };
521
522 auto entryCondition = S_C::MoreThan( 0 ) && S_C::OnlyTypes( busEntryTypes );
523
524 auto singleSheetCondition = S_C::Count( 1 ) && S_C::OnlyTypes( sheetTypes );
525
526 auto makeSymbolUnitMenu = [&]( TOOL_INTERACTIVE* tool )
527 {
528 std::shared_ptr<SYMBOL_UNIT_MENU> menu = std::make_shared<SYMBOL_UNIT_MENU>();
529 menu->SetTool( tool );
530 tool->GetToolMenu().RegisterSubMenu( menu );
531 return menu.get();
532 };
533
534 auto makeBodyStyleMenu = [&]( TOOL_INTERACTIVE* tool )
535 {
536 std::shared_ptr<BODY_STYLE_MENU> menu = std::make_shared<BODY_STYLE_MENU>();
537 menu->SetTool( tool );
538 tool->GetToolMenu().RegisterSubMenu( menu );
539 return menu.get();
540 };
541
542 auto makePinFunctionMenu = [&]( TOOL_INTERACTIVE* tool )
543 {
544 std::shared_ptr<ALT_PIN_FUNCTION_MENU> menu = std::make_shared<ALT_PIN_FUNCTION_MENU>();
545 menu->SetTool( tool );
546 tool->GetToolMenu().RegisterSubMenu( menu );
547 return menu.get();
548 };
549
550 auto makePinTricksMenu = [&]( TOOL_INTERACTIVE* tool )
551 {
552 std::shared_ptr<PIN_TRICKS_MENU> menu = std::make_shared<PIN_TRICKS_MENU>();
553 menu->SetTool( tool );
554 tool->GetToolMenu().RegisterSubMenu( menu );
555 return menu.get();
556 };
557
558 auto makeTransformMenu = [&]()
559 {
560 CONDITIONAL_MENU* menu = new CONDITIONAL_MENU( moveTool );
561 menu->SetUntranslatedTitle( _HKI( "Transform Selection" ) );
562
563 menu->AddItem( SCH_ACTIONS::rotateCCW, orientCondition );
564 menu->AddItem( SCH_ACTIONS::rotateCW, orientCondition );
565 menu->AddItem( SCH_ACTIONS::mirrorV, orientCondition );
566 menu->AddItem( SCH_ACTIONS::mirrorH, orientCondition );
567
568 return menu;
569 };
570
571 auto makeAttributesMenu = [&]()
572 {
573 CONDITIONAL_MENU* menu = new CONDITIONAL_MENU( moveTool );
574 menu->SetUntranslatedTitle( _HKI( "Attributes" ) );
575
580
581 return menu;
582 };
583
584 auto makeEditFieldsMenu = [&]()
585 {
586 CONDITIONAL_MENU* menu = new CONDITIONAL_MENU( m_selectionTool );
587 menu->SetUntranslatedTitle( _HKI( "Edit Main Fields" ) );
588
592
593 return menu;
594 };
595
596 auto makeConvertToMenu = [&]()
597 {
598 CONDITIONAL_MENU* menu = new CONDITIONAL_MENU( m_selectionTool );
599 menu->SetUntranslatedTitle( _HKI( "Change To" ) );
600 menu->SetIcon( BITMAPS::right );
601
602 menu->AddItem( SCH_ACTIONS::toLabel, toLabelCondition );
603 menu->AddItem( SCH_ACTIONS::toDLabel, toCLabelCondition );
604 menu->AddItem( SCH_ACTIONS::toHLabel, toHLabelCondition );
605 menu->AddItem( SCH_ACTIONS::toGLabel, toGLabelCondition );
606 menu->AddItem( SCH_ACTIONS::toText, toTextCondition );
607 menu->AddItem( SCH_ACTIONS::toTextBox, toTextBoxCondition );
608
609 return menu;
610 };
611
612 const auto canCopyText = SCH_CONDITIONS::OnlyTypes( {
621 SCH_PIN_T,
624 } );
625
626 //
627 // Add edit actions to the move tool menu
628 //
629 CONDITIONAL_MENU& moveMenu = moveTool->GetToolMenu().GetMenu();
630
631 moveMenu.AddSeparator();
632 moveMenu.AddMenu( makeSymbolUnitMenu( moveTool ), S_C::SingleMultiUnitSymbol, 1 );
633 moveMenu.AddMenu( makeBodyStyleMenu( moveTool ), S_C::SingleMultiBodyStyleSymbol, 1 );
634
635 moveMenu.AddMenu( makeTransformMenu(), orientCondition, 200 );
636 moveMenu.AddMenu( makeAttributesMenu(), S_C::HasType( SCH_SYMBOL_T ), 200 );
637 moveMenu.AddItem( SCH_ACTIONS::swap, swapSelectionCondition, 200 );
638 moveMenu.AddItem( SCH_ACTIONS::properties, propertiesCondition, 200 );
639 moveMenu.AddMenu( makeEditFieldsMenu(), S_C::SingleSymbol, 200 );
640
641 moveMenu.AddSeparator();
642 moveMenu.AddItem( ACTIONS::cut, S_C::IdleSelection );
643 moveMenu.AddItem( ACTIONS::copy, S_C::IdleSelection );
644 moveMenu.AddItem( ACTIONS::copyAsText, canCopyText && S_C::IdleSelection );
645 moveMenu.AddItem( ACTIONS::doDelete, S_C::NotEmpty );
646 moveMenu.AddItem( ACTIONS::duplicate, duplicateCondition );
647
648 //
649 // Add editing actions to the drawing tool menu
650 //
651 CONDITIONAL_MENU& drawMenu = drawingTools->GetToolMenu().GetMenu();
652
653 drawMenu.AddItem( SCH_ACTIONS::clearHighlight, haveHighlight && SCH_CONDITIONS::Idle, 1 );
654 drawMenu.AddSeparator( haveHighlight && SCH_CONDITIONS::Idle, 1 );
655
656 drawMenu.AddItem( SCH_ACTIONS::enterSheet, sheetSelection && SCH_CONDITIONS::Idle, 1 );
657 drawMenu.AddSeparator( sheetSelection && SCH_CONDITIONS::Idle, 1 );
658
659 drawMenu.AddMenu( makeSymbolUnitMenu( drawingTools ), S_C::SingleMultiUnitSymbol, 1 );
660 drawMenu.AddMenu( makeBodyStyleMenu( drawingTools ), S_C::SingleMultiBodyStyleSymbol, 1 );
661
662 drawMenu.AddMenu( makeTransformMenu(), orientCondition, 200 );
663 drawMenu.AddMenu( makeAttributesMenu(), S_C::HasType( SCH_SYMBOL_T ), 200 );
664 drawMenu.AddItem( SCH_ACTIONS::properties, propertiesCondition, 200 );
665 drawMenu.AddMenu( makeEditFieldsMenu(), S_C::SingleSymbol, 200 );
666 drawMenu.AddItem( SCH_ACTIONS::autoplaceFields, autoplaceCondition, 200 );
667
669
670 drawMenu.AddItem( SCH_ACTIONS::toLabel, anyTextTool && S_C::Idle, 200 );
671 drawMenu.AddItem( SCH_ACTIONS::toHLabel, anyTextTool && S_C::Idle, 200 );
672 drawMenu.AddItem( SCH_ACTIONS::toGLabel, anyTextTool && S_C::Idle, 200 );
673 drawMenu.AddItem( SCH_ACTIONS::toText, anyTextTool && S_C::Idle, 200 );
674 drawMenu.AddItem( SCH_ACTIONS::toTextBox, anyTextTool && S_C::Idle, 200 );
675
676 //
677 // Add editing actions to the selection tool menu
678 //
679 CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
680
681 selToolMenu.AddMenu( makeSymbolUnitMenu( m_selectionTool ), S_C::SingleMultiUnitSymbol, 1 );
682 selToolMenu.AddMenu( makeBodyStyleMenu( m_selectionTool ), S_C::SingleMultiBodyStyleSymbol, 1 );
683 selToolMenu.AddMenu( makePinFunctionMenu( m_selectionTool ), S_C::SingleMultiFunctionPin, 1 );
684 selToolMenu.AddMenu( makePinTricksMenu( m_selectionTool ), S_C::AllPinsOrSheetPins, 1 );
685
686 selToolMenu.AddMenu( makeTransformMenu(), orientCondition, 200 );
687 selToolMenu.AddMenu( makeAttributesMenu(), S_C::HasType( SCH_SYMBOL_T ), 200 );
688 selToolMenu.AddItem( SCH_ACTIONS::swap, swapSelectionCondition, 200 );
689 selToolMenu.AddItem( SCH_ACTIONS::properties, propertiesCondition, 200 );
690 selToolMenu.AddMenu( makeEditFieldsMenu(), S_C::SingleSymbol, 200 );
691 selToolMenu.AddItem( SCH_ACTIONS::autoplaceFields, autoplaceCondition, 200 );
692
698 selToolMenu.AddMenu( makeConvertToMenu(), toChangeCondition, 200 );
699
700 selToolMenu.AddItem( SCH_ACTIONS::cleanupSheetPins, sheetHasUndefinedPins, 250 );
701
702 selToolMenu.AddSeparator( 300 );
703 selToolMenu.AddItem( ACTIONS::cut, S_C::IdleSelection, 300 );
704 selToolMenu.AddItem( ACTIONS::copy, S_C::IdleSelection, 300 );
705 selToolMenu.AddItem( ACTIONS::copyAsText, canCopyText && S_C::IdleSelection, 300 );
706 selToolMenu.AddItem( ACTIONS::paste, S_C::Idle, 300 );
707 selToolMenu.AddItem( ACTIONS::pasteSpecial, S_C::Idle, 300 );
708 selToolMenu.AddItem( ACTIONS::doDelete, S_C::NotEmpty, 300 );
709 selToolMenu.AddItem( ACTIONS::duplicate, duplicateCondition, 300 );
710
711 selToolMenu.AddSeparator( 400 );
712 selToolMenu.AddItem( ACTIONS::selectAll, hasElements, 400 );
713 selToolMenu.AddItem( ACTIONS::unselectAll, hasElements, 400 );
714
715 ACTION_MANAGER* mgr = m_toolMgr->GetActionManager();
716 // clang-format off
717 mgr->SetConditions( SCH_ACTIONS::setDNP, ACTION_CONDITIONS().Check( attribDNPCond ) );
718 mgr->SetConditions( SCH_ACTIONS::setExcludeFromSimulation, ACTION_CONDITIONS().Check( attribExcludeFromSimCond ) );
719 mgr->SetConditions( SCH_ACTIONS::setExcludeFromBOM, ACTION_CONDITIONS().Check( attribExcludeFromBOMCond ) );
720 mgr->SetConditions( SCH_ACTIONS::setExcludeFromBoard, ACTION_CONDITIONS().Check( attribExcludeFromBoardCond ) );
721 // clang-format on
722
723 return true;
724}
725
726
727const std::vector<KICAD_T> SCH_EDIT_TOOL::RotatableItems = {
729 SCH_TABLECELL_T, // will be promoted to parent table(s)
733};
734
735
736const std::vector<KICAD_T> SCH_EDIT_TOOL::SwappableItems = {
740};
741
742
744{
745 bool clockwise = ( aEvent.Matches( SCH_ACTIONS::rotateCW.MakeEvent() ) );
746 SCH_SELECTION& selection = m_selectionTool->RequestSelection( RotatableItems, true, false );
747
748 wxLogTrace( "KICAD_SCH_MOVE", "SCH_EDIT_TOOL::Rotate: start, clockwise=%d, selection size=%u", clockwise,
749 selection.GetSize() );
750
751 if( selection.GetSize() == 0 )
752 return 0;
753
754 SCH_ITEM* head = nullptr;
755 int principalItemCount = 0; // User-selected items (as opposed to connected wires)
756 VECTOR2I rotPoint;
757 bool moving = false;
758 SCH_COMMIT localCommit( m_toolMgr );
759 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
760 SCH_SCREEN* screen = m_frame->GetScreen();
761
762 std::map<SCH_SHEET_PIN*, SCH_NO_CONNECT*> noConnects;
763
764 if( !commit )
765 commit = &localCommit;
766
767 for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
768 {
769 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
770
771 if( item->HasFlag( SELECTED_BY_DRAG ) )
772 continue;
773
774 principalItemCount++;
775
776 if( !head )
777 head = item;
778 }
779
780 if( head && head->IsMoving() )
781 moving = true;
782
783 if( principalItemCount == 1 )
784 {
785 if( moving && selection.HasReferencePoint() )
786 rotPoint = selection.GetReferencePoint();
787 else if( head->IsConnectable() )
788 rotPoint = head->GetPosition();
789 else
790 rotPoint = m_frame->GetNearestHalfGridPosition( head->GetBoundingBox().GetCenter() );
791
792 if( !moving )
793 commit->Modify( head, screen, RECURSE_MODE::RECURSE );
794
795 switch( head->Type() )
796 {
797 case SCH_SYMBOL_T:
798 {
799 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( head );
800
801 symbol->Rotate( rotPoint, !clockwise );
802
803 if( m_frame->eeconfig()->m_AutoplaceFields.enable )
804 {
805 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
806
807 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
808 symbol->AutoplaceFields( screen, fieldsAutoplaced );
809 }
810
811 break;
812 }
813
814 case SCH_TEXT_T:
815 case SCH_LABEL_T:
817 case SCH_HIER_LABEL_T:
819 {
820 SCH_TEXT* textItem = static_cast<SCH_TEXT*>( head );
821 textItem->Rotate90( clockwise );
822 break;
823 }
824
825 case SCH_SHEET_PIN_T:
826 {
827 // Rotate pin within parent sheet
828 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( head );
829 SCH_SHEET* sheet = pin->GetParent();
830
831 for( SCH_ITEM* ncItem : screen->Items().Overlapping( SCH_NO_CONNECT_T, pin->GetTextPos() ) )
832 noConnects[pin] = static_cast<SCH_NO_CONNECT*>( ncItem );
833
834 pin->Rotate( sheet->GetBoundingBox().GetCenter(), !clockwise );
835
836 break;
837 }
838
839 case SCH_LINE_T:
840 {
841 SCH_LINE* line = static_cast<SCH_LINE*>( head );
842
843 // Equal checks for both and neither. We need this because on undo
844 // the item will have both flags cleared, but will be selected, so it is possible
845 // for the user to get a selected line with neither endpoint selected. We
846 // set flags to make sure Rotate() works when we call it.
847 if( line->HasFlag( STARTPOINT ) == line->HasFlag( ENDPOINT ) )
848 {
849 line->SetFlags( STARTPOINT | ENDPOINT );
850
851 // When we allow off grid items, the rotPoint should be set to the midpoint
852 // of the line to allow rotation around the center, and the next if
853 // should become an else-if
854 }
855
856 if( line->HasFlag( STARTPOINT ) )
857 rotPoint = line->GetEndPoint();
858 else if( line->HasFlag( ENDPOINT ) )
859 rotPoint = line->GetStartPoint();
860 }
861
863 case SCH_JUNCTION_T:
864 case SCH_NO_CONNECT_T:
866 case SCH_BUS_WIRE_ENTRY_T: head->Rotate( rotPoint, !clockwise ); break;
867
868 case SCH_FIELD_T:
869 {
870 SCH_FIELD* field = static_cast<SCH_FIELD*>( head );
871
872 if( field->GetTextAngle().IsHorizontal() )
874 else
876
877 // Now that we're moving a field, they're no longer autoplaced.
878 static_cast<SCH_ITEM*>( head->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
879
880 break;
881 }
882
883 case SCH_RULE_AREA_T:
884 case SCH_SHAPE_T:
885 case SCH_TEXTBOX_T: head->Rotate( rotPoint, !clockwise ); break;
886
887 case SCH_GROUP_T:
888 {
889 // Rotate the group on itself. Groups do not have an anchor point.
890 SCH_GROUP* group = static_cast<SCH_GROUP*>( head );
891 rotPoint = m_frame->GetNearestHalfGridPosition( group->GetPosition() );
892
893 group->Rotate( rotPoint, !clockwise );
894
895 group->Move( rotPoint - m_frame->GetNearestHalfGridPosition( group->GetPosition() ) );
896
897 break;
898 }
899
900 case SCH_TABLE_T:
901 {
902 // Rotate the table on itself. Tables do not have an anchor point.
903 SCH_TABLE* table = static_cast<SCH_TABLE*>( head );
904 rotPoint = m_frame->GetNearestHalfGridPosition( table->GetCenter() );
905
906 table->Rotate( rotPoint, !clockwise );
907
908 table->Move( rotPoint - m_frame->GetNearestHalfGridPosition( table->GetCenter() ) );
909
910 break;
911 }
912
913 case SCH_BITMAP_T:
914 head->Rotate( rotPoint, clockwise );
915
916 // The bitmap is cached in Opengl: clear the cache to redraw
918 break;
919
920 case SCH_SHEET_T:
921 {
922 // Rotate the sheet on itself. Sheets do not have an anchor point.
923 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( head );
924
925 noConnects = sheet->GetNoConnects();
926
927 rotPoint = m_frame->GetNearestHalfGridPosition( sheet->GetRotationCenter() );
928 sheet->Rotate( rotPoint, !clockwise );
929
930 break;
931 }
932
933 default: UNIMPLEMENTED_FOR( head->GetClass() );
934 }
935
936 m_frame->UpdateItem( head, false, true );
937 }
938 else
939 {
940 if( moving && selection.HasReferencePoint() )
941 rotPoint = selection.GetReferencePoint();
942 else
943 rotPoint = m_frame->GetNearestHalfGridPosition( selection.GetCenter() );
944 }
945
946 for( EDA_ITEM* edaItem : selection )
947 {
948 SCH_ITEM* item = static_cast<SCH_ITEM*>( edaItem );
949
950 // We've already rotated the user selected item if there was only one. We're just
951 // here to rotate the ends of wires that were attached to it.
952 if( principalItemCount == 1 && !item->HasFlag( SELECTED_BY_DRAG ) )
953 continue;
954
955 if( !moving )
956 commit->Modify( item, screen, RECURSE_MODE::RECURSE );
957
958 if( item->Type() == SCH_LINE_T )
959 {
960 SCH_LINE* line = (SCH_LINE*) item;
961
962 line->Rotate( rotPoint, !clockwise );
963 }
964 else if( item->Type() == SCH_SHEET_PIN_T )
965 {
966 if( item->GetParent()->IsSelected() )
967 {
968 // parent will rotate us
969 }
970 else
971 {
972 // rotate within parent
973 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
974 SCH_SHEET* sheet = pin->GetParent();
975
976 for( SCH_ITEM* ncItem : screen->Items().Overlapping( SCH_NO_CONNECT_T, pin->GetTextPos() ) )
977 noConnects[pin] = static_cast<SCH_NO_CONNECT*>( ncItem );
978
979 pin->Rotate( sheet->GetBodyBoundingBox().GetCenter(), !clockwise );
980 }
981 }
982 else if( item->Type() == SCH_FIELD_T )
983 {
984 if( item->GetParent()->IsSelected() )
985 {
986 // parent will rotate us
987 }
988 else
989 {
990 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
991
992 field->Rotate( rotPoint, !clockwise );
993
994 // Now that we're moving a field, they're no longer autoplaced.
995 static_cast<SCH_ITEM*>( field->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
996 }
997 }
998 else if( item->Type() == SCH_TABLE_T )
999 {
1000 SCH_TABLE* table = static_cast<SCH_TABLE*>( item );
1001 VECTOR2I beforeCenter = table->GetCenter();
1002
1003 table->Rotate( rotPoint, !clockwise );
1004 RotatePoint( beforeCenter, rotPoint, clockwise ? -ANGLE_90 : ANGLE_90 );
1005
1006 table->Move( beforeCenter - table->GetCenter() );
1007 }
1008 else if( item->Type() == SCH_SHEET_T )
1009 {
1010 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1011
1012 noConnects = sheet->GetNoConnects();
1013
1014 sheet->Rotate( rotPoint, !clockwise );
1015 }
1016 else
1017 {
1018 VECTOR2I posBefore = item->GetPosition();
1019 item->Rotate( rotPoint, !clockwise );
1020 VECTOR2I posAfter = item->GetPosition();
1021 wxLogTrace( "KICAD_SCH_MOVE", " SCH_EDIT_TOOL::Rotate: item type=%d rotated, pos (%d,%d) -> (%d,%d)",
1022 item->Type(), posBefore.x, posBefore.y, posAfter.x, posAfter.y );
1023 }
1024
1025 m_frame->UpdateItem( item, false, true );
1026 updateItem( item, true );
1027 }
1028
1029 wxLogTrace( "KICAD_SCH_MOVE", "SCH_EDIT_TOOL::Rotate: complete, moving=%d", moving );
1030
1031 if( moving )
1032 {
1033 wxLogTrace( "KICAD_SCH_MOVE", "SCH_EDIT_TOOL::Rotate: posting refreshPreview" );
1034 m_toolMgr->PostAction( ACTIONS::refreshPreview );
1035 }
1036 else
1037 {
1038 for( auto& [sheetPin, noConnect] : noConnects )
1039 {
1040 if( noConnect->GetPosition() != sheetPin->GetTextPos() )
1041 {
1042 commit->Modify( noConnect, screen );
1043 noConnect->SetPosition( sheetPin->GetTextPos() );
1044 updateItem( noConnect, true );
1045 }
1046 }
1047
1048 SCH_SELECTION selectionCopy = selection;
1049
1050 if( selection.IsHover() )
1051 m_toolMgr->RunAction( ACTIONS::selectionClear );
1052
1054 lwbTool->TrimOverLappingWires( commit, &selectionCopy );
1055 lwbTool->AddJunctionsIfNeeded( commit, &selectionCopy );
1056
1057 m_frame->Schematic().CleanUp( commit );
1058
1059 if( !localCommit.Empty() )
1060 localCommit.Push( _( "Rotate" ) );
1061 }
1062
1063 return 0;
1064}
1065
1066
1068{
1069 SCH_SELECTION& selection = m_selectionTool->RequestSelection( RotatableItems, false, false );
1070
1071 if( selection.GetSize() == 0 )
1072 return 0;
1073
1074 bool vertical = ( aEvent.Matches( SCH_ACTIONS::mirrorV.MakeEvent() ) );
1075 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
1076 bool connections = false;
1077 bool moving = item->IsMoving();
1078 SCH_COMMIT localCommit( m_toolMgr );
1079 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
1080 SCH_SCREEN* screen = m_frame->GetScreen();
1081
1082 std::map<SCH_SHEET_PIN*, SCH_NO_CONNECT*> noConnects;
1083
1084 if( !commit )
1085 commit = &localCommit;
1086
1087 if( selection.GetSize() == 1 )
1088 {
1089 if( !moving )
1090 commit->Modify( item, screen, RECURSE_MODE::RECURSE );
1091
1092 switch( item->Type() )
1093 {
1094 case SCH_SYMBOL_T:
1095 {
1096 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1097
1098 if( vertical )
1099 symbol->SetOrientation( SYM_MIRROR_X );
1100 else
1101 symbol->SetOrientation( SYM_MIRROR_Y );
1102
1104 break;
1105 }
1106
1107 case SCH_TEXT_T:
1108 case SCH_LABEL_T:
1109 case SCH_GLOBAL_LABEL_T:
1110 case SCH_HIER_LABEL_T:
1112 {
1113 SCH_TEXT* textItem = static_cast<SCH_TEXT*>( item );
1114 textItem->MirrorSpinStyle( !vertical );
1115 break;
1116 }
1117
1118 case SCH_SHEET_PIN_T:
1119 {
1120 // mirror within parent sheet
1121 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
1122 SCH_SHEET* sheet = pin->GetParent();
1123
1124 for( SCH_ITEM* ncItem : screen->Items().Overlapping( SCH_NO_CONNECT_T, pin->GetTextPos() ) )
1125 noConnects[pin] = static_cast<SCH_NO_CONNECT*>( ncItem );
1126
1127 if( vertical )
1128 pin->MirrorVertically( sheet->GetBoundingBox().GetCenter().y );
1129 else
1130 pin->MirrorHorizontally( sheet->GetBoundingBox().GetCenter().x );
1131
1132 break;
1133 }
1134
1135 case SCH_FIELD_T:
1136 {
1137 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
1138
1139 if( vertical )
1141 else
1143
1144 // Now that we're re-justifying a field, they're no longer autoplaced.
1145 static_cast<SCH_ITEM*>( field->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
1146
1147 break;
1148 }
1149
1150 case SCH_BITMAP_T:
1151 if( vertical )
1152 item->MirrorVertically( item->GetPosition().y );
1153 else
1154 item->MirrorHorizontally( item->GetPosition().x );
1155
1156 // The bitmap is cached in Opengl: clear the cache to redraw
1158 break;
1159
1160 case SCH_SHEET_T:
1161 {
1162 noConnects = static_cast<SCH_SHEET*>( item )->GetNoConnects();
1163
1164 // Mirror the sheet on itself. Sheets do not have a anchor point.
1165 VECTOR2I mirrorPoint = m_frame->GetNearestHalfGridPosition( item->GetBoundingBox().Centre() );
1166
1167 if( vertical )
1168 item->MirrorVertically( mirrorPoint.y );
1169 else
1170 item->MirrorHorizontally( mirrorPoint.x );
1171
1172 break;
1173 }
1174
1175 default:
1176 if( vertical )
1177 item->MirrorVertically( item->GetPosition().y );
1178 else
1179 item->MirrorHorizontally( item->GetPosition().x );
1180
1181 break;
1182 }
1183
1184 connections = item->IsConnectable();
1185 m_frame->UpdateItem( item, false, true );
1186 }
1187 else if( selection.GetSize() > 1 )
1188 {
1189 VECTOR2I mirrorPoint = m_frame->GetNearestHalfGridPosition( selection.GetCenter() );
1190
1191 for( EDA_ITEM* edaItem : selection )
1192 {
1193 item = static_cast<SCH_ITEM*>( edaItem );
1194
1195 if( !moving )
1196 commit->Modify( item, screen, RECURSE_MODE::RECURSE );
1197
1198 if( item->Type() == SCH_SHEET_PIN_T )
1199 {
1200 if( item->GetParent()->IsSelected() )
1201 {
1202 // parent will mirror us
1203 }
1204 else
1205 {
1206 // mirror within parent sheet
1207 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
1208 SCH_SHEET* sheet = pin->GetParent();
1209
1210 if( vertical )
1211 pin->MirrorVertically( sheet->GetBoundingBox().GetCenter().y );
1212 else
1213 pin->MirrorHorizontally( sheet->GetBoundingBox().GetCenter().x );
1214 }
1215 }
1216 else if( item->Type() == SCH_FIELD_T )
1217 {
1218 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
1219
1220 if( vertical )
1222 else
1224
1225 // Now that we're re-justifying a field, they're no longer autoplaced.
1226 static_cast<SCH_ITEM*>( field->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
1227 }
1228 else
1229 {
1230 if( vertical )
1231 item->MirrorVertically( mirrorPoint.y );
1232 else
1233 item->MirrorHorizontally( mirrorPoint.x );
1234 }
1235
1236 connections |= item->IsConnectable();
1237 m_frame->UpdateItem( item, false, true );
1238 }
1239 }
1240
1241 // Update R-Tree for modified items
1242 for( EDA_ITEM* selected : selection )
1243 updateItem( selected, true );
1244
1245 if( item->IsMoving() )
1246 {
1247 m_toolMgr->RunAction( ACTIONS::refreshPreview );
1248 }
1249 else
1250 {
1251 for( auto& [sheetPin, noConnect] : noConnects )
1252 {
1253 if( noConnect->GetPosition() != sheetPin->GetTextPos() )
1254 {
1255 commit->Modify( noConnect, screen );
1256 noConnect->SetPosition( sheetPin->GetTextPos() );
1257 updateItem( noConnect, true );
1258 }
1259 }
1260
1261 SCH_SELECTION selectionCopy = selection;
1262
1263 if( selection.IsHover() )
1264 m_toolMgr->RunAction( ACTIONS::selectionClear );
1265
1266 if( connections )
1267 {
1269 lwbTool->TrimOverLappingWires( commit, &selectionCopy );
1270 lwbTool->AddJunctionsIfNeeded( commit, &selectionCopy );
1271
1272 m_frame->Schematic().CleanUp( commit );
1273 }
1274
1275 if( !localCommit.Empty() )
1276 localCommit.Push( _( "Mirror" ) );
1277 }
1278
1279 return 0;
1280}
1281
1291static void swapFieldPositionsWithMatching( std::vector<SCH_FIELD>& aAFields, std::vector<SCH_FIELD>& aBFields,
1292 unsigned aFallbackRotationsCCW )
1293{
1294 std::set<wxString> handledKeys;
1295
1296 const auto swapFieldTextProps = []( SCH_FIELD& aField, SCH_FIELD& bField )
1297 {
1298 const VECTOR2I aRelPos = aField.GetPosition() - aField.GetParentPosition();
1299 const GR_TEXT_H_ALIGN_T aTextJustifyH = aField.GetHorizJustify();
1300 const GR_TEXT_V_ALIGN_T aTextJustifyV = aField.GetVertJustify();
1301 const EDA_ANGLE aTextAngle = aField.GetTextAngle();
1302
1303 const VECTOR2I bRelPos = bField.GetPosition() - bField.GetParentPosition();
1304 const GR_TEXT_H_ALIGN_T bTextJustifyH = bField.GetHorizJustify();
1305 const GR_TEXT_V_ALIGN_T bTextJustifyV = bField.GetVertJustify();
1306 const EDA_ANGLE bTextAngle = bField.GetTextAngle();
1307
1308 aField.SetPosition( aField.GetParentPosition() + bRelPos );
1309 aField.SetHorizJustify( bTextJustifyH );
1310 aField.SetVertJustify( bTextJustifyV );
1311 aField.SetTextAngle( bTextAngle );
1312
1313 bField.SetPosition( bField.GetParentPosition() + aRelPos );
1314 bField.SetHorizJustify( aTextJustifyH );
1315 bField.SetVertJustify( aTextJustifyV );
1316 bField.SetTextAngle( aTextAngle );
1317 };
1318
1319 for( SCH_FIELD& aField : aAFields )
1320 {
1321 const wxString name = aField.GetCanonicalName();
1322
1323 auto it = std::find_if( aBFields.begin(), aBFields.end(),
1324 [name]( const SCH_FIELD& bField )
1325 {
1326 return bField.GetCanonicalName() == name;
1327 } );
1328
1329 if( it != aBFields.end() )
1330 {
1331 // We have a field with the same key in both labels
1332 SCH_FIELD& bField = *it;
1333 swapFieldTextProps( aField, bField );
1334 }
1335 else
1336 {
1337 // We only have this field in A, so just rotate it
1338 for( unsigned ii = 0; ii < aFallbackRotationsCCW; ii++ )
1339 {
1340 aField.Rotate( aField.GetParentPosition(), true );
1341 }
1342 }
1343
1344 // And keep track that we did this one
1345 handledKeys.insert( name );
1346 }
1347
1348 // Any fields in B that weren't in A weren't handled and need to be rotated
1349 // in reverse
1350 for( SCH_FIELD& bField : aBFields )
1351 {
1352 const wxString bName = bField.GetCanonicalName();
1353 if( handledKeys.find( bName ) == handledKeys.end() )
1354 {
1355 for( unsigned ii = 0; ii < aFallbackRotationsCCW; ii++ )
1356 {
1357 bField.Rotate( bField.GetParentPosition(), false );
1358 }
1359 }
1360 }
1361}
1362
1363
1365{
1366 SCH_SELECTION& selection = m_selectionTool->RequestSelection( SwappableItems );
1367 std::vector<EDA_ITEM*> sorted = selection.GetItemsSortedBySelectionOrder();
1368
1369 if( selection.Size() < 2 )
1370 return 0;
1371
1372 // Sheet pins are special, we need to make sure if we have any sheet pins,
1373 // that we only have sheet pins, and that they have the same parent
1374 if( selection.CountType( SCH_SHEET_PIN_T ) > 0 )
1375 {
1376 if( !selection.OnlyContains( { SCH_SHEET_PIN_T } ) )
1377 return 0;
1378
1379 EDA_ITEM* parent = selection.Front()->GetParent();
1380
1381 for( EDA_ITEM* item : selection )
1382 {
1383 if( item->GetParent() != parent )
1384 return 0;
1385 }
1386 }
1387
1388 bool moving = selection.Front()->IsMoving();
1389 bool connections = false;
1390
1391 SCH_COMMIT localCommit( m_toolMgr );
1392 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
1393
1394 if( !commit )
1395 commit = &localCommit;
1396
1397 for( size_t i = 0; i < sorted.size() - 1; i++ )
1398 {
1399 SCH_ITEM* a = static_cast<SCH_ITEM*>( sorted[i] );
1400 SCH_ITEM* b = static_cast<SCH_ITEM*>( sorted[( i + 1 ) % sorted.size()] );
1401
1402 if( !moving )
1403 {
1404 commit->Modify( a, m_frame->GetScreen(), RECURSE_MODE::RECURSE );
1405 commit->Modify( b, m_frame->GetScreen(), RECURSE_MODE::RECURSE );
1406 }
1407
1408 VECTOR2I aPos = a->GetPosition(), bPos = b->GetPosition();
1409 std::swap( aPos, bPos );
1410
1411 // Sheet pins need to have their sides swapped before we change their
1412 // positions
1413 if( a->Type() == SCH_SHEET_PIN_T )
1414 {
1415 SCH_SHEET_PIN* aPin = static_cast<SCH_SHEET_PIN*>( a );
1416 SCH_SHEET_PIN* bPin = static_cast<SCH_SHEET_PIN*>( b );
1417 SHEET_SIDE aSide = aPin->GetSide(), bSide = bPin->GetSide();
1418 std::swap( aSide, bSide );
1419 aPin->SetSide( aSide );
1420 bPin->SetSide( bSide );
1421 }
1422
1423 a->SetPosition( aPos );
1424 b->SetPosition( bPos );
1425
1426 if( a->Type() == b->Type() )
1427 {
1428 switch( a->Type() )
1429 {
1430 case SCH_LABEL_T:
1431 case SCH_GLOBAL_LABEL_T:
1432 case SCH_HIER_LABEL_T:
1434 {
1435 SCH_LABEL_BASE& aLabelBase = static_cast<SCH_LABEL_BASE&>( *a );
1436 SCH_LABEL_BASE& bLabelBase = static_cast<SCH_LABEL_BASE&>( *b );
1437
1438 const SPIN_STYLE aSpinStyle = aLabelBase.GetSpinStyle();
1439 const SPIN_STYLE bSpinStyle = bLabelBase.GetSpinStyle();
1440 const GR_TEXT_V_ALIGN_T aVertJustify = aLabelBase.GetVertJustify();
1441 const GR_TEXT_V_ALIGN_T bVertJustify = bLabelBase.GetVertJustify();
1442
1443 // First, swap the label orientations
1444 aLabelBase.SetSpinStyle( bSpinStyle );
1445 bLabelBase.SetSpinStyle( aSpinStyle );
1446 aLabelBase.SetVertJustify( bVertJustify );
1447 bLabelBase.SetVertJustify( aVertJustify );
1448
1449 // And swap the fields as best we can
1450 std::vector<SCH_FIELD>& aFields = aLabelBase.GetFields();
1451 std::vector<SCH_FIELD>& bFields = bLabelBase.GetFields();
1452
1453 const unsigned rotationsAtoB = aSpinStyle.CCWRotationsTo( bSpinStyle );
1454
1455 swapFieldPositionsWithMatching( aFields, bFields, rotationsAtoB );
1456 break;
1457 }
1458 case SCH_TEXT_T:
1459 case SCH_TEXTBOX_T:
1460 {
1461 EDA_TEXT* aText = dynamic_cast<EDA_TEXT*>( a );
1462 EDA_TEXT* bText = dynamic_cast<EDA_TEXT*>( b );
1463
1464 if( !aText || !bText )
1465 break;
1466
1467 const GR_TEXT_H_ALIGN_T aHorizJustify = aText->GetHorizJustify();
1468 const GR_TEXT_V_ALIGN_T aVertJustify = aText->GetVertJustify();
1469 const GR_TEXT_H_ALIGN_T bHorizJustify = bText->GetHorizJustify();
1470 const GR_TEXT_V_ALIGN_T bVertJustify = bText->GetVertJustify();
1471
1472 aText->SetHorizJustify( bHorizJustify );
1473 aText->SetVertJustify( bVertJustify );
1474 bText->SetHorizJustify( aHorizJustify );
1475 bText->SetVertJustify( aVertJustify );
1476 break;
1477 }
1478 case SCH_SYMBOL_T:
1479 {
1480 SCH_SYMBOL* aSymbol = static_cast<SCH_SYMBOL*>( a );
1481 SCH_SYMBOL* bSymbol = static_cast<SCH_SYMBOL*>( b );
1482
1483 // Only swap orientations when both symbols are the same library symbol.
1484 // Different symbols (e.g. LED vs resistor) have different default orientations,
1485 // so swapping their orientations leads to unexpected visual results.
1486 if( aSymbol->GetLibId() == bSymbol->GetLibId() )
1487 {
1488 int aOrient = aSymbol->GetOrientation();
1489 int bOrient = bSymbol->GetOrientation();
1490 std::swap( aOrient, bOrient );
1491 aSymbol->SetOrientation( aOrient );
1492 bSymbol->SetOrientation( bOrient );
1493 }
1494
1495 break;
1496 }
1497 default: break;
1498 }
1499 }
1500
1501 connections |= a->IsConnectable();
1502 connections |= b->IsConnectable();
1503 m_frame->UpdateItem( a, false, true );
1504 m_frame->UpdateItem( b, false, true );
1505 }
1506
1507 if( moving )
1508 {
1509 m_toolMgr->PostAction( ACTIONS::refreshPreview );
1510 }
1511 else
1512 {
1513 if( selection.IsHover() )
1514 m_toolMgr->RunAction( ACTIONS::selectionClear );
1515
1516 if( connections )
1517 m_frame->TestDanglingEnds();
1518 m_frame->OnModify();
1519
1520 if( !localCommit.Empty() )
1521 localCommit.Push( _( "Swap" ) );
1522 }
1523
1524 return 0;
1525}
1526
1527
1528/*
1529 * This command always works on the instance owned by the schematic, never directly on the
1530 * external library file. Pins that still reference their library definition are swapped by
1531 * touching that shared lib pin first; afterwards we call UpdatePins() so the schematic now owns a
1532 * cached copy with the new geometry. Pins that already have an instance-local copy simply swap in
1533 * place. In both cases the undo stack captures the modified pins (and the parent symbol) so the
1534 * user can revert the change. Saving the schematic writes the updated pin order into the sheet,
1535 * while the global symbol library remains untouched unless the user explicitly pushes it later.
1536 */
1538{
1539 wxCHECK( m_frame, 0 );
1540
1541 if( !m_frame->eeconfig()->m_Input.allow_unconstrained_pin_swaps )
1542 return 0;
1543
1544 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_PIN_T } );
1545 std::vector<EDA_ITEM*> sorted = selection.GetItemsSortedBySelectionOrder();
1546
1547 if( selection.Size() < 2 )
1548 return 0;
1549
1550 EDA_ITEM* parent = selection.Front()->GetParent();
1551
1552 if( !parent || parent->Type() != SCH_SYMBOL_T )
1553 return 0;
1554
1555 SCH_SYMBOL* parentSymbol = static_cast<SCH_SYMBOL*>( parent );
1556
1557 // All pins need to be on the same symbol
1558 for( EDA_ITEM* item : selection )
1559 {
1560 if( item->GetParent() != parent )
1561 return 0;
1562 }
1563
1564 std::set<wxString> sharedSheetPaths;
1565 std::set<wxString> sharedProjectNames;
1566
1567 if( SymbolHasSheetInstances( *parentSymbol, m_frame->Prj().GetProjectName(), &sharedSheetPaths,
1568 &sharedProjectNames ) )
1569 {
1570 // This will give us nice names for our project, but not when the sheet is shared across
1571 // multiple projects. But, in that case we bail early and just list the project names so it isn't an issue.
1572 std::set<wxString> friendlySheets;
1573
1574 if( !sharedSheetPaths.empty() )
1575 friendlySheets = GetSheetNamesFromPaths( sharedSheetPaths, m_frame->Schematic() );
1576
1577 if( !sharedProjectNames.empty() )
1578 {
1579 wxString projects = AccumulateDescriptions( sharedProjectNames );
1580
1581 if( projects.IsEmpty() )
1582 {
1583 m_frame->ShowInfoBarError( _( "Pin swaps are disabled for symbols shared across other projects. "
1584 "Duplicate the sheet to edit pins independently." ) );
1585 }
1586 else
1587 {
1588 m_frame->ShowInfoBarError(
1589 wxString::Format( _( "Pin swaps are disabled for symbols shared across other projects (%s). "
1590 "Duplicate the sheet to edit pins independently." ),
1591 projects ) );
1592 }
1593 }
1594 else if( !friendlySheets.empty() )
1595 {
1596 wxString sheets = AccumulateDescriptions( friendlySheets );
1597
1598 m_frame->ShowInfoBarError(
1599 wxString::Format( _( "Pin swaps are disabled for symbols used by multiple sheet instances (%s). "
1600 "Duplicate the sheet to edit pins independently." ),
1601 sheets ) );
1602 }
1603 else
1604 {
1605 m_frame->ShowInfoBarError(
1606 _( "Pin swaps are disabled for shared symbols. Duplicate the sheet to edit pins independently." ) );
1607 }
1608
1609 return 0;
1610 }
1611
1612 bool connections = false;
1613
1614 SCH_COMMIT localCommit( m_toolMgr );
1615 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
1616
1617 if( !commit )
1618 commit = &localCommit;
1619
1620 // Stage the parent symbol so undo/redo captures the cache copy that UpdatePins() may rebuild
1621 // after we touch any shared library pins.
1622 commit->Modify( parentSymbol, m_frame->GetScreen(), RECURSE_MODE::RECURSE ); // RECURSE is harmless here
1623
1624 bool swappedLibPins = false;
1625
1626 for( size_t i = 0; i < sorted.size() - 1; i++ )
1627 {
1628 SCH_PIN* aPin = static_cast<SCH_PIN*>( sorted[i] );
1629 SCH_PIN* bPin = static_cast<SCH_PIN*>( sorted[( i + 1 ) % sorted.size()] );
1630
1631 // Record both pins in the commit and swap their geometry. SwapPinGeometry returns true if
1632 // it had to operate on the shared library pins (meaning the schematic instance still
1633 // referenced them), in which case UpdatePins() below promotes the symbol to an instance
1634 // copy that reflects the new pin order.
1635 commit->Modify( aPin, m_frame->GetScreen(), RECURSE_MODE::RECURSE );
1636 commit->Modify( bPin, m_frame->GetScreen(), RECURSE_MODE::RECURSE );
1637
1638 swappedLibPins |= SwapPinGeometry( aPin, bPin );
1639
1640 connections |= aPin->IsConnectable();
1641 connections |= bPin->IsConnectable();
1642 m_frame->UpdateItem( aPin, false, true );
1643 m_frame->UpdateItem( bPin, false, true );
1644 }
1645
1646 if( swappedLibPins )
1647 parentSymbol->UpdatePins(); // clone the library data into the schematic cache with new geometry
1648
1649 // Refresh changed symbol in screen R-Tree / lib caches
1650 m_frame->UpdateItem( parentSymbol, false, true );
1651
1652 SCH_SELECTION selectionCopy = selection;
1653
1654 if( selection.IsHover() )
1655 m_toolMgr->RunAction( ACTIONS::selectionClear );
1656
1657 // Reconcile any wiring that was connected to the swapped pins so the schematic stays tidy and
1658 // the undo stack captures the resulting edits to wires and junctions.
1660 lwbTool->TrimOverLappingWires( commit, &selectionCopy );
1661 lwbTool->AddJunctionsIfNeeded( commit, &selectionCopy );
1662
1663 m_frame->Schematic().CleanUp( commit );
1664
1665 if( connections )
1666 m_frame->TestDanglingEnds();
1667
1668 m_frame->OnModify();
1669
1670 if( !localCommit.Empty() )
1671 localCommit.Push( _( "Swap Pins" ) );
1672
1673 return 0;
1674}
1675
1676
1677// Used by SwapPinLabels() and SwapUnitLabels() to find the single net label connected to a pin
1679 const SCH_SHEET_PATH& aSheetPath )
1680{
1681 if( !aGraph || !aPin )
1682 return nullptr;
1683
1684 CONNECTION_SUBGRAPH* sg = aGraph->GetSubgraphForItem( aPin );
1685
1686 if( !sg )
1687 return nullptr;
1688
1689 const std::set<SCH_ITEM*>& items = sg->GetItems();
1690
1691 size_t pinCount = 0;
1692 SCH_LABEL_BASE* label = nullptr;
1693
1694 for( SCH_ITEM* item : items )
1695 {
1696 if( item->Type() == SCH_PIN_T )
1697 pinCount++;
1698
1699 switch( item->Type() )
1700 {
1701 case SCH_LABEL_T:
1702 case SCH_GLOBAL_LABEL_T:
1703 case SCH_HIER_LABEL_T:
1704 {
1705 SCH_CONNECTION* conn = item->Connection( &aSheetPath );
1706
1707 if( conn && conn->IsNet() )
1708 {
1709 if( label )
1710 return nullptr; // more than one label
1711
1712 label = static_cast<SCH_LABEL_BASE*>( item );
1713 }
1714
1715 break;
1716 }
1717 default: break;
1718 }
1719 }
1720
1721 if( pinCount != 1 )
1722 return nullptr;
1723
1724 return label;
1725}
1726
1727
1729{
1730 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_PIN_T } );
1731 std::vector<EDA_ITEM*> orderedPins = selection.GetItemsSortedBySelectionOrder();
1732
1733 if( orderedPins.size() < 2 )
1734 return 0;
1735
1736 CONNECTION_GRAPH* connectionGraph = m_frame->Schematic().ConnectionGraph();
1737
1738 const SCH_SHEET_PATH& sheetPath = m_frame->GetCurrentSheet();
1739
1740 std::vector<SCH_LABEL_BASE*> labels;
1741
1742 for( EDA_ITEM* item : orderedPins )
1743 {
1744 SCH_PIN* pin = static_cast<SCH_PIN*>( item );
1745 SCH_LABEL_BASE* label = findSingleNetLabelForPin( pin, connectionGraph, sheetPath );
1746
1747 if( !label )
1748 {
1749 m_frame->ShowInfoBarError(
1750 _( "Each selected pin must have exactly one attached net label and no other pin connections." ) );
1751 return 0;
1752 }
1753
1754 labels.push_back( label );
1755 }
1756
1757 if( labels.size() >= 2 )
1758 {
1759 SCH_COMMIT commit( m_frame );
1760
1761 for( SCH_LABEL_BASE* lb : labels )
1762 commit.Modify( lb, m_frame->GetScreen() );
1763
1764 for( size_t i = 0; i < labels.size() - 1; ++i )
1765 {
1766 SCH_LABEL_BASE* a = labels[i];
1767 SCH_LABEL_BASE* b = labels[( i + 1 ) % labels.size()];
1768 wxString aText = a->GetText();
1769 wxString bText = b->GetText();
1770 a->SetText( bText );
1771 b->SetText( aText );
1772 }
1773
1774 commit.Push( _( "Swap Pin Labels" ) );
1775 }
1776
1777 return 0;
1778}
1779
1780
1782{
1783 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_SYMBOL_T } );
1784 std::vector<SCH_SYMBOL*> selectedUnits = GetSameSymbolMultiUnitSelection( selection );
1785
1786 if( selectedUnits.size() < 2 )
1787 return 0;
1788
1789 CONNECTION_GRAPH* connectionGraph = m_frame->Schematic().ConnectionGraph();
1790
1791 const SCH_SHEET_PATH& sheetPath = m_frame->GetCurrentSheet();
1792
1793 // Build ordered label vectors (sorted by pin X/Y) for each selected unit
1794 std::vector<std::vector<SCH_LABEL_BASE*>> symbolLabelVectors;
1795
1796 for( SCH_SYMBOL* symbol : selectedUnits )
1797 {
1798 std::vector<std::pair<VECTOR2I, SCH_LABEL_BASE*>> byPos;
1799
1800 for( SCH_PIN* pin : symbol->GetPins( &sheetPath ) )
1801 {
1802 SCH_LABEL_BASE* label = findSingleNetLabelForPin( pin, connectionGraph, sheetPath );
1803
1804 if( !label )
1805 {
1806 m_frame->ShowInfoBarError( _( "Each pin of selected units must have exactly one attached net label and "
1807 "no other pin connections." ) );
1808 return 0;
1809 }
1810
1811 byPos.emplace_back( pin->GetPosition(), label );
1812 }
1813
1814 // Sort labels by pin position (X, then Y)
1815 std::sort( byPos.begin(), byPos.end(),
1816 []( const auto& a, const auto& b )
1817 {
1818 if( a.first.x != b.first.x )
1819 return a.first.x < b.first.x;
1820
1821 return a.first.y < b.first.y;
1822 } );
1823
1824 // Discard position, just keep the order
1825 std::vector<SCH_LABEL_BASE*> labels;
1826
1827 for( const auto& pr : byPos )
1828 labels.push_back( pr.second );
1829
1830 symbolLabelVectors.push_back( labels );
1831 }
1832
1833 // All selected units are guaranteed to have identical pin counts by GetSameSymbolMultiUnitSelection()
1834 const size_t pinCount = symbolLabelVectors.front().size();
1835
1836 // Perform cyclic swap of labels across all selected symbols, per pin index
1837 SCH_COMMIT commit( m_frame );
1838
1839 for( size_t pin = 0; pin < pinCount; pin++ )
1840 {
1841 for( auto& vec : symbolLabelVectors )
1842 commit.Modify( vec[pin], m_frame->GetScreen() );
1843
1844 wxString carry = symbolLabelVectors.back()[pin]->GetText();
1845
1846 for( size_t i = 0; i < symbolLabelVectors.size(); i++ )
1847 {
1848 SCH_LABEL_BASE* lbl = symbolLabelVectors[i][pin];
1849 wxString next = lbl->GetText();
1850 lbl->SetText( carry );
1851 carry = next;
1852 }
1853 }
1854
1855 if( !commit.Empty() )
1856 commit.Push( _( "Swap Unit Labels" ) );
1857
1858 return 0;
1859}
1860
1861
1863{
1864 const std::vector<std::unique_ptr<SCH_ITEM>>& sourceItems = m_frame->GetRepeatItems();
1865
1866 if( sourceItems.empty() )
1867 return 0;
1868
1869 m_toolMgr->RunAction( ACTIONS::selectionClear );
1870
1871 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1872 SCH_COMMIT commit( m_toolMgr );
1873 SCH_SELECTION newItems;
1874
1875 for( const std::unique_ptr<SCH_ITEM>& item : sourceItems )
1876 {
1877 SCH_ITEM* newItem = item->Duplicate( IGNORE_PARENT_GROUP );
1878 bool restore_state = false;
1879
1880 // Ensure newItem has a suitable parent: the current screen, because an item from
1881 // a list of items to repeat must be attached to this current screen
1882 newItem->SetParent( m_frame->GetScreen() );
1883
1884 if( SCH_GROUP* enteredGroup = selectionTool->GetEnteredGroup() )
1885 {
1886 if( newItem->IsGroupableType() )
1887 {
1888 commit.Modify( enteredGroup, m_frame->GetScreen(), RECURSE_MODE::NO_RECURSE );
1889 enteredGroup->AddItem( newItem );
1890 }
1891 }
1892
1893 if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( newItem ) )
1894 {
1895 // If incrementing tries to go below zero, tell user why the value is repeated
1896 if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
1897 {
1898 if( !label->IncrementLabel( cfg->m_Drawing.repeat_label_increment ) )
1899 m_frame->ShowInfoBarWarning( _( "Label value cannot go below zero" ), true );
1900 }
1901 }
1902
1903 // If cloning a symbol then put into 'move' mode.
1904 if( newItem->Type() == SCH_SYMBOL_T )
1905 {
1906 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( true );
1907 newItem->Move( cursorPos - newItem->GetPosition() );
1908 }
1909 else if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
1910 {
1911 newItem->Move( VECTOR2I( schIUScale.MilsToIU( cfg->m_Drawing.default_repeat_offset_x ),
1912 schIUScale.MilsToIU( cfg->m_Drawing.default_repeat_offset_y ) ) );
1913 }
1914
1915 // If cloning a sheet, check that we aren't going to create recursion
1916 if( newItem->Type() == SCH_SHEET_T )
1917 {
1918 SCH_SHEET_PATH* currentSheet = &m_frame->GetCurrentSheet();
1919 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( newItem );
1920
1921 if( m_frame->CheckSheetForRecursion( sheet, currentSheet ) )
1922 {
1923 // Clear out the filename so that the user can pick a new one
1924 const wxString originalFileName = sheet->GetFileName();
1925 const wxString originalScreenFileName = sheet->GetScreen()->GetFileName();
1926
1927 sheet->SetFileName( wxEmptyString );
1928 sheet->GetScreen()->SetFileName( wxEmptyString );
1929 restore_state = !m_frame->EditSheetProperties( sheet, currentSheet );
1930
1931 if( restore_state )
1932 {
1933 sheet->SetFileName( originalFileName );
1934 sheet->GetScreen()->SetFileName( originalScreenFileName );
1935 }
1936 }
1937 }
1938
1939 m_toolMgr->RunAction<EDA_ITEM*>( ACTIONS::selectItem, newItem );
1940 newItem->SetFlags( IS_NEW );
1941 m_frame->AddToScreen( newItem, m_frame->GetScreen() );
1942 commit.Added( newItem, m_frame->GetScreen() );
1943
1944 if( newItem->Type() == SCH_SYMBOL_T )
1945 {
1946 SCHEMATIC_SETTINGS& projSettings = m_frame->Schematic().Settings();
1947 int annotateStartNum = projSettings.m_AnnotateStartNum;
1948 ANNOTATE_ORDER_T annotateOrder = static_cast<ANNOTATE_ORDER_T>( projSettings.m_AnnotateSortOrder );
1949 ANNOTATE_ALGO_T annotateAlgo = static_cast<ANNOTATE_ALGO_T>( projSettings.m_AnnotateMethod );
1950
1951 if( m_frame->eeconfig()->m_AnnotatePanel.automatic )
1952 {
1953 static_cast<SCH_SYMBOL*>( newItem )->ClearAnnotation( nullptr, false );
1954 NULL_REPORTER reporter;
1955 m_frame->AnnotateSymbols( &commit, ANNOTATE_SELECTION, annotateOrder, annotateAlgo,
1956 true /* recursive */, annotateStartNum, false, false, false,
1957 reporter );
1958 }
1959
1960 // Annotation clears the selection so re-add the item
1961 m_toolMgr->RunAction<EDA_ITEM*>( ACTIONS::selectItem, newItem );
1962
1963 restore_state = !m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit );
1964 }
1965
1966 if( restore_state )
1967 {
1968 commit.Revert();
1969 }
1970 else
1971 {
1972 newItems.Add( newItem );
1973
1975 lwbTool->TrimOverLappingWires( &commit, &newItems );
1976 lwbTool->AddJunctionsIfNeeded( &commit, &newItems );
1977
1978 m_frame->Schematic().CleanUp( &commit );
1979 commit.Push( _( "Repeat Item" ) );
1980 }
1981 }
1982
1983 if( !newItems.Empty() )
1984 m_frame->SaveCopyForRepeatItem( static_cast<SCH_ITEM*>( newItems[0] ) );
1985
1986 for( size_t ii = 1; ii < newItems.GetSize(); ++ii )
1987 m_frame->AddCopyForRepeatItem( static_cast<SCH_ITEM*>( newItems[ii] ) );
1988
1989 return 0;
1990}
1991
1992
1994{
1995 SCH_SCREEN* screen = m_frame->GetScreen();
1996 std::deque<EDA_ITEM*> items = m_selectionTool->RequestSelection( SCH_COLLECTOR::DeletableItems ).GetItems();
1997 SCH_COMMIT commit( m_toolMgr );
1998 std::vector<VECTOR2I> pts;
1999 bool updateHierarchy = false;
2000
2001 if( items.empty() )
2002 return 0;
2003
2004 // Don't leave a freed pointer in the selection
2005 m_toolMgr->RunAction( ACTIONS::selectionClear );
2006
2007 for( EDA_ITEM* item : items )
2008 item->ClearFlags( STRUCT_DELETED );
2009
2010 for( EDA_ITEM* item : items )
2011 {
2012 SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item );
2013
2014 if( !sch_item )
2015 continue;
2016
2017 if( sch_item->IsConnectable() )
2018 {
2019 std::vector<VECTOR2I> tmp_pts = sch_item->GetConnectionPoints();
2020 pts.insert( pts.end(), tmp_pts.begin(), tmp_pts.end() );
2021 }
2022
2023 if( sch_item->Type() == SCH_JUNCTION_T )
2024 {
2025 sch_item->SetFlags( STRUCT_DELETED );
2026 // clean up junctions at the end
2027 }
2028 else if( sch_item->Type() == SCH_SHEET_PIN_T )
2029 {
2030 SCH_SHEET_PIN* pin = (SCH_SHEET_PIN*) sch_item;
2031 SCH_SHEET* sheet = pin->GetParent();
2032
2033 if( !alg::contains( items, sheet ) )
2034 {
2035 commit.Modify( sheet, m_frame->GetScreen() );
2036 sheet->RemovePin( pin );
2037 }
2038 }
2039 else if( sch_item->Type() == SCH_FIELD_T )
2040 {
2041 // Hide field
2042 commit.Modify( item, m_frame->GetScreen() );
2043 static_cast<SCH_FIELD*>( sch_item )->SetVisible( false );
2044 }
2045 else if( sch_item->Type() == SCH_TABLECELL_T )
2046 {
2047 // Clear contents of table cell
2048 commit.Modify( item, m_frame->GetScreen() );
2049 static_cast<SCH_TABLECELL*>( sch_item )->SetText( wxEmptyString );
2050 }
2051 else if( sch_item->Type() == SCH_RULE_AREA_T )
2052 {
2053 sch_item->SetFlags( STRUCT_DELETED );
2054 commit.Remove( item, m_frame->GetScreen() );
2055 }
2056 else if( sch_item->Type() == SCH_GROUP_T )
2057 {
2058 // Groups need to delete their children
2059 sch_item->RunOnChildren(
2060 [&]( SCH_ITEM* aChild )
2061 {
2062 aChild->SetFlags( STRUCT_DELETED );
2063 commit.Remove( aChild, m_frame->GetScreen() );
2064 },
2066
2067 sch_item->SetFlags( STRUCT_DELETED );
2068 commit.Remove( sch_item, m_frame->GetScreen() );
2069 }
2070 else
2071 {
2072 sch_item->SetFlags( STRUCT_DELETED );
2073 commit.Remove( item, m_frame->GetScreen() );
2074 updateHierarchy |= ( sch_item->Type() == SCH_SHEET_T );
2075 }
2076 }
2077
2078 for( const VECTOR2I& point : pts )
2079 {
2080 SCH_ITEM* junction = screen->GetItem( point, 0, SCH_JUNCTION_T );
2081
2082 if( !junction )
2083 continue;
2084
2085 if( junction->HasFlag( STRUCT_DELETED ) || !screen->IsExplicitJunction( point ) )
2086 m_frame->DeleteJunction( &commit, junction );
2087 }
2088
2089 commit.Push( _( "Delete" ) );
2090
2091 if( updateHierarchy )
2092 m_frame->UpdateHierarchyNavigator();
2093
2094 return 0;
2095}
2096
2097
2099{
2100 KICAD_T parentType = aField->GetParent() ? aField->GetParent()->Type() : SCHEMATIC_T;
2101 SCH_COMMIT commit( m_toolMgr );
2102
2103 // Save old symbol in undo list if not already in edit, or moving.
2104 if( aField->GetEditFlags() == 0 ) // i.e. not edited, or moved
2105 commit.Modify( aField, m_frame->GetScreen() );
2106
2107 if( parentType == SCH_SYMBOL_T && aField->GetId() == FIELD_T::REFERENCE )
2108 static_cast<SCH_ITEM*>( aField->GetParent() )->SetConnectivityDirty();
2109
2110 wxString caption;
2111
2112 // Use title caps for mandatory fields. "Edit Sheet name Field" looks dorky.
2113 if( aField->IsMandatory() )
2114 {
2115 wxString fieldName = GetDefaultFieldName( aField->GetId(), DO_TRANSLATE );
2116 caption.Printf( _( "Edit %s Field" ), TitleCaps( fieldName ) );
2117 }
2118 else
2119 {
2120 caption.Printf( _( "Edit '%s' Field" ), aField->GetName() );
2121 }
2122
2123 DIALOG_FIELD_PROPERTIES dlg( m_frame, caption, aField );
2124
2125 // The footprint field dialog can invoke a KIWAY_PLAYER so we must use a quasi-modal
2126 if( dlg.ShowQuasiModal() != wxID_OK )
2127 return;
2128
2129 dlg.UpdateField( &commit, aField, &m_frame->GetCurrentSheet() );
2130
2131 if( m_frame->eeconfig()->m_AutoplaceFields.enable || parentType == SCH_SHEET_T )
2132 {
2133 SCH_ITEM* parent = static_cast<SCH_ITEM*>( aField->GetParent() );
2134 AUTOPLACE_ALGO fieldsAutoplaced = parent->GetFieldsAutoplaced();
2135
2136 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
2137 parent->AutoplaceFields( m_frame->GetScreen(), fieldsAutoplaced );
2138 }
2139
2140 if( !commit.Empty() )
2141 commit.Push( caption );
2142}
2143
2144
2146{
2147 SCH_SELECTION sel = m_selectionTool->RequestSelection( { SCH_FIELD_T, SCH_SYMBOL_T, SCH_PIN_T } );
2148
2149 if( sel.Size() != 1 )
2150 return 0;
2151
2152 bool clearSelection = sel.IsHover();
2153 EDA_ITEM* item = sel.Front();
2154
2155 if( item->Type() == SCH_FIELD_T )
2156 {
2157 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
2158
2159 if( ( aEvent.IsAction( &SCH_ACTIONS::editReference ) && field->GetId() != FIELD_T::REFERENCE )
2160 || ( aEvent.IsAction( &SCH_ACTIONS::editValue ) && field->GetId() != FIELD_T::VALUE )
2161 || ( aEvent.IsAction( &SCH_ACTIONS::editFootprint ) && field->GetId() != FIELD_T::FOOTPRINT ) )
2162 {
2163 item = field->GetParentSymbol();
2164
2165 m_selectionTool->ClearSelection( true );
2166
2167 // If the field to edit is not a symbol field, we cannot edit the ref, value or footprint
2168 if( item == nullptr )
2169 return 0;
2170
2171 m_selectionTool->AddItemToSel( item );
2172 }
2173 }
2174
2175 if( item->Type() == SCH_SYMBOL_T )
2176 {
2177 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2178
2179 if( aEvent.IsAction( &SCH_ACTIONS::editReference ) )
2180 {
2182 }
2183 else if( aEvent.IsAction( &SCH_ACTIONS::editValue ) )
2184 {
2186 }
2187 else if( aEvent.IsAction( &SCH_ACTIONS::editFootprint ) )
2188 {
2189 if( !symbol->IsPower() )
2191 }
2192 }
2193 else if( item->Type() == SCH_FIELD_T )
2194 {
2195 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
2196
2197 editFieldText( field );
2198
2199 if( !field->IsVisible() )
2200 clearSelection = true;
2201 }
2202 else if( item->Type() == SCH_PIN_T )
2203 {
2204 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item->GetParent() );
2205
2206 if( symbol )
2207 {
2208 if( aEvent.IsAction( &SCH_ACTIONS::editReference ) )
2209 {
2211 }
2212 else if( aEvent.IsAction( &SCH_ACTIONS::editValue ) )
2213 {
2215 }
2216 else if( aEvent.IsAction( &SCH_ACTIONS::editFootprint ) )
2217 {
2218 if( !symbol->IsPower() )
2220 }
2221 }
2222 }
2223
2224 if( clearSelection )
2225 m_toolMgr->RunAction( ACTIONS::selectionClear );
2226
2227 return 0;
2228}
2229
2230
2232{
2233 SCH_SELECTION& selection = m_selectionTool->RequestSelection( RotatableItems );
2234 SCH_COMMIT commit( m_toolMgr );
2235 SCH_ITEM* head = static_cast<SCH_ITEM*>( selection.Front() );
2236 bool moving = head && head->IsMoving();
2237
2238 if( selection.Empty() )
2239 return 0;
2240
2241 std::vector<SCH_ITEM*> autoplaceItems;
2242
2243 for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
2244 {
2245 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
2246
2247 if( item->IsType( SCH_COLLECTOR::FieldOwners ) )
2248 autoplaceItems.push_back( item );
2249 else if( item->GetParent() && item->GetParent()->IsType( SCH_COLLECTOR::FieldOwners ) )
2250 autoplaceItems.push_back( static_cast<SCH_ITEM*>( item->GetParent() ) );
2251 }
2252
2253 for( SCH_ITEM* sch_item : autoplaceItems )
2254 {
2255 if( !moving && !sch_item->IsNew() )
2256 commit.Modify( sch_item, m_frame->GetScreen() );
2257
2258 sch_item->AutoplaceFields( m_frame->GetScreen(), AUTOPLACE_MANUAL );
2259
2260 updateItem( sch_item, true );
2261 }
2262
2263 if( moving )
2264 {
2265 m_toolMgr->PostAction( ACTIONS::refreshPreview );
2266 }
2267 else
2268 {
2269 if( !commit.Empty() )
2270 commit.Push( _( "Autoplace Fields" ) );
2271
2272 if( selection.IsHover() )
2273 m_toolMgr->RunAction( ACTIONS::selectionClear );
2274 }
2275
2276 return 0;
2277}
2278
2279
2281{
2282 SCH_SYMBOL* selectedSymbol = nullptr;
2283 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_SYMBOL_T } );
2284
2285 if( !selection.Empty() )
2286 selectedSymbol = dynamic_cast<SCH_SYMBOL*>( selection.Front() );
2287
2289
2292
2293 DIALOG_CHANGE_SYMBOLS dlg( m_frame, selectedSymbol, mode );
2294
2295 // QuasiModal required to invoke symbol browser
2296 dlg.ShowQuasiModal();
2297
2298 if( selection.IsHover() )
2299 m_toolMgr->RunAction( ACTIONS::selectionClear );
2300
2301 return 0;
2302}
2303
2304
2306{
2307 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_SYMBOL_T } );
2308
2309 if( selection.Empty() )
2310 return 0;
2311
2312 SCH_SYMBOL* symbol = (SCH_SYMBOL*) selection.Front();
2313 SCH_COMMIT commit( m_toolMgr );
2314
2315 if( !symbol->IsNew() )
2316 commit.Modify( symbol, m_frame->GetScreen() );
2317
2318 int nextBodyStyle = symbol->GetBodyStyle() + 1;
2319
2320 if( nextBodyStyle > symbol->GetBodyStyleCount() )
2321 nextBodyStyle = 1;
2322
2323 m_frame->SelectBodyStyle( symbol, nextBodyStyle );
2324
2325 if( symbol->IsNew() )
2326 m_toolMgr->PostAction( ACTIONS::refreshPreview );
2327
2328 if( !commit.Empty() )
2329 commit.Push( _( "Change Body Style" ) );
2330
2331 if( selection.IsHover() )
2332 m_toolMgr->RunAction( ACTIONS::selectionClear );
2333
2334 return 0;
2335}
2336
2337
2339{
2340 SCH_SELECTION& selection = m_selectionTool->RequestSelection();
2341 bool clearSelection = selection.IsHover();
2342
2343 if( selection.Empty() )
2344 {
2345 if( getView()->IsLayerVisible( LAYER_SCHEMATIC_DRAWINGSHEET ) )
2346 {
2347 DS_PROXY_VIEW_ITEM* ds = m_frame->GetCanvas()->GetView()->GetDrawingSheet();
2348 VECTOR2D cursorPos = getViewControls()->GetCursorPosition( false );
2349
2350 if( ds && ds->HitTestDrawingSheetItems( getView(), cursorPos ) )
2351 m_toolMgr->PostAction( ACTIONS::pageSettings );
2352 }
2353
2354 return 0;
2355 }
2356
2357 EDA_ITEM* curr_item = selection.Front();
2358
2359 // If a single pin is selected, promote to its parent symbol
2360 if( ( selection.GetSize() == 1 ) && ( curr_item->Type() == SCH_PIN_T ) )
2361 {
2362 EDA_ITEM* parent = curr_item->GetParent();
2363
2364 if( parent->Type() == SCH_SYMBOL_T )
2365 curr_item = parent;
2366 }
2367
2368 switch( curr_item->Type() )
2369 {
2370 case SCH_LINE_T:
2372 case SCH_JUNCTION_T:
2374 {
2375 std::deque<SCH_LINE*> lines;
2376
2377 for( EDA_ITEM* selItem : selection.Items() )
2378 lines.push_back( static_cast<SCH_LINE*>( selItem ) );
2379
2380 DIALOG_LINE_PROPERTIES dlg( m_frame, lines );
2381
2382 dlg.ShowModal();
2383 }
2384 else if( SELECTION_CONDITIONS::OnlyTypes( { SCH_JUNCTION_T } )( selection ) )
2385 {
2386 std::deque<SCH_JUNCTION*> junctions;
2387
2388 for( EDA_ITEM* selItem : selection.Items() )
2389 junctions.push_back( static_cast<SCH_JUNCTION*>( selItem ) );
2390
2391 DIALOG_JUNCTION_PROPS dlg( m_frame, junctions );
2392
2393 dlg.ShowModal();
2394 }
2396 SCH_JUNCTION_T } )( selection ) )
2397 {
2398 std::deque<SCH_ITEM*> items;
2399
2400 for( EDA_ITEM* selItem : selection.Items() )
2401 items.push_back( static_cast<SCH_ITEM*>( selItem ) );
2402
2403 DIALOG_WIRE_BUS_PROPERTIES dlg( m_frame, items );
2404
2405 dlg.ShowModal();
2406 }
2407 else
2408 {
2409 return 0;
2410 }
2411
2412 break;
2413
2414 case SCH_MARKER_T:
2415 if( SELECTION_CONDITIONS::OnlyTypes( { SCH_MARKER_T } )( selection ) )
2416 {
2417 SCH_INSPECTION_TOOL* inspectionTool = m_toolMgr->GetTool<SCH_INSPECTION_TOOL>();
2418
2419 if( inspectionTool )
2420 inspectionTool->CrossProbe( static_cast<SCH_MARKER*>( selection.Front() ) );
2421 }
2422 break;
2423
2424 case SCH_TABLECELL_T:
2425 if( SELECTION_CONDITIONS::OnlyTypes( { SCH_TABLECELL_T } )( selection ) )
2426 {
2427 std::vector<SCH_TABLECELL*> cells;
2428
2429 for( EDA_ITEM* item : selection.Items() )
2430 cells.push_back( static_cast<SCH_TABLECELL*>( item ) );
2431
2433
2434 // QuasiModal required for syntax help and Scintilla auto-complete
2435 dlg.ShowQuasiModal();
2436
2438 {
2439 SCH_TABLE* table = static_cast<SCH_TABLE*>( cells[0]->GetParent() );
2441
2442 tableDlg.ShowModal();
2443 }
2444 }
2445
2446 break;
2447
2448 default:
2449 if( selection.Size() > 1 )
2450 return 0;
2451
2452 EditProperties( curr_item );
2453 }
2454
2455 if( clearSelection )
2456 m_toolMgr->RunAction( ACTIONS::selectionClear );
2457
2458 return 0;
2459}
2460
2461
2463{
2464 switch( aItem->Type() )
2465 {
2466 case SCH_SYMBOL_T:
2467 {
2468 int retval;
2469 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( aItem );
2470
2471 // This needs to be scoped so the dialog destructor removes blocking status
2472 // before we launch the next dialog.
2473 {
2474 DIALOG_SYMBOL_PROPERTIES symbolPropsDialog( m_frame, symbol );
2475
2476 // This dialog itself subsequently can invoke a KIWAY_PLAYER as a quasimodal
2477 // frame. Therefore this dialog as a modal frame parent, MUST be run under
2478 // quasimodal mode for the quasimodal frame support to work. So don't use
2479 // the QUASIMODAL macros here.
2480 retval = symbolPropsDialog.ShowQuasiModal();
2481 }
2482
2483 if( retval == SYMBOL_PROPS_EDIT_OK )
2484 {
2485 if( m_frame->eeconfig()->m_AutoplaceFields.enable )
2486 {
2487 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
2488
2489 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
2490 symbol->AutoplaceFields( m_frame->GetScreen(), fieldsAutoplaced );
2491 }
2492
2493 m_frame->OnModify();
2494 }
2495 else if( retval == SYMBOL_PROPS_EDIT_SCHEMATIC_SYMBOL )
2496 {
2497 if( KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR, true ) )
2498 {
2499 SYMBOL_EDIT_FRAME* editor = static_cast<SYMBOL_EDIT_FRAME*>( frame );
2500
2501 if( wxWindow* blocking_win = editor->Kiway().GetBlockingDialog() )
2502 blocking_win->Close( true );
2503
2504 // The broken library symbol link indicator cannot be edited.
2505 if( symbol->IsMissingLibSymbol() )
2506 return;
2507
2508 editor->LoadSymbolFromSchematic( symbol );
2509 editor->Show( true );
2510 editor->Raise();
2511 }
2512 }
2513 else if( retval == SYMBOL_PROPS_EDIT_LIBRARY_SYMBOL )
2514 {
2515 if( KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR, true ) )
2516 {
2517 SYMBOL_EDIT_FRAME* editor = static_cast<SYMBOL_EDIT_FRAME*>( frame );
2518
2519 if( wxWindow* blocking_win = editor->Kiway().GetBlockingDialog() )
2520 blocking_win->Close( true );
2521
2522 editor->LoadSymbol( symbol->GetLibId(), symbol->GetUnit(), symbol->GetBodyStyle() );
2523 editor->Show( true );
2524 editor->Raise();
2525 }
2526 }
2527 else if( retval == SYMBOL_PROPS_WANT_UPDATE_SYMBOL )
2528 {
2530 dlg.ShowQuasiModal();
2531 }
2532 else if( retval == SYMBOL_PROPS_WANT_EXCHANGE_SYMBOL )
2533 {
2535 dlg.ShowQuasiModal();
2536 }
2537
2538 break;
2539 }
2540
2541 case SCH_SHEET_T:
2542 {
2543 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
2544 bool isUndoable = false;
2545 bool doClearAnnotation = false;
2546 bool okPressed = false;
2547 bool updateHierarchyNavigator = false;
2548
2549 // Keep track of existing sheet paths. EditSheet() can modify this list.
2550 // Note that we use the validity checking/repairing version here just to make sure
2551 // we've got a valid hierarchy to begin with.
2552 SCH_SHEET_LIST originalHierarchy;
2553 originalHierarchy.BuildSheetList( &m_frame->Schematic().Root(), true );
2554
2555 SCH_COMMIT commit( m_toolMgr );
2556 commit.Modify( sheet, m_frame->GetScreen() );
2557 okPressed = m_frame->EditSheetProperties( sheet, &m_frame->GetCurrentSheet(), &isUndoable, &doClearAnnotation,
2558 &updateHierarchyNavigator );
2559
2560 if( okPressed )
2561 {
2562 if( isUndoable )
2563 {
2564 commit.Push( _( "Edit Sheet Properties" ) );
2565 }
2566 else
2567 {
2568 std::vector<SCH_ITEM*> items;
2569
2570 items.emplace_back( sheet );
2571 m_frame->Schematic().OnItemsRemoved( items );
2572 m_frame->Schematic().OnItemsAdded( items );
2573 m_frame->OnModify();
2574 m_frame->Schematic().RefreshHierarchy();
2575 m_frame->UpdateHierarchyNavigator();
2576 }
2577 }
2578 else
2579 {
2580 // If we are renaming files, the undo/redo list becomes invalid and must be cleared.
2581 m_frame->ClearUndoRedoList();
2582 m_frame->OnModify();
2583 }
2584
2585 // If the sheet file is changed and new sheet contents are loaded then we have to
2586 // clear the annotations on the new content (as it may have been set from some other
2587 // sheet path reference)
2588 if( doClearAnnotation )
2589 {
2590 SCH_SCREENS screensList( &m_frame->Schematic().Root() );
2591
2592 // We clear annotation of new sheet paths here:
2593 screensList.ClearAnnotationOfNewSheetPaths( originalHierarchy );
2594
2595 // Clear annotation of g_CurrentSheet itself, because its sheetpath is not a new
2596 // path, but symbols managed by its sheet path must have their annotation cleared
2597 // because they are new:
2598 sheet->GetScreen()->ClearAnnotation( &m_frame->GetCurrentSheet(), false );
2599 }
2600
2601 if( okPressed )
2602 m_frame->GetCanvas()->Refresh();
2603
2604 if( updateHierarchyNavigator )
2605 m_frame->UpdateHierarchyNavigator();
2606
2607 break;
2608 }
2609
2610 case SCH_SHEET_PIN_T:
2611 {
2612 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( aItem );
2614
2615 // QuasiModal required for help dialog
2616 dlg.ShowQuasiModal();
2617 break;
2618 }
2619
2620 case SCH_TEXT_T:
2621 case SCH_TEXTBOX_T:
2622 {
2623 DIALOG_TEXT_PROPERTIES dlg( m_frame, static_cast<SCH_ITEM*>( aItem ) );
2624
2625 // QuasiModal required for syntax help and Scintilla auto-complete
2626 dlg.ShowQuasiModal();
2627 break;
2628 }
2629
2630 case SCH_TABLE_T:
2631 {
2632 DIALOG_TABLE_PROPERTIES dlg( m_frame, static_cast<SCH_TABLE*>( aItem ) );
2633
2634 // QuasiModal required for Scintilla auto-complete
2635 dlg.ShowQuasiModal();
2636 break;
2637 }
2638
2639 case SCH_LABEL_T:
2640 case SCH_GLOBAL_LABEL_T:
2641 case SCH_HIER_LABEL_T:
2643 {
2644 DIALOG_LABEL_PROPERTIES dlg( m_frame, static_cast<SCH_LABEL_BASE*>( aItem ), false );
2645
2646 // QuasiModal for syntax help and Scintilla auto-complete
2647 dlg.ShowQuasiModal();
2648 break;
2649 }
2650
2651 case SCH_FIELD_T:
2652 {
2653 SCH_FIELD* field = static_cast<SCH_FIELD*>( aItem );
2654
2655 editFieldText( field );
2656
2657 if( !field->IsVisible() )
2658 m_toolMgr->RunAction( ACTIONS::selectionClear );
2659
2660 break;
2661 }
2662
2663 case SCH_SHAPE_T:
2664 {
2665 DIALOG_SHAPE_PROPERTIES dlg( m_frame, static_cast<SCH_SHAPE*>( aItem ) );
2666
2667 dlg.ShowModal();
2668 break;
2669 }
2670
2671 case SCH_BITMAP_T:
2672 {
2673 SCH_BITMAP& bitmap = static_cast<SCH_BITMAP&>( *aItem );
2674 DIALOG_IMAGE_PROPERTIES dlg( m_frame, bitmap );
2675
2676 if( dlg.ShowModal() == wxID_OK )
2677 {
2678 // The bitmap is cached in Opengl: clear the cache in case it has become invalid
2680 }
2681
2682 break;
2683 }
2684
2685 case SCH_RULE_AREA_T:
2686 {
2687 DIALOG_SHAPE_PROPERTIES dlg( m_frame, static_cast<SCH_SHAPE*>( aItem ) );
2688 dlg.SetTitle( _( "Rule Area Properties" ) );
2689
2690 dlg.ShowModal();
2691 break;
2692 }
2693
2694 case SCH_NO_CONNECT_T:
2695 case SCH_PIN_T: break;
2696
2697 case SCH_GROUP_T:
2698 m_toolMgr->RunAction( ACTIONS::groupProperties, static_cast<EDA_GROUP*>( static_cast<SCH_GROUP*>( aItem ) ) );
2699
2700 break;
2701
2702 default: // Unexpected item
2703 wxFAIL_MSG( wxString( "Cannot edit schematic item type " ) + aItem->GetClass() );
2704 }
2705
2706 updateItem( aItem, true );
2707}
2708
2709
2711{
2712 KICAD_T convertTo = aEvent.Parameter<KICAD_T>();
2713 SCH_SELECTION selection =
2715 SCH_COMMIT localCommit( m_toolMgr );
2716 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
2717
2718 if( !commit )
2719 commit = &localCommit;
2720
2721 for( unsigned int i = 0; i < selection.GetSize(); ++i )
2722 {
2723 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( selection.GetItem( i ) );
2724
2725 if( item && item->Type() != convertTo )
2726 {
2727 EDA_TEXT* sourceText = dynamic_cast<EDA_TEXT*>( item );
2728 bool selected = item->IsSelected();
2729 SCH_ITEM* newtext = nullptr;
2730 VECTOR2I position = item->GetPosition();
2731 wxString txt;
2732 wxString href;
2735
2736 wxCHECK2( sourceText, continue );
2737
2738 switch( item->Type() )
2739 {
2740 case SCH_LABEL_T:
2741 case SCH_GLOBAL_LABEL_T:
2742 case SCH_HIER_LABEL_T:
2743 {
2744 SCH_LABEL_BASE* label = static_cast<SCH_LABEL_BASE*>( item );
2745
2746 txt = UnescapeString( label->GetText() );
2747 spinStyle = label->GetSpinStyle();
2748 shape = label->GetShape();
2749 href = label->GetHyperlink();
2750 break;
2751 }
2752
2754 {
2755 SCH_DIRECTIVE_LABEL* dirlabel = static_cast<SCH_DIRECTIVE_LABEL*>( item );
2756
2757 // a SCH_DIRECTIVE_LABEL has no text
2758 txt = _( "<empty>" );
2759
2760 spinStyle = dirlabel->GetSpinStyle();
2761 href = dirlabel->GetHyperlink();
2762 break;
2763 }
2764
2765 case SCH_TEXT_T:
2766 {
2767 SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
2768
2769 txt = text->GetText();
2770 href = text->GetHyperlink();
2771 break;
2772 }
2773
2774 case SCH_TEXTBOX_T:
2775 {
2776 SCH_TEXTBOX* textbox = static_cast<SCH_TEXTBOX*>( item );
2777 BOX2I bbox = textbox->GetBoundingBox();
2778
2779 bbox.SetOrigin( bbox.GetLeft() + textbox->GetMarginLeft(), bbox.GetTop() + textbox->GetMarginTop() );
2780 bbox.SetEnd( bbox.GetRight() - textbox->GetMarginRight(),
2781 bbox.GetBottom() - textbox->GetMarginBottom() );
2782
2783 if( convertTo == SCH_LABEL_T || convertTo == SCH_HIER_LABEL_T || convertTo == SCH_GLOBAL_LABEL_T )
2784 {
2785 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
2786 wxCHECK( text, 0 );
2787 int textSize = text->GetTextSize().y;
2788 bbox.Inflate( KiROUND( item->Schematic()->Settings().m_LabelSizeRatio * textSize ) );
2789 }
2790
2791 txt = textbox->GetText();
2792
2793 if( textbox->GetTextAngle().IsVertical() )
2794 {
2795 if( textbox->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
2796 {
2797 spinStyle = SPIN_STYLE::SPIN::BOTTOM;
2798 position = VECTOR2I( bbox.Centre().x, bbox.GetOrigin().y );
2799 }
2800 else
2801 {
2802 spinStyle = SPIN_STYLE::SPIN::UP;
2803 position = VECTOR2I( bbox.Centre().x, bbox.GetEnd().y );
2804 }
2805 }
2806 else
2807 {
2808 if( textbox->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
2809 {
2810 spinStyle = SPIN_STYLE::SPIN::LEFT;
2811 position = VECTOR2I( bbox.GetEnd().x, bbox.Centre().y );
2812 }
2813 else
2814 {
2815 spinStyle = SPIN_STYLE::SPIN::RIGHT;
2816 position = VECTOR2I( bbox.GetOrigin().x, bbox.Centre().y );
2817 }
2818 }
2819
2820 position = m_frame->GetNearestGridPosition( position );
2821 href = textbox->GetHyperlink();
2822 break;
2823 }
2824
2825 default: UNIMPLEMENTED_FOR( item->GetClass() ); break;
2826 }
2827
2828 auto getValidNetname = []( const wxString& aText )
2829 {
2830 wxString local_txt = aText;
2831 local_txt.Replace( "\n", "_" );
2832 local_txt.Replace( "\r", "_" );
2833 local_txt.Replace( "\t", "_" );
2834
2835 // Bus groups can have spaces; bus vectors and signal names cannot
2836 if( !NET_SETTINGS::ParseBusGroup( aText, nullptr, nullptr ) )
2837 local_txt.Replace( " ", "_" );
2838
2839 // label strings are "escaped" i.e. a '/' is replaced by "{slash}"
2840 local_txt = EscapeString( local_txt, CTX_NETNAME );
2841
2842 if( local_txt.IsEmpty() )
2843 return _( "<empty>" );
2844 else
2845 return local_txt;
2846 };
2847
2848 switch( convertTo )
2849 {
2850 case SCH_LABEL_T:
2851 {
2852 SCH_LABEL_BASE* new_label = new SCH_LABEL( position, getValidNetname( txt ) );
2853
2854 new_label->SetShape( shape );
2855 new_label->SetAttributes( *sourceText, false );
2856 new_label->SetSpinStyle( spinStyle );
2857 new_label->SetHyperlink( href );
2858
2859 if( item->Type() == SCH_GLOBAL_LABEL_T || item->Type() == SCH_HIER_LABEL_T )
2860 {
2861 if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::UP )
2862 new_label->MirrorVertically( position.y );
2863 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::BOTTOM )
2864 new_label->MirrorVertically( position.y );
2865 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::LEFT )
2866 new_label->MirrorHorizontally( position.x );
2867 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::RIGHT )
2868 new_label->MirrorHorizontally( position.x );
2869 }
2870
2871 newtext = new_label;
2872 break;
2873 }
2874
2875 case SCH_GLOBAL_LABEL_T:
2876 {
2877 SCH_LABEL_BASE* new_label = new SCH_GLOBALLABEL( position, getValidNetname( txt ) );
2878
2879 new_label->SetShape( shape );
2880 new_label->SetAttributes( *sourceText, false );
2881 new_label->SetSpinStyle( spinStyle );
2882 new_label->SetHyperlink( href );
2883
2884 if( item->Type() == SCH_LABEL_T )
2885 {
2886 if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::UP )
2887 new_label->MirrorVertically( position.y );
2888 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::BOTTOM )
2889 new_label->MirrorVertically( position.y );
2890 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::LEFT )
2891 new_label->MirrorHorizontally( position.x );
2892 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::RIGHT )
2893 new_label->MirrorHorizontally( position.x );
2894 }
2895
2896 newtext = new_label;
2897 break;
2898 }
2899
2900 case SCH_HIER_LABEL_T:
2901 {
2902 SCH_LABEL_BASE* new_label = new SCH_HIERLABEL( position, getValidNetname( txt ) );
2903
2904 new_label->SetShape( shape );
2905 new_label->SetAttributes( *sourceText, false );
2906 new_label->SetSpinStyle( spinStyle );
2907 new_label->SetHyperlink( href );
2908
2909 if( item->Type() == SCH_LABEL_T )
2910 {
2911 if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::UP )
2912 new_label->MirrorVertically( position.y );
2913 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::BOTTOM )
2914 new_label->MirrorVertically( position.y );
2915 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::LEFT )
2916 new_label->MirrorHorizontally( position.x );
2917 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::RIGHT )
2918 new_label->MirrorHorizontally( position.x );
2919 }
2920
2921 newtext = new_label;
2922 break;
2923 }
2924
2926 {
2927 SCH_LABEL_BASE* new_label = new SCH_DIRECTIVE_LABEL( position );
2928
2929 // A SCH_DIRECTIVE_LABEL usually has at least one field containing the net class
2930 // name. If we're copying from a text object assume the text is the netclass
2931 // name. Otherwise, we'll just copy the fields which will either have a netclass
2932 // or not.
2933 if( !dynamic_cast<SCH_LABEL_BASE*>( item ) )
2934 {
2935 SCH_FIELD netclass( new_label, FIELD_T::USER, wxT( "Netclass" ) );
2936 netclass.SetText( txt );
2937 netclass.SetTextPos( position );
2938 new_label->GetFields().push_back( netclass );
2939 }
2940
2941 new_label->SetShape( LABEL_FLAG_SHAPE::F_ROUND );
2942 new_label->SetAttributes( *sourceText, false );
2943 new_label->SetSpinStyle( spinStyle );
2944 new_label->SetHyperlink( href );
2945 newtext = new_label;
2946 break;
2947 }
2948
2949 case SCH_TEXT_T:
2950 {
2951 SCH_TEXT* new_text = new SCH_TEXT( position, txt );
2952
2953 new_text->SetAttributes( *sourceText, false );
2954 new_text->SetHyperlink( href );
2955 newtext = new_text;
2956 break;
2957 }
2958
2959 case SCH_TEXTBOX_T:
2960 {
2961 SCH_TEXTBOX* new_textbox = new SCH_TEXTBOX( LAYER_NOTES, 0, FILL_T::NO_FILL, txt );
2962 BOX2I bbox = item->GetBoundingBox();
2963
2964 if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( item ) )
2965 bbox.Inflate( -label->GetLabelBoxExpansion() );
2966
2967 new_textbox->SetAttributes( *sourceText, false );
2968
2969 bbox.SetOrigin( bbox.GetLeft() - new_textbox->GetMarginLeft(),
2970 bbox.GetTop() - new_textbox->GetMarginTop() );
2971 bbox.SetEnd( bbox.GetRight() + new_textbox->GetMarginRight(),
2972 bbox.GetBottom() + new_textbox->GetMarginBottom() );
2973
2974 VECTOR2I topLeft = bbox.GetPosition();
2975 VECTOR2I botRight = bbox.GetEnd();
2976
2977 // Add 1/20 of the margin at the end to reduce line-breaking changes.
2978 int slop = new_textbox->GetLegacyTextMargin() / 20;
2979
2980 if( sourceText->GetTextAngle() == ANGLE_VERTICAL )
2981 {
2982 if( sourceText->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
2983 botRight.y += slop;
2984 else
2985 topLeft.y -= slop;
2986 }
2987 else
2988 {
2989 if( sourceText->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
2990 topLeft.x -= slop;
2991 else
2992 botRight.x += slop;
2993 }
2994
2995 new_textbox->SetPosition( topLeft );
2996 new_textbox->SetEnd( botRight );
2997
2998 new_textbox->SetHyperlink( href );
2999 newtext = new_textbox;
3000 break;
3001 }
3002
3003 default: UNIMPLEMENTED_FOR( wxString::Format( "%d.", convertTo ) ); break;
3004 }
3005
3006 wxCHECK2( newtext, continue );
3007
3008 // Copy the old text item settings to the new one. Justifications are not copied
3009 // because they are not used in labels. Justifications will be set to default value
3010 // in the new text item type.
3011 //
3012 newtext->SetFlags( item->GetEditFlags() );
3013
3014 EDA_TEXT* eda_text = dynamic_cast<EDA_TEXT*>( item );
3015 EDA_TEXT* new_eda_text = dynamic_cast<EDA_TEXT*>( newtext );
3016
3017 wxCHECK2( eda_text && new_eda_text, continue );
3018
3019 new_eda_text->SetFont( eda_text->GetFont() );
3020 new_eda_text->SetTextSize( eda_text->GetTextSize() );
3021 new_eda_text->SetTextThickness( eda_text->GetTextThickness() );
3022
3023 // Must be after SetTextSize()
3024 new_eda_text->SetBold( eda_text->IsBold() );
3025 new_eda_text->SetItalic( eda_text->IsItalic() );
3026
3027 newtext->AutoplaceFields( m_frame->GetScreen(), AUTOPLACE_AUTO );
3028
3029 SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( item );
3030 SCH_LABEL_BASE* new_label = dynamic_cast<SCH_LABEL_BASE*>( newtext );
3031
3032 if( label && new_label )
3033 {
3034 new_label->AddFields( label->GetFields() );
3035
3036 // A SCH_GLOBALLABEL has a specific field for intersheet references that has
3037 // no meaning for other labels
3038 std::erase_if( new_label->GetFields(),
3039 [&]( SCH_FIELD& field )
3040 {
3041 return field.GetId() == FIELD_T::INTERSHEET_REFS
3042 && new_label->Type() != SCH_GLOBAL_LABEL_T;
3043 } );
3044 }
3045
3046 if( selected )
3047 m_toolMgr->RunAction<EDA_ITEM*>( ACTIONS::unselectItem, item );
3048
3049 m_frame->RemoveFromScreen( item, m_frame->GetScreen() );
3050
3051 if( commit->GetStatus( item, m_frame->GetScreen() ) == CHT_ADD )
3052 commit->Unstage( item, m_frame->GetScreen() );
3053 else
3054 commit->Removed( item, m_frame->GetScreen() );
3055
3056 m_frame->AddToScreen( newtext, m_frame->GetScreen() );
3057 commit->Added( newtext, m_frame->GetScreen() );
3058
3059 if( selected )
3060 m_toolMgr->RunAction<EDA_ITEM*>( ACTIONS::selectItem, newtext );
3061 }
3062 }
3063
3064 if( !localCommit.Empty() )
3065 localCommit.Push( _( "Change To" ) );
3066
3067 if( selection.IsHover() )
3068 m_toolMgr->RunAction( ACTIONS::selectionClear );
3069
3070 return 0;
3071}
3072
3073
3075{
3076 static std::vector<KICAD_T> justifiableItems = { SCH_FIELD_T, SCH_TEXT_T, SCH_TEXTBOX_T, SCH_LABEL_T };
3077
3078 SCH_SELECTION& selection = m_selectionTool->RequestSelection( justifiableItems );
3079
3080 if( selection.GetSize() == 0 )
3081 return 0;
3082
3083 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
3084 bool moving = item->IsMoving();
3085 SCH_COMMIT localCommit( m_toolMgr );
3086 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
3087
3088 if( !commit )
3089 commit = &localCommit;
3090
3091 auto setJustify = [&]( EDA_TEXT* aTextItem )
3092 {
3093 if( aEvent.Matches( ACTIONS::leftJustify.MakeEvent() ) )
3094 aTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
3095 else if( aEvent.Matches( ACTIONS::centerJustify.MakeEvent() ) )
3096 aTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
3097 else
3098 aTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
3099 };
3100
3101 for( EDA_ITEM* edaItem : selection )
3102 {
3103 item = static_cast<SCH_ITEM*>( edaItem );
3104
3105 if( !moving )
3106 commit->Modify( item, m_frame->GetScreen() );
3107
3108 if( item->Type() == SCH_FIELD_T )
3109 {
3110 setJustify( static_cast<SCH_FIELD*>( item ) );
3111
3112 // Now that we're re-justifying a field, they're no longer autoplaced.
3113 static_cast<SCH_ITEM*>( item->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
3114 }
3115 else if( item->Type() == SCH_TEXT_T )
3116 {
3117 setJustify( static_cast<SCH_TEXT*>( item ) );
3118 }
3119 else if( item->Type() == SCH_TEXTBOX_T )
3120 {
3121 setJustify( static_cast<SCH_TEXTBOX*>( item ) );
3122 }
3123 else if( item->Type() == SCH_LABEL_T )
3124 {
3125 SCH_LABEL* label = static_cast<SCH_LABEL*>( item );
3126
3127 if( label->GetTextAngle() == ANGLE_HORIZONTAL )
3128 setJustify( label );
3129 }
3130
3131 m_frame->UpdateItem( item, false, true );
3132 }
3133
3134 // Update R-Tree for modified items
3135 for( EDA_ITEM* selected : selection )
3136 updateItem( selected, true );
3137
3138 if( item->IsMoving() )
3139 {
3140 m_toolMgr->RunAction( ACTIONS::refreshPreview );
3141 }
3142 else
3143 {
3144 SCH_SELECTION selectionCopy = selection;
3145
3146 if( selection.IsHover() )
3147 m_toolMgr->RunAction( ACTIONS::selectionClear );
3148
3149 if( !localCommit.Empty() )
3150 {
3151 if( aEvent.Matches( ACTIONS::leftJustify.MakeEvent() ) )
3152 localCommit.Push( _( "Left Justify" ) );
3153 else if( aEvent.Matches( ACTIONS::centerJustify.MakeEvent() ) )
3154 localCommit.Push( _( "Center Justify" ) );
3155 else
3156 localCommit.Push( _( "Right Justify" ) );
3157 }
3158 }
3159
3160 return 0;
3161}
3162
3163
3165{
3166 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_SHEET_T } );
3167 SCH_SHEET* sheet = (SCH_SHEET*) selection.Front();
3168 SCH_COMMIT commit( m_toolMgr );
3169
3170 if( !sheet || !sheet->HasUndefinedPins() )
3171 return 0;
3172
3173 if( !IsOK( m_frame, _( "Do you wish to delete the unreferenced pins from this sheet?" ) ) )
3174 return 0;
3175
3176 commit.Modify( sheet, m_frame->GetScreen() );
3177
3178 sheet->CleanupSheet();
3179
3180 updateItem( sheet, true );
3181
3182 commit.Push( _( "Cleanup Sheet Pins" ) );
3183
3184 if( selection.IsHover() )
3185 m_toolMgr->RunAction( ACTIONS::selectionClear );
3186
3187 return 0;
3188}
3189
3190
3192{
3193 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_SHEET_T } );
3194
3195 if( selection.GetSize() > 1 )
3196 return 0;
3197
3198 SCH_SHEET* sheet = (SCH_SHEET*) selection.Front();
3199
3200 SCH_SHEET_PATH instance = m_frame->GetCurrentSheet();
3201
3202 SCH_SCREEN* screen;
3203
3204 if( sheet )
3205 {
3206 // When changing the page number of a selected sheet, the current screen owns the sheet.
3207 screen = m_frame->GetScreen();
3208
3209 instance.push_back( sheet );
3210 }
3211 else
3212 {
3213 SCH_SHEET_PATH prevInstance = instance;
3214
3215 // When change the page number in the screen, the previous screen owns the sheet.
3216 if( prevInstance.size() )
3217 {
3218 prevInstance.pop_back();
3219 screen = prevInstance.LastScreen();
3220 }
3221 else
3222 {
3223 // The root sheet and root screen are effectively the same thing.
3224 screen = m_frame->GetScreen();
3225 }
3226
3227 sheet = m_frame->GetCurrentSheet().Last();
3228 }
3229
3230 wxString msg;
3231 wxString sheetPath = instance.PathHumanReadable( false );
3232 wxString pageNumber = instance.GetPageNumber();
3233
3234 msg.Printf( _( "Enter page number for sheet path%s" ),
3235 ( sheetPath.Length() > 20 ) ? "\n" + sheetPath : " " + sheetPath );
3236
3237 wxTextEntryDialog dlg( m_frame, msg, _( "Edit Sheet Page Number" ), pageNumber );
3238
3239 dlg.SetTextValidator( wxFILTER_ALPHANUMERIC ); // No white space.
3240
3241 if( dlg.ShowModal() == wxID_CANCEL || dlg.GetValue() == instance.GetPageNumber() )
3242 return 0;
3243
3244 SCH_COMMIT commit( m_frame );
3245
3246 commit.Modify( sheet, screen );
3247
3248 instance.SetPageNumber( dlg.GetValue() );
3249
3250 if( instance == m_frame->GetCurrentSheet() )
3251 {
3252 m_frame->GetScreen()->SetPageNumber( dlg.GetValue() );
3253 m_frame->OnPageSettingsChange();
3254 }
3255
3256 commit.Push( wxS( "Change Sheet Page Number" ) );
3257
3258 if( selection.IsHover() )
3259 m_toolMgr->RunAction( ACTIONS::selectionClear );
3260
3261 return 0;
3262}
3263
3264
3266{
3267 return m_toolMgr->RunAction( SCH_ACTIONS::importSheet, aEvent.Parameter<wxString*>() );
3268}
3269
3270
3272{
3273 wxString* filename = aEvent.Parameter<wxString*>();
3274
3275 if( !filename )
3276 return 0;
3277
3278 SCH_BITMAP* image = new SCH_BITMAP( VECTOR2I( 0, 0 ) );
3279
3280 if( !image->GetReferenceImage().ReadImageFile( *filename ) )
3281 {
3282 wxMessageBox( wxString::Format( _( "Could not load image from '%s'." ), *filename ) );
3283 delete image;
3284 return 0;
3285 }
3286
3287 return m_toolMgr->RunAction( SCH_ACTIONS::placeImage, image );
3288}
3289
3290
3292 std::set<std::pair<SCH_SYMBOL*, SCH_SCREEN*>>& aCollectedUnits )
3293{
3294 for( EDA_ITEM* item : aSelection )
3295 {
3296 if( item->Type() == SCH_SYMBOL_T )
3297 {
3298 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
3299
3300 aCollectedUnits.insert( { symbol, m_frame->GetScreen() } );
3301
3302 // The attributes should be kept in sync in multi-unit parts.
3303 // Of course the symbol must be annotated to collect other units.
3304 if( symbol->IsAnnotated( &m_frame->GetCurrentSheet() ) )
3305 {
3306 wxString ref = symbol->GetRef( &m_frame->GetCurrentSheet() );
3307 int unit = symbol->GetUnit();
3308 LIB_ID libId = symbol->GetLibId();
3309
3310 for( SCH_SHEET_PATH& sheet : m_frame->Schematic().Hierarchy() )
3311 {
3312 SCH_SCREEN* screen = sheet.LastScreen();
3313 std::vector<SCH_SYMBOL*> otherUnits;
3314
3315 CollectOtherUnits( ref, unit, libId, sheet, &otherUnits );
3316
3317 for( SCH_SYMBOL* otherUnit : otherUnits )
3318 aCollectedUnits.insert( { otherUnit, screen } );
3319 }
3320 }
3321 }
3322 }
3323}
3324
3325
3327{
3328 SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_SYMBOL_T } );
3329 SCH_COMMIT commit( m_toolMgr );
3330 SCH_SHEET_PATH* sheet = &m_frame->GetCurrentSheet();
3331 wxString variant = m_frame->Schematic().GetCurrentVariant();
3332
3333 std::set<std::pair<SCH_SYMBOL*, SCH_SCREEN*>> collectedUnits;
3334
3335 collectUnits( selection, collectedUnits );
3336 bool new_state = false;
3337
3338 for( const auto& [symbol, _] : collectedUnits )
3339 {
3340 if( ( aEvent.IsAction( &SCH_ACTIONS::setDNP ) && !symbol->GetDNP( sheet, variant ) )
3341 || ( aEvent.IsAction( &SCH_ACTIONS::setExcludeFromSimulation ) && !symbol->GetExcludedFromSim( sheet, variant ) )
3342 || ( aEvent.IsAction( &SCH_ACTIONS::setExcludeFromBOM ) && !symbol->GetExcludedFromBOM( sheet, variant ) )
3343 || ( aEvent.IsAction( &SCH_ACTIONS::setExcludeFromBoard ) && !symbol->GetExcludedFromBoard( sheet, variant ) ) )
3344 {
3345 new_state = true;
3346 break;
3347 }
3348 }
3349
3350 for( const auto& [symbol, screen] : collectedUnits )
3351 {
3352 commit.Modify( symbol, screen );
3353
3354 if( aEvent.IsAction( &SCH_ACTIONS::setDNP ) )
3355 symbol->SetDNP( new_state );
3356
3358 symbol->SetExcludedFromSim( new_state );
3359
3361 symbol->SetExcludedFromBOM( new_state );
3362
3364 symbol->SetExcludedFromBoard( new_state );
3365 }
3366
3367 if( !commit.Empty() )
3368 commit.Push( _( "Toggle Attribute" ) );
3369
3370 if( selection.IsHover() )
3371 m_toolMgr->RunAction( ACTIONS::selectionClear );
3372
3373 return 0;
3374}
3375
3376
3377wxString SCH_EDIT_TOOL::FixERCErrorMenuText( const std::shared_ptr<RC_ITEM>& aERCItem )
3378{
3379 if( aERCItem->GetErrorCode() == ERCE_SIMULATION_MODEL || aERCItem->GetErrorCode() == ERCE_FOOTPRINT_FILTERS
3380 || aERCItem->GetErrorCode() == ERCE_FOOTPRINT_LINK_ISSUES )
3381 {
3382 return _( "Edit Symbol Properties..." );
3383 }
3384 else if( aERCItem->GetErrorCode() == ERCE_LIB_SYMBOL_ISSUES )
3385 {
3386 return m_frame->GetRunMenuCommandDescription( SCH_ACTIONS::showSymbolLibTable );
3387 }
3388 else if( aERCItem->GetErrorCode() == ERCE_LIB_SYMBOL_MISMATCH )
3389 {
3390 return m_frame->GetRunMenuCommandDescription( SCH_ACTIONS::updateSymbol );
3391 }
3392 else if( aERCItem->GetErrorCode() == ERCE_UNANNOTATED || aERCItem->GetErrorCode() == ERCE_DUPLICATE_REFERENCE )
3393 {
3394 return m_frame->GetRunMenuCommandDescription( SCH_ACTIONS::annotate );
3395 }
3396 else if( aERCItem->GetErrorCode() == ERCE_UNDEFINED_NETCLASS )
3397 {
3398 return _( "Edit Netclasses..." );
3399 }
3400
3401 return wxEmptyString;
3402}
3403
3404
3405void SCH_EDIT_TOOL::FixERCError( const std::shared_ptr<RC_ITEM>& aERCItem )
3406{
3407 SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3408
3409 wxCHECK( frame, /* void */ );
3410
3411 if( aERCItem->GetErrorCode() == ERCE_SIMULATION_MODEL || aERCItem->GetErrorCode() == ERCE_FOOTPRINT_FILTERS
3412 || aERCItem->GetErrorCode() == ERCE_FOOTPRINT_LINK_ISSUES )
3413 {
3414 if( EDA_ITEM* item = frame->ResolveItem( aERCItem->GetMainItemID() ) )
3415 EditProperties( item );
3416 }
3417 else if( aERCItem->GetErrorCode() == ERCE_LIB_SYMBOL_ISSUES )
3418 {
3420 }
3421 else if( aERCItem->GetErrorCode() == ERCE_LIB_SYMBOL_MISMATCH )
3422 {
3423 EDA_ITEM* item = frame->ResolveItem( aERCItem->GetMainItemID() );
3424
3425 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item ) )
3426 {
3428 dlg.ShowQuasiModal();
3429 }
3430 }
3431 else if( aERCItem->GetErrorCode() == ERCE_UNANNOTATED || aERCItem->GetErrorCode() == ERCE_DUPLICATE_REFERENCE )
3432 {
3433 m_toolMgr->RunAction( SCH_ACTIONS::annotate );
3434 }
3435 else if( aERCItem->GetErrorCode() == ERCE_UNDEFINED_NETCLASS )
3436 {
3437 frame->ShowSchematicSetupDialog( _( "Net Classes" ) );
3438 }
3439}
3440
3441
3443{
3444 // clang-format off
3450 Go( &SCH_EDIT_TOOL::Swap, SCH_ACTIONS::swap.MakeEvent() );
3456
3462
3482
3483
3488
3492
3495 // clang-format on
3496}
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:136
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:167
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:98
virtual VECTOR2I GetPosition() const
Definition eda_item.h:277
virtual void SetPosition(const VECTOR2I &aPos)
Definition eda_item.h:278
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:110
EDA_ITEM_FLAGS GetEditFlags() const
Definition eda_item.h:153
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:147
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:149
bool IsSelected() const
Definition eda_item.h:127
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:197
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.h:113
EDA_ITEM * GetParent() const
Definition eda_item.h:112
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:151
bool IsMoving() const
Definition eda_item.h:125
bool IsNew() const
Definition eda_item.h:124
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:544
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:588
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:445
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:429
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:296
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition eda_text.cpp:347
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:282
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:311
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:319
void SetFont(KIFONT::FONT *aFont)
Definition eda_text.cpp:511
VECTOR2I GetTextSize() const
Definition eda_text.h:261
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:421
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:1462
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 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 setExcludeFromSimulation
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)
void collectUnits(const SCH_SELECTION &aSelection, std::set< std::pair< SCH_SYMBOL *, SCH_SCREEN * > > &aCollectedUnits)
Set up handlers for various events.
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:167
virtual bool IsConnectable() const
Definition sch_item.h:526
virtual void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo)
Definition sch_item.h:628
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode)
Definition sch_item.h:630
const SYMBOL * GetParentSymbol() const
Definition sch_item.cpp:258
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:252
int GetBodyStyle() const
Definition sch_item.h:247
virtual void MirrorHorizontally(int aCenter)
Mirror item horizontally about aCenter.
Definition sch_item.h:406
virtual void Move(const VECTOR2I &aMoveVector)
Move the item by aMoveVector to a new position.
Definition sch_item.h:398
int GetUnit() const
Definition sch_item.h:238
void SetConnectivityDirty(bool aDirty=true)
Definition sch_item.h:589
void SetFieldsAutoplaced(AUTOPLACE_ALGO aAlgo)
Definition sch_item.h:626
virtual void Rotate(const VECTOR2I &aCenter, bool aRotateCCW)
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition sch_item.h:422
AUTOPLACE_ALGO GetFieldsAutoplaced() const
Return whether the fields have been automatically placed.
Definition sch_item.h:625
wxString GetClass() const override
Return the class name.
Definition sch_item.h:177
bool IsGroupableType() const
Definition sch_item.cpp:112
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition sch_item.h:541
bool IsType(const std::vector< KICAD_T > &aScanTypes) const override
Check whether the item is one of the listed types.
Definition sch_item.h:182
virtual void MirrorVertically(int aCenter)
Mirror item vertically about aCenter.
Definition sch_item.h:414
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:407
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:391
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:747
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:118
const wxString & GetFileName() const
Definition sch_screen.h:153
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:382
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:376
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:145
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 IsAnnotated(const SCH_SHEET_PATH *aSheet) const
Check if the symbol has a valid annotation (reference) for the given sheet path.
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
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
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:66
int GetLegacyTextMargin() const
int GetMarginLeft() const
Definition sch_textbox.h:63
int GetMarginRight() const
Definition sch_textbox.h:65
int GetMarginTop() const
Definition sch_textbox.h:64
virtual void Rotate90(bool aClockwise)
Definition sch_text.cpp:211
virtual void MirrorSpinStyle(bool aLeftRight)
Definition sch_text.cpp:222
void updateItem(EDA_ITEM *aItem, bool aUpdateRTree) const
int Increment(const TOOL_EVENT &aEvent)
int InteractiveDelete(const TOOL_EVENT &aEvent)
bool Init() override
Init() is called once upon a registration of the tool.
SCH_TOOL_BASE(const std::string &aName)
SCH_SELECTION_TOOL * m_selectionTool
static SELECTION_CONDITION HasTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if among the selected items there is at least one of a given types.
static SELECTION_CONDITION HasType(KICAD_T aType)
Create a functor that tests if among the selected items there is at least one of a given type.
static bool NotEmpty(const SELECTION &aSelection)
Test if there are any items selected.
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
static bool IdleSelection(const SELECTION &aSelection)
Test if all selected items are not being edited.
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
virtual void Add(EDA_ITEM *aItem)
Definition selection.cpp: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))
@ 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:51
@ NO_RECURSE
Definition eda_item.h:52
#define IGNORE_PARENT_GROUP
Definition eda_item.h:55
#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:90
@ ID_POPUP_SCH_SELECT_UNIT
Definition eeschema_id.h:89
@ ID_POPUP_SCH_SELECT_BODY_STYLE
Definition eeschema_id.h:99
@ ID_POPUP_SCH_PLACE_UNIT1
Definition eeschema_id.h:96
@ ID_POPUP_SCH_SELECT_BODY_STYLE1
@ ID_POPUP_SCH_PIN_TRICKS_NET_LABEL
@ ID_POPUP_SCH_PIN_TRICKS_NO_CONNECT
@ ID_POPUP_SCH_SELECT_UNIT_END
Definition eeschema_id.h:93
@ 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:68
@ AUTOPLACE_MANUAL
Definition sch_item.h:71
@ AUTOPLACE_NONE
Definition sch_item.h:69
@ AUTOPLACE_AUTO
Definition sch_item.h:70
@ BASE
Definition sch_item.h:59
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