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 <sch_actions.h>
35#include <sch_tool_utils.h>
36#include <increment.h>
37#include <algorithm>
38#include <string_utils.h>
39#include <sch_bitmap.h>
40#include <sch_bus_entry.h>
41#include <sch_commit.h>
42#include <sch_group.h>
43#include <sch_junction.h>
44#include <sch_marker.h>
45#include <sch_rule_area.h>
46#include <sch_sheet_pin.h>
47#include <sch_textbox.h>
48#include <sch_table.h>
50#include <eeschema_id.h>
61#include <dialogs/dialog_text_properties.h>
62#include <dialogs/dialog_tablecell_properties.h>
63#include <dialogs/dialog_table_properties.h>
64#include <pgm_base.h>
67#include <core/kicad_algo.h>
68#include <view/view_controls.h>
69#include <wx/textdlg.h>
71
72
74{
75public:
77 ACTION_MENU( true )
78 {
79 SetIcon( BITMAPS::component_select_unit );
80 SetTitle( _( "Symbol Unit" ) );
81 }
82
83protected:
84 ACTION_MENU* create() const override
85 {
86 return new SYMBOL_UNIT_MENU();
87 }
88
89private:
90 void update() override
91 {
93 SCH_SELECTION& selection = selTool->GetSelection();
94 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( selection.Front() );
95
96 Clear();
97
98 wxCHECK( symbol, /* void */ );
99
100 const int unit = symbol->GetUnit();
101 const int nUnits = symbol->GetLibSymbolRef()->GetUnitCount();
102 const std::set<int> missingUnits = GetUnplacedUnitsForSymbol( *symbol );
103
104 for( int ii = 0; ii < nUnits; ii++ )
105 {
106 wxString unit_text = symbol->GetUnitDisplayName( ii + 1, false );
107
108 if( missingUnits.count( ii + 1 ) == 0 )
109 unit_text += _( " (already placed)" );
110
111 wxMenuItem* item = Append( ID_POPUP_SCH_SELECT_UNIT1 + ii, unit_text, wxEmptyString,
112 wxITEM_CHECK );
113
114 if( unit == ii + 1 )
115 item->Check( true );
116
117 // The ID max for these submenus is ID_POPUP_SCH_SELECT_UNIT_END
118 // See eeschema_id to modify this value.
120 break; // We have used all IDs for these submenus
121 }
122
123 {
124 AppendSeparator();
125
126 wxMenuItem* item = Add( SCH_ACTIONS::placeNextSymbolUnit );
127 item->Enable( missingUnits.size() );
128 }
129 }
130};
131
132
134{
135public:
137 ACTION_MENU( true )
138 {
139 SetIcon( BITMAPS::body_style );
140 SetTitle( _( "Body Style" ) );
141 }
142
143protected:
144 ACTION_MENU* create() const override
145 {
146 return new BODY_STYLE_MENU();
147 }
148
149private:
150 void update() override
151 {
153 SCH_SELECTION& selection = selTool->GetSelection();
154 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( selection.Front() );
155 wxMenuItem* item;
156
157 Clear();
158
159 wxCHECK( symbol, /* void */ );
160
161 item = Append( ID_POPUP_SCH_SELECT_BASE, _( "Standard" ), wxEmptyString, wxITEM_CHECK );
162 item->Check( symbol->GetBodyStyle() == BODY_STYLE::BASE );
163
164 item = Append( ID_POPUP_SCH_SELECT_ALT, _( "Alternate" ), wxEmptyString, wxITEM_CHECK );
165 item->Check( symbol->GetBodyStyle() != BODY_STYLE::BASE );
166 }
167};
168
169
171{
172public:
174 ACTION_MENU( true )
175 {
176 SetIcon( BITMAPS::component_select_unit );
177 SetTitle( _( "Pin Function" ) );
178 }
179
180protected:
181 ACTION_MENU* create() const override
182 {
183 return new ALT_PIN_FUNCTION_MENU();
184 }
185
186private:
187 void update() override
188 {
190 SCH_SELECTION& selection = selTool->GetSelection();
191 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( selection.Front() );
192 SCH_PIN* libPin = pin ? pin->GetLibPin() : nullptr;
193
194 Clear();
195
196 wxCHECK( libPin, /* void */ );
197
198 wxMenuItem* item = Append( ID_POPUP_SCH_ALT_PIN_FUNCTION, libPin->GetName(), wxEmptyString,
199 wxITEM_CHECK );
200
201 if( pin->GetAlt().IsEmpty() || ( pin->GetAlt() == libPin->GetName() ) )
202 item->Check( true );
203
204 int ii = 1;
205
206 for( const auto& [ name, definition ] : libPin->GetAlternates() )
207 {
208 // The default pin name is set above, avoid setting it again.
209 if( name == libPin->GetName() )
210 continue;
211
212 item = Append( ID_POPUP_SCH_ALT_PIN_FUNCTION + ii, name, wxEmptyString, wxITEM_CHECK );
213
214 if( name == pin->GetAlt() )
215 item->Check( true );
216
217 // The ID max for these submenus is ID_POPUP_SCH_ALT_PIN_FUNCTION_END
218 // See eeschema_id to modify this value.
220 break; // We have used all IDs for these submenus
221 }
222 }
223};
224
225
227{
228public:
230 {
231 SetIcon( BITMAPS::pin );
232 SetTitle( _( "Pin Helpers" ) );
233 }
234
235protected:
236 ACTION_MENU* create() const override { return new PIN_TRICKS_MENU(); }
237
238private:
239 void update() override
240 {
242 SCH_SELECTION& selection = selTool->GetSelection();
243 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( selection.Front() );
244 SCH_SHEET_PIN* sheetPin = dynamic_cast<SCH_SHEET_PIN*>( selection.Front() );
245
246 Clear();
247
248 if( !pin && !sheetPin )
249 return;
250
251 Add( _( "Wire" ), ID_POPUP_SCH_PIN_TRICKS_WIRE, BITMAPS::add_line );
252 Add( _( "No Connect" ), ID_POPUP_SCH_PIN_TRICKS_NO_CONNECT, BITMAPS::noconn );
253 Add( _( "Net Label" ), ID_POPUP_SCH_PIN_TRICKS_NET_LABEL, BITMAPS::add_label );
254 Add( _( "Hierarchical Label" ), ID_POPUP_SCH_PIN_TRICKS_HIER_LABEL, BITMAPS::add_hierarchical_label );
255 Add( _( "Global Label" ), ID_POPUP_SCH_PIN_TRICKS_GLOBAL_LABEL, BITMAPS::add_glabel );
256 }
257};
258
259
261 SCH_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveEdit" )
262{
263 m_pickerItem = nullptr;
264}
265
266
268
270{
272
275
276 wxASSERT_MSG( drawingTools, "eeshema.InteractiveDrawing tool is not available" );
277
278 auto hasElements =
279 [this]( const SELECTION& aSel )
280 {
281 return !m_frame->GetScreen()->Items().empty();
282 };
283
284 auto sheetHasUndefinedPins =
285 []( const SELECTION& aSel )
286 {
287 if( aSel.Size() == 1 && aSel.Front()->Type() == SCH_SHEET_T )
288 return static_cast<SCH_SHEET*>( aSel.Front() )->HasUndefinedPins();
289
290 return false;
291 };
292
293 auto attribDNPCond =
294 [] ( const SELECTION& aSel )
295 {
296 return std::all_of( aSel.Items().begin(), aSel.Items().end(),
297 []( const EDA_ITEM* item )
298 {
299 return !item->IsType( { SCH_SYMBOL_T } )
300 || static_cast<const SCH_SYMBOL*>( item )->GetDNP();
301 } );
302 };
303
304 auto attribExcludeFromSimCond =
305 [] ( const SELECTION& aSel )
306 {
307 return std::all_of( aSel.Items().begin(), aSel.Items().end(),
308 []( const EDA_ITEM* item )
309 {
310 return !item->IsType( { SCH_SYMBOL_T } )
311 || static_cast<const SCH_SYMBOL*>( item )->GetExcludedFromSim();
312 } );
313 };
314
315 auto attribExcludeFromBOMCond =
316 [] ( const SELECTION& aSel )
317 {
318 return std::all_of( aSel.Items().begin(), aSel.Items().end(),
319 []( const EDA_ITEM* item )
320 {
321 return !item->IsType( { SCH_SYMBOL_T } )
322 || static_cast<const SCH_SYMBOL*>( item )->GetExcludedFromBOM();
323 } );
324 };
325
326
327 auto attribExcludeFromBoardCond =
328 [] ( 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 )->GetExcludedFromBoard();
335 } );
336 };
337
338 static const std::vector<KICAD_T> sheetTypes = { SCH_SHEET_T };
339
340 auto sheetSelection = S_C::Count( 1 ) && S_C::OnlyTypes( sheetTypes );
341
342 auto haveHighlight =
343 [&]( const SELECTION& sel )
344 {
345 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
346
347 return editFrame && !editFrame->GetHighlightedConnection().IsEmpty();
348 };
349
350 auto anyTextTool =
351 [this]( const SELECTION& aSel )
352 {
353 return ( m_frame->IsCurrentTool( SCH_ACTIONS::placeLabel )
354 || m_frame->IsCurrentTool( SCH_ACTIONS::placeClassLabel )
355 || m_frame->IsCurrentTool( SCH_ACTIONS::placeGlobalLabel )
356 || m_frame->IsCurrentTool( SCH_ACTIONS::placeHierLabel )
357 || m_frame->IsCurrentTool( SCH_ACTIONS::placeSchematicText ) );
358 };
359
360 auto duplicateCondition =
361 []( const SELECTION& aSel )
362 {
364 return false;
365
366 return true;
367 };
368
369 auto orientCondition =
370 []( const SELECTION& aSel )
371 {
373 return false;
374
376 };
377
378 auto propertiesCondition =
379 [&]( const SELECTION& aSel )
380 {
381 if( aSel.GetSize() == 0 )
382 {
383 if( getView()->IsLayerVisible( LAYER_SCHEMATIC_DRAWINGSHEET ) )
384 {
385 DS_PROXY_VIEW_ITEM* ds = m_frame->GetCanvas()->GetView()->GetDrawingSheet();
386 VECTOR2D cursor = getViewControls()->GetCursorPosition( false );
387
388 if( ds && ds->HitTestDrawingSheetItems( getView(), cursor ) )
389 return true;
390 }
391
392 return false;
393 }
394
395 SCH_ITEM* firstItem = dynamic_cast<SCH_ITEM*>( aSel.Front() );
396 const SCH_SELECTION* eeSelection = dynamic_cast<const SCH_SELECTION*>( &aSel );
397
398 if( !firstItem || !eeSelection )
399 return false;
400
401 switch( firstItem->Type() )
402 {
403 case SCH_SYMBOL_T:
404 case SCH_SHEET_T:
405 case SCH_SHEET_PIN_T:
406 case SCH_TEXT_T:
407 case SCH_TEXTBOX_T:
408 case SCH_TABLE_T:
409 case SCH_TABLECELL_T:
410 case SCH_LABEL_T:
412 case SCH_HIER_LABEL_T:
414 case SCH_RULE_AREA_T:
415 case SCH_FIELD_T:
416 case SCH_SHAPE_T:
417 case SCH_BITMAP_T:
418 case SCH_GROUP_T:
419 return aSel.GetSize() == 1;
420
421 case SCH_LINE_T:
423 case SCH_JUNCTION_T:
424 if( std::all_of( aSel.Items().begin(), aSel.Items().end(),
425 [&]( const EDA_ITEM* item )
426 {
427 return item->Type() == SCH_LINE_T
428 && static_cast<const SCH_LINE*>( item )->IsGraphicLine();
429 } ) )
430 {
431 return true;
432 }
433 else if( std::all_of( aSel.Items().begin(), aSel.Items().end(),
434 [&]( const EDA_ITEM* item )
435 {
436 return item->Type() == SCH_JUNCTION_T;
437 } ) )
438 {
439 return true;
440 }
441 else if( std::all_of( aSel.Items().begin(), aSel.Items().end(),
442 [&]( const EDA_ITEM* item )
443 {
444 const SCH_ITEM* schItem = dynamic_cast<const SCH_ITEM*>( item );
445
446 wxCHECK( schItem, false );
447
448 return ( schItem->HasLineStroke() && schItem->IsConnectable() )
449 || item->Type() == SCH_JUNCTION_T;
450 } ) )
451 {
452 return true;
453 }
454
455 return false;
456
457 default:
458 return false;
459 }
460 };
461
462 auto autoplaceCondition =
463 []( const SELECTION& aSel )
464 {
465 for( const EDA_ITEM* item : aSel )
466 {
467 if( item->IsType( SCH_COLLECTOR::FieldOwners ) )
468 return true;
469 }
470
471 return false;
472 };
473
474 // allTextTypes does not include SCH_SHEET_PIN_T because one cannot convert other
475 // types to/from this type, living only in a SHEET
476 static const std::vector<KICAD_T> allTextTypes = { SCH_LABEL_T,
482
483 auto toChangeCondition = ( S_C::OnlyTypes( allTextTypes ) );
484
485 static const std::vector<KICAD_T> toLabelTypes = { SCH_DIRECTIVE_LABEL_T,
490
491 auto toLabelCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toLabelTypes ) )
492 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
493
494 static const std::vector<KICAD_T> toCLabelTypes = { SCH_LABEL_T,
499
500 auto toCLabelCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toCLabelTypes ) )
501 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
502
503 static const std::vector<KICAD_T> toHLabelTypes = { SCH_LABEL_T,
508
509 auto toHLabelCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toHLabelTypes ) )
510 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
511
512 static const std::vector<KICAD_T> toGLabelTypes = { SCH_LABEL_T,
517
518 auto toGLabelCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toGLabelTypes ) )
519 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
520
521 static const std::vector<KICAD_T> toTextTypes = { SCH_LABEL_T,
526
527 auto toTextCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toTextTypes ) )
528 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
529
530 static const std::vector<KICAD_T> toTextBoxTypes = { SCH_LABEL_T,
534 SCH_TEXT_T };
535
536 auto toTextBoxCondition = ( S_C::Count( 1 ) && S_C::OnlyTypes( toTextBoxTypes ) )
537 || ( S_C::MoreThan( 1 ) && S_C::OnlyTypes( allTextTypes ) );
538
539 static const std::vector<KICAD_T> busEntryTypes = { SCH_BUS_WIRE_ENTRY_T, SCH_BUS_BUS_ENTRY_T};
540
541 auto entryCondition = S_C::MoreThan( 0 ) && S_C::OnlyTypes( busEntryTypes );
542
543 auto singleSheetCondition = S_C::Count( 1 ) && S_C::OnlyTypes( sheetTypes );
544
545 auto makeSymbolUnitMenu =
546 [&]( TOOL_INTERACTIVE* tool )
547 {
548 std::shared_ptr<SYMBOL_UNIT_MENU> menu = std::make_shared<SYMBOL_UNIT_MENU>();
549 menu->SetTool( tool );
550 tool->GetToolMenu().RegisterSubMenu( menu );
551 return menu.get();
552 };
553
554 auto makeBodyStyleMenu =
555 [&]( TOOL_INTERACTIVE* tool )
556 {
557 std::shared_ptr<BODY_STYLE_MENU> menu = std::make_shared<BODY_STYLE_MENU>();
558 menu->SetTool( tool );
559 tool->GetToolMenu().RegisterSubMenu( menu );
560 return menu.get();
561 };
562
563 auto makePinFunctionMenu =
564 [&]( TOOL_INTERACTIVE* tool )
565 {
566 std::shared_ptr<ALT_PIN_FUNCTION_MENU> menu = std::make_shared<ALT_PIN_FUNCTION_MENU>();
567 menu->SetTool( tool );
568 tool->GetToolMenu().RegisterSubMenu( menu );
569 return menu.get();
570 };
571
572 auto makePinTricksMenu =
573 [&]( TOOL_INTERACTIVE* tool )
574 {
575 std::shared_ptr<PIN_TRICKS_MENU> menu = std::make_shared<PIN_TRICKS_MENU>();
576 menu->SetTool( tool );
577 tool->GetToolMenu().RegisterSubMenu( menu );
578 return menu.get();
579 };
580
581 auto makeTransformMenu =
582 [&]()
583 {
584 CONDITIONAL_MENU* menu = new CONDITIONAL_MENU( moveTool );
585 menu->SetTitle( _( "Transform Selection" ) );
586
587 menu->AddItem( SCH_ACTIONS::rotateCCW, orientCondition );
588 menu->AddItem( SCH_ACTIONS::rotateCW, orientCondition );
589 menu->AddItem( SCH_ACTIONS::mirrorV, orientCondition );
590 menu->AddItem( SCH_ACTIONS::mirrorH, orientCondition );
591
592 return menu;
593 };
594
595 auto makeAttributesMenu =
596 [&]()
597 {
598 CONDITIONAL_MENU* menu = new CONDITIONAL_MENU( moveTool );
599 menu->SetTitle( _( "Attributes" ) );
600
605
606 return menu;
607 };
608
609 auto makeEditFieldsMenu =
610 [&]()
611 {
612 CONDITIONAL_MENU* menu = new CONDITIONAL_MENU( m_selectionTool );
613 menu->SetTitle( _( "Edit Main Fields" ) );
614
618
619 return menu;
620 };
621
622 auto makeConvertToMenu =
623 [&]()
624 {
625 CONDITIONAL_MENU* menu = new CONDITIONAL_MENU( m_selectionTool );
626 menu->SetTitle( _( "Change To" ) );
627 menu->SetIcon( BITMAPS::right );
628
629 menu->AddItem( SCH_ACTIONS::toLabel, toLabelCondition );
630 menu->AddItem( SCH_ACTIONS::toCLabel, toCLabelCondition );
631 menu->AddItem( SCH_ACTIONS::toHLabel, toHLabelCondition );
632 menu->AddItem( SCH_ACTIONS::toGLabel, toGLabelCondition );
633 menu->AddItem( SCH_ACTIONS::toText, toTextCondition );
634 menu->AddItem( SCH_ACTIONS::toTextBox, toTextBoxCondition );
635
636 return menu;
637 };
638
639 const auto canCopyText = SCH_CONDITIONS::OnlyTypes( {
648 SCH_PIN_T,
651 } );
652
653 //
654 // Add edit actions to the move tool menu
655 //
656 CONDITIONAL_MENU& moveMenu = moveTool->GetToolMenu().GetMenu();
657
658 moveMenu.AddSeparator();
659 moveMenu.AddMenu( makeSymbolUnitMenu( moveTool ), S_C::SingleMultiUnitSymbol, 1 );
660 moveMenu.AddMenu( makeBodyStyleMenu( moveTool ), S_C::SingleDeMorganSymbol, 1 );
661
662 moveMenu.AddMenu( makeTransformMenu(), orientCondition, 200 );
663 moveMenu.AddMenu( makeAttributesMenu(), S_C::HasType( SCH_SYMBOL_T ), 200 );
664 moveMenu.AddItem( SCH_ACTIONS::swap, SELECTION_CONDITIONS::MoreThan( 1 ), 200);
665 moveMenu.AddItem( SCH_ACTIONS::properties, propertiesCondition, 200 );
666 moveMenu.AddMenu( makeEditFieldsMenu(), S_C::SingleSymbol, 200 );
667
668 moveMenu.AddSeparator();
669 moveMenu.AddItem( ACTIONS::cut, S_C::IdleSelection );
670 moveMenu.AddItem( ACTIONS::copy, S_C::IdleSelection );
671 moveMenu.AddItem( ACTIONS::copyAsText, canCopyText && S_C::IdleSelection );
672 moveMenu.AddItem( ACTIONS::doDelete, S_C::NotEmpty );
673 moveMenu.AddItem( ACTIONS::duplicate, duplicateCondition );
674
675 //
676 // Add editing actions to the drawing tool menu
677 //
678 CONDITIONAL_MENU& drawMenu = drawingTools->GetToolMenu().GetMenu();
679
680 drawMenu.AddItem( SCH_ACTIONS::clearHighlight, haveHighlight && SCH_CONDITIONS::Idle, 1 );
681 drawMenu.AddSeparator( haveHighlight && SCH_CONDITIONS::Idle, 1 );
682
683 drawMenu.AddItem( SCH_ACTIONS::enterSheet, sheetSelection && SCH_CONDITIONS::Idle, 1 );
684 drawMenu.AddSeparator( sheetSelection && SCH_CONDITIONS::Idle, 1 );
685
686 drawMenu.AddMenu( makeSymbolUnitMenu( drawingTools ), S_C::SingleMultiUnitSymbol, 1 );
687 drawMenu.AddMenu( makeBodyStyleMenu( drawingTools ), S_C::SingleDeMorganSymbol, 1 );
688
689 drawMenu.AddMenu( makeTransformMenu(), orientCondition, 200 );
690 drawMenu.AddMenu( makeAttributesMenu(), S_C::HasType( SCH_SYMBOL_T ), 200 );
691 drawMenu.AddItem( SCH_ACTIONS::properties, propertiesCondition, 200 );
692 drawMenu.AddMenu( makeEditFieldsMenu(), S_C::SingleSymbol, 200 );
693 drawMenu.AddItem( SCH_ACTIONS::autoplaceFields, autoplaceCondition, 200 );
694
696
697 drawMenu.AddItem( SCH_ACTIONS::toLabel, anyTextTool && S_C::Idle, 200 );
698 drawMenu.AddItem( SCH_ACTIONS::toHLabel, anyTextTool && S_C::Idle, 200 );
699 drawMenu.AddItem( SCH_ACTIONS::toGLabel, anyTextTool && S_C::Idle, 200 );
700 drawMenu.AddItem( SCH_ACTIONS::toText, anyTextTool && S_C::Idle, 200 );
701 drawMenu.AddItem( SCH_ACTIONS::toTextBox, anyTextTool && S_C::Idle, 200 );
702
703 //
704 // Add editing actions to the selection tool menu
705 //
706 CONDITIONAL_MENU& selToolMenu = m_selectionTool->GetToolMenu().GetMenu();
707
708 selToolMenu.AddMenu( makeSymbolUnitMenu( m_selectionTool ), S_C::SingleMultiUnitSymbol, 1 );
709 selToolMenu.AddMenu( makeBodyStyleMenu( m_selectionTool ), S_C::SingleDeMorganSymbol, 1 );
710 selToolMenu.AddMenu( makePinFunctionMenu( m_selectionTool ), S_C::SingleMultiFunctionPin, 1 );
711 selToolMenu.AddMenu( makePinTricksMenu( m_selectionTool ), S_C::AllPinsOrSheetPins, 1 );
712
713 selToolMenu.AddMenu( makeTransformMenu(), orientCondition, 200 );
714 selToolMenu.AddMenu( makeAttributesMenu(), S_C::HasType( SCH_SYMBOL_T ), 200 );
716 selToolMenu.AddItem( SCH_ACTIONS::properties, propertiesCondition, 200 );
717 selToolMenu.AddMenu( makeEditFieldsMenu(), S_C::SingleSymbol, 200 );
718 selToolMenu.AddItem( SCH_ACTIONS::autoplaceFields, autoplaceCondition, 200 );
719
725 selToolMenu.AddMenu( makeConvertToMenu(), toChangeCondition, 200 );
726
727 selToolMenu.AddItem( SCH_ACTIONS::cleanupSheetPins, sheetHasUndefinedPins, 250 );
728
729 selToolMenu.AddSeparator( 300 );
730 selToolMenu.AddItem( ACTIONS::cut, S_C::IdleSelection, 300 );
731 selToolMenu.AddItem( ACTIONS::copy, S_C::IdleSelection, 300 );
732 selToolMenu.AddItem( ACTIONS::copyAsText, canCopyText && S_C::IdleSelection, 300 );
733 selToolMenu.AddItem( ACTIONS::paste, S_C::Idle, 300 );
734 selToolMenu.AddItem( ACTIONS::pasteSpecial, S_C::Idle, 300 );
735 selToolMenu.AddItem( ACTIONS::doDelete, S_C::NotEmpty, 300 );
736 selToolMenu.AddItem( ACTIONS::duplicate, duplicateCondition, 300 );
737
738 selToolMenu.AddSeparator( 400 );
739 selToolMenu.AddItem( ACTIONS::selectAll, hasElements, 400 );
740 selToolMenu.AddItem( ACTIONS::unselectAll, hasElements, 400 );
741
742 ACTION_MANAGER* mgr = m_toolMgr->GetActionManager();
743 // clang-format off
744 mgr->SetConditions( SCH_ACTIONS::setDNP, ACTION_CONDITIONS().Check( attribDNPCond ) );
745 mgr->SetConditions( SCH_ACTIONS::setExcludeFromSimulation, ACTION_CONDITIONS().Check( attribExcludeFromSimCond ) );
746 mgr->SetConditions( SCH_ACTIONS::setExcludeFromBOM, ACTION_CONDITIONS().Check( attribExcludeFromBOMCond ) );
747 mgr->SetConditions( SCH_ACTIONS::setExcludeFromBoard, ACTION_CONDITIONS().Check( attribExcludeFromBoardCond ) );
748 // clang-format on
749
750 return true;
751}
752
753
754const std::vector<KICAD_T> SCH_EDIT_TOOL::RotatableItems = {
760 SCH_TABLECELL_T, // will be promoted to parent table(s)
776};
777
778
780{
781 bool clockwise = ( aEvent.Matches( SCH_ACTIONS::rotateCW.MakeEvent() ) );
782 SCH_SELECTION& selection = m_selectionTool->RequestSelection( RotatableItems, true, false );
783
784 if( selection.GetSize() == 0 )
785 return 0;
786
787 SCH_ITEM* head = nullptr;
788 int principalItemCount = 0; // User-selected items (as opposed to connected wires)
789 VECTOR2I rotPoint;
790 bool moving = false;
791 SCH_COMMIT localCommit( m_toolMgr );
792 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
793
794 if( !commit )
795 commit = &localCommit;
796
797 for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
798 {
799 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
800
801 if( item->HasFlag( SELECTED_BY_DRAG ) )
802 continue;
803
804 principalItemCount++;
805
806 if( !head )
807 head = item;
808 }
809
810 if( head && head->IsMoving() )
811 moving = true;
812
813 if( principalItemCount == 1 )
814 {
815 if( moving && selection.HasReferencePoint() )
816 rotPoint = selection.GetReferencePoint();
817 else if( head->IsConnectable() )
818 rotPoint = head->GetPosition();
819 else
821
822 if( !moving )
823 commit->Modify( head, m_frame->GetScreen(), RECURSE_MODE::RECURSE );
824
825 switch( head->Type() )
826 {
827 case SCH_SYMBOL_T:
828 {
829 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( head );
830
831 symbol->Rotate( rotPoint, !clockwise );
832
834 {
835 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
836
837 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
838 symbol->AutoplaceFields( m_frame->GetScreen(), fieldsAutoplaced );
839 }
840
841 break;
842 }
843
844 case SCH_TEXT_T:
845 case SCH_LABEL_T:
847 case SCH_HIER_LABEL_T:
849 {
850 SCH_TEXT* textItem = static_cast<SCH_TEXT*>( head );
851 textItem->Rotate90( clockwise );
852 break;
853 }
854
855 case SCH_SHEET_PIN_T:
856 {
857 // Rotate pin within parent sheet
858 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( head );
859 SCH_SHEET* sheet = pin->GetParent();
860
861 pin->Rotate( sheet->GetBoundingBox().GetCenter(), !clockwise );
862
863 break;
864 }
865
866 case SCH_LINE_T:
867 {
868 SCH_LINE* line = static_cast<SCH_LINE*>( head );
869
870 // Equal checks for both and neither. We need this because on undo
871 // the item will have both flags cleared, but will be selected, so it is possible
872 // for the user to get a selected line with neither endpoint selected. We
873 // set flags to make sure Rotate() works when we call it.
874 if( line->HasFlag( STARTPOINT ) == line->HasFlag( ENDPOINT ) )
875 {
876 line->SetFlags( STARTPOINT | ENDPOINT );
877
878 // When we allow off grid items, the rotPoint should be set to the midpoint
879 // of the line to allow rotation around the center, and the next if
880 // should become an else-if
881 }
882
883 if( line->HasFlag( STARTPOINT ) )
884 rotPoint = line->GetEndPoint();
885 else if( line->HasFlag( ENDPOINT ) )
886 rotPoint = line->GetStartPoint();
887 }
888
890 case SCH_JUNCTION_T:
891 case SCH_NO_CONNECT_T:
894 head->Rotate( rotPoint, !clockwise );
895
896 break;
897
898 case SCH_FIELD_T:
899 {
900 SCH_FIELD* field = static_cast<SCH_FIELD*>( head );
901
902 if( field->GetTextAngle().IsHorizontal() )
904 else
906
907 // Now that we're moving a field, they're no longer autoplaced.
908 static_cast<SCH_ITEM*>( head->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
909
910 break;
911 }
912
913 case SCH_RULE_AREA_T:
914 case SCH_SHAPE_T:
915 case SCH_TEXTBOX_T:
916 head->Rotate( rotPoint, !clockwise );
917
918 break;
919
920 case SCH_GROUP_T:
921 {
922 // Rotate the group on itself. Groups do not have an anchor point.
923 SCH_GROUP* group = static_cast<SCH_GROUP*>( head );
924 rotPoint = m_frame->GetNearestHalfGridPosition( group->GetPosition() );
925
926 group->Rotate( rotPoint, !clockwise );
927
928 group->Move( rotPoint - m_frame->GetNearestHalfGridPosition( group->GetPosition() ) );
929
930 break;
931 }
932
933 case SCH_TABLE_T:
934 {
935 // Rotate the table on itself. Tables do not have an anchor point.
936 SCH_TABLE* table = static_cast<SCH_TABLE*>( head );
937 rotPoint = m_frame->GetNearestHalfGridPosition( table->GetCenter() );
938
939 table->Rotate( rotPoint, !clockwise );
940
941 table->Move( rotPoint - m_frame->GetNearestHalfGridPosition( table->GetCenter() ) );
942
943 break;
944 }
945
946 case SCH_BITMAP_T:
947 head->Rotate( rotPoint, !clockwise );
948
949 // The bitmap is cached in Opengl: clear the cache to redraw
951 break;
952
953 case SCH_SHEET_T:
954 {
955 // Rotate the sheet on itself. Sheets do not have an anchor point.
956 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( head );
957
959 sheet->Rotate( rotPoint, !clockwise );
960
961 break;
962 }
963
964 default:
965 UNIMPLEMENTED_FOR( head->GetClass() );
966 }
967
968 m_frame->UpdateItem( head, false, true );
969 }
970 else
971 {
972 if( moving && selection.HasReferencePoint() )
973 rotPoint = selection.GetReferencePoint();
974 else
975 rotPoint = m_frame->GetNearestHalfGridPosition( selection.GetCenter() );
976 }
977
978 for( EDA_ITEM* edaItem : selection )
979 {
980 SCH_ITEM* item = static_cast<SCH_ITEM*>( edaItem );
981
982 // We've already rotated the user selected item if there was only one. We're just
983 // here to rotate the ends of wires that were attached to it.
984 if( principalItemCount == 1 && !item->HasFlag( SELECTED_BY_DRAG ) )
985 continue;
986
987 if( !moving )
988 commit->Modify( item, m_frame->GetScreen(), RECURSE_MODE::RECURSE );
989
990 if( item->Type() == SCH_LINE_T )
991 {
992 SCH_LINE* line = (SCH_LINE*) item;
993
994 line->Rotate( rotPoint, !clockwise );
995 }
996 else if( item->Type() == SCH_SHEET_PIN_T )
997 {
998 if( item->GetParent()->IsSelected() )
999 {
1000 // parent will rotate us
1001 }
1002 else
1003 {
1004 // rotate within parent
1005 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
1006 SCH_SHEET* sheet = pin->GetParent();
1007
1008 pin->Rotate( sheet->GetBodyBoundingBox().GetCenter(), !clockwise );
1009 }
1010 }
1011 else if( item->Type() == SCH_FIELD_T )
1012 {
1013 if( item->GetParent()->IsSelected() )
1014 {
1015 // parent will rotate us
1016 }
1017 else
1018 {
1019 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
1020
1021 field->Rotate( rotPoint, !clockwise );
1022
1023 // Now that we're moving a field, they're no longer autoplaced.
1024 static_cast<SCH_ITEM*>( field->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
1025 }
1026 }
1027 else if( item->Type() == SCH_TABLE_T )
1028 {
1029 SCH_TABLE* table = static_cast<SCH_TABLE*>( item );
1030 VECTOR2I beforeCenter = table->GetCenter();
1031
1032 table->Rotate( rotPoint, !clockwise );
1033 RotatePoint( beforeCenter, rotPoint, clockwise ? -ANGLE_90 : ANGLE_90 );
1034
1035 table->Move( beforeCenter - table->GetCenter() );
1036 }
1037 else
1038 {
1039 item->Rotate( rotPoint, !clockwise );
1040 }
1041
1042 m_frame->UpdateItem( item, false, true );
1043 updateItem( item, true );
1044 }
1045
1046 if( moving )
1047 {
1049 }
1050 else
1051 {
1052 SCH_SELECTION selectionCopy = selection;
1053
1054 if( selection.IsHover() )
1056
1058 lwbTool->TrimOverLappingWires( commit, &selectionCopy );
1059 lwbTool->AddJunctionsIfNeeded( commit, &selectionCopy );
1060
1061 m_frame->Schematic().CleanUp( commit );
1062
1063 if( !localCommit.Empty() )
1064 localCommit.Push( _( "Rotate" ) );
1065 }
1066
1067 return 0;
1068}
1069
1070
1072{
1073 SCH_SELECTION& selection = m_selectionTool->RequestSelection( RotatableItems, false, false );
1074
1075 if( selection.GetSize() == 0 )
1076 return 0;
1077
1078 bool vertical = ( aEvent.Matches( SCH_ACTIONS::mirrorV.MakeEvent() ) );
1079 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
1080 bool connections = false;
1081 bool moving = item->IsMoving();
1082 SCH_COMMIT localCommit( m_toolMgr );
1083 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
1084
1085 if( !commit )
1086 commit = &localCommit;
1087
1088 if( selection.GetSize() == 1 )
1089 {
1090 if( !moving )
1091 commit->Modify( item, m_frame->GetScreen(), RECURSE_MODE::RECURSE );
1092
1093 switch( item->Type() )
1094 {
1095 case SCH_SYMBOL_T:
1096 {
1097 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1098
1099 if( vertical )
1100 symbol->SetOrientation( SYM_MIRROR_X );
1101 else
1102 symbol->SetOrientation( SYM_MIRROR_Y );
1103
1105 break;
1106 }
1107
1108 case SCH_TEXT_T:
1109 case SCH_LABEL_T:
1110 case SCH_GLOBAL_LABEL_T:
1111 case SCH_HIER_LABEL_T:
1113 {
1114 SCH_TEXT* textItem = static_cast<SCH_TEXT*>( item );
1115 textItem->MirrorSpinStyle( !vertical );
1116 break;
1117 }
1118
1119 case SCH_SHEET_PIN_T:
1120 {
1121 // mirror within parent sheet
1122 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
1123 SCH_SHEET* sheet = pin->GetParent();
1124
1125 if( vertical )
1126 pin->MirrorVertically( sheet->GetBoundingBox().GetCenter().y );
1127 else
1128 pin->MirrorHorizontally( sheet->GetBoundingBox().GetCenter().x );
1129
1130 break;
1131 }
1132
1133 case SCH_FIELD_T:
1134 {
1135 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
1136
1137 if( vertical )
1139 else
1141
1142 // Now that we're re-justifying a field, they're no longer autoplaced.
1143 static_cast<SCH_ITEM*>( field->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
1144
1145 break;
1146 }
1147
1148 case SCH_BITMAP_T:
1149 if( vertical )
1150 item->MirrorVertically( item->GetPosition().y );
1151 else
1152 item->MirrorHorizontally( item->GetPosition().x );
1153
1154 // The bitmap is cached in Opengl: clear the cache to redraw
1156 break;
1157
1158 case SCH_SHEET_T:
1159 {
1160 // Mirror the sheet on itself. Sheets do not have a anchor point.
1162
1163 if( vertical )
1164 item->MirrorVertically( mirrorPoint.y );
1165 else
1166 item->MirrorHorizontally( mirrorPoint.x );
1167
1168 break;
1169 }
1170
1171 default:
1172 if( vertical )
1173 item->MirrorVertically( item->GetPosition().y );
1174 else
1175 item->MirrorHorizontally( item->GetPosition().x );
1176
1177 break;
1178 }
1179
1180 connections = item->IsConnectable();
1181 m_frame->UpdateItem( item, false, true );
1182 }
1183 else if( selection.GetSize() > 1 )
1184 {
1185 VECTOR2I mirrorPoint = m_frame->GetNearestHalfGridPosition( selection.GetCenter() );
1186
1187 for( EDA_ITEM* edaItem : selection )
1188 {
1189 item = static_cast<SCH_ITEM*>( edaItem );
1190
1191 if( !moving )
1192 commit->Modify( item, m_frame->GetScreen(), RECURSE_MODE::RECURSE );
1193
1194 if( item->Type() == SCH_SHEET_PIN_T )
1195 {
1196 if( item->GetParent()->IsSelected() )
1197 {
1198 // parent will mirror us
1199 }
1200 else
1201 {
1202 // mirror within parent sheet
1203 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
1204 SCH_SHEET* sheet = pin->GetParent();
1205
1206 if( vertical )
1207 pin->MirrorVertically( sheet->GetBoundingBox().GetCenter().y );
1208 else
1209 pin->MirrorHorizontally( sheet->GetBoundingBox().GetCenter().x );
1210 }
1211 }
1212 else if( item->Type() == SCH_FIELD_T )
1213 {
1214 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
1215
1216 if( vertical )
1218 else
1220
1221 // Now that we're re-justifying a field, they're no longer autoplaced.
1222 static_cast<SCH_ITEM*>( field->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
1223 }
1224 else
1225 {
1226 if( vertical )
1227 item->MirrorVertically( mirrorPoint.y );
1228 else
1229 item->MirrorHorizontally( mirrorPoint.x );
1230 }
1231
1232 connections |= item->IsConnectable();
1233 m_frame->UpdateItem( item, false, true );
1234 }
1235 }
1236
1237 // Update R-Tree for modified items
1238 for( EDA_ITEM* selected : selection )
1239 updateItem( selected, true );
1240
1241 if( item->IsMoving() )
1242 {
1244 }
1245 else
1246 {
1247 SCH_SELECTION selectionCopy = selection;
1248
1249 if( selection.IsHover() )
1251
1252 if( connections )
1253 {
1255 lwbTool->TrimOverLappingWires( commit, &selectionCopy );
1256 lwbTool->AddJunctionsIfNeeded( commit, &selectionCopy );
1257
1258 m_frame->Schematic().CleanUp( commit );
1259 }
1260
1261 if( !localCommit.Empty() )
1262 localCommit.Push( _( "Mirror" ) );
1263 }
1264
1265 return 0;
1266}
1267
1268
1269const std::vector<KICAD_T> swappableItems = {
1272 SCH_TEXT_T,
1285};
1286
1287
1298static void swapFieldPositionsWithMatching( std::vector<SCH_FIELD>& aAFields,
1299 std::vector<SCH_FIELD>& aBFields,
1300 unsigned aFallbackRotationsCCW )
1301{
1302 std::set<wxString> handledKeys;
1303
1304 const auto swapFieldTextProps = []( SCH_FIELD& aField, SCH_FIELD& bField )
1305 {
1306 const VECTOR2I aRelPos = aField.GetPosition() - aField.GetParentPosition();
1307 const GR_TEXT_H_ALIGN_T aTextJustifyH = aField.GetHorizJustify();
1308 const GR_TEXT_V_ALIGN_T aTextJustifyV = aField.GetVertJustify();
1309 const EDA_ANGLE aTextAngle = aField.GetTextAngle();
1310
1311 const VECTOR2I bRelPos = bField.GetPosition() - bField.GetParentPosition();
1312 const GR_TEXT_H_ALIGN_T bTextJustifyH = bField.GetHorizJustify();
1313 const GR_TEXT_V_ALIGN_T bTextJustifyV = bField.GetVertJustify();
1314 const EDA_ANGLE bTextAngle = bField.GetTextAngle();
1315
1316 aField.SetPosition( aField.GetParentPosition() + bRelPos );
1317 aField.SetHorizJustify( bTextJustifyH );
1318 aField.SetVertJustify( bTextJustifyV );
1319 aField.SetTextAngle( bTextAngle );
1320
1321 bField.SetPosition( bField.GetParentPosition() + aRelPos );
1322 bField.SetHorizJustify( aTextJustifyH );
1323 bField.SetVertJustify( aTextJustifyV );
1324 bField.SetTextAngle( aTextAngle );
1325 };
1326
1327 for( SCH_FIELD& aField : aAFields )
1328 {
1329 const wxString name = aField.GetCanonicalName();
1330
1331 auto it = std::find_if( aBFields.begin(), aBFields.end(),
1332 [name]( const SCH_FIELD& bField )
1333 {
1334 return bField.GetCanonicalName() == name;
1335 } );
1336
1337 if( it != aBFields.end() )
1338 {
1339 // We have a field with the same key in both labels
1340 SCH_FIELD& bField = *it;
1341 swapFieldTextProps( aField, bField );
1342 }
1343 else
1344 {
1345 // We only have this field in A, so just rotate it
1346 for( unsigned ii = 0; ii < aFallbackRotationsCCW; ii++ )
1347 {
1348 aField.Rotate( aField.GetParentPosition(), true );
1349 }
1350 }
1351
1352 // And keep track that we did this one
1353 handledKeys.insert( name );
1354 }
1355
1356 // Any fields in B that weren't in A weren't handled and need to be rotated
1357 // in reverse
1358 for( SCH_FIELD& bField : aBFields )
1359 {
1360 const wxString bName = bField.GetCanonicalName();
1361 if( handledKeys.find( bName ) == handledKeys.end() )
1362 {
1363 for( unsigned ii = 0; ii < aFallbackRotationsCCW; ii++ )
1364 {
1365 bField.Rotate( bField.GetParentPosition(), false );
1366 }
1367 }
1368 }
1369}
1370
1371
1373{
1375 std::vector<EDA_ITEM*> sorted = selection.GetItemsSortedBySelectionOrder();
1376
1377 // Sheet pins are special, we need to make sure if we have any sheet pins,
1378 // that we only have sheet pins, and that they have the same parent
1379 if( selection.CountType( SCH_SHEET_PIN_T ) > 0 )
1380 {
1381 if( !selection.OnlyContains( { SCH_SHEET_PIN_T } ) )
1382 return 0;
1383
1384 SCH_SHEET_PIN* firstPin = static_cast<SCH_SHEET_PIN*>( selection.Front() );
1385 SCH_SHEET* parent = firstPin->GetParent();
1386
1387 for( EDA_ITEM* item : selection )
1388 {
1389 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( item );
1390
1391 if( pin->GetParent() != parent )
1392 return 0;
1393 }
1394 }
1395
1396 if( selection.Size() < 2 )
1397 return 0;
1398
1399 bool isMoving = selection.Front()->IsMoving();
1400 bool appendUndo = isMoving;
1401 bool connections = false;
1402
1403 for( size_t i = 0; i < sorted.size() - 1; i++ )
1404 {
1405 SCH_ITEM* a = static_cast<SCH_ITEM*>( sorted[i] );
1406 SCH_ITEM* b = static_cast<SCH_ITEM*>( sorted[( i + 1 ) % sorted.size()] );
1407
1408 VECTOR2I aPos = a->GetPosition(), bPos = b->GetPosition();
1409 std::swap( aPos, bPos );
1410
1411 saveCopyInUndoList( a, UNDO_REDO::CHANGED, appendUndo );
1412 appendUndo = true;
1413 saveCopyInUndoList( b, UNDO_REDO::CHANGED, appendUndo );
1414
1415 // Sheet pins need to have their sides swapped before we change their
1416 // positions
1417 if( a->Type() == SCH_SHEET_PIN_T )
1418 {
1419 SCH_SHEET_PIN* aPin = static_cast<SCH_SHEET_PIN*>( a );
1420 SCH_SHEET_PIN* bPin = static_cast<SCH_SHEET_PIN*>( b );
1421 SHEET_SIDE aSide = aPin->GetSide(), bSide = bPin->GetSide();
1422 std::swap( aSide, bSide );
1423 aPin->SetSide( aSide );
1424 bPin->SetSide( bSide );
1425 }
1426
1427 a->SetPosition( aPos );
1428 b->SetPosition( bPos );
1429
1430 if( a->Type() == b->Type() )
1431 {
1432 switch( a->Type() )
1433 {
1434 case SCH_LABEL_T:
1435 case SCH_GLOBAL_LABEL_T:
1436 case SCH_HIER_LABEL_T:
1438 {
1439 SCH_LABEL_BASE& aLabelBase = static_cast<SCH_LABEL_BASE&>( *a );
1440 SCH_LABEL_BASE& bLabelBase = static_cast<SCH_LABEL_BASE&>( *b );
1441
1442 const SPIN_STYLE aSpinStyle = aLabelBase.GetSpinStyle();
1443 const SPIN_STYLE bSpinStyle = bLabelBase.GetSpinStyle();
1444
1445 // First, swap the label orientations
1446 aLabelBase.SetSpinStyle( bSpinStyle );
1447 bLabelBase.SetSpinStyle( aSpinStyle );
1448
1449 // And swap the fields as best we can
1450 std::vector<SCH_FIELD>& aFields = aLabelBase.GetFields();
1451 std::vector<SCH_FIELD>& bFields = bLabelBase.GetFields();
1452
1453 const unsigned rotationsAtoB = aSpinStyle.CCWRotationsTo( bSpinStyle );
1454
1455 swapFieldPositionsWithMatching( aFields, bFields, rotationsAtoB );
1456 break;
1457 }
1458 case SCH_SYMBOL_T:
1459 {
1460 SCH_SYMBOL* aSymbol = static_cast<SCH_SYMBOL*>( a );
1461 SCH_SYMBOL* bSymbol = static_cast<SCH_SYMBOL*>( b );
1462 int aOrient = aSymbol->GetOrientation(), bOrient = bSymbol->GetOrientation();
1463 std::swap( aOrient, bOrient );
1464 aSymbol->SetOrientation( aOrient );
1465 bSymbol->SetOrientation( bOrient );
1466 break;
1467 }
1468 default: break;
1469 }
1470 }
1471
1472 connections |= a->IsConnectable();
1473 connections |= b->IsConnectable();
1474 m_frame->UpdateItem( a, false, true );
1475 m_frame->UpdateItem( b, false, true );
1476 }
1477
1478 // Update R-Tree for modified items
1479 for( EDA_ITEM* selected : selection )
1480 updateItem( selected, true );
1481
1482 if( isMoving )
1483 {
1485 }
1486 else
1487 {
1488 if( selection.IsHover() )
1490
1491 if( connections )
1493
1494 m_frame->OnModify();
1495 }
1496
1497 return 0;
1498}
1499
1500
1502{
1503 const std::vector<std::unique_ptr<SCH_ITEM>>& sourceItems = m_frame->GetRepeatItems();
1504
1505 if( sourceItems.empty() )
1506 return 0;
1507
1509
1511 SCH_COMMIT commit( m_toolMgr );
1512 SCH_SELECTION newItems;
1513
1514 for( const std::unique_ptr<SCH_ITEM>& item : sourceItems )
1515 {
1516 SCH_ITEM* newItem = item->Duplicate( IGNORE_PARENT_GROUP );
1517 bool restore_state = false;
1518
1519 // Ensure newItem has a suitable parent: the current screen, because an item from
1520 // a list of items to repeat must be attached to this current screen
1521 newItem->SetParent( m_frame->GetScreen() );
1522
1523 if( SCH_GROUP* enteredGroup = selectionTool->GetEnteredGroup() )
1524 {
1525 if( newItem->IsGroupableType() )
1526 {
1527 commit.Modify( enteredGroup, m_frame->GetScreen(), RECURSE_MODE::NO_RECURSE );
1528 enteredGroup->AddItem( newItem );
1529 }
1530 }
1531
1532 if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( newItem ) )
1533 {
1534 // If incrementing tries to go below zero, tell user why the value is repeated
1535 if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
1536 {
1537 if( !label->IncrementLabel( cfg->m_Drawing.repeat_label_increment ) )
1538 m_frame->ShowInfoBarWarning( _( "Label value cannot go below zero" ), true );
1539 }
1540 }
1541
1542 // If cloning a symbol then put into 'move' mode.
1543 if( newItem->Type() == SCH_SYMBOL_T )
1544 {
1545 VECTOR2I cursorPos = getViewControls()->GetCursorPosition( true );
1546 newItem->Move( cursorPos - newItem->GetPosition() );
1547 }
1548 else if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
1549 {
1550 newItem->Move( VECTOR2I( schIUScale.MilsToIU( cfg->m_Drawing.default_repeat_offset_x ),
1551 schIUScale.MilsToIU( cfg->m_Drawing.default_repeat_offset_y ) ) );
1552 }
1553
1554 // If cloning a sheet, check that we aren't going to create recursion
1555 if( newItem->Type() == SCH_SHEET_T )
1556 {
1557 SCH_SHEET_PATH* currentSheet = &m_frame->GetCurrentSheet();
1558 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( newItem );
1559
1560 if( m_frame->CheckSheetForRecursion( sheet, currentSheet ) )
1561 {
1562 // Clear out the filename so that the user can pick a new one
1563 const wxString originalFileName = sheet->GetFileName();
1564 const wxString originalScreenFileName = sheet->GetScreen()->GetFileName();
1565
1566 sheet->SetFileName( wxEmptyString );
1567 sheet->GetScreen()->SetFileName( wxEmptyString );
1568 restore_state = !m_frame->EditSheetProperties( sheet, currentSheet );
1569
1570 if( restore_state )
1571 {
1572 sheet->SetFileName( originalFileName );
1573 sheet->GetScreen()->SetFileName( originalScreenFileName );
1574 }
1575 }
1576 }
1577
1579 newItem->SetFlags( IS_NEW );
1580 m_frame->AddToScreen( newItem, m_frame->GetScreen() );
1581 commit.Added( newItem, m_frame->GetScreen() );
1582
1583 if( newItem->Type() == SCH_SYMBOL_T )
1584 {
1586 SCHEMATIC_SETTINGS& projSettings = m_frame->Schematic().Settings();
1587 int annotateStartNum = projSettings.m_AnnotateStartNum;
1588
1589 if( annotate.automatic )
1590 {
1591 static_cast<SCH_SYMBOL*>( newItem )->ClearAnnotation( nullptr, false );
1592 NULL_REPORTER reporter;
1594 (ANNOTATE_ORDER_T) annotate.sort_order,
1595 (ANNOTATE_ALGO_T) annotate.method, true /* recursive */,
1596 annotateStartNum, false, false, reporter );
1597 }
1598
1599 // Annotation clears the selection so re-add the item
1601
1602 restore_state = !m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit );
1603 }
1604
1605 if( restore_state )
1606 {
1607 commit.Revert();
1608 }
1609 else
1610 {
1611 newItems.Add( newItem );
1612
1614 lwbTool->TrimOverLappingWires( &commit, &newItems );
1615 lwbTool->AddJunctionsIfNeeded( &commit, &newItems );
1616
1617 m_frame->Schematic().CleanUp( &commit );
1618 commit.Push( _( "Repeat Item" ) );
1619 }
1620 }
1621
1622 if( !newItems.Empty() )
1623 m_frame->SaveCopyForRepeatItem( static_cast<SCH_ITEM*>( newItems[0] ) );
1624
1625 for( size_t ii = 1; ii < newItems.GetSize(); ++ii )
1626 m_frame->AddCopyForRepeatItem( static_cast<SCH_ITEM*>( newItems[ii] ) );
1627
1628 return 0;
1629}
1630
1631
1632static std::vector<KICAD_T> deletableItems =
1633{
1636 SCH_LINE_T,
1641 SCH_TEXT_T,
1643 SCH_TABLECELL_T, // Clear contents
1653 SCH_FIELD_T, // Will be hidden
1656};
1657
1658
1660{
1661 SCH_SCREEN* screen = m_frame->GetScreen();
1662 std::deque<EDA_ITEM*> items = m_selectionTool->RequestSelection( deletableItems ).GetItems();
1663 SCH_COMMIT commit( m_toolMgr );
1664 std::vector<VECTOR2I> pts;
1665 bool updateHierarchy = false;
1666
1667 if( items.empty() )
1668 return 0;
1669
1670 // Don't leave a freed pointer in the selection
1672
1673 for( EDA_ITEM* item : items )
1674 item->ClearFlags( STRUCT_DELETED );
1675
1676 for( EDA_ITEM* item : items )
1677 {
1678 SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item );
1679
1680 if( !sch_item )
1681 continue;
1682
1683 if( sch_item->IsConnectable() )
1684 {
1685 std::vector<VECTOR2I> tmp_pts = sch_item->GetConnectionPoints();
1686 pts.insert( pts.end(), tmp_pts.begin(), tmp_pts.end() );
1687 }
1688
1689 if( sch_item->Type() == SCH_JUNCTION_T )
1690 {
1691 sch_item->SetFlags( STRUCT_DELETED );
1692 // clean up junctions at the end
1693 }
1694 else if( sch_item->Type() == SCH_SHEET_PIN_T )
1695 {
1696 SCH_SHEET_PIN* pin = (SCH_SHEET_PIN*) sch_item;
1697 SCH_SHEET* sheet = pin->GetParent();
1698
1699 if( !alg::contains( items, sheet ) )
1700 {
1701 commit.Modify( sheet, m_frame->GetScreen() );
1702 sheet->RemovePin( pin );
1703 }
1704 }
1705 else if( sch_item->Type() == SCH_FIELD_T )
1706 {
1707 // Hide field
1708 commit.Modify( item, m_frame->GetScreen() );
1709 static_cast<SCH_FIELD*>( sch_item )->SetVisible( false );
1710 }
1711 else if( sch_item->Type() == SCH_TABLECELL_T )
1712 {
1713 // Clear contents of table cell
1714 commit.Modify( item, m_frame->GetScreen() );
1715 static_cast<SCH_TABLECELL*>( sch_item )->SetText( wxEmptyString );
1716 }
1717 else if( sch_item->Type() == SCH_RULE_AREA_T )
1718 {
1719 sch_item->SetFlags( STRUCT_DELETED );
1720 commit.Remove( item, m_frame->GetScreen() );
1721 }
1722 else if( sch_item->Type() == SCH_GROUP_T )
1723 {
1724 // Groups need to delete their children
1725 sch_item->RunOnChildren(
1726 [&]( SCH_ITEM* aChild )
1727 {
1728 aChild->SetFlags( STRUCT_DELETED );
1729 commit.Remove( aChild, m_frame->GetScreen() );
1730 },
1731 RECURSE_MODE::RECURSE );
1732
1733 sch_item->SetFlags( STRUCT_DELETED );
1734 commit.Remove( sch_item, m_frame->GetScreen() );
1735 }
1736 else
1737 {
1738 sch_item->SetFlags( STRUCT_DELETED );
1739 commit.Remove( item, m_frame->GetScreen() );
1740 updateHierarchy |= ( sch_item->Type() == SCH_SHEET_T );
1741 }
1742 }
1743
1744 for( const VECTOR2I& point : pts )
1745 {
1746 SCH_ITEM* junction = screen->GetItem( point, 0, SCH_JUNCTION_T );
1747
1748 if( !junction )
1749 continue;
1750
1751 if( junction->HasFlag( STRUCT_DELETED ) || !screen->IsExplicitJunction( point ) )
1752 m_frame->DeleteJunction( &commit, junction );
1753 }
1754
1755 commit.Push( _( "Delete" ) );
1756
1757 if( updateHierarchy )
1759
1760 return 0;
1761}
1762
1763
1764#define HITTEST_THRESHOLD_PIXELS 5
1765
1766
1768{
1770
1772 m_pickerItem = nullptr;
1773
1774 // Deactivate other tools; particularly important if another PICKER is currently running
1775 Activate();
1776
1777 picker->SetCursor( KICURSOR::REMOVE );
1778 picker->SetSnapping( false );
1779 picker->ClearHandlers();
1780
1781 picker->SetClickHandler(
1782 [this]( const VECTOR2D& aPosition ) -> bool
1783 {
1784 if( m_pickerItem )
1785 {
1787 selectionTool->UnbrightenItem( m_pickerItem );
1788 selectionTool->AddItemToSel( m_pickerItem, true /*quiet mode*/ );
1790 m_pickerItem = nullptr;
1791 }
1792
1793 return true;
1794 } );
1795
1796 picker->SetMotionHandler(
1797 [this]( const VECTOR2D& aPos )
1798 {
1799 SCH_COLLECTOR collector;
1800 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
1801 collector.Collect( m_frame->GetScreen(), deletableItems, aPos );
1802
1804 selectionTool->GuessSelectionCandidates( collector, aPos );
1805
1806 EDA_ITEM* item = collector.GetCount() == 1 ? collector[ 0 ] : nullptr;
1807
1808 if( m_pickerItem != item )
1809 {
1810 if( m_pickerItem )
1811 selectionTool->UnbrightenItem( m_pickerItem );
1812
1813 m_pickerItem = item;
1814
1815 if( m_pickerItem )
1816 selectionTool->BrightenItem( m_pickerItem );
1817 }
1818 } );
1819
1820 picker->SetFinalizeHandler(
1821 [this]( const int& aFinalState )
1822 {
1823 if( m_pickerItem )
1824 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
1825
1826 // Wake the selection tool after exiting to ensure the cursor gets updated
1828 } );
1829
1831
1832 return 0;
1833}
1834
1835
1837{
1838 KICAD_T parentType = aField->GetParent() ? aField->GetParent()->Type() : SCHEMATIC_T;
1839 SCH_COMMIT commit( m_toolMgr );
1840
1841 // Save old symbol in undo list if not already in edit, or moving.
1842 if( aField->GetEditFlags() == 0 ) // i.e. not edited, or moved
1843 commit.Modify( aField, m_frame->GetScreen() );
1844
1845 if( parentType == SCH_SYMBOL_T && aField->GetId() == FIELD_T::REFERENCE )
1846 static_cast<SCH_ITEM*>( aField->GetParent() )->SetConnectivityDirty();
1847
1848 wxString caption;
1849
1850 // Use title caps for mandatory fields. "Edit Sheet name Field" looks dorky.
1851 if( aField->IsMandatory() )
1852 {
1853 wxString fieldName = GetDefaultFieldName( aField->GetId(), DO_TRANSLATE );
1854 caption.Printf( _( "Edit %s Field" ), TitleCaps( fieldName ) );
1855 }
1856 else
1857 {
1858 caption.Printf( _( "Edit '%s' Field" ), aField->GetName() );
1859 }
1860
1861 DIALOG_FIELD_PROPERTIES dlg( m_frame, caption, aField );
1862
1863 // The footprint field dialog can invoke a KIWAY_PLAYER so we must use a quasi-modal
1864 if( dlg.ShowQuasiModal() != wxID_OK )
1865 return;
1866
1867 dlg.UpdateField( &commit, aField, &m_frame->GetCurrentSheet() );
1868
1869 if( m_frame->eeconfig()->m_AutoplaceFields.enable || parentType == SCH_SHEET_T )
1870 {
1871 SCH_ITEM* parent = static_cast<SCH_ITEM*>( aField->GetParent() );
1872 AUTOPLACE_ALGO fieldsAutoplaced = parent->GetFieldsAutoplaced();
1873
1874 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
1875 parent->AutoplaceFields( m_frame->GetScreen(), fieldsAutoplaced );
1876 }
1877
1878 if( !commit.Empty() )
1879 commit.Push( caption );
1880}
1881
1882
1884{
1887 SCH_PIN_T } );
1888
1889 if( sel.Size() != 1 )
1890 return 0;
1891
1892 bool clearSelection = sel.IsHover();
1893 EDA_ITEM* item = sel.Front();
1894
1895 if( item->Type() == SCH_FIELD_T )
1896 {
1897 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
1898
1899 if( ( aEvent.IsAction( &SCH_ACTIONS::editReference ) && field->GetId() != FIELD_T::REFERENCE )
1900 || ( aEvent.IsAction( &SCH_ACTIONS::editValue ) && field->GetId() != FIELD_T::VALUE )
1901 || ( aEvent.IsAction( &SCH_ACTIONS::editFootprint ) && field->GetId() != FIELD_T::FOOTPRINT ) )
1902 {
1903 item = field->GetParentSymbol();
1904
1906
1907 // If the field to edit is not a symbol field, we cannot edit the ref, value or footprint
1908 if( item == nullptr )
1909 return 0;
1910
1912 }
1913 }
1914
1915 if( item->Type() == SCH_SYMBOL_T )
1916 {
1917 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1918
1919 if( aEvent.IsAction( &SCH_ACTIONS::editReference ) )
1920 {
1921 editFieldText( symbol->GetField( FIELD_T::REFERENCE ) );
1922 }
1923 else if( aEvent.IsAction( &SCH_ACTIONS::editValue ) )
1924 {
1925 editFieldText( symbol->GetField( FIELD_T::VALUE ) );
1926 }
1927 else if( aEvent.IsAction( &SCH_ACTIONS::editFootprint ) )
1928 {
1929 if( !symbol->IsPower() )
1930 editFieldText( symbol->GetField( FIELD_T::FOOTPRINT ) );
1931 }
1932 }
1933 else if( item->Type() == SCH_FIELD_T )
1934 {
1935 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
1936
1937 editFieldText( field );
1938
1939 if( !field->IsVisible() )
1940 clearSelection = true;
1941 }
1942 else if( item->Type() == SCH_PIN_T )
1943 {
1944 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item->GetParent() );
1945
1946 if( symbol )
1947 {
1948 if( aEvent.IsAction( &SCH_ACTIONS::editReference ) )
1949 {
1950 editFieldText( symbol->GetField( FIELD_T::REFERENCE ) );
1951 }
1952 else if( aEvent.IsAction( &SCH_ACTIONS::editValue ) )
1953 {
1954 editFieldText( symbol->GetField( FIELD_T::VALUE ) );
1955 }
1956 else if( aEvent.IsAction( &SCH_ACTIONS::editFootprint ) )
1957 {
1958 if( !symbol->IsPower() )
1959 editFieldText( symbol->GetField( FIELD_T::FOOTPRINT ) );
1960 }
1961 }
1962 }
1963
1964 if( clearSelection )
1966
1967 return 0;
1968}
1969
1970
1972{
1974 SCH_COMMIT commit( m_toolMgr );
1975 SCH_ITEM* head = static_cast<SCH_ITEM*>( selection.Front() );
1976 bool moving = head && head->IsMoving();
1977
1978 if( selection.Empty() )
1979 return 0;
1980
1981 std::vector<SCH_ITEM*> autoplaceItems;
1982
1983 for( unsigned ii = 0; ii < selection.GetSize(); ii++ )
1984 {
1985 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetItem( ii ) );
1986
1987 if( item->IsType( SCH_COLLECTOR::FieldOwners ) )
1988 autoplaceItems.push_back( item );
1989 else if( item->GetParent() && item->GetParent()->IsType( SCH_COLLECTOR::FieldOwners ) )
1990 autoplaceItems.push_back( static_cast<SCH_ITEM*>( item->GetParent() ) );
1991 }
1992
1993 for( SCH_ITEM* sch_item : autoplaceItems )
1994 {
1995 if( !moving && !sch_item->IsNew() )
1996 commit.Modify( sch_item, m_frame->GetScreen() );
1997
1998 sch_item->AutoplaceFields( m_frame->GetScreen(), AUTOPLACE_MANUAL );
1999
2000 updateItem( sch_item, true );
2001 }
2002
2003 if( moving )
2004 {
2006 }
2007 else
2008 {
2009 if( !commit.Empty() )
2010 commit.Push( _( "Autoplace Fields" ) );
2011
2012 if( selection.IsHover() )
2014 }
2015
2016 return 0;
2017}
2018
2019
2021{
2022 SCH_SYMBOL* selectedSymbol = nullptr;
2024
2025 if( !selection.Empty() )
2026 selectedSymbol = dynamic_cast<SCH_SYMBOL*>( selection.Front() );
2027
2029
2030 if( aEvent.IsAction( &SCH_ACTIONS::changeSymbol )
2031 || aEvent.IsAction( &SCH_ACTIONS::changeSymbols ) )
2032 {
2034 }
2035
2036 DIALOG_CHANGE_SYMBOLS dlg( m_frame, selectedSymbol, mode );
2037
2038 // QuasiModal required to invoke symbol browser
2039 dlg.ShowQuasiModal();
2040
2041 if( selection.IsHover() )
2043
2044 return 0;
2045}
2046
2047
2049{
2051
2052 if( selection.Empty() )
2053 return 0;
2054
2055 SCH_SYMBOL* symbol = (SCH_SYMBOL*) selection.Front();
2056
2058 && symbol->GetBodyStyle() == BODY_STYLE::BASE )
2059 {
2060 return 0;
2061 }
2062
2064 && symbol->GetBodyStyle() == BODY_STYLE::DEMORGAN )
2065 {
2066 return 0;
2067 }
2068
2069 SCH_COMMIT commit( m_toolMgr );
2070
2071 if( !symbol->IsNew() )
2072 commit.Modify( symbol, m_frame->GetScreen() );
2073
2074 m_frame->FlipBodyStyle( symbol );
2075
2076 if( symbol->IsNew() )
2078
2079 if( !commit.Empty() )
2080 commit.Push( _( "Change Body Style" ) );
2081
2082 if( selection.IsHover() )
2084
2085 return 0;
2086}
2087
2088
2090{
2092 bool clearSelection = selection.IsHover();
2093
2094 if( selection.Empty() )
2095 {
2096 if( getView()->IsLayerVisible( LAYER_SCHEMATIC_DRAWINGSHEET ) )
2097 {
2099 VECTOR2D cursorPos = getViewControls()->GetCursorPosition( false );
2100
2101 if( ds && ds->HitTestDrawingSheetItems( getView(), cursorPos ) )
2103 }
2104
2105 return 0;
2106 }
2107
2108 EDA_ITEM* curr_item = selection.Front();
2109
2110 // If a single pin is selected, promote to its parent symbol
2111 if( ( selection.GetSize() == 1 ) && ( curr_item->Type() == SCH_PIN_T ) )
2112 {
2113 EDA_ITEM* parent = curr_item->GetParent();
2114
2115 if( parent->Type() == SCH_SYMBOL_T )
2116 curr_item = parent;
2117 }
2118
2119 switch( curr_item->Type() )
2120 {
2121 case SCH_LINE_T:
2123 case SCH_JUNCTION_T:
2124 case SCH_TABLECELL_T:
2125 break;
2126
2127 default:
2128 if( selection.Size() > 1 )
2129 return 0;
2130
2131 break;
2132 }
2133
2134 switch( curr_item->Type() )
2135 {
2136 case SCH_SYMBOL_T:
2137 {
2138 int retval;
2139 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( curr_item );
2140
2141 // This needs to be scoped so the dialog destructor removes blocking status
2142 // before we launch the next dialog.
2143 {
2144 DIALOG_SYMBOL_PROPERTIES symbolPropsDialog( m_frame, symbol );
2145
2146 // This dialog itself subsequently can invoke a KIWAY_PLAYER as a quasimodal
2147 // frame. Therefore this dialog as a modal frame parent, MUST be run under
2148 // quasimodal mode for the quasimodal frame support to work. So don't use
2149 // the QUASIMODAL macros here.
2150 retval = symbolPropsDialog.ShowQuasiModal();
2151 }
2152
2153 if( retval == SYMBOL_PROPS_EDIT_OK )
2154 {
2156 {
2157 AUTOPLACE_ALGO fieldsAutoplaced = symbol->GetFieldsAutoplaced();
2158
2159 if( fieldsAutoplaced == AUTOPLACE_AUTO || fieldsAutoplaced == AUTOPLACE_MANUAL )
2160 symbol->AutoplaceFields( m_frame->GetScreen(), fieldsAutoplaced );
2161 }
2162
2163 m_frame->OnModify();
2164 }
2165 else if( retval == SYMBOL_PROPS_EDIT_SCHEMATIC_SYMBOL )
2166 {
2167 if( KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR, true ) )
2168 {
2169 SYMBOL_EDIT_FRAME* editor = static_cast<SYMBOL_EDIT_FRAME*>( frame );
2170
2171 if( wxWindow* blocking_win = editor->Kiway().GetBlockingDialog() )
2172 blocking_win->Close( true );
2173
2174 // The broken library symbol link indicator cannot be edited.
2175 if( symbol->IsMissingLibSymbol() )
2176 return 0;
2177
2178 editor->LoadSymbolFromSchematic( symbol );
2179 editor->Show( true );
2180 editor->Raise();
2181 }
2182 }
2183 else if( retval == SYMBOL_PROPS_EDIT_LIBRARY_SYMBOL )
2184 {
2185 if( KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR, true ) )
2186 {
2187 SYMBOL_EDIT_FRAME* editor = static_cast<SYMBOL_EDIT_FRAME*>( frame );
2188
2189 if( wxWindow* blocking_win = editor->Kiway().GetBlockingDialog() )
2190 blocking_win->Close( true );
2191
2192 editor->LoadSymbol( symbol->GetLibId(), symbol->GetUnit(), symbol->GetBodyStyle() );
2193 editor->Show( true );
2194 editor->Raise();
2195 }
2196 }
2197 else if( retval == SYMBOL_PROPS_WANT_UPDATE_SYMBOL )
2198 {
2200 dlg.ShowQuasiModal();
2201 }
2202 else if( retval == SYMBOL_PROPS_WANT_EXCHANGE_SYMBOL )
2203 {
2205 dlg.ShowQuasiModal();
2206 }
2207
2208 break;
2209 }
2210
2211 case SCH_SHEET_T:
2212 {
2213 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( curr_item );
2214 bool isUndoable = false;
2215 bool doClearAnnotation = false;
2216 bool okPressed = false;
2217 bool updateHierarchyNavigator = false;
2218
2219 // Keep track of existing sheet paths. EditSheet() can modify this list.
2220 // Note that we use the validity checking/repairing version here just to make sure
2221 // we've got a valid hierarchy to begin with.
2222 SCH_SHEET_LIST originalHierarchy;
2223 originalHierarchy.BuildSheetList( &m_frame->Schematic().Root(), true );
2224
2225 SCH_COMMIT commit( m_toolMgr );
2226 commit.Modify( sheet, m_frame->GetScreen() );
2227 okPressed = m_frame->EditSheetProperties( sheet, &m_frame->GetCurrentSheet(), &isUndoable,
2228 &doClearAnnotation, &updateHierarchyNavigator );
2229
2230 if( okPressed )
2231 {
2232 if( isUndoable )
2233 {
2234 commit.Push( _( "Edit Sheet Properties" ) );
2235 }
2236 else
2237 {
2238 std::vector<SCH_ITEM*> items;
2239
2240 items.emplace_back( sheet );
2241 m_frame->Schematic().OnItemsRemoved( items );
2242 m_frame->Schematic().OnItemsAdded( items );
2243 m_frame->OnModify();
2246 }
2247 }
2248 else
2249 {
2250 // If we are renaming files, the undo/redo list becomes invalid and must be cleared.
2252 m_frame->OnModify();
2253 }
2254
2255 // If the sheet file is changed and new sheet contents are loaded then we have to
2256 // clear the annotations on the new content (as it may have been set from some other
2257 // sheet path reference)
2258 if( doClearAnnotation )
2259 {
2260 SCH_SCREENS screensList( &m_frame->Schematic().Root() );
2261
2262 // We clear annotation of new sheet paths here:
2263 screensList.ClearAnnotationOfNewSheetPaths( originalHierarchy );
2264
2265 // Clear annotation of g_CurrentSheet itself, because its sheetpath is not a new
2266 // path, but symbols managed by its sheet path must have their annotation cleared
2267 // because they are new:
2268 sheet->GetScreen()->ClearAnnotation( &m_frame->GetCurrentSheet(), false );
2269 }
2270
2271 if( okPressed )
2273
2274 if( updateHierarchyNavigator )
2276
2277 break;
2278 }
2279
2280 case SCH_SHEET_PIN_T:
2281 {
2282 SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( curr_item );
2284
2285 // QuasiModal required for help dialog
2286 dlg.ShowQuasiModal();
2287 break;
2288 }
2289
2290 case SCH_TEXT_T:
2291 case SCH_TEXTBOX_T:
2292 {
2293 DIALOG_TEXT_PROPERTIES dlg( m_frame, static_cast<SCH_ITEM*>( curr_item ) );
2294
2295 // QuasiModal required for syntax help and Scintilla auto-complete
2296 dlg.ShowQuasiModal();
2297 break;
2298 }
2299
2300 case SCH_TABLECELL_T:
2301 if( SELECTION_CONDITIONS::OnlyTypes( { SCH_TABLECELL_T } )( selection ) )
2302 {
2303 std::vector<SCH_TABLECELL*> cells;
2304
2305 for( EDA_ITEM* item : selection.Items() )
2306 cells.push_back( static_cast<SCH_TABLECELL*>( item ) );
2307
2309
2310 dlg.ShowModal();
2311
2313 {
2314 SCH_TABLE* table = static_cast<SCH_TABLE*>( cells[0]->GetParent() );
2316
2317 tableDlg.ShowModal();
2318 }
2319 }
2320
2321 break;
2322
2323 case SCH_TABLE_T:
2324 {
2325 DIALOG_TABLE_PROPERTIES dlg( m_frame, static_cast<SCH_TABLE*>( curr_item ) );
2326
2327 // QuasiModal required for Scintilla auto-complete
2328 dlg.ShowQuasiModal();
2329 break;
2330 }
2331
2332 case SCH_LABEL_T:
2333 case SCH_GLOBAL_LABEL_T:
2334 case SCH_HIER_LABEL_T:
2336 {
2337 DIALOG_LABEL_PROPERTIES dlg( m_frame, static_cast<SCH_LABEL_BASE*>( curr_item ), false );
2338
2339 // QuasiModal for syntax help and Scintilla auto-complete
2340 dlg.ShowQuasiModal();
2341 break;
2342 }
2343
2344 case SCH_FIELD_T:
2345 {
2346 SCH_FIELD* field = static_cast<SCH_FIELD*>( curr_item );
2347
2348 editFieldText( field );
2349
2350 if( !field->IsVisible() )
2351 clearSelection = true;
2352
2353 break;
2354 }
2355
2356 case SCH_SHAPE_T:
2357 {
2358 DIALOG_SHAPE_PROPERTIES dlg( m_frame, static_cast<SCH_SHAPE*>( curr_item ) );
2359
2360 dlg.ShowModal();
2361 break;
2362 }
2363
2364 case SCH_BITMAP_T:
2365 {
2366 SCH_BITMAP& bitmap = static_cast<SCH_BITMAP&>( *curr_item );
2367 DIALOG_IMAGE_PROPERTIES dlg( m_frame, bitmap );
2368
2369 if( dlg.ShowModal() == wxID_OK )
2370 {
2371 // The bitmap is cached in Opengl: clear the cache in case it has become invalid
2373 }
2374
2375 break;
2376 }
2377
2378 case SCH_RULE_AREA_T:
2379 {
2380 DIALOG_SHAPE_PROPERTIES dlg( m_frame, static_cast<SCH_SHAPE*>( curr_item ) );
2381 dlg.SetTitle( _( "Rule Area Properties" ) );
2382
2383 dlg.ShowModal();
2384 break;
2385 }
2386
2387 case SCH_LINE_T:
2389 case SCH_JUNCTION_T:
2391 {
2392 std::deque<SCH_LINE*> lines;
2393
2394 for( EDA_ITEM* selItem : selection.Items() )
2395 lines.push_back( static_cast<SCH_LINE*>( selItem ) );
2396
2397 DIALOG_LINE_PROPERTIES dlg( m_frame, lines );
2398
2399 dlg.ShowModal();
2400 }
2401 else if( SELECTION_CONDITIONS::OnlyTypes( { SCH_JUNCTION_T } )( selection ) )
2402 {
2403 std::deque<SCH_JUNCTION*> junctions;
2404
2405 for( EDA_ITEM* selItem : selection.Items() )
2406 junctions.push_back( static_cast<SCH_JUNCTION*>( selItem ) );
2407
2408 DIALOG_JUNCTION_PROPS dlg( m_frame, junctions );
2409
2410 dlg.ShowModal();
2411 }
2415 SCH_JUNCTION_T } )( selection ) )
2416 {
2417 std::deque<SCH_ITEM*> items;
2418
2419 for( EDA_ITEM* selItem : selection.Items() )
2420 items.push_back( static_cast<SCH_ITEM*>( selItem ) );
2421
2422 DIALOG_WIRE_BUS_PROPERTIES dlg( m_frame, items );
2423
2424 dlg.ShowModal();
2425 }
2426 else
2427 {
2428 return 0;
2429 }
2430
2431 break;
2432
2433 case SCH_MARKER_T:
2434 if( SELECTION_CONDITIONS::OnlyTypes( { SCH_MARKER_T } )( selection ) )
2435 {
2437
2438 if( inspectionTool )
2439 inspectionTool->CrossProbe( static_cast<SCH_MARKER*> ( selection.Front() ) );
2440 }
2441 break;
2442
2443 case SCH_NO_CONNECT_T:
2444 case SCH_PIN_T:
2445 break;
2446
2447 case SCH_GROUP_T:
2449 static_cast<EDA_GROUP*>( static_cast<SCH_GROUP*>( curr_item ) ) );
2450
2451 break;
2452
2453 default: // Unexpected item
2454 wxFAIL_MSG( wxString( "Cannot edit schematic item type " ) + curr_item->GetClass() );
2455 }
2456
2457 updateItem( curr_item, true );
2458
2459 if( clearSelection )
2461
2462 return 0;
2463}
2464
2465
2467{
2468 KICAD_T convertTo = aEvent.Parameter<KICAD_T>();
2470 SCH_TEXT_T,
2471 SCH_TEXTBOX_T } );
2472 SCH_COMMIT localCommit( m_toolMgr );
2473 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
2474
2475 if( !commit )
2476 commit = &localCommit;
2477
2478 for( unsigned int i = 0; i < selection.GetSize(); ++i )
2479 {
2480 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( selection.GetItem( i ) );
2481
2482 if( item && item->Type() != convertTo )
2483 {
2484 EDA_TEXT* sourceText = dynamic_cast<EDA_TEXT*>( item );
2485 bool selected = item->IsSelected();
2486 SCH_ITEM* newtext = nullptr;
2487 VECTOR2I position = item->GetPosition();
2488 wxString txt;
2489 wxString href;
2491 LABEL_FLAG_SHAPE shape = LABEL_FLAG_SHAPE::L_UNSPECIFIED;
2492
2493 wxCHECK2( sourceText, continue );
2494
2495 switch( item->Type() )
2496 {
2497 case SCH_LABEL_T:
2498 case SCH_GLOBAL_LABEL_T:
2499 case SCH_HIER_LABEL_T:
2500 {
2501 SCH_LABEL_BASE* label = static_cast<SCH_LABEL_BASE*>( item );
2502
2503 txt = UnescapeString( label->GetText() );
2504 spinStyle = label->GetSpinStyle();
2505 shape = label->GetShape();
2506 href = label->GetHyperlink();
2507 break;
2508 }
2509
2511 {
2512 SCH_DIRECTIVE_LABEL* dirlabel = static_cast<SCH_DIRECTIVE_LABEL*>( item );
2513
2514 // a SCH_DIRECTIVE_LABEL has no text
2515 txt = _( "<empty>" );
2516
2517 spinStyle = dirlabel->GetSpinStyle();
2518 href = dirlabel->GetHyperlink();
2519 break;
2520 }
2521
2522 case SCH_TEXT_T:
2523 {
2524 SCH_TEXT* text = static_cast<SCH_TEXT*>( item );
2525
2526 txt = text->GetText();
2527 href = text->GetHyperlink();
2528 break;
2529 }
2530
2531 case SCH_TEXTBOX_T:
2532 {
2533 SCH_TEXTBOX* textbox = static_cast<SCH_TEXTBOX*>( item );
2534 BOX2I bbox = textbox->GetBoundingBox();
2535
2536 bbox.SetOrigin( bbox.GetLeft() + textbox->GetMarginLeft(),
2537 bbox.GetTop() + textbox->GetMarginTop() );
2538 bbox.SetEnd( bbox.GetRight() - textbox->GetMarginRight(),
2539 bbox.GetBottom() - textbox->GetMarginBottom() );
2540
2541 if( convertTo == SCH_LABEL_T
2542 || convertTo == SCH_HIER_LABEL_T
2543 || convertTo == SCH_GLOBAL_LABEL_T )
2544 {
2545 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( item );
2546 wxCHECK( text, 0 );
2547 int textSize = text->GetTextSize().y;
2548 bbox.Inflate( KiROUND( item->Schematic()->Settings().m_LabelSizeRatio * textSize ) );
2549 }
2550
2551 txt = textbox->GetText();
2552
2553 if( textbox->GetTextAngle().IsVertical() )
2554 {
2555 if( textbox->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
2556 {
2557 spinStyle = SPIN_STYLE::SPIN::BOTTOM;
2558 position = VECTOR2I( bbox.Centre().x, bbox.GetOrigin().y );
2559 }
2560 else
2561 {
2562 spinStyle = SPIN_STYLE::SPIN::UP;
2563 position = VECTOR2I( bbox.Centre().x, bbox.GetEnd().y );
2564 }
2565 }
2566 else
2567 {
2568 if( textbox->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
2569 {
2570 spinStyle = SPIN_STYLE::SPIN::LEFT;
2571 position = VECTOR2I( bbox.GetEnd().x, bbox.Centre().y );
2572 }
2573 else
2574 {
2575 spinStyle = SPIN_STYLE::SPIN::RIGHT;
2576 position = VECTOR2I( bbox.GetOrigin().x, bbox.Centre().y );
2577 }
2578 }
2579
2580 position = m_frame->GetNearestGridPosition( position );
2581 href = textbox->GetHyperlink();
2582 break;
2583 }
2584
2585 default:
2586 UNIMPLEMENTED_FOR( item->GetClass() );
2587 break;
2588 }
2589
2590 auto getValidNetname =
2591 []( const wxString& aText )
2592 {
2593 wxString local_txt = aText;
2594 local_txt.Replace( "\n", "_" );
2595 local_txt.Replace( "\r", "_" );
2596 local_txt.Replace( "\t", "_" );
2597
2598 // Bus groups can have spaces; bus vectors and signal names cannot
2599 if( !NET_SETTINGS::ParseBusGroup( aText, nullptr, nullptr ) )
2600 local_txt.Replace( " ", "_" );
2601
2602 // label strings are "escaped" i.e. a '/' is replaced by "{slash}"
2603 local_txt = EscapeString( local_txt, CTX_NETNAME );
2604
2605 if( local_txt.IsEmpty() )
2606 return _( "<empty>" );
2607 else
2608 return local_txt;
2609 };
2610
2611 switch( convertTo )
2612 {
2613 case SCH_LABEL_T:
2614 {
2615 SCH_LABEL_BASE* new_label = new SCH_LABEL( position, getValidNetname( txt ) );
2616
2617 new_label->SetShape( shape );
2618 new_label->SetAttributes( *sourceText, false );
2619 new_label->SetSpinStyle( spinStyle );
2620 new_label->SetHyperlink( href );
2621
2622 if( item->Type() == SCH_GLOBAL_LABEL_T || item->Type() == SCH_HIER_LABEL_T )
2623 {
2624 if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::UP )
2625 new_label->MirrorVertically( position.y );
2626 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::BOTTOM )
2627 new_label->MirrorVertically( position.y );
2628 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::LEFT )
2629 new_label->MirrorHorizontally( position.x );
2630 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::RIGHT )
2631 new_label->MirrorHorizontally( position.x );
2632 }
2633
2634 newtext = new_label;
2635 break;
2636 }
2637
2638 case SCH_GLOBAL_LABEL_T:
2639 {
2640 SCH_LABEL_BASE* new_label = new SCH_GLOBALLABEL( position, getValidNetname( txt ) );
2641
2642 new_label->SetShape( shape );
2643 new_label->SetAttributes( *sourceText, false );
2644 new_label->SetSpinStyle( spinStyle );
2645 new_label->SetHyperlink( href );
2646
2647 if( item->Type() == SCH_LABEL_T )
2648 {
2649 if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::UP )
2650 new_label->MirrorVertically( position.y );
2651 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::BOTTOM )
2652 new_label->MirrorVertically( position.y );
2653 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::LEFT )
2654 new_label->MirrorHorizontally( position.x );
2655 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::RIGHT )
2656 new_label->MirrorHorizontally( position.x );
2657 }
2658
2659 newtext = new_label;
2660 break;
2661 }
2662
2663 case SCH_HIER_LABEL_T:
2664 {
2665 SCH_LABEL_BASE* new_label = new SCH_HIERLABEL( position, getValidNetname( txt ) );
2666
2667 new_label->SetShape( shape );
2668 new_label->SetAttributes( *sourceText, false );
2669 new_label->SetSpinStyle( spinStyle );
2670 new_label->SetHyperlink( href );
2671
2672 if( item->Type() == SCH_LABEL_T )
2673 {
2674 if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::UP )
2675 new_label->MirrorVertically( position.y );
2676 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::BOTTOM )
2677 new_label->MirrorVertically( position.y );
2678 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::LEFT )
2679 new_label->MirrorHorizontally( position.x );
2680 else if( static_cast<SCH_LABEL_BASE*>( item )->GetSpinStyle() == SPIN_STYLE::SPIN::RIGHT )
2681 new_label->MirrorHorizontally( position.x );
2682 }
2683
2684 newtext = new_label;
2685 break;
2686 }
2687
2689 {
2690 SCH_LABEL_BASE* new_label = new SCH_DIRECTIVE_LABEL( position );
2691
2692 // A SCH_DIRECTIVE_LABEL usually has at least one field containing the net class
2693 // name. If we're copying from a text object assume the text is the netclass
2694 // name. Otherwise, we'll just copy the fields which will either have a netclass
2695 // or not.
2696 if( !dynamic_cast<SCH_LABEL_BASE*>( item ) )
2697 {
2698 SCH_FIELD netclass( new_label, FIELD_T::USER, wxT( "Netclass" ) );
2699 netclass.SetText( txt );
2700 netclass.SetTextPos( position );
2701 new_label->GetFields().push_back( netclass );
2702 }
2703
2704 new_label->SetShape( LABEL_FLAG_SHAPE::F_ROUND );
2705 new_label->SetAttributes( *sourceText, false );
2706 new_label->SetSpinStyle( spinStyle );
2707 new_label->SetHyperlink( href );
2708 newtext = new_label;
2709 break;
2710 }
2711
2712 case SCH_TEXT_T:
2713 {
2714 SCH_TEXT* new_text = new SCH_TEXT( position, txt );
2715
2716 new_text->SetAttributes( *sourceText, false );
2717 new_text->SetHyperlink( href );
2718 newtext = new_text;
2719 break;
2720 }
2721
2722 case SCH_TEXTBOX_T:
2723 {
2724 SCH_TEXTBOX* new_textbox = new SCH_TEXTBOX( LAYER_NOTES, 0, FILL_T::NO_FILL, txt );
2725 BOX2I bbox = item->GetBoundingBox();
2726
2727 if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( item ) )
2728 bbox.Inflate( -label->GetLabelBoxExpansion() );
2729
2730 new_textbox->SetAttributes( *sourceText, false );
2731
2732 bbox.SetOrigin( bbox.GetLeft() - new_textbox->GetMarginLeft(),
2733 bbox.GetTop() - new_textbox->GetMarginTop() );
2734 bbox.SetEnd( bbox.GetRight() + new_textbox->GetMarginRight(),
2735 bbox.GetBottom() + new_textbox->GetMarginBottom() );
2736
2737 VECTOR2I topLeft = bbox.GetPosition();
2738 VECTOR2I botRight = bbox.GetEnd();
2739
2740 // Add 1/20 of the margin at the end to reduce line-breaking changes.
2741 int slop = new_textbox->GetLegacyTextMargin() / 20;
2742
2743 if( sourceText->GetTextAngle() == ANGLE_VERTICAL )
2744 {
2745 if( sourceText->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
2746 botRight.y += slop;
2747 else
2748 topLeft.y -= slop;
2749 }
2750 else
2751 {
2752 if( sourceText->GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
2753 topLeft.x -= slop;
2754 else
2755 botRight.x += slop;
2756 }
2757
2758 new_textbox->SetPosition( topLeft );
2759 new_textbox->SetEnd( botRight );
2760
2761 new_textbox->SetHyperlink( href );
2762 newtext = new_textbox;
2763 break;
2764 }
2765
2766 default:
2767 UNIMPLEMENTED_FOR( wxString::Format( "%d.", convertTo ) );
2768 break;
2769 }
2770
2771 wxCHECK2( newtext, continue );
2772
2773 // Copy the old text item settings to the new one. Justifications are not copied
2774 // because they are not used in labels. Justifications will be set to default value
2775 // in the new text item type.
2776 //
2777 newtext->SetFlags( item->GetEditFlags() );
2778
2779 EDA_TEXT* eda_text = dynamic_cast<EDA_TEXT*>( item );
2780 EDA_TEXT* new_eda_text = dynamic_cast<EDA_TEXT*>( newtext );
2781
2782 wxCHECK2( eda_text && new_eda_text, continue );
2783
2784 new_eda_text->SetFont( eda_text->GetFont() );
2785 new_eda_text->SetTextSize( eda_text->GetTextSize() );
2786 new_eda_text->SetTextThickness( eda_text->GetTextThickness() );
2787
2788 // Must be after SetTextSize()
2789 new_eda_text->SetBold( eda_text->IsBold() );
2790 new_eda_text->SetItalic( eda_text->IsItalic() );
2791
2793
2794 SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( item );
2795 SCH_LABEL_BASE* new_label = dynamic_cast<SCH_LABEL_BASE*>( newtext );
2796
2797 if( label && new_label )
2798 {
2799 new_label->AddFields( label->GetFields() );
2800
2801 // A SCH_GLOBALLABEL has a specific field for intersheet references that has
2802 // no meaning for other labels
2803 std::erase_if( new_label->GetFields(),
2804 [&]( SCH_FIELD& field )
2805 {
2806 return field.GetId() == FIELD_T::INTERSHEET_REFS
2807 && new_label->Type() != SCH_GLOBAL_LABEL_T;
2808 } );
2809 }
2810
2811 if( selected )
2813
2815
2816 if( item->IsNew() )
2817 commit->Unstage( item, m_frame->GetScreen() );
2818 else
2819 commit->Removed( item, m_frame->GetScreen() );
2820
2821 m_frame->AddToScreen( newtext, m_frame->GetScreen() );
2822 commit->Added( newtext, m_frame->GetScreen() );
2823
2824 if( selected )
2826
2827 // Otherwise, pointer is owned by the undo stack
2828 if( item->IsNew() )
2829 delete item;
2830 }
2831 }
2832
2833 if( !localCommit.Empty() )
2834 localCommit.Push( _( "Change To" ) );
2835
2836 if( selection.IsHover() )
2838
2839 return 0;
2840}
2841
2842
2844{
2845 static std::vector<KICAD_T> justifiableItems = {
2847 SCH_TEXT_T,
2850 };
2851
2852 SCH_SELECTION& selection = m_selectionTool->RequestSelection( justifiableItems );
2853
2854 if( selection.GetSize() == 0 )
2855 return 0;
2856
2857 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.Front() );
2858 bool moving = item->IsMoving();
2859 SCH_COMMIT localCommit( m_toolMgr );
2860 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
2861
2862 if( !commit )
2863 commit = &localCommit;
2864
2865 auto setJustify =
2866 [&]( EDA_TEXT* aTextItem )
2867 {
2868 if( aEvent.Matches( ACTIONS::leftJustify.MakeEvent() ) )
2869 aTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
2870 else if( aEvent.Matches( ACTIONS::centerJustify.MakeEvent() ) )
2871 aTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
2872 else
2873 aTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
2874 };
2875
2876 for( EDA_ITEM* edaItem : selection )
2877 {
2878 item = static_cast<SCH_ITEM*>( edaItem );
2879
2880 if( !moving )
2881 commit->Modify( item, m_frame->GetScreen() );
2882
2883 if( item->Type() == SCH_FIELD_T )
2884 {
2885 setJustify( static_cast<SCH_FIELD*>( item ) );
2886
2887 // Now that we're re-justifying a field, they're no longer autoplaced.
2888 static_cast<SCH_ITEM*>( item->GetParent() )->SetFieldsAutoplaced( AUTOPLACE_NONE );
2889 }
2890 else if( item->Type() == SCH_TEXT_T )
2891 {
2892 setJustify( static_cast<SCH_TEXT*>( item ) );
2893 }
2894 else if( item->Type() == SCH_TEXTBOX_T )
2895 {
2896 setJustify( static_cast<SCH_TEXTBOX*>( item ) );
2897 }
2898 else if( item->Type() == SCH_LABEL_T )
2899 {
2900 SCH_LABEL* label = static_cast<SCH_LABEL*>( item );
2901
2902 if( label->GetTextAngle() == ANGLE_HORIZONTAL )
2903 setJustify( label );
2904 }
2905
2906 m_frame->UpdateItem( item, false, true );
2907 }
2908
2909 // Update R-Tree for modified items
2910 for( EDA_ITEM* selected : selection )
2911 updateItem( selected, true );
2912
2913 if( item->IsMoving() )
2914 {
2916 }
2917 else
2918 {
2919 SCH_SELECTION selectionCopy = selection;
2920
2921 if( selection.IsHover() )
2923
2924 if( !localCommit.Empty() )
2925 {
2926 if( aEvent.Matches( ACTIONS::leftJustify.MakeEvent() ) )
2927 localCommit.Push( _( "Left Justify" ) );
2928 else if( aEvent.Matches( ACTIONS::centerJustify.MakeEvent() ) )
2929 localCommit.Push( _( "Center Justify" ) );
2930 else
2931 localCommit.Push( _( "Right Justify" ) );
2932 }
2933 }
2934
2935 return 0;
2936}
2937
2938
2940{
2941 bool isSlice = aEvent.Matches( SCH_ACTIONS::slice.MakeEvent() );
2944 SCH_SCREEN* screen = m_frame->GetScreen();
2945 SCH_COMMIT commit( m_toolMgr );
2946 std::vector<SCH_LINE*> lines;
2947
2948 // Save the current orthogonal mode so we can restore it later
2949 static enum LINE_MODE lineMode = LINE_MODE::LINE_MODE_90;
2950 static bool lineModeChanged = false;
2951
2952 auto revertLineMode =
2953 [&]()
2954 {
2955 if( lineModeChanged )
2956 {
2957 if( lineMode == LINE_MODE::LINE_MODE_90 )
2959 else if( lineMode == LINE_MODE::LINE_MODE_45)
2961
2962 lineModeChanged = false;
2963 }
2964 };
2965
2966 for( EDA_ITEM* item : selection )
2967 {
2968 if( item->Type() == SCH_LINE_T )
2969 lines.push_back( static_cast<SCH_LINE*>( item ) );
2970 }
2971
2973
2974 for( SCH_LINE* line : lines )
2975 {
2976 SCH_LINE* newLine;
2977
2978 // We let the user select the break point if they're on a single line
2979 if( lines.size() == 1 && line->HitTest( cursorPos ) && !line->IsEndPoint( cursorPos ) )
2980 m_frame->Schematic().BreakSegment( &commit, line, cursorPos, &newLine, screen );
2981 else
2982 m_frame->Schematic().BreakSegment( &commit, line, line->GetMidPoint(), &newLine, screen );
2983
2984 // Make sure both endpoints are deselected
2985 newLine->ClearFlags( ENDPOINT | STARTPOINT );
2986 line->SetFlags( ENDPOINT );
2987
2988 // If we're a break, we want to drag both wires.
2989 // Side note: the drag/move tool only checks whether the first item is
2990 // new to determine if it should append undo or not, someday this should
2991 // be cleaned up and explictly controlled but for now the newLine
2992 // selection addition must be after the existing line.
2993 if( !isSlice )
2994 {
2995 m_selectionTool->AddItemToSel( newLine );
2996 newLine->SetFlags( STARTPOINT );
2997 }
2998 }
2999
3000 if( !lines.empty() )
3001 {
3002 if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
3003 {
3004 if( cfg->m_Drawing.line_mode != LINE_MODE::LINE_MODE_FREE )
3005 {
3006 lineMode = (enum LINE_MODE) cfg->m_Drawing.line_mode;
3007 lineModeChanged = true;
3009 }
3010 }
3011
3013
3014 if( m_toolMgr->RunSynchronousAction( SCH_ACTIONS::drag, &commit, isSlice ) )
3015 {
3016 commit.Push( isSlice ? _( "Slice Wire" ) : _( "Break Wire" ) );
3017
3018 // Breaking wires is usually a repeated action, e.g. to add bends
3019 if( !isSlice )
3021 else
3022 revertLineMode();
3023 }
3024 else
3025 {
3026 commit.Revert();
3027 revertLineMode();
3028 }
3029 }
3030
3031 if( selection.IsHover() )
3033
3034 return 0;
3035}
3036
3037
3039{
3041 SCH_SHEET* sheet = (SCH_SHEET*) selection.Front();
3042 SCH_COMMIT commit( m_toolMgr );
3043
3044 if( !sheet || !sheet->HasUndefinedPins() )
3045 return 0;
3046
3047 if( !IsOK( m_frame, _( "Do you wish to delete the unreferenced pins from this sheet?" ) ) )
3048 return 0;
3049
3050 commit.Modify( sheet, m_frame->GetScreen() );
3051
3052 sheet->CleanupSheet();
3053
3054 updateItem( sheet, true );
3055
3056 commit.Push( _( "Cleanup Sheet Pins" ) );
3057
3058 if( selection.IsHover() )
3060
3061 return 0;
3062}
3063
3064
3066{
3068
3069 if( selection.GetSize() > 1 )
3070 return 0;
3071
3072 SCH_SHEET* sheet = (SCH_SHEET*) selection.Front();
3073
3075
3076 SCH_SCREEN* screen;
3077
3078 if( sheet )
3079 {
3080 // When changing the page number of a selected sheet, the current screen owns the sheet.
3081 screen = m_frame->GetScreen();
3082
3083 instance.push_back( sheet );
3084 }
3085 else
3086 {
3087 SCH_SHEET_PATH prevInstance = instance;
3088
3089 // When change the page number in the screen, the previous screen owns the sheet.
3090 if( prevInstance.size() )
3091 {
3092 prevInstance.pop_back();
3093 screen = prevInstance.LastScreen();
3094 }
3095 else
3096 {
3097 // The root sheet and root screen are effectively the same thing.
3098 screen = m_frame->GetScreen();
3099 }
3100
3101 sheet = m_frame->GetCurrentSheet().Last();
3102 }
3103
3104 wxString msg;
3105 wxString sheetPath = instance.PathHumanReadable( false );
3106 wxString pageNumber = instance.GetPageNumber();
3107
3108 msg.Printf( _( "Enter page number for sheet path%s" ),
3109 ( sheetPath.Length() > 20 ) ? "\n" + sheetPath : " " + sheetPath );
3110
3111 wxTextEntryDialog dlg( m_frame, msg, _( "Edit Sheet Page Number" ), pageNumber );
3112
3113 dlg.SetTextValidator( wxFILTER_ALPHANUMERIC ); // No white space.
3114
3115 if( dlg.ShowModal() == wxID_CANCEL || dlg.GetValue() == instance.GetPageNumber() )
3116 return 0;
3117
3118 SCH_COMMIT commit( m_frame );
3119
3120 commit.Modify( sheet, screen );
3121
3122 instance.SetPageNumber( dlg.GetValue() );
3123
3124 if( instance == m_frame->GetCurrentSheet() )
3125 {
3126 m_frame->GetScreen()->SetPageNumber( dlg.GetValue() );
3128 }
3129
3130 commit.Push( wxS( "Change Sheet Page Number" ) );
3131
3132 if( selection.IsHover() )
3134
3135 return 0;
3136}
3137
3138
3140{
3141 const ACTIONS::INCREMENT incParam = aEvent.Parameter<ACTIONS::INCREMENT>();
3142 static const std::vector<KICAD_T> incrementable = { SCH_LABEL_T, SCH_GLOBAL_LABEL_T,
3144 SCH_SELECTION& selection = m_selectionTool->RequestSelection( incrementable );
3145
3146 if( selection.Empty() )
3147 return 0;
3148
3149 KICAD_T type = selection.Front()->Type();
3150 bool allSameType = true;
3151
3152 for( EDA_ITEM* item : selection )
3153 {
3154 if( item->Type() != type )
3155 {
3156 allSameType = false;
3157 break;
3158 }
3159 }
3160
3161 // Incrementing multiple types at once seems confusing
3162 // though it would work.
3163 if( !allSameType )
3164 return 0;
3165
3166 STRING_INCREMENTER incrementer;
3167 // In schematics, it's probably less common to be operating
3168 // on pin numbers which are usually IOSQXZ-skippy.
3169 incrementer.SetSkipIOSQXZ( false );
3170
3171 // If we're coming via another action like 'Move', use that commit
3172 SCH_COMMIT localCommit( m_toolMgr );
3173 SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
3174
3175 if( !commit )
3176 commit = &localCommit;
3177
3178 const auto modifyItem =
3179 [&]( EDA_ITEM& aItem )
3180 {
3181 if( aItem.IsNew() )
3183 else
3184 commit->Modify( &aItem, m_frame->GetScreen() );
3185 };
3186
3187 for( EDA_ITEM* item : selection )
3188 {
3189 switch( item->Type() )
3190 {
3191 case SCH_LABEL_T:
3192 case SCH_GLOBAL_LABEL_T:
3193 case SCH_HIER_LABEL_T:
3194 case SCH_TEXT_T:
3195 {
3196 SCH_TEXT& label = static_cast<SCH_TEXT&>( *item );
3197
3198 std::optional<wxString> newLabel = incrementer.Increment( label.GetText(),
3199 incParam.Delta,
3200 incParam.Index );
3201
3202 if( newLabel )
3203 {
3204 modifyItem( label );
3205 label.SetText( *newLabel );
3206 }
3207 break;
3208 }
3209 default:
3210 // No increment for other items (yet)
3211 break;
3212 }
3213 }
3214
3215 commit->Push( _( "Increment" ) );
3216
3217 if( selection.IsHover() )
3219
3220 return 0;
3221}
3222
3223
3225{
3226 return m_toolMgr->RunAction( SCH_ACTIONS::importSheet, aEvent.Parameter<wxString*>() );
3227}
3228
3229
3231 std::set<std::pair<SCH_SYMBOL*, SCH_SCREEN*>>& aCollectedUnits )
3232{
3233 for( EDA_ITEM* item : aSelection )
3234 {
3235 if( item->Type() == SCH_SYMBOL_T )
3236 {
3237 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
3238
3239 aCollectedUnits.insert( { symbol, m_frame->GetScreen() } );
3240
3241 // The attributes should be kept in sync in multi-unit parts.
3242 // Of course the symbol must be annotated to collect other units.
3243 if( symbol->IsAnnotated( &m_frame->GetCurrentSheet() ) )
3244 {
3245 wxString ref = symbol->GetRef( &m_frame->GetCurrentSheet() );
3246 int unit = symbol->GetUnit();
3247 LIB_ID libId = symbol->GetLibId();
3248
3249 for( SCH_SHEET_PATH& sheet : m_frame->Schematic().Hierarchy() )
3250 {
3251 SCH_SCREEN* screen = sheet.LastScreen();
3252 std::vector<SCH_SYMBOL*> otherUnits;
3253
3254 CollectOtherUnits( ref, unit, libId, sheet, &otherUnits );
3255
3256 for( SCH_SYMBOL* otherUnit : otherUnits )
3257 aCollectedUnits.insert( { otherUnit, screen } );
3258 }
3259 }
3260 }
3261 }
3262}
3263
3264
3266{
3268 SCH_COMMIT commit( m_toolMgr );
3269
3270 std::set<std::pair<SCH_SYMBOL*, SCH_SCREEN*>> collectedUnits;
3271
3272 collectUnits( selection, collectedUnits );
3273 bool new_state = false;
3274
3275 for( const auto& [symbol, _] : collectedUnits )
3276 {
3277 if( ( aEvent.IsAction( &SCH_ACTIONS::setDNP ) && !symbol->GetDNP() )
3278 || ( aEvent.IsAction( &SCH_ACTIONS::setExcludeFromSimulation ) && !symbol->GetExcludedFromSim() )
3279 || ( aEvent.IsAction( &SCH_ACTIONS::setExcludeFromBOM ) && !symbol->GetExcludedFromBOM() )
3280 || ( aEvent.IsAction( &SCH_ACTIONS::setExcludeFromBoard ) && !symbol->GetExcludedFromBoard() ) )
3281 {
3282 new_state = true;
3283 break;
3284 }
3285 }
3286
3287 for( const auto& [symbol, screen] : collectedUnits )
3288 {
3289 commit.Modify( symbol, screen );
3290
3291 if( aEvent.IsAction( &SCH_ACTIONS::setDNP ) )
3292 symbol->SetDNP( new_state );
3293
3295 symbol->SetExcludedFromSim( new_state );
3296
3298 symbol->SetExcludedFromBOM( new_state );
3299
3301 symbol->SetExcludedFromBoard( new_state );
3302 }
3303
3304 if( !commit.Empty() )
3305 commit.Push( _( "Toggle Attribute" ) );
3306
3307 if( selection.IsHover() )
3309
3310 return 0;
3311}
3312
3313
3315{
3316 // clang-format off
3322 Go( &SCH_EDIT_TOOL::Swap, SCH_ACTIONS::swap.MakeEvent() );
3325
3331
3353
3356
3361
3365
3367 // clang-format on
3368}
const char * name
Definition: DXF_plotter.cpp:62
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:114
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:224
static TOOL_ACTION unselectItem
Definition: actions.h:225
static TOOL_ACTION copy
Definition: actions.h:78
static TOOL_ACTION pickerTool
Definition: actions.h:250
static TOOL_ACTION pasteSpecial
Definition: actions.h:81
static TOOL_ACTION groupProperties
Definition: actions.h:244
static TOOL_ACTION rightJustify
Definition: actions.h:89
static TOOL_ACTION pageSettings
Definition: actions.h:63
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition: actions.h:211
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:221
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:156
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...
Define the structure of a menu based on ACTIONs.
Definition: action_menu.h:49
TOOL_MANAGER * getToolManager() const
Return an instance of TOOL_MANAGER class.
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.
Definition: action_menu.cpp:92
void SetIcon(BITMAPS aIcon)
Assign an icon for the entry.
Definition: action_menu.cpp:78
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 SetPageNumber(const wxString &aPageNumber)
Definition: base_screen.h:79
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
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:83
int m_Threshold
Definition: collector.h:236
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition: commit.h:91
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:85
void Unstage(EDA_ITEM *aItem, BASE_SCREEN *aScreen)
Definition: commit.cpp:122
bool Empty() const
Definition: commit.h:152
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:107
COMMIT & Removed(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Definition: commit.h:97
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.
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 ShowQuasiModal()
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
virtual void ClearUndoRedoList()
Clear the undo and redo list using ClearUndoORRedoList()
void ShowInfoBarWarning(const wxString &aWarningMsg, bool aShowCloseButton=false)
Show the WX_INFOBAR displayed on the top of the canvas with a message and a warning icon on the left ...
VECTOR2I GetNearestGridPosition(const VECTOR2I &aPosition) const
Return the nearest aGridSize location to aPosition.
VECTOR2I GetNearestHalfGridPosition(const VECTOR2I &aPosition) const
Return the nearest aGridSize / 2 location to aPosition.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
A set of EDA_ITEMs (i.e., without duplicates).
Definition: eda_group.h:46
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:98
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:272
virtual void SetPosition(const VECTOR2I &aPos)
Definition: eda_item.h:273
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:110
EDA_ITEM_FLAGS GetEditFlags() const
Definition: eda_item.h:148
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:142
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:144
bool IsSelected() const
Definition: eda_item.h:127
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:192
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:113
EDA_ITEM * GetParent() const
Definition: eda_item.h:112
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:146
bool IsMoving() const
Definition: eda_item.h:125
bool IsNew() const
Definition: eda_item.h:124
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:219
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:79
bool IsItalic() const
Definition: eda_text.h:166
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:144
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:533
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:97
virtual bool IsVisible() const
Definition: eda_text.h:184
void SetTextPos(const VECTOR2I &aPoint)
Definition: eda_text.cpp:578
KIFONT::FONT * GetFont() const
Definition: eda_text.h:244
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition: eda_text.cpp:433
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:417
wxString GetHyperlink() const
Definition: eda_text.h:398
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:197
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.cpp:284
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition: eda_text.cpp:335
bool IsBold() const
Definition: eda_text.h:181
void SetHyperlink(wxString aLink)
Definition: eda_text.h:399
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition: eda_text.h:200
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:270
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:299
int GetTextThickness() const
Definition: eda_text.h:125
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition: eda_text.cpp:307
void SetFont(KIFONT::FONT *aFont)
Definition: eda_text.cpp:499
VECTOR2I GetTextSize() const
Definition: eda_text.h:258
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:409
PANEL_ANNOTATE m_AnnotatePanel
AUTOPLACE_FIELDS m_AutoplaceFields
bool empty() const
Definition: sch_rtree.h:179
DS_PROXY_VIEW_ITEM * GetDrawingSheet() const
Definition: sch_view.h:120
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:1451
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:55
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
Definition: kiway_player.h:65
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:395
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
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:217
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition: picker_tool.h:92
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition: picker_tool.h:81
void SetSnapping(bool aSnap)
Definition: picker_tool.h:66
void ClearHandlers()
Definition: picker_tool.h:68
void SetCursor(KICURSOR aCursor)
Definition: picker_tool.h:64
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
Definition: picker_tool.h:112
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.
void OnItemsAdded(std::vector< SCH_ITEM * > &aNewItems)
Must be used if Add() is used using a BULK_x ADD_MODE to generate a change event for listeners.
Definition: schematic.cpp:835
void BreakSegment(SCH_COMMIT *aCommit, SCH_LINE *aSegment, const VECTOR2I &aPoint, SCH_LINE **aNewSegment, SCH_SCREEN *aScreen)
Break a single segment into two at the specified point.
Definition: schematic.cpp:1056
void CleanUp(SCH_COMMIT *aCommit, SCH_SCREEN *aScreen=nullptr)
Perform routine schematic cleaning including breaking wire and buses and deleting identical objects s...
Definition: schematic.cpp:1117
void OnItemsRemoved(std::vector< SCH_ITEM * > &aRemovedItems)
Must be used if Remove() is used using a BULK_x REMOVE_MODE to generate a change event for listeners.
Definition: schematic.cpp:841
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:356
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
Definition: schematic.cpp:258
SCH_SHEET & Root() const
Definition: schematic.h:140
void RefreshHierarchy()
Definition: schematic.cpp:266
static TOOL_ACTION rotateCCW
Definition: sch_actions.h:121
static TOOL_ACTION placeClassLabel
Definition: sch_actions.h:79
static TOOL_ACTION placeNextSymbolUnit
Definition: sch_actions.h:67
static TOOL_ACTION editValue
Definition: sch_actions.h:127
static TOOL_ACTION setExcludeFromBOM
Definition: sch_actions.h:184
static TOOL_ACTION mirrorV
Definition: sch_actions.h:122
static TOOL_ACTION clearHighlight
Definition: sch_actions.h:297
static TOOL_ACTION swap
Definition: sch_actions.h:124
static TOOL_ACTION placeGlobalLabel
Definition: sch_actions.h:80
static TOOL_ACTION changeSymbols
Definition: sch_actions.h:153
static TOOL_ACTION updateSymbol
Definition: sch_actions.h:156
static TOOL_ACTION autoplaceFields
Definition: sch_actions.h:129
static TOOL_ACTION changeSymbol
Definition: sch_actions.h:155
static TOOL_ACTION showDeMorganAlternate
Definition: sch_actions.h:132
static TOOL_ACTION toCLabel
Definition: sch_actions.h:135
static TOOL_ACTION properties
Definition: sch_actions.h:125
static TOOL_ACTION editReference
Definition: sch_actions.h:126
static TOOL_ACTION breakWire
Definition: sch_actions.h:140
static TOOL_ACTION toggleDeMorgan
Definition: sch_actions.h:130
static TOOL_ACTION placeHierLabel
Definition: sch_actions.h:81
static TOOL_ACTION placeLabel
Definition: sch_actions.h:78
static TOOL_ACTION toText
Definition: sch_actions.h:138
static TOOL_ACTION toHLabel
Definition: sch_actions.h:136
static TOOL_ACTION lineMode45
Definition: sch_actions.h:266
static TOOL_ACTION rotateCW
Definition: sch_actions.h:120
static TOOL_ACTION importSheet
Definition: sch_actions.h:87
static TOOL_ACTION drag
Definition: sch_actions.h:118
static TOOL_ACTION toLabel
Definition: sch_actions.h:134
static TOOL_ACTION setDNP
Definition: sch_actions.h:187
static TOOL_ACTION editWithLibEdit
Definition: sch_actions.h:172
static TOOL_ACTION cleanupSheetPins
Definition: sch_actions.h:229
static TOOL_ACTION mirrorH
Definition: sch_actions.h:123
static TOOL_ACTION setExcludeFromSimulation
Definition: sch_actions.h:185
static TOOL_ACTION lineMode90
Definition: sch_actions.h:265
static TOOL_ACTION ddAppendFile
Definition: sch_actions.h:303
static TOOL_ACTION slice
Definition: sch_actions.h:141
static TOOL_ACTION placeSchematicText
Definition: sch_actions.h:92
static TOOL_ACTION toTextBox
Definition: sch_actions.h:139
static TOOL_ACTION lineModeFree
Definition: sch_actions.h:264
static TOOL_ACTION updateSymbols
Definition: sch_actions.h:154
static TOOL_ACTION enterSheet
Definition: sch_actions.h:218
static TOOL_ACTION editFootprint
Definition: sch_actions.h:128
static TOOL_ACTION repeatDrawItem
Definition: sch_actions.h:119
static TOOL_ACTION editTextAndGraphics
Definition: sch_actions.h:230
static TOOL_ACTION editPageNumber
Definition: sch_actions.h:160
static TOOL_ACTION showDeMorganStandard
Definition: sch_actions.h:131
static TOOL_ACTION toGLabel
Definition: sch_actions.h:137
static TOOL_ACTION setExcludeFromBoard
Definition: sch_actions.h:186
static TOOL_ACTION move
Definition: sch_actions.h:117
void RemoveFromScreen(EDA_ITEM *aItem, SCH_SCREEN *aScreen) override
Remove an item from the screen (and view) aScreen is the screen the item is located on,...
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
EESCHEMA_SETTINGS * eeconfig() const
void AddToScreen(EDA_ITEM *aItem, SCH_SCREEN *aScreen=nullptr) override
Add an item to the screen (and view) aScreen is the screen the item is located on,...
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
void Collect(SCH_SCREEN *aScreen, const std::vector< KICAD_T > &aScanTypes, const VECTOR2I &aPos, int aUnit=0, int aConvert=0)
Scan a EDA_ITEM using this class's Inspector method which does the collection.
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
Definition: sch_commit.cpp:489
virtual void Revert() override
Revert the commit by restoring the modified items state.
Definition: sch_commit.cpp:567
static SELECTION_CONDITION SingleMultiFunctionPin
static SELECTION_CONDITION SingleSymbol
static SELECTION_CONDITION MultipleSymbolsOrPower
static SELECTION_CONDITION AllPinsOrSheetPins
static SELECTION_CONDITION SingleDeMorganSymbol
static SELECTION_CONDITION SingleSymbolOrPower
static SELECTION_CONDITION SingleMultiUnitSymbol
Tool responsible for drawing/placing items (symbols, wires, buses, labels, etc.).
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
Schematic editor (Eeschema) main window.
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag and update other data struc...
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void AnnotateSymbols(SCH_COMMIT *aCommit, ANNOTATE_SCOPE_T aAnnotateScope, ANNOTATE_ORDER_T aSortOption, ANNOTATE_ALGO_T aAlgoOption, bool aRecursive, int aStartNumber, bool aResetAnnotation, bool aRepairTimestamps, REPORTER &aReporter)
Annotate the symbols in the schematic that are not currently annotated.
Definition: annotate.cpp:213
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
const std::vector< std::unique_ptr< SCH_ITEM > > & GetRepeatItems() const
Return the items which are to be repeated with the insert key.
bool EditSheetProperties(SCH_SHEET *aSheet, SCH_SHEET_PATH *aHierarchy, bool *aIsUndoable=nullptr, bool *aClearAnnotationNewItems=nullptr, bool *aUpdateHierarchyNavigator=nullptr, wxString *aSourceSheetFilename=nullptr)
Edit an existing sheet or add a new sheet to the schematic.
Definition: sheet.cpp:601
void UpdateHierarchyNavigator(bool aRefreshNetNavigator=true, bool aClear=false)
Update the hierarchy navigation tree and history.
void FlipBodyStyle(SCH_SYMBOL *aSymbol)
Definition: picksymbol.cpp:188
void OnPageSettingsChange() override
Called when modifying the page settings.
bool CheckSheetForRecursion(SCH_SHEET *aSheet, SCH_SHEET_PATH *aCurrentSheet)
Verify that aSheet will not cause a recursion error in aCurrentSheet.
Definition: sheet.cpp:54
const wxString & GetHighlightedConnection() const
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false, bool aUpdateRtree=false) override
Mark an item for refresh.
void AddCopyForRepeatItem(const SCH_ITEM *aItem)
void TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
void DeleteJunction(SCH_COMMIT *aCommit, SCH_ITEM *aItem)
Remove a given junction and heals any wire segments under the junction.
void SaveCopyForRepeatItem(const SCH_ITEM *aItem)
Clone aItem and owns that clone in this container.
int ChangeBodyStyle(const TOOL_EVENT &aEvent)
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
static const std::vector< KICAD_T > RotatableItems
Definition: sch_edit_tool.h:42
EDA_ITEM * m_pickerItem
int EditField(const TOOL_EVENT &aEvent)
int EditPageNumber(const TOOL_EVENT &aEvent)
int DoDelete(const TOOL_EVENT &aEvent)
Run the deletion tool.
bool Init() override
Init() is called once upon a registration of the tool.
int CleanupSheetPins(const TOOL_EVENT &aEvent)
void editFieldText(SCH_FIELD *aField)
int Mirror(const TOOL_EVENT &aEvent)
int GlobalEdit(const TOOL_EVENT &aEvent)
Delete the selected items, or the item under the cursor.
int SetAttribute(const TOOL_EVENT &aEvent)
Modify Attributes (DNP, Exclude, etc.) All attributes are set to true unless all symbols already have...
int Properties(const TOOL_EVENT &aEvent)
int Rotate(const TOOL_EVENT &aEvent)
int Increment(const TOOL_EVENT &aEvent)
Increment/decrement something about an item.
void collectUnits(const SCH_SELECTION &aSelection, std::set< std::pair< SCH_SYMBOL *, SCH_SCREEN * > > &aCollectedUnits)
Set up handlers for various events.
int BreakWire(const TOOL_EVENT &aEvent)
int DdAppendFile(const TOOL_EVENT &aEvent)
Drag and drop.
int JustifyText(const TOOL_EVENT &aEvent)
int AutoplaceFields(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 InteractiveDelete(const TOOL_EVENT &aEvent)
int RepeatDrawItem(const TOOL_EVENT &aEvent)
bool IsMandatory() const
Definition: sch_field.cpp:1359
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition: sch_field.cpp:873
VECTOR2I GetPosition() const override
Definition: sch_field.cpp:1337
FIELD_T GetId() const
Definition: sch_field.h:116
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
Definition: sch_field.cpp:1117
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
Definition: sch_field.cpp:1103
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_field.cpp:1317
void SetText(const wxString &aText) override
Definition: sch_field.cpp:1089
VECTOR2I GetParentPosition() const
Definition: sch_field.cpp:1353
A set of SCH_ITEMs (i.e., without duplicates).
Definition: sch_group.h:52
int CrossProbe(const TOOL_EVENT &aEvent)
Called when clicking on a item:
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:168
SCH_ITEM * Duplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr, bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:137
virtual bool IsConnectable() const
Definition: sch_item.h:498
virtual void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo)
Definition: sch_item.h:600
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode)
Definition: sch_item.h:602
const SYMBOL * GetParentSymbol() const
Definition: sch_item.cpp:252
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:246
int GetBodyStyle() const
Definition: sch_item.h:248
virtual void MirrorHorizontally(int aCenter)
Mirror item horizontally about aCenter.
Definition: sch_item.h:377
virtual void Move(const VECTOR2I &aMoveVector)
Move the item by aMoveVector to a new position.
Definition: sch_item.h:369
int GetUnit() const
Definition: sch_item.h:239
void SetFieldsAutoplaced(AUTOPLACE_ALGO aAlgo)
Definition: sch_item.h:598
virtual void Rotate(const VECTOR2I &aCenter, bool aRotateCCW)
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition: sch_item.h:394
AUTOPLACE_ALGO GetFieldsAutoplaced() const
Return whether the fields have been automatically placed.
Definition: sch_item.h:597
wxString GetClass() const override
Return the class name.
Definition: sch_item.h:178
bool IsGroupableType() const
Definition: sch_item.cpp:105
virtual bool HasLineStroke() const
Check if this schematic item has line stoke properties.
Definition: sch_item.h:613
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition: sch_item.h:513
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:386
void AddFields(const std::vector< SCH_FIELD > &aFields)
Definition: sch_label.h:218
void MirrorHorizontally(int aCenter) override
Mirror item horizontally about aCenter.
Definition: sch_label.cpp:465
SPIN_STYLE GetSpinStyle() const
Definition: sch_label.cpp:351
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition: sch_label.h:177
LABEL_FLAG_SHAPE GetShape() const
Definition: sch_label.h:176
void MirrorVertically(int aCenter) override
Mirror item vertically about aCenter.
Definition: sch_label.cpp:484
std::vector< SCH_FIELD > & GetFields()
Definition: sch_label.h:205
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Definition: sch_label.cpp:316
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:376
VECTOR2I GetEndPoint() const
Definition: sch_line.h:144
VECTOR2I GetStartPoint() const
Definition: sch_line.h:139
const std::map< wxString, ALT > & GetAlternates() const
Definition: sch_pin.h:133
const wxString & GetName() const
Definition: sch_pin.cpp:357
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:758
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.
Definition: sch_screen.cpp:482
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition: sch_screen.h:117
const wxString & GetFileName() const
Definition: sch_screen.h:152
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.
Definition: sch_screen.cpp:399
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:123
void ClearAnnotation(SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear the annotation for the symbols in aSheetPath on the screen.
int ClearSelection(const TOOL_EVENT &aEvent)
Select all visible items in sheet.
void GuessSelectionCandidates(SCH_COLLECTOR &collector, const VECTOR2I &aPos)
Apply heuristics to try and determine a single object when multiple are found under the cursor.
SCH_SELECTION & GetSelection()
SCH_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, bool aPromoteCellSelections=false, bool aPromoteGroups=false)
Return either an existing selection (filtered), or the selection at the current cursor position if th...
SCH_GROUP * GetEnteredGroup()
void SetPosition(const VECTOR2I &aPos) override
Definition: sch_shape.h:85
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_shape.cpp:312
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...
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false) const
Return the sheet path in a human readable form made from the sheet names.
SCH_SCREEN * LastScreen()
wxString GetPageNumber() const
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
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.
Definition: sch_sheet_pin.h:66
SHEET_SIDE GetSide() const
SCH_SHEET * GetParent() const
Get the parent sheet object of this sheet pin.
void SetSide(SHEET_SIDE aEdge)
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:47
void SetFileName(const wxString &aFilename)
Definition: sch_sheet.h:327
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:321
VECTOR2I GetRotationCenter() const
Rotating around the boundingBox's center can cause walking when the sheetname or filename is longer t...
Definition: sch_sheet.cpp:722
void CleanupSheet()
Delete sheet label which do not have a corresponding hierarchical label.
Definition: sch_sheet.cpp:585
void RemovePin(const SCH_SHEET_PIN *aSheetPin)
Remove aSheetPin from the sheet.
Definition: sch_sheet.cpp:409
bool HasUndefinedPins() const
Check all sheet labels against schematic for undefined hierarchical labels.
Definition: sch_sheet.cpp:471
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:116
const BOX2I GetBodyBoundingBox() const
Return a bounding box for the sheet body but not the fields.
Definition: sch_sheet.cpp:690
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_sheet.cpp:711
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition: sch_sheet.cpp:904
Schematic symbol object.
Definition: sch_symbol.h:75
wxString GetUnitDisplayName(int aUnit, bool aLabel) const override
Return the display name for a given unit aUnit.
Definition: sch_symbol.cpp:444
bool IsAnnotated(const SCH_SHEET_PATH *aSheet) const
Check if the symbol has a valid annotation (reference) for the given sheet path.
Definition: sch_symbol.cpp:636
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
Automatically orient all the fields in 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.
Definition: sch_symbol.cpp:210
const LIB_ID & GetLibId() const override
Definition: sch_symbol.h:164
int GetOrientation() const override
Get the display symbol orientation.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:183
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
Definition: sch_symbol.cpp:558
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.
Definition: sch_symbol.cpp:760
int GetMarginBottom() const
Definition: sch_textbox.h:66
int GetLegacyTextMargin() const
Definition: sch_textbox.cpp:76
int GetMarginLeft() const
Definition: sch_textbox.h:63
int GetMarginRight() const
Definition: sch_textbox.h:65
int GetMarginTop() const
Definition: sch_textbox.h:64
virtual void Rotate90(bool aClockwise)
Definition: sch_text.cpp:209
virtual void MirrorSpinStyle(bool aLeftRight)
Definition: sch_text.cpp:221
A foundation class for a tool operating on a schematic or symbol.
Definition: sch_tool_base.h:49
void updateItem(EDA_ITEM *aItem, bool aUpdateRTree) const
Similar to getView()->Update(), but handles items that are redrawn by their parents and updating the ...
void saveCopyInUndoList(EDA_ITEM *aItem, UNDO_REDO aType, bool aAppend=false, bool aDirtyConnectivity=true)
bool Init() override
Init() is called once upon a registration of the tool.
Definition: sch_tool_base.h:65
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.
void BrightenItem(EDA_ITEM *aItem)
int AddItemToSel(const TOOL_EVENT &aEvent)
void UnbrightenItem(EDA_ITEM *aItem)
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
virtual KIGFX::VIEW_ITEM * GetItem(unsigned int aIdx) const override
Definition: selection.cpp:75
const std::deque< EDA_ITEM * > GetItems() const
Definition: selection.h:126
VECTOR2I GetReferencePoint() const
Definition: selection.cpp:169
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
Definition: selection.cpp:263
bool OnlyContains(std::vector< KICAD_T > aList) const
Checks if all items in the selection have a type in aList.
Definition: selection.cpp:211
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
Definition: selection.cpp:155
unsigned CCWRotationsTo(const SPIN_STYLE &aOther) const
Get CCW rotation needed to get to the given spin style.
Definition: sch_label.cpp:157
Heuristically increment a string's n'th part from the right.
Definition: increment.h:48
void SetSkipIOSQXZ(bool aSkip)
If a alphabetic part is found, skip the letters I, O, S, Q, X, Z.
Definition: increment.h:54
std::optional< wxString > Increment(const wxString &aStr, int aDelta, size_t aRightIndex) const
Increment the n-th part from the right of the given string.
Definition: increment.cpp:86
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.
TOOL_EVENT MakeEvent() const
Return the event associated with the action (i.e.
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:44
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:220
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:38
Generic, UI-independent tool event.
Definition: tool_event.h:168
bool DisableGridSnapping() const
Definition: tool_event.h:368
bool Matches(const TOOL_EVENT &aEvent) const
Test whether two events match in terms of category & action or command.
Definition: tool_event.h:389
COMMIT * Commit() const
Definition: tool_event.h:280
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
Definition: tool_event.cpp:82
T Parameter() const
Return a parameter assigned to the event.
Definition: tool_event.h:465
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
void Activate()
Run the tool.
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
Definition: tool_manager.h:235
bool RunSynchronousAction(const TOOL_ACTION &aAction, COMMIT *aCommit, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:197
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:251
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
#define IGNORE_PARENT_GROUP
Definition: eda_item.h:55
#define IS_NEW
New item, just created.
#define SELECTED_BY_DRAG
Item was algorithmically selected as a dragged item.
#define STRUCT_DELETED
flag indication structures to be erased
#define ENDPOINT
ends. (Used to support dragging.)
#define STARTPOINT
When a line is selected, these flags indicate which.
@ ID_POPUP_SCH_PIN_TRICKS_HIER_LABEL
Definition: eeschema_id.h:95
@ ID_POPUP_SCH_PIN_TRICKS_WIRE
Definition: eeschema_id.h:93
@ ID_POPUP_SCH_ALT_PIN_FUNCTION
Definition: eeschema_id.h:99
@ ID_POPUP_SCH_SELECT_UNIT1
Definition: eeschema_id.h:83
@ ID_POPUP_SCH_SELECT_UNIT
Definition: eeschema_id.h:82
@ ID_POPUP_SCH_SELECT_BASE
Definition: eeschema_id.h:88
@ ID_POPUP_SCH_SELECT_ALT
Definition: eeschema_id.h:89
@ ID_POPUP_SCH_PIN_TRICKS_NET_LABEL
Definition: eeschema_id.h:94
@ ID_POPUP_SCH_PIN_TRICKS_NO_CONNECT
Definition: eeschema_id.h:92
@ ID_POPUP_SCH_SELECT_UNIT_END
Definition: eeschema_id.h:86
@ ID_POPUP_SCH_ALT_PIN_FUNCTION_END
Definition: eeschema_id.h:100
@ ID_POPUP_SCH_PIN_TRICKS_GLOBAL_LABEL
Definition: eeschema_id.h:96
LINE_MODE
@ FRAME_SCH_SYMBOL_EDITOR
Definition: frame_type.h:35
@ LAYER_NOTES
Definition: layer_ids.h:457
@ LAYER_SCHEMATIC_DRAWINGSHEET
Definition: layer_ids.h:485
#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
see class PGM_BASE
void CollectOtherUnits(const wxString &aRef, int aUnit, const LIB_ID &aLibId, SCH_SHEET_PATH &aSheet, std::vector< SCH_SYMBOL * > *otherUnits)
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...
#define HITTEST_THRESHOLD_PIXELS
static std::vector< KICAD_T > deletableItems
const std::vector< KICAD_T > swappableItems
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
LABEL_FLAG_SHAPE
Definition: sch_label.h:99
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.
Definition: sch_sheet_pin.h:46
std::set< int > GetUnplacedUnitsForSymbol(const SCH_SYMBOL &aSym)
Get a list of unplaced (i.e.
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
Definition: string_utils.h:53
Functors that can be used to figure out how the action controls should be displayed in the UI and if ...
constexpr int MilsToIU(int mils) const
Definition: base_units.h:97
@ 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
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:174
@ SCH_TABLE_T
Definition: typeinfo.h:166
@ SCH_LINE_T
Definition: typeinfo.h:164
@ SCH_NO_CONNECT_T
Definition: typeinfo.h:161
@ SCH_SYMBOL_T
Definition: typeinfo.h:173
@ SCH_TABLECELL_T
Definition: typeinfo.h:167
@ SCH_ITEM_LOCATE_WIRE_T
Definition: typeinfo.h:187
@ SCH_FIELD_T
Definition: typeinfo.h:151
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:172
@ SCH_LABEL_T
Definition: typeinfo.h:168
@ SCH_SHEET_T
Definition: typeinfo.h:176
@ SCH_ITEM_LOCATE_BUS_T
Definition: typeinfo.h:188
@ SCH_MARKER_T
Definition: typeinfo.h:159
@ SCH_SHAPE_T
Definition: typeinfo.h:150
@ SCH_RULE_AREA_T
Definition: typeinfo.h:171
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:170
@ SCH_BUS_BUS_ENTRY_T
Definition: typeinfo.h:163
@ SCH_LABEL_LOCATE_ANY_T
Definition: typeinfo.h:192
@ SCH_ITEM_LOCATE_GRAPHIC_LINE_T
Definition: typeinfo.h:189
@ SCHEMATIC_T
Definition: typeinfo.h:205
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:175
@ SCH_TEXT_T
Definition: typeinfo.h:152
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:162
@ SCH_BITMAP_T
Definition: typeinfo.h:165
@ SCH_TEXTBOX_T
Definition: typeinfo.h:153
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:169
@ SCH_JUNCTION_T
Definition: typeinfo.h:160
@ SCH_PIN_T
Definition: typeinfo.h:154
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695