KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_drawing_tools.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-2023 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 "sch_sheet_path.h"
26#include <memory>
27
28#include <kiplatform/ui.h>
29#include <optional>
30#include <project_sch.h>
38#include <sch_actions.h>
39#include <sch_tool_utils.h>
40#include <sch_edit_frame.h>
41#include <pgm_base.h>
42#include <design_block.h>
44#include <eeschema_id.h>
45#include <confirm.h>
46#include <view/view_controls.h>
47#include <view/view.h>
48#include <sch_symbol.h>
49#include <sch_no_connect.h>
50#include <sch_group.h>
51#include <sch_line.h>
52#include <sch_junction.h>
53#include <sch_bus_entry.h>
54#include <sch_rule_area.h>
55#include <sch_text.h>
56#include <sch_textbox.h>
57#include <sch_table.h>
58#include <sch_tablecell.h>
59#include <sch_sheet.h>
60#include <sch_sheet_pin.h>
61#include <sch_label.h>
62#include <sch_bitmap.h>
63#include <schematic.h>
64#include <sch_commit.h>
65#include <scoped_set_reset.h>
66#include <symbol_library.h>
67#include <eeschema_settings.h>
69#include <dialogs/dialog_text_properties.h>
72#include <dialogs/dialog_table_properties.h>
75#include <string_utils.h>
77#include <wx/filedlg.h>
78#include <wx/msgdlg.h>
79
81 SCH_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveDrawing" ),
82 m_lastSheetPinType( LABEL_FLAG_SHAPE::L_INPUT ),
83 m_lastGlobalLabelShape( LABEL_FLAG_SHAPE::L_INPUT ),
84 m_lastNetClassFlagShape( LABEL_FLAG_SHAPE::F_ROUND ),
85 m_lastTextOrientation( SPIN_STYLE::RIGHT ),
86 m_lastTextBold( false ),
87 m_lastTextItalic( false ),
88 m_lastTextAngle( ANGLE_0 ),
89 m_lastTextboxAngle( ANGLE_0 ),
90 m_lastTextHJustify( GR_TEXT_H_ALIGN_CENTER ),
91 m_lastTextVJustify( GR_TEXT_V_ALIGN_CENTER ),
92 m_lastTextboxHJustify( GR_TEXT_H_ALIGN_LEFT ),
93 m_lastTextboxVJustify( GR_TEXT_V_ALIGN_TOP ),
94 m_lastFillStyle( FILL_T::NO_FILL ),
95 m_lastTextboxFillStyle( FILL_T::NO_FILL ),
96 m_lastFillColor( COLOR4D::UNSPECIFIED ),
97 m_lastTextboxFillColor( COLOR4D::UNSPECIFIED ),
98 m_lastStroke( 0, LINE_STYLE::DEFAULT, COLOR4D::UNSPECIFIED ),
99 m_lastTextboxStroke( 0, LINE_STYLE::DEFAULT, COLOR4D::UNSPECIFIED ),
100 m_mruPath( wxEmptyString ),
101 m_lastAutoLabelRotateOnPlacement( false ),
102 m_drawingRuleArea( false ),
103 m_inDrawingTool( false )
104{
105}
106
107
109{
111
112 auto belowRootSheetCondition =
113 [&]( const SELECTION& aSel )
114 {
115 return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
116 };
117
118 auto inDrawingRuleArea =
119 [&]( const SELECTION& aSel )
120 {
121 return m_drawingRuleArea;
122 };
123
124 CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
125 ctxMenu.AddItem( SCH_ACTIONS::leaveSheet, belowRootSheetCondition, 150 );
126 ctxMenu.AddItem( SCH_ACTIONS::closeOutline, inDrawingRuleArea, 200 );
127 ctxMenu.AddItem( SCH_ACTIONS::deleteLastPoint, inDrawingRuleArea, 200 );
128
129 return true;
130}
131
132
134{
136
137 SCH_SYMBOL* symbol = toolParams.m_Symbol;
138
139 // If we get a parameterised symbol, we probably just want to place that and get out of the placmeent tool,
140 // rather than popping up the chooser afterwards
141 bool placeOneOnly = symbol != nullptr;
142
144 std::vector<PICKED_SYMBOL>* historyList = nullptr;
145 bool ignorePrimePosition = false;
146 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
147 SCHEMATIC_SETTINGS& schSettings = m_frame->Schematic().Settings();
148 SCH_SCREEN* screen = m_frame->GetScreen();
149 bool keepSymbol = false;
150 bool placeAllUnits = false;
151
152 if( m_inDrawingTool )
153 return 0;
154
156
159 VECTOR2I cursorPos;
160
161 // First we need to get all instances of this sheet so we can annotate whatever symbols we place on all copies
162 SCH_SHEET_LIST hierarchy = m_frame->Schematic().Hierarchy();
164 newInstances.SortByPageNumbers();
165
166 // Get a list of all references in the schematic to avoid duplicates wherever they're placed
167 SCH_REFERENCE_LIST existingRefs;
168 hierarchy.GetSymbols( existingRefs );
169 existingRefs.SortByReferenceOnly();
170
171 if( aEvent.IsAction( &SCH_ACTIONS::placeSymbol ) )
172 {
173 historyList = &m_symbolHistoryList;
174 }
175 else if (aEvent.IsAction( &SCH_ACTIONS::placePower ) )
176 {
177 historyList = &m_powerHistoryList;
178 filter.FilterPowerSymbols( true );
179 }
180 else
181 {
182 wxFAIL_MSG( "PlaceSymbol(): unexpected request" );
183 }
184
185 m_frame->PushTool( aEvent );
186
187 auto addSymbol =
188 [this]( SCH_SYMBOL* aSymbol )
189 {
191 m_selectionTool->AddItemToSel( aSymbol );
192
193 aSymbol->SetFlags( IS_NEW | IS_MOVING );
194
196 m_view->AddToPreview( aSymbol, false ); // Add, but not give ownership
197
198 // Set IS_MOVING again, as AddItemToCommitAndScreen() will have cleared it.
199 aSymbol->SetFlags( IS_MOVING );
201 };
202
203 auto setCursor =
204 [&]()
205 {
206 m_frame->GetCanvas()->SetCurrentCursor( symbol ? KICURSOR::MOVING : KICURSOR::COMPONENT );
207 };
208
209 auto cleanup =
210 [&]()
211 {
214 delete symbol;
215 symbol = nullptr;
216
217 existingRefs.Clear();
218 hierarchy.GetSymbols( existingRefs );
219 existingRefs.SortByReferenceOnly();
220 };
221
222 auto annotate =
223 [&]()
224 {
226
227 // Then we need to annotate all instances by sheet
228 for( SCH_SHEET_PATH& instance : newInstances )
229 {
230 SCH_REFERENCE newReference( symbol, instance );
232 refs.AddItem( newReference );
233 refs.SetRefDesTracker( schSettings.m_refDesTracker );
234
235 if( cfg->m_AnnotatePanel.automatic || newReference.AlwaysAnnotate() )
236 {
239 schSettings.m_AnnotateStartNum, existingRefs, false,
240 &hierarchy );
241
242 refs.UpdateAnnotation();
243
244 // Update existing refs for next iteration
245 for( size_t i = 0; i < refs.GetCount(); i++ )
246 existingRefs.AddItem( refs[i] );
247 }
248 }
249
251 };
252
253 Activate();
254
255 // Must be done after Activate() so that it gets set into the correct context
256 getViewControls()->ShowCursor( true );
257
258 // Set initial cursor
259 setCursor();
260
261 // Prime the pump
262 if( symbol )
263 {
264 addSymbol( symbol );
265
266 if( toolParams.m_Reannotate )
267 annotate();
268
269 getViewControls()->WarpMouseCursor( getViewControls()->GetMousePosition( false ) );
270 }
271 else if( aEvent.HasPosition() )
272 {
273 m_toolMgr->PrimeTool( aEvent.Position() );
274 }
275 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
276 {
277 m_toolMgr->PrimeTool( { 0, 0 } );
278 ignorePrimePosition = true;
279 }
280
281 // Main loop: keep receiving events
282 while( TOOL_EVENT* evt = Wait() )
283 {
284 setCursor();
285 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
286 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
287
288 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
289 controls->ForceCursorPosition( true, cursorPos );
290
291 // The tool hotkey is interpreted as a click when drawing
292 bool isSyntheticClick = symbol && evt->IsActivate() && evt->HasPosition() && evt->Matches( aEvent );
293
294 if( evt->IsCancelInteractive() || ( symbol && evt->IsAction( &ACTIONS::undo ) ) )
295 {
297
298 if( symbol )
299 {
300 cleanup();
301 }
302 else
303 {
304 m_frame->PopTool( aEvent );
305 break;
306 }
307 }
308 else if( evt->IsActivate() && !isSyntheticClick )
309 {
310 if( symbol && evt->IsMoveTool() )
311 {
312 // we're already moving our own item; ignore the move tool
313 evt->SetPassEvent( false );
314 continue;
315 }
316
317 if( symbol )
318 {
319 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel symbol creation." ) );
320 evt->SetPassEvent( false );
321 continue;
322 }
323
324 if( evt->IsMoveTool() )
325 {
326 // leave ourselves on the stack so we come back after the move
327 break;
328 }
329 else
330 {
331 m_frame->PopTool( aEvent );
332 break;
333 }
334 }
335 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) || isSyntheticClick )
336 {
337 if( !symbol )
338 {
340
343
344 std::set<UTF8> unique_libid;
345 std::vector<PICKED_SYMBOL> alreadyPlaced;
346
347 for( SCH_SHEET_PATH& sheet : hierarchy )
348 {
349 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
350 {
351 SCH_SYMBOL* s = static_cast<SCH_SYMBOL*>( item );
352
353 if( !unique_libid.insert( s->GetLibId().Format() ).second )
354 continue;
355
356 LIB_SYMBOL* libSymbol = SchGetLibSymbol( s->GetLibId(), libs, cache );
357
358 if( libSymbol )
359 {
360 PICKED_SYMBOL pickedSymbol;
361 pickedSymbol.LibId = libSymbol->GetLibId();
362 alreadyPlaced.push_back( pickedSymbol );
363 }
364 }
365 }
366
367 // Pick the symbol to be placed
368 bool footprintPreviews = m_frame->eeconfig()->m_Appearance.footprint_preview;
369 PICKED_SYMBOL sel = m_frame->PickSymbolFromLibrary( &filter, *historyList, alreadyPlaced,
370 footprintPreviews );
371
372 keepSymbol = sel.KeepSymbol;
373 placeAllUnits = sel.PlaceAllUnits;
374
375 LIB_SYMBOL* libSymbol = sel.LibId.IsValid() ? m_frame->GetLibSymbol( sel.LibId ) : nullptr;
376
377 if( !libSymbol )
378 continue;
379
380 // If we started with a hotkey which has a position then warp back to that.
381 // Otherwise update to the current mouse position pinned inside the autoscroll
382 // boundaries.
383 if( evt->IsPrime() && !ignorePrimePosition )
384 {
385 cursorPos = grid.Align( evt->Position(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
386 getViewControls()->WarpMouseCursor( cursorPos, true );
387 }
388 else
389 {
391 cursorPos = grid.Align( getViewControls()->GetMousePosition(),
392 GRID_HELPER_GRIDS::GRID_CONNECTABLE );
393 }
394
396
397 if( !libSymbol->IsLocalPower() && cfg->m_Drawing.new_power_symbols == POWER_SYMBOLS::LOCAL )
398 {
399 libSymbol->SetLocalPower();
400 wxString keywords = libSymbol->GetKeyWords();
401
402 // Adjust the KiCad library default fields to match the new power symbol type
403 if( keywords.Contains( wxT( "global power" ) ) )
404 {
405 keywords.Replace( wxT( "global power" ), wxT( "local power" ) );
406 libSymbol->SetKeyWords( keywords );
407 }
408
409 wxString desc = libSymbol->GetDescription();
410
411 if( desc.Contains( wxT( "global label" ) ) )
412 {
413 desc.Replace( wxT( "global label" ), wxT( "local label" ) );
414 libSymbol->SetDescription( desc );
415 }
416 }
417 else if( !libSymbol->IsGlobalPower()
418 && cfg->m_Drawing.new_power_symbols == POWER_SYMBOLS::GLOBAL )
419 {
420 // We do not currently have local power symbols in the KiCad library, so
421 // don't update any fields
422 libSymbol->SetGlobalPower();
423 }
424
425 symbol = new SCH_SYMBOL( *libSymbol, &m_frame->GetCurrentSheet(), sel, cursorPos,
426 &m_frame->Schematic() );
427 addSymbol( symbol );
428 annotate();
429
430 // Update the list of references for the next symbol placement.
431 SCH_REFERENCE placedSymbolReference( symbol, m_frame->GetCurrentSheet() );
432 existingRefs.AddItem( placedSymbolReference );
433 existingRefs.SortByReferenceOnly();
434
436 {
437 // Not placed yet, so pass a nullptr screen reference
438 symbol->AutoplaceFields( nullptr, AUTOPLACE_AUTO );
439 }
440
441 // Update cursor now that we have a symbol
442 setCursor();
443 }
444 else
445 {
447 m_frame->AddToScreen( symbol, screen );
448
450 symbol->AutoplaceFields( screen, AUTOPLACE_AUTO );
451
453
454 SCH_COMMIT commit( m_toolMgr );
455 commit.Added( symbol, screen );
456
458 lwbTool->TrimOverLappingWires( &commit, &m_selectionTool->GetSelection() );
459 lwbTool->AddJunctionsIfNeeded( &commit, &m_selectionTool->GetSelection() );
460
461 commit.Push( _( "Place Symbol" ) );
462
463 if( placeOneOnly )
464 {
465 m_frame->PopTool( aEvent );
466 break;
467 }
468
469 SCH_SYMBOL* nextSymbol = nullptr;
470
471 if( keepSymbol || placeAllUnits )
472 {
473 SCH_REFERENCE currentReference( symbol, m_frame->GetCurrentSheet() );
474 SCHEMATIC& schematic = m_frame->Schematic();
475
476 if( placeAllUnits )
477 {
478 while( currentReference.GetUnit() <= symbol->GetUnitCount()
479 && schematic.Contains( currentReference ) )
480 {
481 currentReference.SetUnit( currentReference.GetUnit() + 1 );
482 }
483
484 if( currentReference.GetUnit() > symbol->GetUnitCount() )
485 {
486 currentReference.SetUnit( 1 );
487 }
488 }
489
490 // We are either stepping to the next unit or next symbol
491 if( keepSymbol || currentReference.GetUnit() > 1 )
492 {
493 nextSymbol = static_cast<SCH_SYMBOL*>( symbol->Duplicate( IGNORE_PARENT_GROUP ) );
494 nextSymbol->SetUnit( currentReference.GetUnit() );
495 nextSymbol->SetUnitSelection( currentReference.GetUnit() );
496
497 addSymbol( nextSymbol );
498 symbol = nextSymbol;
499
500 if( currentReference.GetUnit() == 1 )
501 annotate();
502
503 // Update the list of references for the next symbol placement.
504 SCH_REFERENCE placedSymbolReference( symbol, m_frame->GetCurrentSheet() );
505 existingRefs.AddItem( placedSymbolReference );
506 existingRefs.SortByReferenceOnly();
507 }
508 }
509
510 symbol = nextSymbol;
511 }
512 }
513 else if( evt->IsClick( BUT_RIGHT ) )
514 {
515 // Warp after context menu only if dragging...
516 if( !symbol )
518
519 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
520 }
521 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
522 {
523 if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_UNIT
524 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_UNIT_END )
525 {
526 int unit = *evt->GetCommandId() - ID_POPUP_SCH_SELECT_UNIT;
527
528 if( symbol )
529 {
530 m_frame->SelectUnit( symbol, unit );
532 }
533 }
534 else if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_BASE
535 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_ALT )
536 {
537 int bodyStyle = ( *evt->GetCommandId() - ID_POPUP_SCH_SELECT_BASE ) + 1;
538
539 if( symbol && symbol->GetBodyStyle() != bodyStyle )
540 {
541 m_frame->FlipBodyStyle( symbol );
543 }
544 }
545 }
546 else if( evt->IsAction( &ACTIONS::duplicate )
547 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem ) )
548 {
549 if( symbol )
550 {
551 // This doesn't really make sense; we'll just end up dragging a stack of
552 // objects so we ignore the duplicate and just carry on.
553 wxBell();
554 continue;
555 }
556
557 // Exit. The duplicate will run in its own loop.
558 m_frame->PopTool( aEvent );
559 evt->SetPassEvent();
560 break;
561 }
562 else if( symbol && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
563 {
564 symbol->SetPosition( cursorPos );
566 m_view->AddToPreview( symbol, false ); // Add, but not give ownership
567 m_frame->SetMsgPanel( symbol );
568 }
569 else if( symbol && evt->IsAction( &ACTIONS::doDelete ) )
570 {
571 cleanup();
572 }
573 else if( symbol && evt->IsAction( &ACTIONS::redo ) )
574 {
575 wxBell();
576 }
577 else
578 {
579 evt->SetPassEvent();
580 }
581
582 // Enable autopanning and cursor capture only when there is a symbol to be placed
583 getViewControls()->SetAutoPan( symbol != nullptr );
584 getViewControls()->CaptureCursor( symbol != nullptr );
585 }
586
587 getViewControls()->SetAutoPan( false );
588 getViewControls()->CaptureCursor( false );
589 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
590
591 return 0;
592}
593
594
596{
597 SCH_SYMBOL* symbol = aEvent.Parameter<SCH_SYMBOL*>();
598
599 // TODO: get from selection
600 if( !symbol )
601 {
602 static const std::vector<KICAD_T> symbolTypes = { SCH_SYMBOL_T };
603 SCH_SELECTION& selection = m_selectionTool->RequestSelection( symbolTypes );
604
605 if( selection.Size() != 1 )
606 {
607 m_frame->ShowInfoBarMsg( _( "Select a single symbol to place the next unit." ) );
608 return 0;
609 }
610
611 wxCHECK( selection.Front()->Type() == SCH_SYMBOL_T, 0 );
612 symbol = static_cast<SCH_SYMBOL*>( selection.Front() );
613 }
614
615 if( !symbol )
616 return 0;
617
618 if( !symbol->IsMulti() )
619 {
620 m_frame->ShowInfoBarMsg( _( "This symbol has only one unit." ) );
621 return 0;
622 }
623
624 const std::set<int> missingUnits = GetUnplacedUnitsForSymbol( *symbol );
625
626 if( missingUnits.empty() )
627 {
628 m_frame->ShowInfoBarMsg( _( "All units of this symbol are already placed." ) );
629 return 0;
630 }
631
632 // Find the lowest unit number that is missing
633 const int nextMissing = *std::min_element( missingUnits.begin(), missingUnits.end() );
634
635 std::unique_ptr<SCH_SYMBOL> newSymbol = std::make_unique<SCH_SYMBOL>( *symbol );
636 const SCH_SHEET_PATH& sheetPath = m_frame->GetCurrentSheet();
637
638 newSymbol->SetUnitSelection( &sheetPath, nextMissing );
639 newSymbol->SetUnit( nextMissing );
640 newSymbol->SetRefProp( symbol->GetRef( &sheetPath, false ) );
641
642 // Post the new symbol - don't reannotate it - we set the reference ourselves
644 SCH_ACTIONS::PLACE_SYMBOL_PARAMS{ newSymbol.release(), false } );
645 return 0;
646}
647
648
650{
651 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
653 SCHEMATIC_SETTINGS& schSettings = m_frame->Schematic().Settings();
654 SCH_SCREEN* screen = m_frame->GetScreen();
655 SCH_SHEET_PATH& sheetPath = m_frame->GetCurrentSheet();
656
659 VECTOR2I cursorPos;
660
661 if( !cfg || !common_settings )
662 return 0;
663
664 if( m_inDrawingTool )
665 return 0;
666
667 bool placingDesignBlock = aEvent.IsAction( &SCH_ACTIONS::placeDesignBlock );
668
669 std::unique_ptr<DESIGN_BLOCK> designBlock;
670 wxString sheetFileName = wxEmptyString;
671
672 if( placingDesignBlock )
673 {
675
676 if( designBlockPane->GetSelectedLibId().IsValid() )
677 {
678 designBlock.reset( designBlockPane->GetDesignBlock( designBlockPane->GetSelectedLibId(),
679 true, true ) );
680
681 if( !designBlock )
682 return 0;
683
684 sheetFileName = designBlock->GetSchematicFile();
685 }
686 }
687 else
688 {
689 wxString* importSourceFile = aEvent.Parameter<wxString*>();
690
691 if( importSourceFile != nullptr )
692 sheetFileName = *importSourceFile;
693 }
694
695 auto setCursor =
696 [&]()
697 {
698 m_frame->GetCanvas()->SetCurrentCursor( designBlock ? KICURSOR::MOVING
699 : KICURSOR::COMPONENT );
700 };
701
702 auto placeSheetContents =
703 [&]()
704 {
705 SCH_COMMIT commit( m_toolMgr );
707
708 EDA_ITEMS newItems;
709 bool keepAnnotations = cfg->m_DesignBlockChooserPanel.keep_annotations;
710 bool placeAsGroup = cfg->m_DesignBlockChooserPanel.place_as_group;
711
712 selectionTool->ClearSelection();
713
714 // Mark all existing items on the screen so we don't select them after appending
715 for( EDA_ITEM* item : screen->Items() )
716 item->SetFlags( SKIP_STRUCT );
717
718 if( !m_frame->LoadSheetFromFile( sheetPath.Last(), &sheetPath, sheetFileName, true,
719 placingDesignBlock ) )
720 {
721 return false;
722 }
723
725
726 m_frame->SyncView();
727 m_frame->OnModify();
728 m_frame->HardRedraw(); // Full reinit of the current screen and the display.
729
730 SCH_GROUP* group = nullptr;
731
732 if( placeAsGroup )
733 {
734 group = new SCH_GROUP( screen );
735
736 if( designBlock )
737 {
738 group->SetName( designBlock->GetLibId().GetLibItemName() );
739 group->SetDesignBlockLibId( designBlock->GetLibId() );
740 }
741 else
742 {
743 group->SetName( wxFileName( sheetFileName ).GetName() );
744 }
745 }
746
747 // Select all new items
748 for( EDA_ITEM* item : screen->Items() )
749 {
750 if( !item->HasFlag( SKIP_STRUCT ) )
751 {
752 if( item->Type() == SCH_SYMBOL_T && !keepAnnotations )
753 static_cast<SCH_SYMBOL*>( item )->ClearAnnotation( &sheetPath, false );
754
755 if( item->Type() == SCH_LINE_T )
756 item->SetFlags( STARTPOINT | ENDPOINT );
757
758 if( placeAsGroup )
759 group->AddItem( item );
760
761 commit.Added( item, screen );
762 newItems.emplace_back( item );
763 }
764 else
765 {
766 item->ClearFlags( SKIP_STRUCT );
767 }
768 }
769
770 if( placeAsGroup )
771 {
772 commit.Add( group, screen );
773 selectionTool->AddItemToSel( group );
774 }
775 else
776 {
777 selectionTool->AddItemsToSel( &newItems, true );
778 }
779
780 cursorPos = grid.Align( controls->GetMousePosition(),
781 grid.GetSelectionGrid( selectionTool->GetSelection() ) );
782 controls->ForceCursorPosition( true, cursorPos );
783
784 // Move everything to our current mouse position now
785 // that we have a selection to get a reference point
786 VECTOR2I anchorPos = selectionTool->GetSelection().GetReferencePoint();
787 VECTOR2I delta = cursorPos - anchorPos;
788
789 // Will all be SCH_ITEMs as these were pulled from the screen->Items()
790 for( EDA_ITEM* item : newItems )
791 static_cast<SCH_ITEM*>( item )->Move( delta );
792
793 if( !keepAnnotations )
794 {
796
797 if( annotate.automatic )
798 {
799 NULL_REPORTER reporter;
801 (ANNOTATE_ORDER_T) annotate.sort_order,
802 (ANNOTATE_ALGO_T) annotate.method, true /* recursive */,
803 schSettings.m_AnnotateStartNum, false, false, reporter );
804 }
805
806 // Annotation will clear selection, so we need to restore it
807 for( EDA_ITEM* item : newItems )
808 {
809 if( item->Type() == SCH_LINE_T )
810 item->SetFlags( STARTPOINT | ENDPOINT );
811 }
812
813 selectionTool->AddItemsToSel( &newItems, true );
814 }
815
816 // Start moving selection, cancel undoes the insertion
817 bool placed = m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit );
818
819 // Update our cursor position to the new location in case we're placing repeated copies
820 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
821
822 if( placed )
823 {
824 commit.Push( placingDesignBlock ? _( "Add Design Block" )
825 : _( "Import Schematic Sheet Content" ) );
826 }
827 else
828 {
829 commit.Revert();
830 }
831
833
834 return placed;
835 };
836
837 // Whether we are placing the sheet as a sheet, or as its contents, we need to get a filename
838 // if we weren't provided one
839 if( sheetFileName.IsEmpty() )
840 {
841 wxString path;
842 wxString file;
843
844 if (!placingDesignBlock)
845 {
846 if( sheetFileName.IsEmpty() )
847 {
848 path = wxPathOnly( m_frame->Prj().GetProjectFullName() );
849 file = wxEmptyString;
850 }
851 else
852 {
853 path = wxPathOnly( sheetFileName );
854 file = wxFileName( sheetFileName ).GetFullName();
855 }
856
857 // Open file chooser dialog even if we have been provided a file so the user
858 // can select the options they want
859 wxFileDialog dlg( m_frame, _( "Choose Schematic" ), path, file,
860 FILEEXT::KiCadSchematicFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
861
862 FILEDLG_IMPORT_SHEET_CONTENTS dlgHook( cfg );
863 dlg.SetCustomizeHook( dlgHook );
864
865 if( dlg.ShowModal() == wxID_CANCEL )
866 return 0;
867
868 sheetFileName = dlg.GetPath();
869
871 }
872
873 if( sheetFileName.IsEmpty() )
874 return 0;
875 }
876
877 // If we're placing sheet contents, we don't even want to run our tool loop, just add the items
878 // to the canvas and run the move tool
880 {
881 while( placeSheetContents() && cfg->m_DesignBlockChooserPanel.repeated_placement )
882 {}
883
886 return 0;
887 }
888
889 // We're placing a sheet as a sheet, we need to run a small tool loop to get the starting
890 // coordinate of the sheet drawing
891 m_frame->PushTool( aEvent );
892
893 Activate();
894
895 // Must be done after Activate() so that it gets set into the correct context
896 getViewControls()->ShowCursor( true );
897
898 // Set initial cursor
899 setCursor();
900
901 if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
902 {
903 m_toolMgr->PrimeTool( { 0, 0 } );
904 }
905
906 // Main loop: keep receiving events
907 while( TOOL_EVENT* evt = Wait() )
908 {
909 setCursor();
910 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
911 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
912
913 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
914 controls->ForceCursorPosition( true, cursorPos );
915
916 // The tool hotkey is interpreted as a click when drawing
917 bool isSyntheticClick = designBlock && evt->IsActivate() && evt->HasPosition() && evt->Matches( aEvent );
918
919 if( evt->IsCancelInteractive() || ( designBlock && evt->IsAction( &ACTIONS::undo ) ) )
920 {
922 break;
923 }
924 else if( evt->IsActivate() && !isSyntheticClick )
925 {
927 break;
928 }
929 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) || isSyntheticClick )
930 {
931 if( placingDesignBlock )
932 {
933 // drawSheet must delete designBlock
935 }
936 else
937 {
938 // drawSheet must delete sheetFileName
939 m_toolMgr->PostAction( SCH_ACTIONS::drawSheetFromFile, new wxString( sheetFileName ) );
940 }
941
942 break;
943 }
944 else if( evt->IsClick( BUT_RIGHT ) )
945 {
946 // Warp after context menu only if dragging...
947 if( !designBlock )
949
950 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
951 }
952 else if( evt->IsAction( &ACTIONS::duplicate )
953 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem ) )
954 {
955 wxBell();
956 }
957 else
958 {
959 evt->SetPassEvent();
960 }
961 }
962
963 m_frame->PopTool( aEvent );
964 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
965
966 return 0;
967}
968
969
971{
972 SCH_BITMAP* image = aEvent.Parameter<SCH_BITMAP*>();
973 bool immediateMode = image != nullptr;
974 bool ignorePrimePosition = false;
975 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
976
977 if( m_inDrawingTool )
978 return 0;
979
981
984 VECTOR2I cursorPos;
985
987
988 // Add all the drawable symbols to preview
989 if( image )
990 {
991 image->SetPosition( getViewControls()->GetCursorPosition() );
993 m_view->AddToPreview( image, false ); // Add, but not give ownership
994 }
995
996 m_frame->PushTool( aEvent );
997
998 auto setCursor =
999 [&]()
1000 {
1001 if( image )
1002 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
1003 else
1004 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1005 };
1006
1007 auto cleanup =
1008 [&] ()
1009 {
1013 delete image;
1014 image = nullptr;
1015 };
1016
1017 Activate();
1018
1019 // Must be done after Activate() so that it gets set into the correct context
1020 getViewControls()->ShowCursor( true );
1021
1022 // Set initial cursor
1023 setCursor();
1024
1025 // Prime the pump
1026 if( image )
1027 {
1029 }
1030 else if( aEvent.HasPosition() )
1031 {
1032 m_toolMgr->PrimeTool( aEvent.Position() );
1033 }
1034 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
1035 {
1036 m_toolMgr->PrimeTool( { 0, 0 } );
1037 ignorePrimePosition = true;
1038 }
1039
1040 // Main loop: keep receiving events
1041 while( TOOL_EVENT* evt = Wait() )
1042 {
1043 setCursor();
1044 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1045 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1046
1047 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
1048 controls->ForceCursorPosition( true, cursorPos );
1049
1050 // The tool hotkey is interpreted as a click when drawing
1051 bool isSyntheticClick = image && evt->IsActivate() && evt->HasPosition() && evt->Matches( aEvent );
1052
1053 if( evt->IsCancelInteractive() || ( image && evt->IsAction( &ACTIONS::undo ) ) )
1054 {
1056
1057 if( image )
1058 {
1059 cleanup();
1060 }
1061 else
1062 {
1063 m_frame->PopTool( aEvent );
1064 break;
1065 }
1066
1067 if( immediateMode )
1068 {
1069 m_frame->PopTool( aEvent );
1070 break;
1071 }
1072 }
1073 else if( evt->IsActivate() && !isSyntheticClick )
1074 {
1075 if( image && evt->IsMoveTool() )
1076 {
1077 // we're already moving our own item; ignore the move tool
1078 evt->SetPassEvent( false );
1079 continue;
1080 }
1081
1082 if( image )
1083 {
1084 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel image creation." ) );
1085 evt->SetPassEvent( false );
1086 continue;
1087 }
1088
1089 if( evt->IsMoveTool() )
1090 {
1091 // leave ourselves on the stack so we come back after the move
1092 break;
1093 }
1094 else
1095 {
1096 m_frame->PopTool( aEvent );
1097 break;
1098 }
1099 }
1100 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) || isSyntheticClick )
1101 {
1102 if( !image )
1103 {
1105
1106 wxFileDialog dlg( m_frame, _( "Choose Image" ), m_mruPath, wxEmptyString,
1107 _( "Image Files" ) + wxS( " " ) + wxImage::GetImageExtWildcard(),
1108 wxFD_OPEN );
1109
1110 if( dlg.ShowModal() != wxID_OK )
1111 continue;
1112
1113 // If we started with a hotkey which has a position then warp back to that.
1114 // Otherwise update to the current mouse position pinned inside the autoscroll
1115 // boundaries.
1116 if( evt->IsPrime() && !ignorePrimePosition )
1117 {
1118 cursorPos = grid.Align( evt->Position() );
1119 getViewControls()->WarpMouseCursor( cursorPos, true );
1120 }
1121 else
1122 {
1124 cursorPos = getViewControls()->GetMousePosition();
1125 }
1126
1127 wxString fullFilename = dlg.GetPath();
1128 m_mruPath = wxPathOnly( fullFilename );
1129
1130 if( wxFileExists( fullFilename ) )
1131 image = new SCH_BITMAP( cursorPos );
1132
1133 if( !image || !image->GetReferenceImage().ReadImageFile( fullFilename ) )
1134 {
1135 wxMessageBox( wxString::Format( _( "Could not load image from '%s'." ), fullFilename ) );
1136 delete image;
1137 image = nullptr;
1138 continue;
1139 }
1140
1141 image->SetFlags( IS_NEW | IS_MOVING );
1142
1144
1146 m_view->AddToPreview( image, false ); // Add, but not give ownership
1147 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
1148
1150
1151 getViewControls()->SetCursorPosition( cursorPos, false );
1152 setCursor();
1153 }
1154 else
1155 {
1156 SCH_COMMIT commit( m_toolMgr );
1157 commit.Add( image, m_frame->GetScreen() );
1158 commit.Push( _( "Place Image" ) );
1159
1160 image = nullptr;
1162
1164
1165 if( immediateMode )
1166 {
1167 m_frame->PopTool( aEvent );
1168 break;
1169 }
1170 }
1171 }
1172 else if( evt->IsClick( BUT_RIGHT ) )
1173 {
1174 // Warp after context menu only if dragging...
1175 if( !image )
1177
1178 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
1179 }
1180 else if( evt->IsAction( &ACTIONS::duplicate )
1181 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem ) )
1182 {
1183 if( image )
1184 {
1185 // This doesn't really make sense; we'll just end up dragging a stack of
1186 // objects so we ignore the duplicate and just carry on.
1187 wxBell();
1188 continue;
1189 }
1190
1191 // Exit. The duplicate will run in its own loop.
1192 m_frame->PopTool( aEvent );
1193 evt->SetPassEvent();
1194 break;
1195 }
1196 else if( image && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
1197 {
1198 image->SetPosition( cursorPos );
1200 m_view->AddToPreview( image, false ); // Add, but not give ownership
1201 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
1203 }
1204 else if( image && evt->IsAction( &ACTIONS::doDelete ) )
1205 {
1206 cleanup();
1207 }
1208 else if( image && evt->IsAction( &ACTIONS::redo ) )
1209 {
1210 wxBell();
1211 }
1212 else
1213 {
1214 evt->SetPassEvent();
1215 }
1216
1217 // Enable autopanning and cursor capture only when there is an image to be placed
1218 getViewControls()->SetAutoPan( image != nullptr );
1219 getViewControls()->CaptureCursor( image != nullptr );
1220 }
1221
1222 getViewControls()->SetAutoPan( false );
1223 getViewControls()->CaptureCursor( false );
1224 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1225
1226 return 0;
1227}
1228
1229
1231{
1232 if( m_inDrawingTool )
1233 return 0;
1234
1236
1237 // Note: PlaceImportedGraphics() will convert PCB_SHAPE_T and PCB_TEXT_T to footprint
1238 // items if needed
1240 int dlgResult = dlg.ShowModal();
1241
1242 std::list<std::unique_ptr<EDA_ITEM>>& list = dlg.GetImportedItems();
1243
1244 if( dlgResult != wxID_OK )
1245 return 0;
1246
1247 // Ensure the list is not empty:
1248 if( list.empty() )
1249 {
1250 wxMessageBox( _( "No graphic items found in file." ) );
1251 return 0;
1252 }
1253
1255
1257 std::vector<SCH_ITEM*> newItems; // all new items, including group
1258 std::vector<SCH_ITEM*> selectedItems; // the group, or newItems if no group
1259 SCH_SELECTION preview;
1260 SCH_COMMIT commit( m_toolMgr );
1261
1262 for( std::unique_ptr<EDA_ITEM>& ptr : list )
1263 {
1264 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( ptr.get() );
1265 wxCHECK2_MSG( item, continue, wxString::Format( "Bad item type: ", ptr->Type() ) );
1266
1267 newItems.push_back( item );
1268 selectedItems.push_back( item );
1269 preview.Add( item );
1270
1271 ptr.release();
1272 }
1273
1274 if( !dlg.IsPlacementInteractive() )
1275 {
1276 // Place the imported drawings
1277 for( SCH_ITEM* item : newItems )
1278 commit.Add(item, m_frame->GetScreen());
1279
1280 commit.Push( _( "Import Graphic" ) );
1281 return 0;
1282 }
1283
1284 m_view->Add( &preview );
1285
1286 // Clear the current selection then select the drawings so that edit tools work on them
1288
1289 EDA_ITEMS selItems( selectedItems.begin(), selectedItems.end() );
1291
1292 m_frame->PushTool( aEvent );
1293
1294 auto setCursor =
1295 [&]()
1296 {
1297 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
1298 };
1299
1300 Activate();
1301 // Must be done after Activate() so that it gets set into the correct context
1302 controls->ShowCursor( true );
1303 controls->ForceCursorPosition( false );
1304 // Set initial cursor
1305 setCursor();
1306
1307 //SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DXF );
1309
1310 // Now move the new items to the current cursor position:
1311 VECTOR2I cursorPos = controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
1312 VECTOR2I delta = cursorPos;
1313 VECTOR2I currentOffset;
1314
1315 for( SCH_ITEM* item : selectedItems )
1316 item->Move( delta );
1317
1318 currentOffset += delta;
1319
1320 m_view->Update( &preview );
1321
1322 // Main loop: keep receiving events
1323 while( TOOL_EVENT* evt = Wait() )
1324 {
1325 setCursor();
1326
1327 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1328 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1329
1330 cursorPos = grid.Align( controls->GetMousePosition(), GRID_GRAPHICS );
1331 controls->ForceCursorPosition( true, cursorPos );
1332
1333 if( evt->IsCancelInteractive() || evt->IsActivate() )
1334 {
1336
1337 for( SCH_ITEM* item : newItems )
1338 delete item;
1339
1340 break;
1341 }
1342 else if( evt->IsMotion() )
1343 {
1344 delta = cursorPos - currentOffset;
1345
1346 for( SCH_ITEM* item : selectedItems )
1347 item->Move( delta );
1348
1349 currentOffset += delta;
1350
1351 m_view->Update( &preview );
1352 }
1353 else if( evt->IsClick( BUT_RIGHT ) )
1354 {
1355 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
1356 }
1357 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1358 {
1359 // Place the imported drawings
1360 for( SCH_ITEM* item : newItems )
1361 commit.Add( item, m_frame->GetScreen() );
1362
1363 commit.Push( _( "Import Graphic" ) );
1364 break; // This is a one-shot command, not a tool
1365 }
1366 else
1367 {
1368 evt->SetPassEvent();
1369 }
1370 }
1371
1372 preview.Clear();
1373 m_view->Remove( &preview );
1374
1375 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1376 controls->ForceCursorPosition( false );
1377
1378 m_frame->PopTool( aEvent );
1379
1380 return 0;
1381}
1382
1383
1385{
1386 VECTOR2I cursorPos;
1387 KICAD_T type = aEvent.Parameter<KICAD_T>();
1390 SCH_ITEM* previewItem;
1391 bool loggedInfoBarError = false;
1392 wxString description;
1393 SCH_SCREEN* screen = m_frame->GetScreen();
1394 bool allowRepeat = false; // Set to true to allow new item repetition
1395
1396 if( m_inDrawingTool )
1397 return 0;
1398
1400
1401 if( type == SCH_JUNCTION_T && aEvent.HasPosition() )
1402 {
1404 SCH_LINE* wire = dynamic_cast<SCH_LINE*>( selection.Front() );
1405
1406 if( wire )
1407 {
1408 SEG seg( wire->GetStartPoint(), wire->GetEndPoint() );
1409 VECTOR2I nearest = seg.NearestPoint( getViewControls()->GetCursorPosition() );
1410 getViewControls()->SetCrossHairCursorPosition( nearest, false );
1411 getViewControls()->WarpMouseCursor( getViewControls()->GetCursorPosition(), true );
1412 }
1413 }
1414
1415 switch( type )
1416 {
1417 case SCH_NO_CONNECT_T:
1418 previewItem = new SCH_NO_CONNECT( cursorPos );
1419 previewItem->SetParent( screen );
1420 description = _( "Add No Connect Flag" );
1421 allowRepeat = true;
1422 break;
1423
1424 case SCH_JUNCTION_T:
1425 previewItem = new SCH_JUNCTION( cursorPos );
1426 previewItem->SetParent( screen );
1427 description = _( "Add Junction" );
1428 break;
1429
1431 previewItem = new SCH_BUS_WIRE_ENTRY( cursorPos );
1432 previewItem->SetParent( screen );
1433 description = _( "Add Wire to Bus Entry" );
1434 allowRepeat = true;
1435 break;
1436
1437 default:
1438 wxASSERT_MSG( false, "Unknown item type in SCH_DRAWING_TOOLS::SingleClickPlace" );
1439 return 0;
1440 }
1441
1443
1444 cursorPos = aEvent.HasPosition() ? aEvent.Position() : controls->GetMousePosition();
1445
1446 m_frame->PushTool( aEvent );
1447
1448 auto setCursor =
1449 [&]()
1450 {
1451 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PLACE );
1452 };
1453
1454 Activate();
1455
1456 // Must be done after Activate() so that it gets set into the correct context
1457 getViewControls()->ShowCursor( true );
1458
1459 // Set initial cursor
1460 setCursor();
1461
1463 m_view->AddToPreview( previewItem->Clone() );
1464
1465 // Prime the pump
1466 if( aEvent.HasPosition() && type != SCH_SHEET_PIN_T )
1467 m_toolMgr->PrimeTool( aEvent.Position() );
1468 else
1470
1471 // Main loop: keep receiving events
1472 while( TOOL_EVENT* evt = Wait() )
1473 {
1474 setCursor();
1475 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1476 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1477
1478 cursorPos = evt->IsPrime() ? evt->Position() : controls->GetMousePosition();
1479 cursorPos = grid.BestSnapAnchor( cursorPos, grid.GetItemGrid( previewItem ), nullptr );
1480 controls->ForceCursorPosition( true, cursorPos );
1481
1482 if( evt->IsCancelInteractive() )
1483 {
1484 m_frame->PopTool( aEvent );
1485 break;
1486 }
1487 else if( evt->IsActivate() )
1488 {
1489 if( evt->IsMoveTool() )
1490 {
1491 // leave ourselves on the stack so we come back after the move
1492 break;
1493 }
1494 else
1495 {
1496 m_frame->PopTool( aEvent );
1497 break;
1498 }
1499 }
1500 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1501 {
1502 if( !screen->GetItem( cursorPos, 0, type ) )
1503 {
1504 if( type == SCH_JUNCTION_T )
1505 {
1506 if( !screen->IsExplicitJunctionAllowed( cursorPos ) )
1507 {
1508 m_frame->ShowInfoBarError( _( "Junction location contains no joinable wires and/or pins." ) );
1509 loggedInfoBarError = true;
1510 continue;
1511 }
1512 else if( loggedInfoBarError )
1513 {
1515 }
1516 }
1517
1518 SCH_ITEM* newItem = static_cast<SCH_ITEM*>( previewItem->Clone() );
1519 const_cast<KIID&>( newItem->m_Uuid ) = KIID();
1520 newItem->SetPosition( cursorPos );
1521 newItem->SetFlags( IS_NEW );
1522 m_frame->AddToScreen( newItem, screen );
1523
1524 if( allowRepeat )
1525 m_frame->SaveCopyForRepeatItem( newItem );
1526
1527 SCH_COMMIT commit( m_toolMgr );
1528 commit.Added( newItem, screen );
1529
1530 m_frame->Schematic().CleanUp( &commit );
1531
1532 commit.Push( description );
1533 }
1534
1535 if( evt->IsDblClick( BUT_LEFT ) || type == SCH_SHEET_PIN_T ) // Finish tool.
1536 {
1537 m_frame->PopTool( aEvent );
1538 break;
1539 }
1540 }
1541 else if( evt->IsClick( BUT_RIGHT ) )
1542 {
1543 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
1544 }
1545 else if( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() )
1546 {
1547 previewItem->SetPosition( cursorPos );
1549 m_view->AddToPreview( previewItem->Clone() );
1550 m_frame->SetMsgPanel( previewItem );
1551 }
1552 else if( evt->Category() == TC_COMMAND )
1553 {
1554 if( ( type == SCH_BUS_WIRE_ENTRY_T ) && ( evt->IsAction( &SCH_ACTIONS::rotateCW )
1555 || evt->IsAction( &SCH_ACTIONS::rotateCCW )
1556 || evt->IsAction( &SCH_ACTIONS::mirrorV )
1557 || evt->IsAction( &SCH_ACTIONS::mirrorH ) ) )
1558 {
1559 SCH_BUS_ENTRY_BASE* busItem = static_cast<SCH_BUS_ENTRY_BASE*>( previewItem );
1560
1561 if( evt->IsAction( &SCH_ACTIONS::rotateCW ) )
1562 {
1563 busItem->Rotate( busItem->GetPosition(), false );
1564 }
1565 else if( evt->IsAction( &SCH_ACTIONS::rotateCCW ) )
1566 {
1567 busItem->Rotate( busItem->GetPosition(), true );
1568 }
1569 else if( evt->IsAction( &SCH_ACTIONS::mirrorV ) )
1570 {
1571 busItem->MirrorVertically( busItem->GetPosition().y );
1572 }
1573 else if( evt->IsAction( &SCH_ACTIONS::mirrorH ) )
1574 {
1575 busItem->MirrorHorizontally( busItem->GetPosition().x );
1576 }
1577
1579 m_view->AddToPreview( previewItem->Clone() );
1580 }
1581 else if( evt->IsAction( &SCH_ACTIONS::properties ) )
1582 {
1583 switch( type )
1584 {
1586 {
1587 std::deque<SCH_ITEM*> strokeItems;
1588 strokeItems.push_back( previewItem );
1589
1590 DIALOG_WIRE_BUS_PROPERTIES dlg( m_frame, strokeItems );
1591 dlg.ShowModal();
1592 break;
1593 }
1594
1595 case SCH_JUNCTION_T:
1596 {
1597 std::deque<SCH_JUNCTION*> junctions;
1598 junctions.push_back( static_cast<SCH_JUNCTION*>( previewItem ) );
1599
1600 DIALOG_JUNCTION_PROPS dlg( m_frame, junctions );
1601 dlg.ShowModal();
1602 break;
1603 }
1604
1605 default:
1606 // Do nothing
1607 break;
1608 }
1609
1611 m_view->AddToPreview( previewItem->Clone() );
1612 }
1613 else
1614 {
1615 evt->SetPassEvent();
1616 }
1617 }
1618 else
1619 {
1620 evt->SetPassEvent();
1621 }
1622 }
1623
1624 delete previewItem;
1626
1627 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1628 controls->ForceCursorPosition( false );
1629
1630 return 0;
1631}
1632
1633
1635{
1636 for( SCH_ITEM* item : m_frame->GetScreen()->Items().Overlapping( SCH_LINE_T, aPosition ) )
1637 {
1638 SCH_LINE* line = static_cast<SCH_LINE*>( item );
1639
1640 if( line->GetEditFlags() & STRUCT_DELETED )
1641 continue;
1642
1643 if( line->IsWire() )
1644 return line;
1645 }
1646
1647 return nullptr;
1648}
1649
1650
1652{
1653 wxASSERT( aWire->IsWire() );
1654
1655 SCH_SHEET_PATH sheetPath = m_frame->GetCurrentSheet();
1656
1657 if( SCH_CONNECTION* wireConnection = aWire->Connection( &sheetPath ) )
1658 {
1659 SCH_ITEM* wireDriver = wireConnection->Driver();
1660
1661 if( wireDriver && wireDriver->IsType( { SCH_LABEL_T, SCH_GLOBAL_LABEL_T } ) )
1662 return wireConnection->LocalName();
1663 }
1664
1665 return wxEmptyString;
1666}
1667
1668
1669bool SCH_DRAWING_TOOLS::createNewLabel( const VECTOR2I& aPosition, int aType,
1670 std::list<std::unique_ptr<SCH_LABEL_BASE>>& aLabelList )
1671{
1672 SCHEMATIC* schematic = getModel<SCHEMATIC>();
1673 SCHEMATIC_SETTINGS& settings = schematic->Settings();
1674 SCH_LABEL_BASE* labelItem = nullptr;
1675 SCH_GLOBALLABEL* globalLabel = nullptr;
1676 wxString netName;
1677
1678 switch( aType )
1679 {
1680 case LAYER_LOCLABEL:
1681 labelItem = new SCH_LABEL( aPosition );
1682
1683 if( SCH_LINE* wire = findWire( aPosition ) )
1684 netName = findWireLabelDriverName( wire );
1685
1686 break;
1687
1689 labelItem = new SCH_DIRECTIVE_LABEL( aPosition );
1690 labelItem->SetShape( m_lastNetClassFlagShape );
1691 labelItem->GetFields().emplace_back( labelItem, FIELD_T::USER, wxT( "Netclass" ) );
1692 labelItem->GetFields().emplace_back( labelItem, FIELD_T::USER, wxT( "Component Class" ) );
1693 labelItem->GetFields().back().SetItalic( true );
1694 labelItem->GetFields().back().SetVisible( true );
1695 break;
1696
1697 case LAYER_HIERLABEL:
1698 labelItem = new SCH_HIERLABEL( aPosition );
1699 labelItem->SetShape( m_lastGlobalLabelShape );
1701 break;
1702
1703 case LAYER_GLOBLABEL:
1704 globalLabel = new SCH_GLOBALLABEL( aPosition );
1705 globalLabel->SetShape( m_lastGlobalLabelShape );
1706 globalLabel->GetField( FIELD_T::INTERSHEET_REFS )->SetVisible( settings.m_IntersheetRefsShow );
1708 labelItem = globalLabel;
1709
1710 if( SCH_LINE* wire = findWire( aPosition ) )
1711 netName = findWireLabelDriverName( wire );
1712
1713 break;
1714
1715 default:
1716 wxFAIL_MSG( "SCH_EDIT_FRAME::CreateNewText() unknown layer type" );
1717 return false;
1718 }
1719
1720 labelItem->SetParent( schematic );
1721
1722 labelItem->SetTextSize( VECTOR2I( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
1723
1724 if( aType != LAYER_NETCLASS_REFS )
1725 {
1726 // Must be after SetTextSize()
1727 labelItem->SetBold( m_lastTextBold );
1728 labelItem->SetItalic( m_lastTextItalic );
1729 }
1730
1731 labelItem->SetSpinStyle( m_lastTextOrientation );
1732 labelItem->SetFlags( IS_NEW | IS_MOVING );
1733
1734 if( !netName.IsEmpty() )
1735 {
1736 // Auto-create from attached wire
1737 labelItem->SetText( netName );
1738 }
1739 else
1740 {
1741 DIALOG_LABEL_PROPERTIES dlg( m_frame, labelItem, true );
1742
1743 dlg.SetLabelList( &aLabelList );
1744
1745 // QuasiModal required for syntax help and Scintilla auto-complete
1746 if( dlg.ShowQuasiModal() != wxID_OK )
1747 {
1749 delete labelItem;
1750 return false;
1751 }
1752 }
1753
1754 if( aType != LAYER_NETCLASS_REFS )
1755 {
1756 m_lastTextBold = labelItem->IsBold();
1757 m_lastTextItalic = labelItem->IsItalic();
1758 }
1759
1760 m_lastTextOrientation = labelItem->GetSpinStyle();
1761
1762 if( aType == LAYER_GLOBLABEL || aType == LAYER_HIERLABEL )
1763 {
1764 m_lastGlobalLabelShape = labelItem->GetShape();
1766 }
1767 else if( aType == LAYER_NETCLASS_REFS )
1768 {
1769 m_lastNetClassFlagShape = labelItem->GetShape();
1770 }
1771
1772 if( aLabelList.empty() )
1773 aLabelList.push_back( std::unique_ptr<SCH_LABEL_BASE>( labelItem ) );
1774 else // DIALOG_LABEL_PROPERTIES already filled in aLabelList; labelItem is extraneous to needs
1775 delete labelItem;
1776
1777 return true;
1778}
1779
1780
1782{
1783 SCHEMATIC* schematic = getModel<SCHEMATIC>();
1784 SCHEMATIC_SETTINGS& settings = schematic->Settings();
1785 SCH_TEXT* textItem = nullptr;
1786
1787 textItem = new SCH_TEXT( aPosition );
1788 textItem->SetParent( schematic );
1789 textItem->SetTextSize( VECTOR2I( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
1790 // Must be after SetTextSize()
1791 textItem->SetBold( m_lastTextBold );
1792 textItem->SetItalic( m_lastTextItalic );
1795 textItem->SetTextAngle( m_lastTextAngle );
1796 textItem->SetFlags( IS_NEW | IS_MOVING );
1797
1798 DIALOG_TEXT_PROPERTIES dlg( m_frame, textItem );
1799
1800 // QuasiModal required for syntax help and Scintilla auto-complete
1801 if( dlg.ShowQuasiModal() != wxID_OK )
1802 {
1803 delete textItem;
1804 return nullptr;
1805 }
1806
1807 m_lastTextBold = textItem->IsBold();
1808 m_lastTextItalic = textItem->IsItalic();
1809 m_lastTextHJustify = textItem->GetHorizJustify();
1810 m_lastTextVJustify = textItem->GetVertJustify();
1811 m_lastTextAngle = textItem->GetTextAngle();
1812 return textItem;
1813}
1814
1815
1817{
1818 SCHEMATIC_SETTINGS& settings = aSheet->Schematic()->Settings();
1819 SCH_SHEET_PIN* pin = new SCH_SHEET_PIN( aSheet );
1820
1821 pin->SetFlags( IS_NEW | IS_MOVING );
1822 pin->SetText( std::to_string( aSheet->GetPins().size() + 1 ) );
1823 pin->SetTextSize( VECTOR2I( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
1824 pin->SetPosition( aPosition );
1825 pin->ClearSelected();
1826
1827 m_lastSheetPinType = pin->GetShape();
1828
1829 return pin;
1830}
1831
1832
1834 const VECTOR2I& aPosition,
1835 SCH_HIERLABEL* aLabel )
1836{
1837 auto pin = createNewSheetPin( aSheet, aPosition );
1838 pin->SetText( aLabel->GetText() );
1839 pin->SetShape( aLabel->GetShape() );
1840 return pin;
1841}
1842
1843
1845{
1846 SCH_ITEM* item = nullptr;
1849 bool ignorePrimePosition = false;
1850 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
1851 SCH_SHEET* sheet = nullptr;
1852 wxString description;
1853
1854 if( m_inDrawingTool )
1855 return 0;
1856
1858
1859 bool isText = aEvent.IsAction( &SCH_ACTIONS::placeSchematicText );
1860 bool isGlobalLabel = aEvent.IsAction( &SCH_ACTIONS::placeGlobalLabel );
1861 bool isHierLabel = aEvent.IsAction( &SCH_ACTIONS::placeHierLabel );
1862 bool isClassLabel = aEvent.IsAction( &SCH_ACTIONS::placeClassLabel );
1863 bool isNetLabel = aEvent.IsAction( &SCH_ACTIONS::placeLabel );
1864 bool isSheetPin = aEvent.IsAction( &SCH_ACTIONS::placeSheetPin );
1865
1866 GRID_HELPER_GRIDS snapGrid = isText ? GRID_TEXT : GRID_CONNECTABLE;
1867
1868 // If we have a selected sheet use it, otherwise try to get one under the cursor
1869 if( isSheetPin )
1870 sheet = dynamic_cast<SCH_SHEET*>( m_selectionTool->GetSelection().Front() );
1871
1873
1874 m_frame->PushTool( aEvent );
1875
1876 auto setCursor =
1877 [&]()
1878 {
1879 if( item )
1880 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PLACE );
1881 else if( isText )
1882 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::TEXT );
1883 else if( isGlobalLabel )
1884 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_GLOBAL );
1885 else if( isNetLabel )
1886 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_NET );
1887 else if( isClassLabel )
1888 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_NET ); // JEY TODO: netclass directive cursor
1889 else if( isHierLabel )
1890 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_HIER );
1891 else
1892 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1893 };
1894
1895 auto updatePreview =
1896 [&]()
1897 {
1899 m_view->AddToPreview( item, false );
1900 item->RunOnChildren( [&]( SCH_ITEM* aChild )
1901 {
1902 m_view->AddToPreview( aChild, false );
1903 },
1904 RECURSE_MODE::NO_RECURSE );
1905 m_frame->SetMsgPanel( item );
1906 };
1907
1908 auto cleanup =
1909 [&]()
1910 {
1913 delete item;
1914 item = nullptr;
1915 };
1916
1917 auto prepItemForPlacement =
1918 [&]( SCH_ITEM* aItem, const VECTOR2I& cursorPos )
1919 {
1920 item->SetPosition( cursorPos );
1921
1922 item->SetFlags( IS_NEW | IS_MOVING );
1923
1924 // Not placed yet, so pass a nullptr screen reference
1925 item->AutoplaceFields( nullptr, AUTOPLACE_AUTO );
1926
1927 updatePreview();
1930
1931 // update the cursor so it looks correct before another event
1932 setCursor();
1933 };
1934
1935
1936 Activate();
1937
1938 // Must be done after Activate() so that it gets set into the correct context
1939 controls->ShowCursor( true );
1940
1941 // Set initial cursor
1942 setCursor();
1943
1944 if( aEvent.HasPosition() )
1945 {
1946 m_toolMgr->PrimeTool( aEvent.Position() );
1947 }
1948 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate()
1949 && ( isText || isGlobalLabel || isHierLabel || isClassLabel || isNetLabel ) )
1950 {
1951 m_toolMgr->PrimeTool( { 0, 0 } );
1952 ignorePrimePosition = true;
1953 }
1954
1955 SCH_COMMIT commit( m_toolMgr );
1956 std::list<std::unique_ptr<SCH_LABEL_BASE>> itemsToPlace;
1957
1958 // Main loop: keep receiving events
1959 while( TOOL_EVENT* evt = Wait() )
1960 {
1961 setCursor();
1962 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1963 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1964
1965 VECTOR2I cursorPos = controls->GetMousePosition();
1966 cursorPos = grid.BestSnapAnchor( cursorPos, snapGrid, item );
1967 controls->ForceCursorPosition( true, cursorPos );
1968
1969 // The tool hotkey is interpreted as a click when drawing
1970 bool isSyntheticClick = item && evt->IsActivate() && evt->HasPosition() && evt->Matches( aEvent );
1971
1972 if( evt->IsCancelInteractive() || evt->IsAction( &ACTIONS::undo ) )
1973 {
1975
1976 if( item )
1977 {
1978 cleanup();
1979 }
1980 else
1981 {
1982 m_frame->PopTool( aEvent );
1983 break;
1984 }
1985 }
1986 else if( evt->IsActivate() && !isSyntheticClick )
1987 {
1988 if( item && evt->IsMoveTool() )
1989 {
1990 // we're already moving our own item; ignore the move tool
1991 evt->SetPassEvent( false );
1992 continue;
1993 }
1994
1995 if( item )
1996 {
1997 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel item creation." ) );
1998 evt->SetPassEvent( false );
1999 continue;
2000 }
2001
2002 if( evt->IsPointEditor() )
2003 {
2004 // don't exit (the point editor runs in the background)
2005 }
2006 else if( evt->IsMoveTool() )
2007 {
2008 // leave ourselves on the stack so we come back after the move
2009 break;
2010 }
2011 else
2012 {
2013 m_frame->PopTool( aEvent );
2014 break;
2015 }
2016 }
2017 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) || isSyntheticClick )
2018 {
2019 PLACE_NEXT:
2020 // First click creates...
2021 if( !item )
2022 {
2024
2025 if( isText )
2026 {
2027 item = createNewText( cursorPos );
2028 description = _( "Add Text" );
2029 }
2030 else if( isHierLabel )
2031 {
2032 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
2033 {
2034 auto pin = static_cast<SCH_HIERLABEL*>( m_dialogSyncSheetPin->GetPlacementTemplate() );
2035 SCH_HIERLABEL* label = new SCH_HIERLABEL( cursorPos );
2036 SCHEMATIC* schematic = getModel<SCHEMATIC>();
2037 label->SetText( pin->GetText() );
2038 label->SetShape( pin->GetShape() );
2040 label->SetParent( schematic );
2041 label->SetBold( m_lastTextBold );
2042 label->SetItalic( m_lastTextItalic );
2044 label->SetTextSize( VECTOR2I( schematic->Settings().m_DefaultTextSize,
2045 schematic->Settings().m_DefaultTextSize ) );
2046 label->SetFlags( IS_NEW | IS_MOVING );
2047 itemsToPlace.push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
2048 }
2049 else
2050 {
2051 createNewLabel( cursorPos, LAYER_HIERLABEL, itemsToPlace );
2052 }
2053
2054 description = _( "Add Hierarchical Label" );
2055 }
2056 else if( isNetLabel )
2057 {
2058 createNewLabel( cursorPos, LAYER_LOCLABEL, itemsToPlace );
2059 description = _( "Add Label" );
2060 }
2061 else if( isGlobalLabel )
2062 {
2063 createNewLabel( cursorPos, LAYER_GLOBLABEL, itemsToPlace );
2064 description = _( "Add Label" );
2065 }
2066 else if( isClassLabel )
2067 {
2068 createNewLabel( cursorPos, LAYER_NETCLASS_REFS, itemsToPlace );
2069 description = _( "Add Label" );
2070 }
2071 else if( isSheetPin )
2072 {
2073 EDA_ITEM* i = nullptr;
2074
2075 // If we didn't have a sheet selected, try to find one under the cursor
2076 if( !sheet && m_selectionTool->SelectPoint( cursorPos, { SCH_SHEET_T }, &i ) )
2077 sheet = dynamic_cast<SCH_SHEET*>( i );
2078
2079 if( !sheet )
2080 {
2081 m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( m_frame );
2082 m_statusPopup->SetText( _( "Click over a sheet." ) );
2084 + wxPoint( 20, 20 ) );
2085 m_statusPopup->PopupFor( 2000 );
2086 item = nullptr;
2087 }
2088 else
2089 {
2090 // User is using the 'Sync Sheet Pins' tool
2091 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
2092 {
2094 sheet, cursorPos,
2095 static_cast<SCH_HIERLABEL*>( m_dialogSyncSheetPin->GetPlacementTemplate() ) );
2096 }
2097 else
2098 {
2099 // User is using the 'Place Sheet Pins' tool
2100 SCH_HIERLABEL* label = importHierLabel( sheet );
2101
2102 if( !label )
2103 {
2104 m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( m_frame );
2105 m_statusPopup->SetText( _( "No new hierarchical labels found." ) );
2107 + wxPoint( 20, 20 ) );
2108 m_statusPopup->PopupFor( 2000 );
2109 item = nullptr;
2110
2111 m_frame->PopTool( aEvent );
2112 break;
2113 }
2114
2115 item = createNewSheetPinFromLabel( sheet, cursorPos, label );
2116 }
2117 }
2118
2119 description = _( "Add Sheet Pin" );
2120 }
2121
2122 // If we started with a hotkey which has a position then warp back to that.
2123 // Otherwise update to the current mouse position pinned inside the autoscroll
2124 // boundaries.
2125 if( evt->IsPrime() && !ignorePrimePosition )
2126 {
2127 cursorPos = grid.Align( evt->Position() );
2128 getViewControls()->WarpMouseCursor( cursorPos, true );
2129 }
2130 else
2131 {
2133 cursorPos = getViewControls()->GetMousePosition();
2134 cursorPos = grid.BestSnapAnchor( cursorPos, snapGrid, item );
2135 }
2136
2137 if( !itemsToPlace.empty() )
2138 {
2139 item = itemsToPlace.front().release();
2140 itemsToPlace.pop_front();
2141 }
2142
2143 if( item )
2144 prepItemForPlacement( item, cursorPos );
2145
2146 controls->SetCursorPosition( cursorPos, false );
2147 }
2148 else // ... and second click places:
2149 {
2150 item->ClearFlags( IS_MOVING );
2151
2152 if( item->IsConnectable() )
2154
2155 if( isSheetPin && sheet )
2156 {
2157 // Sheet pins are owned by their parent sheet.
2158 commit.Modify( sheet, m_frame->GetScreen() );
2159 sheet->AddPin( (SCH_SHEET_PIN*) item );
2160 }
2161 else
2162 {
2164 m_frame->AddToScreen( item, m_frame->GetScreen() );
2165 commit.Added( item, m_frame->GetScreen() );
2166 }
2167
2169
2170 commit.Push( description );
2171
2173
2174 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
2175 {
2176 m_dialogSyncSheetPin->EndPlaceItem( item );
2177
2178 if( m_dialogSyncSheetPin->CanPlaceMore() )
2179 {
2180 item = nullptr;
2181 goto PLACE_NEXT;
2182 }
2183
2184 m_frame->PopTool( aEvent );
2186 m_dialogSyncSheetPin->Show( true );
2187 break;
2188 }
2189
2190 item = nullptr;
2191
2192 if( isSheetPin && sheet )
2193 {
2194 SCH_HIERLABEL* label = importHierLabel( sheet );
2195
2196 if( !label )
2197 {
2198 m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( m_frame );
2199 m_statusPopup->SetText( _( "No new hierarchical labels found." ) );
2200 m_statusPopup->Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
2201 m_statusPopup->PopupFor( 2000 );
2202
2203 m_frame->PopTool( aEvent );
2204 break;
2205 }
2206
2207 item = createNewSheetPinFromLabel( sheet, cursorPos, label );
2208 }
2209 else if( !itemsToPlace.empty() )
2210 {
2211 item = itemsToPlace.front().release();
2212 itemsToPlace.pop_front();
2213 prepItemForPlacement( item, cursorPos );
2214 }
2215 }
2216 }
2217 else if( evt->IsClick( BUT_RIGHT ) )
2218 {
2219 // Warp after context menu only if dragging...
2220 if( !item )
2222
2223 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
2224 }
2225 else if( item && evt->IsSelectionEvent() )
2226 {
2227 // This happens if our text was replaced out from under us by ConvertTextType()
2229
2230 if( selection.GetSize() == 1 )
2231 {
2232 item = (SCH_ITEM*) selection.Front();
2233 updatePreview();
2234 }
2235 else
2236 {
2237 item = nullptr;
2238 }
2239 }
2240 else if( evt->IsAction( &ACTIONS::increment ) )
2241 {
2243 }
2244 else if( evt->IsAction( &ACTIONS::duplicate )
2245 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem ) )
2246 {
2247 if( item )
2248 {
2249 // This doesn't really make sense; we'll just end up dragging a stack of
2250 // objects so we ignore the duplicate and just carry on.
2251 wxBell();
2252 continue;
2253 }
2254
2255 // Exit. The duplicate will run in its own loop.
2256 m_frame->PopTool( aEvent );
2257 evt->SetPassEvent();
2258 break;
2259 }
2260 else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
2261 {
2262 item->SetPosition( cursorPos );
2263
2264 // Not placed yet, so pass a nullptr screen reference
2265 item->AutoplaceFields( nullptr, AUTOPLACE_AUTO );
2266
2267 updatePreview();
2268 }
2269 else if( item && evt->IsAction( &ACTIONS::doDelete ) )
2270 {
2271 cleanup();
2272 }
2273 else if( evt->IsAction( &ACTIONS::redo ) )
2274 {
2275 wxBell();
2276 }
2277 else
2278 {
2279 evt->SetPassEvent();
2280 }
2281
2282 // Enable autopanning and cursor capture only when there is an item to be placed
2283 controls->SetAutoPan( item != nullptr );
2284 controls->CaptureCursor( item != nullptr );
2285 }
2286
2287 controls->SetAutoPan( false );
2288 controls->CaptureCursor( false );
2289 controls->ForceCursorPosition( false );
2290 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2291
2292 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->CanPlaceMore() )
2293 {
2294 m_dialogSyncSheetPin->EndPlacement();
2295 m_dialogSyncSheetPin->Show( true );
2296 }
2297
2298 return 0;
2299}
2300
2301
2303{
2304 SCHEMATIC* schematic = getModel<SCHEMATIC>();
2305 SCHEMATIC_SETTINGS& sch_settings = schematic->Settings();
2306 SCH_SHAPE* item = nullptr;
2307 bool isTextBox = aEvent.IsAction( &SCH_ACTIONS::drawTextBox );
2308 SHAPE_T type = aEvent.Parameter<SHAPE_T>();
2309 wxString description;
2310
2311 if( m_inDrawingTool )
2312 return 0;
2313
2315
2318 VECTOR2I cursorPos;
2319
2320 // We might be running as the same shape in another co-routine. Make sure that one
2321 // gets whacked.
2323
2325
2326 m_frame->PushTool( aEvent );
2327
2328 auto setCursor =
2329 [&]()
2330 {
2331 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2332 };
2333
2334 auto cleanup =
2335 [&] ()
2336 {
2339 delete item;
2340 item = nullptr;
2341 };
2342
2343 Activate();
2344
2345 // Must be done after Activate() so that it gets set into the correct context
2346 getViewControls()->ShowCursor( true );
2347
2348 // Set initial cursor
2349 setCursor();
2350
2351 if( aEvent.HasPosition() )
2352 m_toolMgr->PrimeTool( aEvent.Position() );
2353
2354 // Main loop: keep receiving events
2355 while( TOOL_EVENT* evt = Wait() )
2356 {
2357 setCursor();
2358 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2359 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2360
2361 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
2362 controls->ForceCursorPosition( true, cursorPos );
2363
2364 // The tool hotkey is interpreted as a click when drawing
2365 bool isSyntheticClick = item && evt->IsActivate() && evt->HasPosition() && evt->Matches( aEvent );
2366
2367 if( evt->IsCancelInteractive() || ( item && evt->IsAction( &ACTIONS::undo ) ) )
2368 {
2369 if( item )
2370 {
2371 cleanup();
2372 }
2373 else
2374 {
2375 m_frame->PopTool( aEvent );
2376 break;
2377 }
2378 }
2379 else if( evt->IsActivate() && !isSyntheticClick )
2380 {
2381 if( item && evt->IsMoveTool() )
2382 {
2383 // we're already drawing our own item; ignore the move tool
2384 evt->SetPassEvent( false );
2385 continue;
2386 }
2387
2388 if( item )
2389 cleanup();
2390
2391 if( evt->IsPointEditor() )
2392 {
2393 // don't exit (the point editor runs in the background)
2394 }
2395 else if( evt->IsMoveTool() )
2396 {
2397 // leave ourselves on the stack so we come back after the move
2398 break;
2399 }
2400 else
2401 {
2402 m_frame->PopTool( aEvent );
2403 break;
2404 }
2405 }
2406 else if( evt->IsClick( BUT_LEFT ) && !item )
2407 {
2409
2410 if( isTextBox )
2411 {
2413
2414 textbox->SetTextSize( VECTOR2I( sch_settings.m_DefaultTextSize,
2415 sch_settings.m_DefaultTextSize ) );
2416
2417 // Must come after SetTextSize()
2418 textbox->SetBold( m_lastTextBold );
2419 textbox->SetItalic( m_lastTextItalic );
2420
2421 textbox->SetTextAngle( m_lastTextboxAngle );
2424 textbox->SetStroke( m_lastTextboxStroke );
2426 textbox->SetParent( schematic );
2427
2428 item = textbox;
2429 description = _( "Add Text Box" );
2430 }
2431 else
2432 {
2433 item = new SCH_SHAPE( type, LAYER_NOTES, 0, m_lastFillStyle );
2434
2435 item->SetStroke( m_lastStroke );
2437 item->SetParent( schematic );
2438 description = wxString::Format( _( "Add %s" ), item->GetFriendlyName() );
2439 }
2440
2441 item->SetFlags( IS_NEW );
2442 item->BeginEdit( cursorPos );
2443
2445 m_view->AddToPreview( item->Clone() );
2446 }
2447 else if( item && ( evt->IsClick( BUT_LEFT )
2448 || evt->IsDblClick( BUT_LEFT )
2449 || isSyntheticClick
2450 || evt->IsAction( &ACTIONS::finishInteractive ) ) )
2451 {
2452 if( evt->IsDblClick( BUT_LEFT )
2453 || evt->IsAction( &ACTIONS::finishInteractive )
2454 || !item->ContinueEdit( cursorPos ) )
2455 {
2456 item->EndEdit();
2457 item->ClearEditFlags();
2458 item->SetFlags( IS_NEW );
2459
2460 if( isTextBox )
2461 {
2462 SCH_TEXTBOX* textbox = static_cast<SCH_TEXTBOX*>( item );
2463 DIALOG_TEXT_PROPERTIES dlg( m_frame, textbox );
2464
2465 getViewControls()->SetAutoPan( false );
2466 getViewControls()->CaptureCursor( false );
2467
2468 // QuasiModal required for syntax help and Scintilla auto-complete
2469 if( dlg.ShowQuasiModal() != wxID_OK )
2470 {
2471 cleanup();
2472 continue;
2473 }
2474
2475 m_lastTextBold = textbox->IsBold();
2476 m_lastTextItalic = textbox->IsItalic();
2477 m_lastTextboxAngle = textbox->GetTextAngle();
2480 m_lastTextboxStroke = textbox->GetStroke();
2483 }
2484 else
2485 {
2486 m_lastStroke = item->GetStroke();
2487 m_lastFillStyle = item->GetFillMode();
2488 m_lastFillColor = item->GetFillColor();
2489 }
2490
2491 SCH_COMMIT commit( m_toolMgr );
2492 commit.Add( item, m_frame->GetScreen() );
2493 commit.Push( wxString::Format( _( "Draw %s" ), item->GetClass() ) );
2494
2496 item = nullptr;
2497
2500 }
2501 }
2502 else if( evt->IsAction( &ACTIONS::duplicate )
2503 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem ) )
2504 {
2505 if( item )
2506 {
2507 // This doesn't really make sense; we'll just end up dragging a stack of
2508 // objects so we ignore the duplicate and just carry on.
2509 wxBell();
2510 continue;
2511 }
2512
2513 // Exit. The duplicate will run in its own loop.
2514 m_frame->PopTool( aEvent );
2515 evt->SetPassEvent();
2516 break;
2517 }
2518 else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
2519 {
2520 item->CalcEdit( cursorPos );
2522 m_view->AddToPreview( item->Clone() );
2523 m_frame->SetMsgPanel( item );
2524 }
2525 else if( evt->IsDblClick( BUT_LEFT ) && !item )
2526 {
2528 }
2529 else if( evt->IsClick( BUT_RIGHT ) )
2530 {
2531 // Warp after context menu only if dragging...
2532 if( !item )
2534
2535 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
2536 }
2537 else if( item && evt->IsAction( &ACTIONS::redo ) )
2538 {
2539 wxBell();
2540 }
2541 else
2542 {
2543 evt->SetPassEvent();
2544 }
2545
2546 // Enable autopanning and cursor capture only when there is a shape being drawn
2547 getViewControls()->SetAutoPan( item != nullptr );
2548 getViewControls()->CaptureCursor( item != nullptr );
2549 }
2550
2551 getViewControls()->SetAutoPan( false );
2552 getViewControls()->CaptureCursor( false );
2553 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2554 return 0;
2555}
2556
2557
2559{
2560 if( m_inDrawingTool )
2561 return 0;
2562
2564 SCOPED_SET_RESET<bool> scopedDrawMode( m_drawingRuleArea, true );
2565
2568 VECTOR2I cursorPos;
2569
2570 RULE_AREA_CREATE_HELPER ruleAreaTool( *getView(), m_frame, m_toolMgr );
2571 POLYGON_GEOM_MANAGER polyGeomMgr( ruleAreaTool );
2572 bool started = false;
2573
2574 // We might be running as the same shape in another co-routine. Make sure that one
2575 // gets whacked.
2577
2579
2580 m_frame->PushTool( aEvent );
2581
2582 auto setCursor =
2583 [&]()
2584 {
2585 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2586 };
2587
2588 auto cleanup =
2589 [&]()
2590 {
2591 polyGeomMgr.Reset();
2592 started = false;
2593 getViewControls()->SetAutoPan( false );
2594 getViewControls()->CaptureCursor( false );
2596 };
2597
2598 Activate();
2599
2600 // Must be done after Activate() so that it gets set into the correct context
2601 getViewControls()->ShowCursor( true );
2602 //m_controls->ForceCursorPosition( false );
2603
2604 // Set initial cursor
2605 setCursor();
2606
2607 if( aEvent.HasPosition() )
2608 m_toolMgr->PrimeTool( aEvent.Position() );
2609
2610 // Main loop: keep receiving events
2611 while( TOOL_EVENT* evt = Wait() )
2612 {
2613 setCursor();
2614
2615 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2616 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2617
2618 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
2619 controls->ForceCursorPosition( true, cursorPos );
2620
2624
2625 if( evt->IsCancelInteractive() )
2626 {
2627 if( started )
2628 {
2629 cleanup();
2630 }
2631 else
2632 {
2633 m_frame->PopTool( aEvent );
2634
2635 // We've handled the cancel event. Don't cancel other tools
2636 evt->SetPassEvent( false );
2637 break;
2638 }
2639 }
2640 else if( evt->IsActivate() )
2641 {
2642 if( started )
2643 cleanup();
2644
2645 if( evt->IsPointEditor() )
2646 {
2647 // don't exit (the point editor runs in the background)
2648 }
2649 else if( evt->IsMoveTool() )
2650 {
2651 // leave ourselves on the stack so we come back after the move
2652 break;
2653 }
2654 else
2655 {
2656 m_frame->PopTool( aEvent );
2657 break;
2658 }
2659 }
2660 else if( evt->IsClick( BUT_RIGHT ) )
2661 {
2662 if( !started )
2664
2665 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
2666 }
2667 // events that lock in nodes
2668 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
2669 || evt->IsAction( &SCH_ACTIONS::closeOutline ) )
2670 {
2671 // Check if it is double click / closing line (so we have to finish the zone)
2672 const bool endPolygon = evt->IsDblClick( BUT_LEFT )
2673 || evt->IsAction( &SCH_ACTIONS::closeOutline )
2674 || polyGeomMgr.NewPointClosesOutline( cursorPos );
2675
2676 if( endPolygon )
2677 {
2678 polyGeomMgr.SetFinished();
2679 polyGeomMgr.Reset();
2680
2681 started = false;
2682 getViewControls()->SetAutoPan( false );
2683 getViewControls()->CaptureCursor( false );
2684 }
2685 // adding a corner
2686 else if( polyGeomMgr.AddPoint( cursorPos ) )
2687 {
2688 if( !started )
2689 {
2690 started = true;
2691
2692 getViewControls()->SetAutoPan( true );
2693 getViewControls()->CaptureCursor( true );
2694 }
2695 }
2696 }
2697 else if( started
2698 && ( evt->IsAction( &SCH_ACTIONS::deleteLastPoint )
2699 || evt->IsAction( &ACTIONS::doDelete )
2700 || evt->IsAction( &ACTIONS::undo ) ) )
2701 {
2702 if( std::optional<VECTOR2I> last = polyGeomMgr.DeleteLastCorner() )
2703 {
2704 cursorPos = last.value();
2705 getViewControls()->WarpMouseCursor( cursorPos, true );
2706 getViewControls()->ForceCursorPosition( true, cursorPos );
2707 polyGeomMgr.SetCursorPosition( cursorPos );
2708 }
2709 else
2710 {
2711 cleanup();
2712 }
2713 }
2714 else if( started && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) )
2715 {
2716 polyGeomMgr.SetCursorPosition( cursorPos );
2717 }
2718 else
2719 {
2720 evt->SetPassEvent();
2721 }
2722
2723 } // end while
2724
2725 getViewControls()->SetAutoPan( false );
2726 getViewControls()->CaptureCursor( false );
2727 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2728 return 0;
2729}
2730
2731
2733{
2734 SCHEMATIC* schematic = getModel<SCHEMATIC>();
2735 SCH_TABLE* table = nullptr;
2736
2737 if( m_inDrawingTool )
2738 return 0;
2739
2741
2744 VECTOR2I cursorPos;
2745
2746 // We might be running as the same shape in another co-routine. Make sure that one
2747 // gets whacked.
2749
2751
2752 m_frame->PushTool( aEvent );
2753
2754 auto setCursor =
2755 [&]()
2756 {
2757 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2758 };
2759
2760 auto cleanup =
2761 [&] ()
2762 {
2765 delete table;
2766 table = nullptr;
2767 };
2768
2769 Activate();
2770
2771 // Must be done after Activate() so that it gets set into the correct context
2772 getViewControls()->ShowCursor( true );
2773
2774 // Set initial cursor
2775 setCursor();
2776
2777 if( aEvent.HasPosition() )
2778 m_toolMgr->PrimeTool( aEvent.Position() );
2779
2780 // Main loop: keep receiving events
2781 while( TOOL_EVENT* evt = Wait() )
2782 {
2783 setCursor();
2784 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2785 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2786
2787 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
2788 controls->ForceCursorPosition( true, cursorPos );
2789
2790 // The tool hotkey is interpreted as a click when drawing
2791 bool isSyntheticClick = table && evt->IsActivate() && evt->HasPosition() && evt->Matches( aEvent );
2792
2793 if( evt->IsCancelInteractive() || ( table && evt->IsAction( &ACTIONS::undo ) ) )
2794 {
2795 if( table )
2796 {
2797 cleanup();
2798 }
2799 else
2800 {
2801 m_frame->PopTool( aEvent );
2802 break;
2803 }
2804 }
2805 else if( evt->IsActivate() && !isSyntheticClick )
2806 {
2807 if( table && evt->IsMoveTool() )
2808 {
2809 // we're already drawing our own item; ignore the move tool
2810 evt->SetPassEvent( false );
2811 continue;
2812 }
2813
2814 if( table )
2815 cleanup();
2816
2817 if( evt->IsPointEditor() )
2818 {
2819 // don't exit (the point editor runs in the background)
2820 }
2821 else if( evt->IsMoveTool() )
2822 {
2823 // leave ourselves on the stack so we come back after the move
2824 break;
2825 }
2826 else
2827 {
2828 m_frame->PopTool( aEvent );
2829 break;
2830 }
2831 }
2832 else if( evt->IsClick( BUT_LEFT ) && !table )
2833 {
2835
2836 table = new SCH_TABLE( 0 );
2837 table->SetColCount( 1 );
2838
2839 SCH_TABLECELL* tableCell = new SCH_TABLECELL();
2840 int defaultTextSize = schematic->Settings().m_DefaultTextSize;
2841
2842 tableCell->SetTextSize( VECTOR2I( defaultTextSize, defaultTextSize ) );
2843 table->AddCell( tableCell );
2844
2845 table->SetParent( schematic );
2846 table->SetFlags( IS_NEW );
2847 table->SetPosition( cursorPos );
2848
2850 m_view->AddToPreview( table->Clone() );
2851 }
2852 else if( table && ( evt->IsClick( BUT_LEFT )
2853 || evt->IsDblClick( BUT_LEFT )
2854 || isSyntheticClick
2855 || evt->IsAction( &SCH_ACTIONS::finishInteractive ) ) )
2856 {
2857 table->ClearEditFlags();
2858 table->SetFlags( IS_NEW );
2859 table->Normalize();
2860
2862
2863 // QuasiModal required for Scintilla auto-complete
2864 if( dlg.ShowQuasiModal() == wxID_OK )
2865 {
2866 SCH_COMMIT commit( m_toolMgr );
2867 commit.Add( table, m_frame->GetScreen() );
2868 commit.Push( _( "Draw Table" ) );
2869
2872 }
2873 else
2874 {
2875 delete table;
2876 }
2877
2878 table = nullptr;
2880 }
2881 else if( table && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
2882 {
2883 VECTOR2I gridSize = grid.GetGridSize( grid.GetItemGrid( table ) );
2884 int fontSize = schematic->Settings().m_DefaultTextSize;
2885 VECTOR2I origin( table->GetPosition() );
2886 VECTOR2I requestedSize( cursorPos - origin );
2887
2888 int colCount = std::max( 1, requestedSize.x / ( fontSize * 15 ) );
2889 int rowCount = std::max( 1, requestedSize.y / ( fontSize * 2 ) );
2890
2891 VECTOR2I cellSize( std::max( gridSize.x * 5, requestedSize.x / colCount ),
2892 std::max( gridSize.y * 2, requestedSize.y / rowCount ) );
2893
2894 cellSize.x = KiROUND( (double) cellSize.x / gridSize.x ) * gridSize.x;
2895 cellSize.y = KiROUND( (double) cellSize.y / gridSize.y ) * gridSize.y;
2896
2897 table->ClearCells();
2898 table->SetColCount( colCount );
2899
2900 for( int col = 0; col < colCount; ++col )
2901 table->SetColWidth( col, cellSize.x );
2902
2903 for( int row = 0; row < rowCount; ++row )
2904 {
2905 table->SetRowHeight( row, cellSize.y );
2906
2907 for( int col = 0; col < colCount; ++col )
2908 {
2909 SCH_TABLECELL* cell = new SCH_TABLECELL();
2910 int defaultTextSize = schematic->Settings().m_DefaultTextSize;
2911
2912 cell->SetTextSize( VECTOR2I( defaultTextSize, defaultTextSize ) );
2913 cell->SetPosition( origin + VECTOR2I( col * cellSize.x, row * cellSize.y ) );
2914 cell->SetEnd( cell->GetPosition() + cellSize );
2915 table->AddCell( cell );
2916 }
2917 }
2918
2920 m_view->AddToPreview( table->Clone() );
2922 }
2923 else if( evt->IsDblClick( BUT_LEFT ) && !table )
2924 {
2926 }
2927 else if( evt->IsClick( BUT_RIGHT ) )
2928 {
2929 // Warp after context menu only if dragging...
2930 if( !table )
2932
2933 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
2934 }
2935 else if( table && evt->IsAction( &ACTIONS::redo ) )
2936 {
2937 wxBell();
2938 }
2939 else
2940 {
2941 evt->SetPassEvent();
2942 }
2943
2944 // Enable autopanning and cursor capture only when there is a shape being drawn
2945 getViewControls()->SetAutoPan( table != nullptr );
2946 getViewControls()->CaptureCursor( table != nullptr );
2947 }
2948
2949 getViewControls()->SetAutoPan( false );
2950 getViewControls()->CaptureCursor( false );
2951 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2952 return 0;
2953}
2954
2955
2957{
2958 bool isDrawSheetCopy = aEvent.IsAction( &SCH_ACTIONS::drawSheetFromFile );
2959 bool isDrawSheetFromDesignBlock = aEvent.IsAction( &SCH_ACTIONS::drawSheetFromDesignBlock );
2960
2961 std::unique_ptr<DESIGN_BLOCK> designBlock;
2962
2963 SCH_SHEET* sheet = nullptr;
2964 wxString filename;
2965
2966 if( isDrawSheetCopy )
2967 {
2968 wxString* ptr = aEvent.Parameter<wxString*>();
2969 wxCHECK( ptr, 0 );
2970
2971 // We own the string if we're importing a sheet
2972 filename = *ptr;
2973 delete ptr;
2974 }
2975 else if( isDrawSheetFromDesignBlock )
2976 {
2977 designBlock.reset( aEvent.Parameter<DESIGN_BLOCK*>() );
2978 wxCHECK( designBlock, 0 );
2979 filename = designBlock->GetSchematicFile();
2980 }
2981
2982 if( ( isDrawSheetCopy || isDrawSheetFromDesignBlock ) && !wxFileExists( filename ) )
2983 {
2984 wxMessageBox( wxString::Format( _( "File '%s' does not exist." ), filename ) );
2985 return 0;
2986 }
2987
2988 if( m_inDrawingTool )
2989 return 0;
2990
2992
2994 SCHEMATIC_SETTINGS& schSettings = m_frame->Schematic().Settings();
2997 VECTOR2I cursorPos;
2998
3000
3001 m_frame->PushTool( aEvent );
3002
3003 auto setCursor =
3004 [&]()
3005 {
3006 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
3007 };
3008
3009 auto cleanup =
3010 [&] ()
3011 {
3014 delete sheet;
3015 sheet = nullptr;
3016 };
3017
3018 Activate();
3019
3020 // Must be done after Activate() so that it gets set into the correct context
3021 getViewControls()->ShowCursor( true );
3022
3023 // Set initial cursor
3024 setCursor();
3025
3026 if( aEvent.HasPosition() && !( isDrawSheetCopy || isDrawSheetFromDesignBlock ) )
3027 m_toolMgr->PrimeTool( aEvent.Position() );
3028
3029 // Main loop: keep receiving events
3030 while( TOOL_EVENT* evt = Wait() )
3031 {
3032 setCursor();
3033 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
3034 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
3035
3036 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
3037 controls->ForceCursorPosition( true, cursorPos );
3038
3039 // The tool hotkey is interpreted as a click when drawing
3040 bool isSyntheticClick = sheet && evt->IsActivate() && evt->HasPosition()
3041 && evt->Matches( aEvent );
3042
3043 if( evt->IsCancelInteractive() || ( sheet && evt->IsAction( &ACTIONS::undo ) ) )
3044 {
3046
3047 if( sheet )
3048 {
3049 cleanup();
3050 }
3051 else
3052 {
3053 m_frame->PopTool( aEvent );
3054 break;
3055 }
3056 }
3057 else if( evt->IsActivate() && !isSyntheticClick )
3058 {
3059 if( sheet && evt->IsMoveTool() )
3060 {
3061 // we're already drawing our own item; ignore the move tool
3062 evt->SetPassEvent( false );
3063 continue;
3064 }
3065
3066 if( sheet )
3067 {
3068 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel sheet creation." ) );
3069 evt->SetPassEvent( false );
3070 continue;
3071 }
3072
3073 if( evt->IsPointEditor() )
3074 {
3075 // don't exit (the point editor runs in the background)
3076 }
3077 else if( evt->IsMoveTool() )
3078 {
3079 // leave ourselves on the stack so we come back after the move
3080 break;
3081 }
3082 else
3083 {
3084 m_frame->PopTool( aEvent );
3085 break;
3086 }
3087 }
3088 else if( !sheet && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) ) )
3089 {
3091
3092 if( selection.Size() == 1
3093 && selection.Front()->Type() == SCH_SHEET_T
3094 && selection.Front()->GetBoundingBox().Contains( cursorPos ) )
3095 {
3096 if( evt->IsClick( BUT_LEFT ) )
3097 {
3098 // sheet already selected
3099 continue;
3100 }
3101 else if( evt->IsDblClick( BUT_LEFT ) )
3102 {
3104 m_frame->PopTool( aEvent );
3105 break;
3106 }
3107 }
3108
3110
3111 sheet = new SCH_SHEET( m_frame->GetCurrentSheet().Last(), cursorPos );
3112 sheet->SetScreen( nullptr );
3113
3114 if( isDrawSheetCopy )
3115 {
3116 wxFileName fn( filename );
3117
3118 sheet->GetField( FIELD_T::SHEET_NAME )->SetText( fn.GetName() );
3119 sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( fn.GetName() + wxT( "." ) + FILEEXT::KiCadSchematicFileExtension );
3120 }
3121 else if( isDrawSheetFromDesignBlock )
3122 {
3123 wxFileName fn( filename );
3124
3125 sheet->GetField( FIELD_T::SHEET_NAME )->SetText( designBlock->GetLibId().GetLibItemName() );
3126 sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( fn.GetName() + wxT( "." ) + FILEEXT::KiCadSchematicFileExtension );
3127
3128 std::vector<SCH_FIELD>& sheetFields = sheet->GetFields();
3129
3130 // Copy default fields into the sheet
3131 for( const auto& [fieldName, fieldValue] : designBlock->GetFields() )
3132 {
3133 sheetFields.emplace_back( sheet, FIELD_T::USER, fieldName );
3134 sheetFields.back().SetText( fieldValue );
3135 sheetFields.back().SetVisible( false );
3136 }
3137 }
3138 else
3139 {
3140 sheet->GetField( FIELD_T::SHEET_NAME )->SetText( wxT( "Untitled Sheet" ) );
3141 sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( wxString::Format( wxT( "untitled.%s" ), FILEEXT::KiCadSchematicFileExtension ) );
3142 }
3143
3144 sheet->SetFlags( IS_NEW | IS_MOVING );
3148 sizeSheet( sheet, cursorPos );
3149
3150 SCH_SHEET_LIST hierarchy = m_frame->Schematic().Hierarchy();
3152 instance.push_back( sheet );
3153 wxString pageNumber;
3154
3155 // Don't try to be too clever when assigning the next availabe page number. Just use
3156 // the number of sheets plus one.
3157 pageNumber.Printf( wxT( "%d" ), static_cast<int>( hierarchy.size() ) + 1 );
3158 instance.SetPageNumber( pageNumber );
3159
3161 m_view->AddToPreview( sheet->Clone() );
3162 }
3163 else if( sheet && ( evt->IsClick( BUT_LEFT )
3164 || evt->IsDblClick( BUT_LEFT )
3165 || isSyntheticClick
3166 || evt->IsAction( &ACTIONS::finishInteractive ) ) )
3167 {
3168 getViewControls()->SetAutoPan( false );
3169 getViewControls()->CaptureCursor( false );
3170
3171 if( m_frame->EditSheetProperties( static_cast<SCH_SHEET*>( sheet ),
3172 &m_frame->GetCurrentSheet(), nullptr, nullptr,
3173 nullptr, &filename ) )
3174 {
3176
3178
3179 // Use the commit we were provided or make our own
3180 SCH_COMMIT tempCommit = SCH_COMMIT( m_toolMgr );
3181 SCH_COMMIT& c = evt->Commit() ? *( (SCH_COMMIT*) evt->Commit() ) : tempCommit;
3182
3183 // We need to manually add the sheet to the screen otherwise annotation will not be able to find
3184 // the sheet and its symbols to annotate.
3185 m_frame->AddToScreen( sheet );
3186 c.Added( sheet, m_frame->GetScreen() );
3187
3188 // This convoluted logic means we always annotate unless we are drawing a copy/design block
3189 // and the user has explicitly requested we keep the annotations via checkbox
3191
3192 if( annotate.automatic
3193 && !( ( isDrawSheetCopy || isDrawSheetFromDesignBlock )
3195 {
3196 // Annotation will remove this from selection, but we add it back later
3197 m_selectionTool->AddItemToSel( sheet );
3198
3199 NULL_REPORTER reporter;
3202 (ANNOTATE_ALGO_T) annotate.method, true /* recursive */,
3203 schSettings.m_AnnotateStartNum, true, false, reporter );
3204 }
3205
3206 c.Push( isDrawSheetCopy ? "Import Sheet Copy" : "Draw Sheet" );
3207
3208 m_selectionTool->AddItemToSel( sheet );
3209 }
3210 else
3211 {
3213 delete sheet;
3214 }
3215
3216 sheet = nullptr;
3217 }
3218 else if( evt->IsAction( &ACTIONS::duplicate )
3219 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem ) )
3220 {
3221 if( sheet )
3222 {
3223 // This doesn't really make sense; we'll just end up dragging a stack of
3224 // objects so we ignore the duplicate and just carry on.
3225 wxBell();
3226 continue;
3227 }
3228
3229 // Exit. The duplicate will run in its own loop.
3230 m_frame->PopTool( aEvent );
3231 evt->SetPassEvent();
3232 break;
3233 }
3234 else if( sheet && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
3235 {
3236 sizeSheet( sheet, cursorPos );
3238 m_view->AddToPreview( sheet->Clone() );
3239 m_frame->SetMsgPanel( sheet );
3240 }
3241 else if( evt->IsClick( BUT_RIGHT ) )
3242 {
3243 // Warp after context menu only if dragging...
3244 if( !sheet )
3246
3247 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
3248 }
3249 else if( sheet && evt->IsAction( &ACTIONS::redo ) )
3250 {
3251 wxBell();
3252 }
3253 else
3254 {
3255 evt->SetPassEvent();
3256 }
3257
3258 // Enable autopanning and cursor capture only when there is a sheet to be placed
3259 getViewControls()->SetAutoPan( sheet != nullptr );
3260 getViewControls()->CaptureCursor( sheet != nullptr );
3261 }
3262
3263 getViewControls()->SetAutoPan( false );
3264 getViewControls()->CaptureCursor( false );
3265 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
3266
3267 return 0;
3268}
3269
3270
3272{
3273 VECTOR2I pos = aSheet->GetPosition();
3274 VECTOR2I size = aPos - pos;
3275
3276 size.x = std::max( size.x, schIUScale.MilsToIU( MIN_SHEET_WIDTH ) );
3277 size.y = std::max( size.y, schIUScale.MilsToIU( MIN_SHEET_HEIGHT ) );
3278
3280 aSheet->Resize( VECTOR2I( grid.x - pos.x, grid.y - pos.y ) );
3281}
3282
3283
3284int SCH_DRAWING_TOOLS::doSyncSheetsPins( std::list<SCH_SHEET_PATH> sheetPaths )
3285{
3286 if( !sheetPaths.size() )
3287 return 0;
3288
3289 m_dialogSyncSheetPin = std::make_unique<DIALOG_SYNC_SHEET_PINS>(
3290 m_frame, std::move( sheetPaths ),
3291 std::make_shared<SHEET_SYNCHRONIZATION_AGENT>(
3292 [&]( EDA_ITEM* aItem, SCH_SHEET_PATH aPath,
3294 {
3295 SCH_COMMIT commit( m_toolMgr );
3296
3297 if( auto pin = dynamic_cast<SCH_SHEET_PIN*>( aItem ) )
3298 {
3299 commit.Modify( pin->GetParent(), aPath.LastScreen() );
3300 aModify();
3301 commit.Push( _( "Modify sheet pin" ) );
3302 }
3303 else
3304 {
3305 commit.Modify( aItem, aPath.LastScreen() );
3306 aModify();
3307 commit.Push( _( "Modify schematic item" ) );
3308 }
3309
3310 updateItem( aItem, true );
3311 m_frame->OnModify();
3312 },
3313 [&]( EDA_ITEM* aItem, SCH_SHEET_PATH aPath )
3314 {
3317 selectionTool->UnbrightenItem( aItem );
3318 selectionTool->AddItemToSel( aItem, true );
3320 },
3321 [&]( SCH_SHEET* aItem, SCH_SHEET_PATH aPath,
3323 std::set<EDA_ITEM*> aTemplates )
3324 {
3325 switch( aOp )
3326 {
3328 {
3329 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
3330 m_dialogSyncSheetPin->Hide();
3331 m_dialogSyncSheetPin->PreparePlacementTemplate(
3335 break;
3336 }
3338 {
3339 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
3340 m_dialogSyncSheetPin->Hide();
3341 m_dialogSyncSheetPin->PreparePlacementTemplate(
3344 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->SyncSelection( {}, nullptr, { sheet } );
3346 break;
3347 }
3348 }
3349 },
3350 m_toolMgr, m_frame ) );
3351 m_dialogSyncSheetPin->Show( true );
3352 return 0;
3353}
3354
3355
3357{
3358 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( m_selectionTool->GetSelection().Front() );
3359
3360 if( !sheet )
3361 {
3362 VECTOR2I cursorPos = getViewControls()->GetMousePosition();
3363
3364 if( EDA_ITEM* i = nullptr; static_cast<void>(m_selectionTool->SelectPoint( cursorPos, { SCH_SHEET_T }, &i ) ) , i != nullptr )
3365 {
3366 sheet = dynamic_cast<SCH_SHEET*>( i );
3367 }
3368 }
3369
3370 if ( sheet )
3371 {
3373 current.push_back( sheet );
3374 return doSyncSheetsPins( { current } );
3375 }
3376
3377 return 0;
3378}
3379
3380
3382{
3383 if( m_inDrawingTool )
3384 return 0;
3385
3387
3388 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( m_selectionTool->GetSelection().Front() );
3389
3390 if( !sheet )
3391 return 0;
3392
3393 std::vector<SCH_HIERLABEL*> labels = importHierLabels( sheet );
3394
3395 if( labels.empty() )
3396 {
3397 m_frame->PushTool( aEvent );
3398 m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( m_frame );
3399 m_statusPopup->SetText( _( "No new hierarchical labels found." ) );
3400 m_statusPopup->Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
3401 m_statusPopup->PopupFor( 2000 );
3402 m_frame->PopTool( aEvent );
3405 return 0;
3406 }
3407
3409
3410 SCH_COMMIT commit( m_toolMgr );
3411 BOX2I bbox = sheet->GetBoundingBox();
3412 VECTOR2I cursorPos = bbox.GetPosition();
3413 SCH_ITEM* lastPlacedLabel = nullptr;
3414
3415 auto calculatePositionForLabel =
3416 [&]( const SCH_ITEM* lastLabel, const SCH_HIERLABEL* currentLabel ) -> VECTOR2I
3417 {
3418 if( !lastLabel )
3419 return cursorPos;
3420
3421 int lastX = lastLabel->GetPosition().x;
3422 int lastY = lastLabel->GetPosition().y;
3423 int lastWidth = lastLabel->GetBoundingBox().GetWidth();
3424 int lastHeight = lastLabel->GetBoundingBox().GetHeight();
3425
3426 int currentWidth = currentLabel->GetBoundingBox().GetWidth();
3427 int currentHeight = currentLabel->GetBoundingBox().GetHeight();
3428
3429 // If there is enough space, place the label to the right of the last placed label
3430 if( ( lastX + lastWidth + currentWidth ) <= ( bbox.GetPosition().x + bbox.GetSize().x ) )
3431 return { lastX + lastWidth, lastY };
3432
3433 // If not enough space to the right, move to the next row if vertical space allows
3434 if( ( lastY + lastHeight + currentHeight ) <= ( bbox.GetPosition().y + bbox.GetSize().y ) )
3435 return { bbox.GetPosition().x, lastY + lastHeight };
3436
3437 return cursorPos;
3438 };
3439
3440 for( SCH_HIERLABEL* label : labels )
3441 {
3442 if( !lastPlacedLabel )
3443 {
3444 std::vector<SCH_SHEET_PIN*> existingPins = sheet->GetPins();
3445
3446 if( !existingPins.empty() )
3447 {
3448 std::sort( existingPins.begin(), existingPins.end(),
3449 []( const SCH_ITEM* a, const SCH_ITEM* b )
3450 {
3451 return ( a->GetPosition().x < b->GetPosition().x )
3452 || ( a->GetPosition().x == b->GetPosition().x
3453 && a->GetPosition().y < b->GetPosition().y );
3454 } );
3455
3456 lastPlacedLabel = existingPins.back();
3457 }
3458 }
3459
3460 cursorPos = calculatePositionForLabel( lastPlacedLabel, label );
3461 SCH_ITEM* item = createNewSheetPinFromLabel( sheet, cursorPos, label );
3462
3463 if( item )
3464 {
3465 item->SetFlags( IS_NEW | IS_MOVING );
3466 item->AutoplaceFields( nullptr, AUTOPLACE_AUTO );
3467 item->ClearFlags( IS_MOVING );
3468
3469 if( item->IsConnectable() )
3471
3472 commit.Modify( sheet, m_frame->GetScreen() );
3473
3474 sheet->AddPin( static_cast<SCH_SHEET_PIN*>( item ) );
3476
3477 commit.Push( _( "Add Sheet Pin" ) );
3478
3479 lastPlacedLabel = item;
3480 }
3481 }
3482
3483 return 0;
3484}
3485
3486
3488{
3489 static const std::function<void( std::list<SCH_SHEET_PATH>&, SCH_SCREEN*, std::set<SCH_SCREEN*>&,
3490 SCH_SHEET_PATH const& )> getSheetChildren =
3491 []( std::list<SCH_SHEET_PATH>& aPaths, SCH_SCREEN* aScene, std::set<SCH_SCREEN*>& aVisited,
3492 SCH_SHEET_PATH const& aCurPath )
3493 {
3494 if( ! aScene || aVisited.find(aScene) != aVisited.end() )
3495 return ;
3496
3497 std::vector<SCH_ITEM*> sheetChildren;
3498 aScene->GetSheets( &sheetChildren );
3499 aVisited.insert( aScene );
3500
3501 for( SCH_ITEM* child : sheetChildren )
3502 {
3503 SCH_SHEET_PATH cp = aCurPath;
3504 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( child );
3505 cp.push_back( sheet );
3506 aPaths.push_back( cp );
3507 getSheetChildren( aPaths, sheet->GetScreen(), aVisited, cp );
3508 }
3509 };
3510
3511 std::list<SCH_SHEET_PATH> sheetPaths;
3512 std::set<SCH_SCREEN*> visited;
3513 SCH_SHEET_PATH current;
3514 current.push_back( &m_frame->Schematic().Root() );
3515 getSheetChildren( sheetPaths, m_frame->Schematic().Root().GetScreen(), visited, current );
3516
3517 if( sheetPaths.size() == 0 )
3518 {
3519 m_frame->ShowInfoBarMsg( _( "No sub schematic found in the current project" ) );
3520 return 0;
3521 }
3522
3523
3524 return doSyncSheetsPins( std::move( sheetPaths ) );
3525}
3526
3528{
3529 if( !aSheet->GetScreen() )
3530 return nullptr;
3531
3532 std::vector<SCH_HIERLABEL*> labels;
3533
3534 for( EDA_ITEM* item : aSheet->GetScreen()->Items().OfType( SCH_HIER_LABEL_T ) )
3535 {
3536 SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( item );
3537 labels.push_back( label );
3538 }
3539
3540 std::sort( labels.begin(), labels.end(),
3541 []( const SCH_HIERLABEL* label1, const SCH_HIERLABEL* label2 )
3542 {
3543 return StrNumCmp( label1->GetText(), label2->GetText(), true ) < 0;
3544 } );
3545
3546 for( SCH_HIERLABEL* label : labels )
3547 {
3548 if( !aSheet->HasPin( label->GetText() ) )
3549 return label;
3550 }
3551
3552 return nullptr;
3553}
3554
3555
3556std::vector<SCH_HIERLABEL*> SCH_DRAWING_TOOLS::importHierLabels( SCH_SHEET* aSheet )
3557{
3558 if( !aSheet->GetScreen() )
3559 return {};
3560
3561 std::vector<SCH_HIERLABEL*> labels;
3562
3563 for( EDA_ITEM* item : aSheet->GetScreen()->Items().OfType( SCH_HIER_LABEL_T ) )
3564 {
3565 SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( item );
3566
3567 if( !aSheet->HasPin( label->GetText() ) )
3568 labels.push_back( label );
3569 }
3570
3571 return labels;
3572}
3573
3574
3576{
3577 // clang-format off
3607 // clang-format on
3608}
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:114
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
static TOOL_ACTION cancelInteractive
Definition: actions.h:72
static TOOL_ACTION undo
Definition: actions.h:75
static TOOL_ACTION duplicate
Definition: actions.h:84
static TOOL_ACTION activatePointEditor
Definition: actions.h:268
static TOOL_ACTION doDelete
Definition: actions.h:85
static TOOL_ACTION redo
Definition: actions.h:76
static TOOL_ACTION increment
Definition: actions.h:94
static TOOL_ACTION selectionClear
Clear the current selection.
Definition: actions.h:221
static TOOL_ACTION refreshPreview
Definition: actions.h:156
static TOOL_ACTION finishInteractive
Definition: actions.h:73
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition: actions.h:229
PANEL_DESIGN_BLOCK_CHOOSER m_DesignBlockChooserPanel
Definition: app_settings.h:217
constexpr const Vec & GetPosition() const
Definition: box2.h:211
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr size_type GetHeight() const
Definition: box2.h:215
constexpr bool Contains(const Vec &aPoint) const
Definition: box2.h:168
constexpr const SizeVec & GetSize() const
Definition: box2.h:206
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:85
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 & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition: commit.h:79
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.
LIB_ID GetSelectedLibId(int *aUnit=nullptr) const
DESIGN_BLOCK * GetDesignBlock(const LIB_ID &aLibId, bool aUseCacheLib, bool aShowErrorMsg)
Load design block from design block library table.
std::list< std::unique_ptr< EDA_ITEM > > & GetImportedItems()
void SetLabelList(std::list< std::unique_ptr< SCH_LABEL_BASE > > *aLabelList)
FIELDS_GRID_TABLE * GetFieldsGridTable()
int ShowQuasiModal()
int ShowModal() override
void ShowInfoBarMsg(const wxString &aMsg, bool aShowCloseButton=false)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an info icon on the left of...
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
WX_INFOBAR * GetInfoBar()
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
VECTOR2I GetNearestGridPosition(const VECTOR2I &aPosition) const
Return the nearest aGridSize location to aPosition.
void SetCurrentCursor(KICURSOR aCursor)
Set the current cursor shape for this panel.
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 ClearEditFlags()
Definition: eda_item.h:156
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
const KIID m_Uuid
Definition: eda_item.h:516
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
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition: eda_item.h:401
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:113
virtual wxString GetFriendlyName() const
Definition: eda_item.cpp:402
virtual EDA_ITEM * Clone() const
Create a duplicate of this item with linked list members set to NULL.
Definition: eda_item.cpp:118
FILL_T GetFillMode() const
Definition: eda_shape.h:142
void SetFillColor(const COLOR4D &aColor)
Definition: eda_shape.h:153
COLOR4D GetFillColor() const
Definition: eda_shape.h:152
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:219
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
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:417
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:197
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:386
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
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
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition: eda_text.cpp:307
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:409
PANEL_ANNOTATE m_AnnotatePanel
AUTOPLACE_FIELDS m_AutoplaceFields
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition: sch_rtree.h:246
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:241
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
void Update(const KIGFX::VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: sch_view.cpp:60
An interface for classes handling user events controlling the view behavior such as zooming,...
virtual void CaptureCursor(bool aEnabled)
Force the cursor to stay within the drawing panel area.
virtual void ForceCursorPosition(bool aEnabled, const VECTOR2D &aPosition=VECTOR2D(0, 0))
Place the cursor immediately at a given point.
virtual void ShowCursor(bool aEnabled)
Enable or disables display of cursor.
virtual void WarpMouseCursor(const VECTOR2D &aPosition, bool aWorldCoordinates=false, bool aWarpView=false)=0
If enabled (.
virtual void SetCrossHairCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true)=0
Move the graphic crosshair cursor to the requested position expressed in world coordinates.
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
virtual void SetCursorPosition(const VECTOR2D &aPosition, bool aWarpView=true, bool aTriggeredByArrows=false, long aArrowCommand=0)=0
Move cursor to the requested position expressed in world coordinates.
virtual void SetAutoPan(bool aEnabled)
Turn on/off auto panning (this feature is used when there is a tool active (eg.
virtual void PinCursorInsideNonAutoscrollArea(bool aWarpMouseCursor)=0
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:298
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:341
void ClearPreview()
Definition: view.cpp:1707
void RecacheAllItems()
Rebuild GAL display lists.
Definition: view.cpp:1451
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1729
Definition: kiid.h:49
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
bool IsValid() const
Check if this LID_ID is valid.
Definition: lib_id.h:172
UTF8 Format() const
Definition: lib_id.cpp:119
Define a library symbol object.
Definition: lib_symbol.h:85
wxString GetDescription() const override
Definition: lib_symbol.h:170
const LIB_ID & GetLibId() const override
Definition: lib_symbol.h:155
wxString GetKeyWords() const override
Definition: lib_symbol.h:183
void SetGlobalPower()
Definition: lib_symbol.cpp:475
void SetDescription(const wxString &aDescription)
Gets the Description field text value *‍/.
Definition: lib_symbol.h:164
void SetKeyWords(const wxString &aKeyWords)
Definition: lib_symbol.h:181
bool IsLocalPower() const override
Definition: lib_symbol.cpp:423
void SetLocalPower()
Definition: lib_symbol.cpp:439
bool IsGlobalPower() const override
Definition: lib_symbol.cpp:453
A singleton reporter that reports to nowhere.
Definition: reporter.h:217
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition: pgm_base.cpp:565
Class that handles the drawing of a polygon, including management of last corner deletion and drawing...
bool AddPoint(const VECTOR2I &aPt)
Lock in a polygon point.
@ DIRECT
Unconstrained point-to-point.
void SetCursorPosition(const VECTOR2I &aPos)
Set the current cursor position.
bool NewPointClosesOutline(const VECTOR2I &aPt) const
std::optional< VECTOR2I > DeleteLastCorner()
Remove the last-added point from the polygon.
void SetFinished()
Mark the polygon finished and update the client.
void SetLeaderMode(LEADER_MODE aMode)
Set the leader mode to use when calculating the leader/returner lines.
void Reset()
Clear the manager state and start again.
static SYMBOL_LIB_TABLE * SchSymbolLibTable(PROJECT *aProject)
Accessor for project symbol library table.
static SYMBOL_LIBS * SchLibs(PROJECT *aProject)
These are all prefaced with "Sch".
Definition: project_sch.cpp:90
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition: project.cpp:143
An adjunct helper to the DRAWING_TOOL interactive tool, which handles incoming geometry changes from ...
These are loaded from Eeschema settings but then overwritten by the project settings.
std::shared_ptr< REFDES_TRACKER > m_refDesTracker
A list of previously used schematic reference designators.
Holds all the data relating to one schematic.
Definition: schematic.h:88
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
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
bool Contains(const SCH_REFERENCE &aRef) const
Check if the schematic contains the specified reference.
Definition: schematic.cpp:219
SCH_SHEET & Root() const
Definition: schematic.h:140
static TOOL_ACTION rotateCCW
Definition: sch_actions.h:121
static TOOL_ACTION placeClassLabel
Definition: sch_actions.h:79
static TOOL_ACTION placeSheetPin
Definition: sch_actions.h:85
static TOOL_ACTION placeNextSymbolUnit
Definition: sch_actions.h:67
static TOOL_ACTION mirrorV
Definition: sch_actions.h:122
static TOOL_ACTION drawSheetFromFile
Definition: sch_actions.h:83
static TOOL_ACTION placeGlobalLabel
Definition: sch_actions.h:80
static TOOL_ACTION drawTextBox
Definition: sch_actions.h:93
static TOOL_ACTION syncAllSheetsPins
Definition: sch_actions.h:91
static TOOL_ACTION closeOutline
Definition: sch_actions.h:105
static TOOL_ACTION drawArc
Definition: sch_actions.h:97
static TOOL_ACTION drawSheet
Definition: sch_actions.h:82
static TOOL_ACTION properties
Definition: sch_actions.h:125
static TOOL_ACTION leaveSheet
Definition: sch_actions.h:219
static TOOL_ACTION autoplaceAllSheetPins
Definition: sch_actions.h:86
static TOOL_ACTION drawRectangle
Definition: sch_actions.h:95
static TOOL_ACTION placeHierLabel
Definition: sch_actions.h:81
static TOOL_ACTION placeLabel
Definition: sch_actions.h:78
static TOOL_ACTION drawCircle
Definition: sch_actions.h:96
static TOOL_ACTION importGraphics
Definition: sch_actions.h:255
static TOOL_ACTION placeBusWireEntry
Definition: sch_actions.h:77
static TOOL_ACTION drawBezier
Definition: sch_actions.h:98
static TOOL_ACTION rotateCW
Definition: sch_actions.h:120
static TOOL_ACTION importSheet
Definition: sch_actions.h:87
static TOOL_ACTION placeJunction
Definition: sch_actions.h:76
static TOOL_ACTION drawRuleArea
Definition: sch_actions.h:103
static TOOL_ACTION placeSymbol
Definition: sch_actions.h:66
static TOOL_ACTION placeImage
Definition: sch_actions.h:100
static TOOL_ACTION deleteLastPoint
Definition: sch_actions.h:104
static TOOL_ACTION drawSheetFromDesignBlock
Definition: sch_actions.h:84
static TOOL_ACTION mirrorH
Definition: sch_actions.h:123
static TOOL_ACTION placeDesignBlock
Definition: sch_actions.h:69
static TOOL_ACTION drawTable
Definition: sch_actions.h:94
static TOOL_ACTION placeSchematicText
Definition: sch_actions.h:92
static TOOL_ACTION changeSheet
Definition: sch_actions.h:217
static TOOL_ACTION enterSheet
Definition: sch_actions.h:218
static TOOL_ACTION repeatDrawItem
Definition: sch_actions.h:119
static TOOL_ACTION placeNoConnect
Definition: sch_actions.h:75
static TOOL_ACTION move
Definition: sch_actions.h:117
static TOOL_ACTION syncSheetPins
Definition: sch_actions.h:89
static TOOL_ACTION placePower
Definition: sch_actions.h:68
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
PICKED_SYMBOL PickSymbolFromLibrary(const SYMBOL_LIBRARY_FILTER *aFilter, std::vector< PICKED_SYMBOL > &aHistoryList, std::vector< PICKED_SYMBOL > &aAlreadyPlaced, bool aShowFootprints, const LIB_ID *aHighlight=nullptr, bool aAllowFields=true)
Call the library viewer to select symbol to import into schematic.
Definition: picksymbol.cpp:51
void SyncView()
Mark all items for refresh.
EESCHEMA_SETTINGS * eeconfig() const
LIB_SYMBOL * GetLibSymbol(const LIB_ID &aLibId, bool aUseCacheLib=false, bool aShowErrorMsg=false)
Load symbol from symbol library table.
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
Base class for a bus or wire entry.
Definition: sch_bus_entry.h:38
VECTOR2I GetPosition() const override
void MirrorHorizontally(int aCenter) override
Mirror item horizontally about aCenter.
void MirrorVertically(int aCenter) override
Mirror item vertically about aCenter.
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
Class for a wire to bus entry.
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
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
int ImportSheet(const TOOL_EVENT &aEvent)
STROKE_PARAMS m_lastTextboxStroke
GR_TEXT_V_ALIGN_T m_lastTextboxVJustify
SCH_TEXT * createNewText(const VECTOR2I &aPosition)
int PlaceNextSymbolUnit(const TOOL_EVENT &aEvent)
int DrawSheet(const TOOL_EVENT &aEvent)
bool createNewLabel(const VECTOR2I &aPosition, int aType, std::list< std::unique_ptr< SCH_LABEL_BASE > > &aLabelList)
SPIN_STYLE m_lastTextOrientation
int SyncSheetsPins(const TOOL_EVENT &aEvent)
STROKE_PARAMS m_lastStroke
GR_TEXT_H_ALIGN_T m_lastTextboxHJustify
std::vector< PICKED_SYMBOL > m_powerHistoryList
int SingleClickPlace(const TOOL_EVENT &aEvent)
SCH_LINE * findWire(const VECTOR2I &aPosition)
Gets the (global) label name driving this wire, if it is driven by a label.
void sizeSheet(SCH_SHEET *aSheet, const VECTOR2I &aPos)
Set up handlers for various events.
LABEL_FLAG_SHAPE m_lastGlobalLabelShape
LABEL_FLAG_SHAPE m_lastNetClassFlagShape
GR_TEXT_H_ALIGN_T m_lastTextHJustify
int ImportGraphics(const TOOL_EVENT &aEvent)
EDA_ANGLE m_lastTextboxAngle
int DrawRuleArea(const TOOL_EVENT &aEvent)
std::unique_ptr< STATUS_TEXT_POPUP > m_statusPopup
int AutoPlaceAllSheetPins(const TOOL_EVENT &aEvent)
int TwoClickPlace(const TOOL_EVENT &aEvent)
SCH_SHEET_PIN * createNewSheetPin(SCH_SHEET *aSheet, const VECTOR2I &aPosition)
SCH_SHEET_PIN * createNewSheetPinFromLabel(SCH_SHEET *aSheet, const VECTOR2I &aPosition, SCH_HIERLABEL *aLabel)
int SyncAllSheetsPins(const TOOL_EVENT &aEvent)
wxString findWireLabelDriverName(SCH_LINE *aWire)
int DrawTable(const TOOL_EVENT &aEvent)
GR_TEXT_V_ALIGN_T m_lastTextVJustify
std::vector< SCH_HIERLABEL * > importHierLabels(SCH_SHEET *aSheet)
int doSyncSheetsPins(std::list< SCH_SHEET_PATH > aSheets)
Try finding any hierlabel that does not have a sheet pin associated with it.
LABEL_FLAG_SHAPE m_lastSheetPinType
int DrawShape(const TOOL_EVENT &aEvent)
std::unique_ptr< DIALOG_SYNC_SHEET_PINS > m_dialogSyncSheetPin
bool Init() override
Init() is called once upon a registration of the tool.
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
int PlaceSymbol(const TOOL_EVENT &aEvent)
int PlaceImage(const TOOL_EVENT &aEvent)
std::vector< PICKED_SYMBOL > m_symbolHistoryList
SCH_HIERLABEL * importHierLabel(SCH_SHEET *aSheet)
Schematic editor (Eeschema) main window.
SCH_DESIGN_BLOCK_PANE * GetDesignBlockPane() const
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.
bool LoadSheetFromFile(SCH_SHEET *aSheet, SCH_SHEET_PATH *aCurrentSheet, const wxString &aFileName, bool aSkipRecursionCheck=false, bool aSkipLibCheck=false)
Load a the KiCad schematic file aFileName into the sheet aSheet.
Definition: sheet.cpp:169
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
void HardRedraw() override
Rebuild the GAL and redraw the screen.
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
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 SetSheetNumberAndCount()
Set the m_ScreenNumber and m_NumberOfScreens members for screens.
void SelectUnit(SCH_SYMBOL *aSymbol, int aUnit)
Definition: picksymbol.cpp:99
void AutoRotateItem(SCH_SCREEN *aScreen, SCH_ITEM *aItem)
Automatically set the rotation of an item (if the item supports it).
void SaveCopyForRepeatItem(const SCH_ITEM *aItem)
Clone aItem and owns that clone in this container.
void SetText(const wxString &aText) override
Definition: sch_field.cpp:1089
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this label.
Definition: sch_label.cpp:1902
A set of SCH_ITEMs (i.e., without duplicates).
Definition: sch_group.h:52
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Definition: sch_label.cpp:2131
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:168
virtual bool IsConnectable() const
Definition: sch_item.h: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
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:246
virtual void SetUnit(int aUnit)
Definition: sch_item.h:238
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition: sch_item.cpp:352
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
bool AutoRotateOnPlacement() const
autoRotateOnPlacement
Definition: sch_label.cpp:1472
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 SetAutoRotateOnPlacement(bool autoRotate=true)
Definition: sch_label.cpp:1478
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.
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:42
bool IsWire() const
Return true if the line is a wire.
Definition: sch_line.cpp:949
VECTOR2I GetEndPoint() const
Definition: sch_line.h:144
VECTOR2I GetStartPoint() const
Definition: sch_line.h:139
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
void SortByReferenceOnly()
Sort the list of references by reference.
void ReannotateByOptions(ANNOTATE_ORDER_T aSortOption, ANNOTATE_ALGO_T aAlgoOption, int aStartNumber, const SCH_REFERENCE_LIST &aAdditionalRefs, bool aStartAtCurrent, SCH_SHEET_LIST *aHierarchy)
Forces reannotation of the provided references.
void SetRefDesTracker(std::shared_ptr< REFDES_TRACKER > aTracker)
size_t GetCount() const
void AddItem(const SCH_REFERENCE &aItem)
void UpdateAnnotation()
Update the symbol references for the schematic project (or the current sheet).
A helper to define a symbol's reference designator in a schematic.
bool AlwaysAnnotate() const
Verify the reference should always be automatically annotated.
void SetUnit(int aUnit)
int GetUnit() const
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition: sch_screen.h:117
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
bool IsExplicitJunctionAllowed(const VECTOR2I &aPosition) const
Indicate that a junction dot may be placed at the given location.
Definition: sch_screen.cpp:501
bool SelectPoint(const VECTOR2I &aWhere, const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, EDA_ITEM **aItem=nullptr, bool *aSelectionCancelledFlag=nullptr, bool aCheckLocked=false, bool aAdd=false, bool aSubtract=false, bool aExclusiveOr=false)
Perform a click-type selection at a point (usually the cursor position).
int ClearSelection(const TOOL_EVENT &aEvent)
Select all visible items in sheet.
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...
void SetPosition(const VECTOR2I &aPos) override
Definition: sch_shape.h:85
void BeginEdit(const VECTOR2I &aStartPoint) override
Begin drawing a symbol library draw item at aPosition.
Definition: sch_shape.h:89
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_shape.cpp:46
void EndEdit(bool aClosed=false) override
End an object editing action.
Definition: sch_shape.h:92
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: sch_shape.cpp:61
bool ContinueEdit(const VECTOR2I &aPosition) override
Continue an edit in progress at aPosition.
Definition: sch_shape.h:90
void CalcEdit(const VECTOR2I &aPosition) override
Calculate the attributes of an item at aPosition when it is being edited.
Definition: sch_shape.h:91
wxString GetClass() const override
Return the class name.
Definition: sch_shape.h:44
STROKE_PARAMS GetStroke() const override
Definition: sch_shape.h:57
VECTOR2I GetPosition() const override
Definition: sch_shape.h:84
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void SortByPageNumbers(bool aUpdateVirtualPageNums=true)
Sort the list of sheets by page number.
SCH_SHEET_LIST FindAllSheetsForScreen(const SCH_SCREEN *aScreen) const
Return a SCH_SHEET_LIST with a copy of all the SCH_SHEET_PATH using a particular screen.
void GetSymbols(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Add a SCH_REFERENCE object to aReferences for each symbol in the list of sheets.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void UpdateAllScreenReferences() const
Update all the symbol references for this sheet path.
SCH_SCREEN * LastScreen()
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.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:66
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:47
void SetBorderColor(KIGFX::COLOR4D aColor)
Definition: sch_sheet.h:125
void AddPin(SCH_SHEET_PIN *aSheetPin)
Add aSheetPin to the sheet.
Definition: sch_sheet.cpp:398
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_sheet.cpp:131
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
Definition: sch_sheet.cpp:1011
std::vector< SCH_FIELD > & GetFields()
Return a reference to the vector holding the sheet's fields.
Definition: sch_sheet.h:87
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
Definition: sch_sheet.cpp:367
void SetBackgroundColor(KIGFX::COLOR4D aColor)
Definition: sch_sheet.h:128
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:116
VECTOR2I GetPosition() const override
Definition: sch_sheet.h:415
bool HasPin(const wxString &aName) const
Check if the sheet already has a sheet pin named aName.
Definition: sch_sheet.cpp:426
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:137
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_sheet.cpp:711
void SetBorderWidth(int aWidth)
Definition: sch_sheet.h:122
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
Definition: sch_sheet.cpp:635
void Resize(const VECTOR2I &aSize)
Resize this sheet to aSize and adjust all of the labels accordingly.
Definition: sch_sheet.cpp:994
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:187
Schematic symbol object.
Definition: sch_symbol.h:75
const LIB_ID & GetLibId() const override
Definition: sch_symbol.h:164
bool IsMulti() const override
Definition: sch_symbol.h:261
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
Set the selected unit of this symbol on one sheet.
Definition: sch_symbol.cpp:702
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
Definition: sch_symbol.cpp:558
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 ...
bool Init() override
Init() is called once upon a registration of the tool.
Definition: sch_tool_base.h:65
SCH_SELECTION_TOOL * m_selectionTool
RAII class that sets an value at construction and resets it to the original value at destruction.
Definition: seg.h:42
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition: seg.cpp:606
int AddItemsToSel(const TOOL_EVENT &aEvent)
int AddItemToSel(const TOOL_EVENT &aEvent)
void UnbrightenItem(EDA_ITEM *aItem)
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
VECTOR2I GetReferencePoint() const
Definition: selection.cpp:169
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:105
EDA_ITEM * Front() const
Definition: selection.h:177
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:98
int Size() const
Returns the number of selected parts.
Definition: selection.h:121
Helper object to filter a list of libraries.
SYMBOL_LIB * GetCacheLibrary()
Object used to load, save, search, and otherwise manipulate symbol library files.
virtual void PopTool(const TOOL_EVENT &aEvent)
Pops a tool from the stack.
virtual void PushTool(const TOOL_EVENT &aEvent)
NB: the definition of "tool" is different at the user level.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
const std::string & GetName() const
Return the name of the tool.
Definition: tool_base.h:136
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 HasPosition() const
Returns if it this event has a valid position (true for mouse events and context-menu or hotkey-based...
Definition: tool_event.h:257
bool DisableGridSnapping() const
Definition: tool_event.h:368
const VECTOR2D Position() const
Return mouse cursor position in world coordinates.
Definition: tool_event.h:290
bool IsReactivate() const
Control whether the tool is first being pushed to the stack or being reactivated after a pause.
Definition: tool_event.h:270
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).
std::unique_ptr< TOOL_MENU > m_menu
The functions below are not yet implemented - their interface may change.
TOOL_EVENT * Wait(const TOOL_EVENT_LIST &aEventList=TOOL_EVENT(TC_ANY, TA_ANY))
Suspend execution of the tool until an event specified in aEventList arrives.
void Activate()
Run the tool.
void DeactivateTool()
Deactivate the currently active 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
void PrimeTool(const VECTOR2D &aPosition)
"Prime" a tool by sending a cursor left-click event with the mouse position set to the passed in posi...
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
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:515
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:192
This file is part of the common library.
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:411
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:566
#define IGNORE_PARENT_GROUP
Definition: eda_item.h:55
#define IS_NEW
New item, just created.
#define STRUCT_DELETED
flag indication structures to be erased
#define ENDPOINT
ends. (Used to support dragging.)
#define SKIP_STRUCT
flag indicating that the structure should be ignored
#define IS_MOVING
Item being moved.
#define STARTPOINT
When a line is selected, these flags indicate which.
SHAPE_T
Definition: eda_shape.h:43
FILL_T
Definition: eda_shape.h:56
@ 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_SELECT_UNIT_END
Definition: eeschema_id.h:86
@ LINE_MODE_FREE
GRID_HELPER_GRIDS
Definition: grid_helper.h:43
@ GRID_TEXT
Definition: grid_helper.h:50
@ GRID_GRAPHICS
Definition: grid_helper.h:51
@ GRID_CONNECTABLE
Definition: grid_helper.h:47
static const std::string KiCadSchematicFileExtension
static wxString KiCadSchematicFileWildcard()
@ LAYER_HIERLABEL
Definition: layer_ids.h:447
@ LAYER_GLOBLABEL
Definition: layer_ids.h:446
@ LAYER_NOTES
Definition: layer_ids.h:457
@ LAYER_LOCLABEL
Definition: layer_ids.h:445
@ LAYER_NETCLASS_REFS
Definition: layer_ids.h:454
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: wxgtk/ui.cpp:683
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:902
see class PGM_BASE
LIB_SYMBOL * SchGetLibSymbol(const LIB_ID &aLibId, SYMBOL_LIB_TABLE *aLibTable, SYMBOL_LIB *aCacheLib, wxWindow *aParent, bool aShowErrorMsg)
Load symbol from symbol library table.
Class to handle a set of SCH_ITEMs.
@ AUTOPLACE_AUTO
Definition: sch_item.h:71
LABEL_FLAG_SHAPE
Definition: sch_label.h:99
@ F_ROUND
Definition: sch_label.h:108
@ L_INPUT
Definition: sch_label.h:100
ANNOTATE_ORDER_T
Schematic annotation order options.
@ ANNOTATE_SELECTION
Annotate the selection.
ANNOTATE_ALGO_T
Schematic annotation type options.
#define MIN_SHEET_HEIGHT
Definition: sch_sheet.h:40
#define MIN_SHEET_WIDTH
Definition: sch_sheet.h:39
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
std::set< int > GetUnplacedUnitsForSymbol(const SCH_SYMBOL &aSym)
Get a list of unplaced (i.e.
LINE_STYLE
Dashed line types.
Definition: stroke_params.h:46
constexpr int MilsToIU(int mils) const
Definition: base_units.h:97
bool PlaceAllUnits
Definition: sch_screen.h:85
bool KeepSymbol
Definition: sch_screen.h:84
LIB_ID LibId
Definition: sch_screen.h:80
SCH_SYMBOL * m_Symbol
< Provide a symbol to place
Definition: sch_actions.h:308
Definition for symbol library class.
int delta
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
@ TA_CHOICE_MENU_CHOICE
Context menu choice.
Definition: tool_event.h:98
@ TC_COMMAND
Definition: tool_event.h:57
@ MD_SHIFT
Definition: tool_event.h:143
@ BUT_LEFT
Definition: tool_event.h:132
@ BUT_RIGHT
Definition: tool_event.h:133
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ SCH_LINE_T
Definition: typeinfo.h:164
@ SCH_NO_CONNECT_T
Definition: typeinfo.h:161
@ SCH_SYMBOL_T
Definition: typeinfo.h:173
@ SCH_SHEET_T
Definition: typeinfo.h:176
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:170
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:175
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:162
@ SCH_JUNCTION_T
Definition: typeinfo.h:160
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
Definition of file extensions used in Kicad.