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