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 (C) 2019-2024 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 <ee_actions.h>
39#include <ee_tool_utils.h>
40#include <sch_edit_frame.h>
41#include <pgm_base.h>
42#include <design_block.h>
43#include <design_block_pane.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_line.h>
51#include <sch_junction.h>
52#include <sch_bus_entry.h>
53#include <sch_rule_area.h>
54#include <sch_text.h>
55#include <sch_textbox.h>
56#include <sch_table.h>
57#include <sch_tablecell.h>
58#include <sch_sheet.h>
59#include <sch_sheet_pin.h>
60#include <sch_label.h>
61#include <sch_bitmap.h>
62#include <schematic.h>
63#include <sch_commit.h>
64#include <scoped_set_reset.h>
65#include <symbol_library.h>
66#include <eeschema_settings.h>
68#include <dialogs/dialog_text_properties.h>
71#include <dialogs/dialog_table_properties.h>
74#include <string_utils.h>
76#include <wx/filedlg.h>
77#include <wx/msgdlg.h>
78
80 EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveDrawing" ),
81 m_lastSheetPinType( LABEL_FLAG_SHAPE::L_INPUT ),
82 m_lastGlobalLabelShape( LABEL_FLAG_SHAPE::L_INPUT ),
83 m_lastNetClassFlagShape( LABEL_FLAG_SHAPE::F_ROUND ),
84 m_lastTextOrientation( SPIN_STYLE::RIGHT ),
85 m_lastTextBold( false ),
86 m_lastTextItalic( false ),
87 m_lastTextAngle( ANGLE_0 ),
88 m_lastTextboxAngle( ANGLE_0 ),
89 m_lastTextHJustify( GR_TEXT_H_ALIGN_CENTER ),
90 m_lastTextVJustify( GR_TEXT_V_ALIGN_CENTER ),
91 m_lastTextboxHJustify( GR_TEXT_H_ALIGN_LEFT ),
92 m_lastTextboxVJustify( GR_TEXT_V_ALIGN_TOP ),
93 m_lastFillStyle( FILL_T::NO_FILL ),
94 m_lastTextboxFillStyle( FILL_T::NO_FILL ),
95 m_lastFillColor( COLOR4D::UNSPECIFIED ),
96 m_lastTextboxFillColor( COLOR4D::UNSPECIFIED ),
97 m_lastStroke( 0, LINE_STYLE::DEFAULT, COLOR4D::UNSPECIFIED ),
98 m_lastTextboxStroke( 0, LINE_STYLE::DEFAULT, COLOR4D::UNSPECIFIED ),
99 m_mruPath( wxEmptyString ),
100 m_lastAutoLabelRotateOnPlacement( false ),
101 m_drawingRuleArea( false ),
102 m_inDrawingTool( false )
103{
104}
105
106
108{
110
111 auto belowRootSheetCondition =
112 [&]( const SELECTION& aSel )
113 {
114 return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
115 };
116
117 auto inDrawingRuleArea =
118 [&]( const SELECTION& aSel )
119 {
120 return m_drawingRuleArea;
121 };
122
123 CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
124 ctxMenu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 150 );
125 ctxMenu.AddItem( EE_ACTIONS::closeOutline, inDrawingRuleArea, 200 );
126 ctxMenu.AddItem( EE_ACTIONS::deleteLastPoint, inDrawingRuleArea, 200 );
127
128 return true;
129}
130
131
133{
134 const EE_ACTIONS::PLACE_SYMBOL_PARAMS& toolParams =
136
137 SCH_SYMBOL* symbol = toolParams.m_Symbol;
138 // If we get an parameterised symbol, we probably just want to place
139 // that and get out of the placmeent tool, rather than popping the
140 // 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 SCH_SCREEN* screen = m_frame->GetScreen();
148
149 if( m_inDrawingTool )
150 return 0;
151
153
156 VECTOR2I cursorPos;
157
158 // First we need to get all instances of this sheet so we can annotate
159 // whatever symbols we place on all copies
160 SCH_SHEET_LIST hierarchy = m_frame->Schematic().Hierarchy();
161 SCH_SHEET_LIST newInstances =
163 newInstances.SortByPageNumbers();
164
165 // Get a list of all references in the schematic to avoid duplicates wherever
166 // they're placed
167 SCH_REFERENCE_LIST existingRefs;
168 hierarchy.GetSymbols( existingRefs );
169 existingRefs.SortByReferenceOnly();
170
171 if( aEvent.IsAction( &EE_ACTIONS::placeSymbol ) )
172 {
173 historyList = &m_symbolHistoryList;
174 }
175 else if (aEvent.IsAction( &EE_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
207 : KICURSOR::COMPONENT );
208 };
209
210 auto cleanup =
211 [&]()
212 {
215 delete symbol;
216 symbol = nullptr;
217
218 existingRefs.Clear();
219 hierarchy.GetSymbols( existingRefs );
220 existingRefs.SortByReferenceOnly();
221 };
222
223 auto annotate =
224 [&]()
225 {
227
228 // Then we need to annotate all instances by sheet
229 for( SCH_SHEET_PATH& instance : newInstances )
230 {
231 SCH_REFERENCE newReference( symbol, instance );
233 refs.AddItem( newReference );
234
235 if( cfg->m_AnnotatePanel.automatic || newReference.AlwaysAnnotate() )
236 {
240 existingRefs, false, &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()
293 && evt->Matches( aEvent );
294
295 if( evt->IsCancelInteractive() || ( symbol && evt->IsAction( &ACTIONS::undo ) ) )
296 {
298
299 if( symbol )
300 {
301 cleanup();
302 }
303 else
304 {
305 m_frame->PopTool( aEvent );
306 break;
307 }
308 }
309 else if( evt->IsActivate() && !isSyntheticClick )
310 {
311 if( symbol && evt->IsMoveTool() )
312 {
313 // we're already moving our own item; ignore the move tool
314 evt->SetPassEvent( false );
315 continue;
316 }
317
318 if( symbol )
319 {
320 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel symbol creation." ) );
321 evt->SetPassEvent( false );
322 continue;
323 }
324
325 if( evt->IsMoveTool() )
326 {
327 // leave ourselves on the stack so we come back after the move
328 break;
329 }
330 else
331 {
332 m_frame->PopTool( aEvent );
333 break;
334 }
335 }
336 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) || isSyntheticClick )
337 {
338 if( !symbol )
339 {
341
344
345 std::set<UTF8> unique_libid;
346 std::vector<PICKED_SYMBOL> alreadyPlaced;
347
348 for( SCH_SHEET_PATH& sheet : hierarchy )
349 {
350 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
351 {
352 SCH_SYMBOL* s = static_cast<SCH_SYMBOL*>( item );
353
354 if( !unique_libid.insert( s->GetLibId().Format() ).second )
355 continue;
356
357 LIB_SYMBOL* libSymbol = SchGetLibSymbol( s->GetLibId(), libs, cache );
358
359 if( libSymbol )
360 {
361 PICKED_SYMBOL pickedSymbol;
362 pickedSymbol.LibId = libSymbol->GetLibId();
363 alreadyPlaced.push_back( pickedSymbol );
364 }
365 }
366 }
367
368 // Pick the symbol to be placed
369 bool footprintPreviews = m_frame->eeconfig()->m_Appearance.footprint_preview;
370 PICKED_SYMBOL sel = m_frame->PickSymbolFromLibrary( &filter, *historyList,
371 alreadyPlaced,
372 footprintPreviews );
373
374 LIB_SYMBOL* libSymbol = sel.LibId.IsValid() ? m_frame->GetLibSymbol( sel.LibId )
375 : 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
395 symbol = new SCH_SYMBOL( *libSymbol, &m_frame->GetCurrentSheet(), sel, cursorPos,
396 &m_frame->Schematic() );
397 addSymbol( symbol );
398 annotate();
399
400 // Update the list of references for the next symbol placement.
401 SCH_REFERENCE placedSymbolReference( symbol, m_frame->GetCurrentSheet() );
402 existingRefs.AddItem( placedSymbolReference );
403 existingRefs.SortByReferenceOnly();
404
406 symbol->AutoplaceFields( /* aScreen */ nullptr, /* aManual */ false );
407
408 // Update cursor now that we have a symbol
409 setCursor();
410 }
411 else
412 {
414 m_frame->AddToScreen( symbol, screen );
415
417 symbol->AutoplaceFields( screen, false /* aManual */ );
418
420
421 SCH_COMMIT commit( m_toolMgr );
422 commit.Added( symbol, screen );
423
425 lwbTool->TrimOverLappingWires( &commit, &m_selectionTool->GetSelection() );
426 lwbTool->AddJunctionsIfNeeded( &commit, &m_selectionTool->GetSelection() );
427
428 commit.Push( _( "Place Symbol" ) );
429
430 if( placeOneOnly )
431 {
432 m_frame->PopTool( aEvent );
433 break;
434 }
435
436 SCH_SYMBOL* nextSymbol = nullptr;
437
440 {
441 int new_unit = symbol->GetUnit();
442
444 && symbol->GetUnit() < symbol->GetUnitCount() )
445 {
446 new_unit++;
447 }
448 else
449 {
450 new_unit = 1;
451 }
452
453 // We are either stepping to the next unit or next symbol
454 if( m_frame->eeconfig()->m_SymChooserPanel.keep_symbol || new_unit > 1 )
455 {
456 nextSymbol = static_cast<SCH_SYMBOL*>( symbol->Duplicate() );
457 nextSymbol->SetUnit( new_unit );
458 nextSymbol->SetUnitSelection( new_unit );
459
460 // Start new annotation sequence at first unit
461 if( new_unit == 1 )
462 nextSymbol->ClearAnnotation( nullptr, false );
463
464 addSymbol( nextSymbol );
465 symbol = nextSymbol;
466 annotate();
467
468 // Update the list of references for the next symbol placement.
469 SCH_REFERENCE placedSymbolReference( symbol, m_frame->GetCurrentSheet() );
470 existingRefs.AddItem( placedSymbolReference );
471 existingRefs.SortByReferenceOnly();
472 }
473 }
474
475 symbol = nextSymbol;
476 }
477 }
478 else if( evt->IsClick( BUT_RIGHT ) )
479 {
480 // Warp after context menu only if dragging...
481 if( !symbol )
483
484 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
485 }
486 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
487 {
488 if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_UNIT
489 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_UNIT_END )
490 {
491 int unit = *evt->GetCommandId() - ID_POPUP_SCH_SELECT_UNIT;
492
493 if( symbol )
494 {
495 m_frame->SelectUnit( symbol, unit );
497 }
498 }
499 else if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_BASE
500 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_ALT )
501 {
502 int bodyStyle = ( *evt->GetCommandId() - ID_POPUP_SCH_SELECT_BASE ) + 1;
503
504 if( symbol && symbol->GetBodyStyle() != bodyStyle )
505 {
506 m_frame->FlipBodyStyle( symbol );
508 }
509 }
510 }
511 else if( evt->IsAction( &ACTIONS::duplicate )
512 || evt->IsAction( &EE_ACTIONS::repeatDrawItem ) )
513 {
514 if( symbol )
515 {
516 // This doesn't really make sense; we'll just end up dragging a stack of
517 // objects so we ignore the duplicate and just carry on.
518 wxBell();
519 continue;
520 }
521
522 // Exit. The duplicate will run in its own loop.
523 m_frame->PopTool( aEvent );
524 break;
525 }
526 else if( symbol && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
527 {
528 symbol->SetPosition( cursorPos );
530 m_view->AddToPreview( symbol, false ); // Add, but not give ownership
531 m_frame->SetMsgPanel( symbol );
532 }
533 else if( symbol && evt->IsAction( &ACTIONS::doDelete ) )
534 {
535 cleanup();
536 }
537 else if( symbol && evt->IsAction( &ACTIONS::redo ) )
538 {
539 wxBell();
540 }
541 else
542 {
543 evt->SetPassEvent();
544 }
545
546 // Enable autopanning and cursor capture only when there is a symbol to be placed
547 getViewControls()->SetAutoPan( symbol != nullptr );
548 getViewControls()->CaptureCursor( symbol != nullptr );
549 }
550
551 getViewControls()->SetAutoPan( false );
552 getViewControls()->CaptureCursor( false );
553 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
554
555 return 0;
556}
557
558
560{
561 SCH_SYMBOL* symbol = aEvent.Parameter<SCH_SYMBOL*>();
562
563 // TODO: get from selection
564 if( !symbol )
565 {
566 static const std::vector<KICAD_T> symbolTypes = { SCH_SYMBOL_T };
567 EE_SELECTION& selection = m_selectionTool->RequestSelection( symbolTypes );
568
569 if( selection.Size() != 1 )
570 {
571 m_frame->ShowInfoBarMsg( _( "Select a single symbol to place the next unit." ) );
572 return 0;
573 }
574
575 wxCHECK( selection.Front()->Type() == SCH_SYMBOL_T, 0 );
576 symbol = static_cast<SCH_SYMBOL*>( selection.Front() );
577 }
578
579 if( !symbol )
580 return 0;
581
582 if( !symbol->IsMulti() )
583 {
584 m_frame->ShowInfoBarMsg( _( "This symbol has only one unit." ) );
585 return 0;
586 }
587
588 const std::set<int> missingUnits = GetUnplacedUnitsForSymbol( *symbol );
589
590 if( missingUnits.empty() )
591 {
592 m_frame->ShowInfoBarMsg( _( "All units of this symbol are already placed." ) );
593 return 0;
594 }
595
596 // Find the lowest unit number that is missing
597 const int nextMissing = *std::min_element( missingUnits.begin(), missingUnits.end() );
598
599 std::unique_ptr<SCH_SYMBOL> newSymbol = std::make_unique<SCH_SYMBOL>( *symbol );
600 const SCH_SHEET_PATH& sheetPath = m_frame->GetCurrentSheet();
601
602 newSymbol->SetUnitProp( nextMissing );
603 newSymbol->SetRefProp( symbol->GetRef( &sheetPath, false ) );
604
605 // Post the new symbol - don't reannotate it - we set the reference ourselves
607 EE_ACTIONS::PLACE_SYMBOL_PARAMS{ newSymbol.release(), false } );
608 return 0;
609}
610
611
613{
614 bool placingDesignBlock = aEvent.IsAction( &EE_ACTIONS::placeDesignBlock );
615
616 DESIGN_BLOCK* designBlock = nullptr;
617 wxString sheetFileName = wxEmptyString;
618
619 if( placingDesignBlock )
620 {
622 {
623 designBlock =
625
626 if( !designBlock )
627 return 0;
628
629 sheetFileName = designBlock->GetSchematicFile();
630 }
631 }
632 else
633 {
634 wxString* importSourceFile = aEvent.Parameter<wxString*>();
635
636 if( importSourceFile != nullptr )
637 sheetFileName = *importSourceFile;
638 }
639
640 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
642 SCHEMATIC_SETTINGS& schSettings = m_frame->Schematic().Settings();
643 SCH_SCREEN* screen = m_frame->GetScreen();
644 SCH_SHEET_PATH& sheetPath = m_frame->GetCurrentSheet();
645
648 VECTOR2I cursorPos;
649
650 if( !cfg || !common_settings )
651 return 0;
652
653 if( m_inDrawingTool )
654 return 0;
655
656 auto setCursor =
657 [&]()
658 {
659 m_frame->GetCanvas()->SetCurrentCursor( designBlock ? KICURSOR::MOVING
660 : KICURSOR::COMPONENT );
661 };
662
663 auto placeSheetContents =
664 [&]()
665 {
666 SCH_COMMIT commit( m_toolMgr );
668 EDA_ITEMS newItems;
669 bool keepAnnotations = cfg->m_DesignBlockChooserPanel.keep_annotations;
670
671 selectionTool->ClearSelection();
672
673 // Mark all existing items on the screen so we don't select them after appending
674 for( EDA_ITEM* item : screen->Items() )
675 item->SetFlags( SKIP_STRUCT );
676
677 if( !m_frame->LoadSheetFromFile( sheetPath.Last(), &sheetPath, sheetFileName, true,
678 placingDesignBlock ) )
679 return false;
680
682
683 m_frame->SyncView();
684 m_frame->OnModify();
685 m_frame->HardRedraw(); // Full reinit of the current screen and the display.
686
687 // Select all new items
688 for( EDA_ITEM* item : screen->Items() )
689 {
690 if( !item->HasFlag( SKIP_STRUCT ) )
691 {
692 if( item->Type() == SCH_SYMBOL_T && !keepAnnotations )
693 static_cast<SCH_SYMBOL*>( item )->ClearAnnotation( &sheetPath, false );
694
695 if( item->Type() == SCH_LINE_T )
696 item->SetFlags( STARTPOINT | ENDPOINT );
697
698 commit.Added( item, screen );
699 newItems.emplace_back( item );
700 }
701 else
702 item->ClearFlags( SKIP_STRUCT );
703 }
704
705 selectionTool->AddItemsToSel( &newItems, true );
706
707 cursorPos = grid.Align( controls->GetMousePosition(),
708 grid.GetSelectionGrid( selectionTool->GetSelection() ) );
709 controls->ForceCursorPosition( true, cursorPos );
710
711 // Move everything to our current mouse position now
712 // that we have a selection to get a reference point
713 VECTOR2I anchorPos = selectionTool->GetSelection().GetReferencePoint();
714 VECTOR2I delta = cursorPos - anchorPos;
715
716 // Will all be SCH_ITEMs as these were pulled from the screen->Items()
717 for( EDA_ITEM* item : newItems )
718 static_cast<SCH_ITEM*>( item )->Move( delta );
719
720 if( !keepAnnotations )
721 {
723
724 if( annotate.automatic )
725 {
726 NULL_REPORTER reporter;
728 (ANNOTATE_ORDER_T) annotate.sort_order,
729 (ANNOTATE_ALGO_T) annotate.method, true /* recursive */,
730 schSettings.m_AnnotateStartNum, false, false, reporter );
731 }
732
733 // Annotation will clear selection, so we need to restore it
734 for( EDA_ITEM* item : newItems )
735 {
736 if( item->Type() == SCH_LINE_T )
737 item->SetFlags( STARTPOINT | ENDPOINT );
738 }
739
740 selectionTool->AddItemsToSel( &newItems, true );
741 }
742
743 // Start moving selection, cancel undoes the insertion
744 bool placed = m_toolMgr->RunSynchronousAction( EE_ACTIONS::move, &commit );
745
746 // Update our cursor position to the new location in case we're placing repeated copies
747 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
748
749 if( placed )
750 commit.Push( placingDesignBlock ? _( "Add design block" )
751 : _( "Import Schematic Sheet Content..." ) );
752 else
753 commit.Revert();
754
756
757 return placed;
758 };
759
760 // Whether we are placing the sheet as a sheet, or as its contents, we need to get a filename
761 // if we weren't provided one
762 if( sheetFileName.IsEmpty() )
763 {
764 wxString path;
765 wxString file;
766
767 if (!placingDesignBlock) {
768
769 if( sheetFileName.IsEmpty() )
770 {
771 path = wxPathOnly( m_frame->Prj().GetProjectFullName() );
772 file = wxEmptyString;
773 }
774 else
775 {
776 path = wxPathOnly( sheetFileName );
777 file = wxFileName( sheetFileName ).GetFullName();
778 }
779
780 // Open file chooser dialog even if we have been provided a file so the user
781 // can select the options they want
782 wxFileDialog dlg( m_frame, _( "Choose Schematic" ), path, file,
784 wxFD_OPEN | wxFD_FILE_MUST_EXIST );
785
786 FILEDLG_IMPORT_SHEET_CONTENTS dlgHook( cfg );
787 dlg.SetCustomizeHook( dlgHook );
788
789 if( dlg.ShowModal() == wxID_CANCEL )
790 return 0;
791
792 sheetFileName = dlg.GetPath();
793
795 }
796
797 if( sheetFileName.IsEmpty() )
798 return 0;
799 }
800
801 // If we're placing sheet contents, we don't even want to run our tool loop, just add the items
802 // to the canvas and run the move tool
804 {
805 while( placeSheetContents() && cfg->m_DesignBlockChooserPanel.repeated_placement )
806 ;
807
810 delete designBlock;
811 designBlock = nullptr;
812
813 return 0;
814 }
815
816 // We're placing a sheet as a sheet, we need to run a small tool loop to get the starting
817 // coordinate of the sheet drawing
818 m_frame->PushTool( aEvent );
819
820 Activate();
821
822 // Must be done after Activate() so that it gets set into the correct context
823 getViewControls()->ShowCursor( true );
824
825 // Set initial cursor
826 setCursor();
827
828 if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
829 {
830 m_toolMgr->PrimeTool( { 0, 0 } );
831 }
832
833 // Main loop: keep receiving events
834 while( TOOL_EVENT* evt = Wait() )
835 {
836 setCursor();
837 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
838 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
839
840 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
841 controls->ForceCursorPosition( true, cursorPos );
842
843 // The tool hotkey is interpreted as a click when drawing
844 bool isSyntheticClick = designBlock && evt->IsActivate() && evt->HasPosition()
845 && evt->Matches( aEvent );
846
847 if( evt->IsCancelInteractive() || ( designBlock && evt->IsAction( &ACTIONS::undo ) ) )
848 {
850 break;
851 }
852 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) || isSyntheticClick )
853 {
854 if( placingDesignBlock )
856 else
857 {
858 // drawSheet must delete
860 new wxString( sheetFileName ) );
861 }
862
863 break;
864 }
865 else if( evt->IsClick( BUT_RIGHT ) )
866 {
867 // Warp after context menu only if dragging...
868 if( !designBlock )
870
871 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
872 }
873 else if( evt->IsAction( &ACTIONS::duplicate )
874 || evt->IsAction( &EE_ACTIONS::repeatDrawItem ) )
875 {
876 wxBell();
877 }
878 else
879 {
880 evt->SetPassEvent();
881 }
882 }
883
884 m_frame->PopTool( aEvent );
885 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
886
887 return 0;
888}
889
890
892{
893 SCH_BITMAP* image = aEvent.Parameter<SCH_BITMAP*>();
894 bool immediateMode = image != nullptr;
895 bool ignorePrimePosition = false;
896 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
897
898 if( m_inDrawingTool )
899 return 0;
900
902
905 VECTOR2I cursorPos;
906
908
909 // Add all the drawable symbols to preview
910 if( image )
911 {
912 image->SetPosition( getViewControls()->GetCursorPosition() );
914 m_view->AddToPreview( image, false ); // Add, but not give ownership
915 }
916
917 m_frame->PushTool( aEvent );
918
919 auto setCursor =
920 [&]()
921 {
922 if( image )
923 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
924 else
925 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
926 };
927
928 auto cleanup =
929 [&] ()
930 {
934 delete image;
935 image = nullptr;
936 };
937
938 Activate();
939
940 // Must be done after Activate() so that it gets set into the correct context
941 getViewControls()->ShowCursor( true );
942
943 // Set initial cursor
944 setCursor();
945
946 // Prime the pump
947 if( image )
948 {
950 }
951 else if( aEvent.HasPosition() )
952 {
953 m_toolMgr->PrimeTool( aEvent.Position() );
954 }
955 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
956 {
957 m_toolMgr->PrimeTool( { 0, 0 } );
958 ignorePrimePosition = true;
959 }
960
961 // Main loop: keep receiving events
962 while( TOOL_EVENT* evt = Wait() )
963 {
964 setCursor();
965 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
966 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
967
968 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
969 controls->ForceCursorPosition( true, cursorPos );
970
971 // The tool hotkey is interpreted as a click when drawing
972 bool isSyntheticClick = image && evt->IsActivate() && evt->HasPosition()
973 && evt->Matches( aEvent );
974
975 if( evt->IsCancelInteractive() || ( image && evt->IsAction( &ACTIONS::undo ) ) )
976 {
978
979 if( image )
980 {
981 cleanup();
982 }
983 else
984 {
985 m_frame->PopTool( aEvent );
986 break;
987 }
988
989 if( immediateMode )
990 {
991 m_frame->PopTool( aEvent );
992 break;
993 }
994 }
995 else if( evt->IsActivate() && !isSyntheticClick )
996 {
997 if( image && evt->IsMoveTool() )
998 {
999 // we're already moving our own item; ignore the move tool
1000 evt->SetPassEvent( false );
1001 continue;
1002 }
1003
1004 if( image )
1005 {
1006 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel image creation." ) );
1007 evt->SetPassEvent( false );
1008 continue;
1009 }
1010
1011 if( evt->IsMoveTool() )
1012 {
1013 // leave ourselves on the stack so we come back after the move
1014 break;
1015 }
1016 else
1017 {
1018 m_frame->PopTool( aEvent );
1019 break;
1020 }
1021 }
1022 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) || isSyntheticClick )
1023 {
1024 if( !image )
1025 {
1027
1028 wxFileDialog dlg( m_frame, _( "Choose Image" ), m_mruPath, wxEmptyString,
1029 _( "Image Files" ) + wxS( " " ) + wxImage::GetImageExtWildcard(),
1030 wxFD_OPEN );
1031
1032 if( dlg.ShowModal() != wxID_OK )
1033 continue;
1034
1035 // If we started with a hotkey which has a position then warp back to that.
1036 // Otherwise update to the current mouse position pinned inside the autoscroll
1037 // boundaries.
1038 if( evt->IsPrime() && !ignorePrimePosition )
1039 {
1040 cursorPos = grid.Align( evt->Position() );
1041 getViewControls()->WarpMouseCursor( cursorPos, true );
1042 }
1043 else
1044 {
1046 cursorPos = getViewControls()->GetMousePosition();
1047 }
1048
1049 wxString fullFilename = dlg.GetPath();
1050 m_mruPath = wxPathOnly( fullFilename );
1051
1052 if( wxFileExists( fullFilename ) )
1053 image = new SCH_BITMAP( cursorPos );
1054
1055 if( !image || !image->GetReferenceImage().ReadImageFile( fullFilename ) )
1056 {
1057 wxMessageBox( wxString::Format( _( "Could not load image from '%s'." ), fullFilename ) );
1058 delete image;
1059 image = nullptr;
1060 continue;
1061 }
1062
1063 image->SetFlags( IS_NEW | IS_MOVING );
1064
1066
1068 m_view->AddToPreview( image, false ); // Add, but not give ownership
1069 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
1070
1072
1073 getViewControls()->SetCursorPosition( cursorPos, false );
1074 setCursor();
1075 }
1076 else
1077 {
1078 SCH_COMMIT commit( m_toolMgr );
1079 commit.Add( image, m_frame->GetScreen() );
1080 commit.Push( _( "Place Image" ) );
1081
1082 image = nullptr;
1084
1086
1087 if( immediateMode )
1088 {
1089 m_frame->PopTool( aEvent );
1090 break;
1091 }
1092 }
1093 }
1094 else if( evt->IsClick( BUT_RIGHT ) )
1095 {
1096 // Warp after context menu only if dragging...
1097 if( !image )
1099
1100 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
1101 }
1102 else if( evt->IsAction( &ACTIONS::duplicate )
1103 || evt->IsAction( &EE_ACTIONS::repeatDrawItem ) )
1104 {
1105 if( image )
1106 {
1107 // This doesn't really make sense; we'll just end up dragging a stack of
1108 // objects so we ignore the duplicate and just carry on.
1109 wxBell();
1110 continue;
1111 }
1112
1113 // Exit. The duplicate will run in its own loop.
1114 m_frame->PopTool( aEvent );
1115 break;
1116 }
1117 else if( image && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
1118 {
1119 image->SetPosition( cursorPos );
1121 m_view->AddToPreview( image, false ); // Add, but not give ownership
1122 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
1124 }
1125 else if( image && evt->IsAction( &ACTIONS::doDelete ) )
1126 {
1127 cleanup();
1128 }
1129 else if( image && evt->IsAction( &ACTIONS::redo ) )
1130 {
1131 wxBell();
1132 }
1133 else
1134 {
1135 evt->SetPassEvent();
1136 }
1137
1138 // Enable autopanning and cursor capture only when there is an image to be placed
1139 getViewControls()->SetAutoPan( image != nullptr );
1140 getViewControls()->CaptureCursor( image != nullptr );
1141 }
1142
1143 getViewControls()->SetAutoPan( false );
1144 getViewControls()->CaptureCursor( false );
1145 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1146
1147 return 0;
1148}
1149
1150
1152{
1153 if( m_inDrawingTool )
1154 return 0;
1155
1157
1158 // Note: PlaceImportedGraphics() will convert PCB_SHAPE_T and PCB_TEXT_T to footprint
1159 // items if needed
1161 int dlgResult = dlg.ShowModal();
1162
1163 std::list<std::unique_ptr<EDA_ITEM>>& list = dlg.GetImportedItems();
1164
1165 if( dlgResult != wxID_OK )
1166 return 0;
1167
1168 // Ensure the list is not empty:
1169 if( list.empty() )
1170 {
1171 wxMessageBox( _( "No graphic items found in file." ) );
1172 return 0;
1173 }
1174
1176
1178 std::vector<SCH_ITEM*> newItems; // all new items, including group
1179 std::vector<SCH_ITEM*> selectedItems; // the group, or newItems if no group
1180 EE_SELECTION preview;
1181 SCH_COMMIT commit( m_toolMgr );
1182
1183 for( std::unique_ptr<EDA_ITEM>& ptr : list )
1184 {
1185 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( ptr.get() );
1186 wxCHECK2( item, continue );
1187
1188 newItems.push_back( item );
1189 selectedItems.push_back( item );
1190 preview.Add( item );
1191
1192 ptr.release();
1193 }
1194
1195 if( !dlg.IsPlacementInteractive() )
1196 {
1197 // Place the imported drawings
1198 for( SCH_ITEM* item : newItems )
1199 commit.Add(item, m_frame->GetScreen());
1200
1201 commit.Push( _( "Import Graphic" ) );
1202 return 0;
1203 }
1204
1205 m_view->Add( &preview );
1206
1207 // Clear the current selection then select the drawings so that edit tools work on them
1209
1210 EDA_ITEMS selItems( selectedItems.begin(), selectedItems.end() );
1212
1213 m_frame->PushTool( aEvent );
1214
1215 auto setCursor = [&]()
1216 {
1217 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
1218 };
1219
1220 Activate();
1221 // Must be done after Activate() so that it gets set into the correct context
1222 controls->ShowCursor( true );
1223 controls->ForceCursorPosition( false );
1224 // Set initial cursor
1225 setCursor();
1226
1227 //SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DXF );
1229
1230 // Now move the new items to the current cursor position:
1231 VECTOR2I cursorPos = controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
1232 VECTOR2I delta = cursorPos;
1233 VECTOR2I currentOffset;
1234
1235 for( SCH_ITEM* item : selectedItems )
1236 item->Move( delta );
1237
1238 currentOffset += delta;
1239
1240 m_view->Update( &preview );
1241
1242 // Main loop: keep receiving events
1243 while( TOOL_EVENT* evt = Wait() )
1244 {
1245 setCursor();
1246
1247 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1248 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1249
1250 cursorPos = grid.Align( controls->GetMousePosition(), GRID_GRAPHICS );
1251 controls->ForceCursorPosition( true, cursorPos );
1252
1253 if( evt->IsCancelInteractive() || evt->IsActivate() )
1254 {
1256
1257 for( SCH_ITEM* item : newItems )
1258 delete item;
1259
1260 break;
1261 }
1262 else if( evt->IsMotion() )
1263 {
1264 delta = cursorPos - currentOffset;
1265
1266 for( SCH_ITEM* item : selectedItems )
1267 item->Move( delta );
1268
1269 currentOffset += delta;
1270
1271 m_view->Update( &preview );
1272 }
1273 else if( evt->IsClick( BUT_RIGHT ) )
1274 {
1275 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
1276 }
1277 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1278 {
1279 // Place the imported drawings
1280 for( SCH_ITEM* item : newItems )
1281 commit.Add( item, m_frame->GetScreen() );
1282
1283 commit.Push( _( "Import Graphic" ) );
1284 break; // This is a one-shot command, not a tool
1285 }
1286 else
1287 {
1288 evt->SetPassEvent();
1289 }
1290 }
1291
1292 preview.Clear();
1293 m_view->Remove( &preview );
1294
1295 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1296 controls->ForceCursorPosition( false );
1297
1298 m_frame->PopTool( aEvent );
1299
1300 return 0;
1301}
1302
1303
1305{
1306 VECTOR2I cursorPos;
1307 KICAD_T type = aEvent.Parameter<KICAD_T>();
1310 SCH_ITEM* previewItem;
1311 bool loggedInfoBarError = false;
1312 wxString description;
1313 SCH_SCREEN* screen = m_frame->GetScreen();
1314 bool allowRepeat = false; // Set to true to allow new item repetition
1315
1316 if( m_inDrawingTool )
1317 return 0;
1318
1320
1321 if( type == SCH_JUNCTION_T && aEvent.HasPosition() )
1322 {
1324 SCH_LINE* wire = dynamic_cast<SCH_LINE*>( selection.Front() );
1325
1326 if( wire )
1327 {
1328 SEG seg( wire->GetStartPoint(), wire->GetEndPoint() );
1329 VECTOR2I nearest = seg.NearestPoint( getViewControls()->GetCursorPosition() );
1330 getViewControls()->SetCrossHairCursorPosition( nearest, false );
1331 getViewControls()->WarpMouseCursor( getViewControls()->GetCursorPosition(), true );
1332 }
1333 }
1334
1335 switch( type )
1336 {
1337 case SCH_NO_CONNECT_T:
1338 previewItem = new SCH_NO_CONNECT( cursorPos );
1339 previewItem->SetParent( screen );
1340 description = _( "Add No Connect Flag" );
1341 allowRepeat = true;
1342 break;
1343
1344 case SCH_JUNCTION_T:
1345 previewItem = new SCH_JUNCTION( cursorPos );
1346 previewItem->SetParent( screen );
1347 description = _( "Add Junction" );
1348 break;
1349
1351 previewItem = new SCH_BUS_WIRE_ENTRY( cursorPos );
1352 previewItem->SetParent( screen );
1353 description = _( "Add Wire to Bus Entry" );
1354 allowRepeat = true;
1355 break;
1356
1357 default:
1358 wxASSERT_MSG( false, "Unknown item type in SCH_DRAWING_TOOLS::SingleClickPlace" );
1359 return 0;
1360 }
1361
1363
1364 cursorPos = aEvent.HasPosition() ? aEvent.Position() : controls->GetMousePosition();
1365
1366 m_frame->PushTool( aEvent );
1367
1368 auto setCursor =
1369 [&]()
1370 {
1371 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PLACE );
1372 };
1373
1374 Activate();
1375
1376 // Must be done after Activate() so that it gets set into the correct context
1377 getViewControls()->ShowCursor( true );
1378
1379 // Set initial cursor
1380 setCursor();
1381
1383 m_view->AddToPreview( previewItem->Clone() );
1384
1385 // Prime the pump
1386 if( aEvent.HasPosition() && type != SCH_SHEET_PIN_T )
1387 m_toolMgr->PrimeTool( aEvent.Position() );
1388 else
1390
1391 // Main loop: keep receiving events
1392 while( TOOL_EVENT* evt = Wait() )
1393 {
1394 setCursor();
1395 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1396 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1397
1398 cursorPos = evt->IsPrime() ? evt->Position() : controls->GetMousePosition();
1399 cursorPos = grid.BestSnapAnchor( cursorPos, grid.GetItemGrid( previewItem ), nullptr );
1400 controls->ForceCursorPosition( true, cursorPos );
1401
1402 if( evt->IsCancelInteractive() )
1403 {
1404 m_frame->PopTool( aEvent );
1405 break;
1406 }
1407 else if( evt->IsActivate() )
1408 {
1409 if( evt->IsMoveTool() )
1410 {
1411 // leave ourselves on the stack so we come back after the move
1412 break;
1413 }
1414 else
1415 {
1416 m_frame->PopTool( aEvent );
1417 break;
1418 }
1419 }
1420 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1421 {
1422 if( !screen->GetItem( cursorPos, 0, type ) )
1423 {
1424 if( type == SCH_JUNCTION_T )
1425 {
1426 if( !screen->IsExplicitJunctionAllowed( cursorPos ) )
1427 {
1428 m_frame->ShowInfoBarError( _( "Junction location contains no joinable "
1429 "wires and/or pins." ) );
1430 loggedInfoBarError = true;
1431 continue;
1432 }
1433 else if( loggedInfoBarError )
1434 {
1436 }
1437 }
1438
1439 SCH_ITEM* newItem = static_cast<SCH_ITEM*>( previewItem->Clone() );
1440 const_cast<KIID&>( newItem->m_Uuid ) = KIID();
1441 newItem->SetPosition( cursorPos );
1442 newItem->SetFlags( IS_NEW );
1443 m_frame->AddToScreen( newItem, screen );
1444
1445 if( allowRepeat )
1446 m_frame->SaveCopyForRepeatItem( newItem );
1447
1448 SCH_COMMIT commit( m_toolMgr );
1449 commit.Added( newItem, screen );
1450
1451 m_frame->SchematicCleanUp( &commit );
1452
1453 commit.Push( description );
1454 }
1455
1456 if( evt->IsDblClick( BUT_LEFT ) || type == SCH_SHEET_PIN_T ) // Finish tool.
1457 {
1458 m_frame->PopTool( aEvent );
1459 break;
1460 }
1461 }
1462 else if( evt->IsClick( BUT_RIGHT ) )
1463 {
1464 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
1465 }
1466 else if( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() )
1467 {
1468 previewItem->SetPosition( cursorPos );
1470 m_view->AddToPreview( previewItem->Clone() );
1471 m_frame->SetMsgPanel( previewItem );
1472 }
1473 else if( evt->Category() == TC_COMMAND )
1474 {
1475 if( ( type == SCH_BUS_WIRE_ENTRY_T ) && ( evt->IsAction( &EE_ACTIONS::rotateCW )
1476 || evt->IsAction( &EE_ACTIONS::rotateCCW )
1477 || evt->IsAction( &EE_ACTIONS::mirrorV )
1478 || evt->IsAction( &EE_ACTIONS::mirrorH ) ) )
1479 {
1480 SCH_BUS_ENTRY_BASE* busItem = static_cast<SCH_BUS_ENTRY_BASE*>( previewItem );
1481
1482 if( evt->IsAction( &EE_ACTIONS::rotateCW ) )
1483 {
1484 busItem->Rotate( busItem->GetPosition(), false );
1485 }
1486 else if( evt->IsAction( &EE_ACTIONS::rotateCCW ) )
1487 {
1488 busItem->Rotate( busItem->GetPosition(), true );
1489 }
1490 else if( evt->IsAction( &EE_ACTIONS::mirrorV ) )
1491 {
1492 busItem->MirrorVertically( busItem->GetPosition().y );
1493 }
1494 else if( evt->IsAction( &EE_ACTIONS::mirrorH ) )
1495 {
1496 busItem->MirrorHorizontally( busItem->GetPosition().x );
1497 }
1498
1500 m_view->AddToPreview( previewItem->Clone() );
1501 }
1502 else if( evt->IsAction( &EE_ACTIONS::properties ) )
1503 {
1504 switch( type )
1505 {
1507 {
1508 std::deque<SCH_ITEM*> strokeItems;
1509 strokeItems.push_back( previewItem );
1510
1511 DIALOG_WIRE_BUS_PROPERTIES dlg( m_frame, strokeItems );
1512 }
1513 break;
1514
1515 case SCH_JUNCTION_T:
1516 {
1517 std::deque<SCH_JUNCTION*> junctions;
1518 junctions.push_back( static_cast<SCH_JUNCTION*>( previewItem ) );
1519
1520 DIALOG_JUNCTION_PROPS dlg( m_frame, junctions );
1521 }
1522 break;
1523 default:
1524 // Do nothing
1525 break;
1526 }
1527
1529 m_view->AddToPreview( previewItem->Clone() );
1530 }
1531 else
1532 {
1533 evt->SetPassEvent();
1534 }
1535 }
1536 else
1537 {
1538 evt->SetPassEvent();
1539 }
1540 }
1541
1542 delete previewItem;
1544
1545 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1546 controls->ForceCursorPosition( false );
1547
1548 return 0;
1549}
1550
1551
1553{
1554 for( SCH_ITEM* item : m_frame->GetScreen()->Items().Overlapping( SCH_LINE_T, aPosition ) )
1555 {
1556 SCH_LINE* line = static_cast<SCH_LINE*>( item );
1557
1558 if( line->GetEditFlags() & STRUCT_DELETED )
1559 continue;
1560
1561 if( line->IsWire() )
1562 return line;
1563 }
1564
1565 return nullptr;
1566}
1567
1568
1570{
1571 wxASSERT( aWire->IsWire() );
1572
1573 SCH_SHEET_PATH sheetPath = m_frame->GetCurrentSheet();
1574
1575 if( SCH_CONNECTION* wireConnection = aWire->Connection( &sheetPath ) )
1576 {
1577 SCH_ITEM* wireDriver = wireConnection->Driver();
1578
1579 if( wireDriver && wireDriver->IsType( { SCH_LABEL_T, SCH_GLOBAL_LABEL_T } ) )
1580 return wireConnection->LocalName();
1581 }
1582
1583 return wxEmptyString;
1584}
1585
1586
1588{
1589 SCHEMATIC* schematic = getModel<SCHEMATIC>();
1590 SCHEMATIC_SETTINGS& settings = schematic->Settings();
1591 SCH_TEXT* textItem = nullptr;
1592 SCH_LABEL_BASE* labelItem = nullptr;
1593 wxString netName;
1594
1595 switch( aType )
1596 {
1597 case LAYER_NOTES:
1598 textItem = new SCH_TEXT( aPosition );
1599 break;
1600
1601 case LAYER_LOCLABEL:
1602 labelItem = new SCH_LABEL( aPosition );
1603 textItem = labelItem;
1604
1605 if( SCH_LINE* wire = findWire( aPosition ) )
1606 netName = findWireLabelDriverName( wire );
1607
1608 break;
1609
1611 labelItem = new SCH_DIRECTIVE_LABEL( aPosition );
1612 labelItem->SetShape( m_lastNetClassFlagShape );
1613 labelItem->GetFields().emplace_back( SCH_FIELD( {0,0}, 0, labelItem, wxT( "Netclass" ) ) );
1614 labelItem->GetFields().emplace_back(
1615 SCH_FIELD( { 0, 0 }, 0, labelItem, wxT( "Component Class" ) ) );
1616 labelItem->GetFields().back().SetItalic( true );
1617 labelItem->GetFields().back().SetVisible( true );
1618 textItem = labelItem;
1619 break;
1620
1621 case LAYER_HIERLABEL:
1622 labelItem = new SCH_HIERLABEL( aPosition );
1623 labelItem->SetShape( m_lastGlobalLabelShape );
1625 textItem = labelItem;
1626 break;
1627
1628 case LAYER_GLOBLABEL:
1629 labelItem = new SCH_GLOBALLABEL( aPosition );
1630 labelItem->SetShape( m_lastGlobalLabelShape );
1631 labelItem->GetFields()[0].SetVisible( settings.m_IntersheetRefsShow );
1633 textItem = labelItem;
1634
1635 if( SCH_LINE* wire = findWire( aPosition ) )
1636 netName = findWireLabelDriverName( wire );
1637
1638 break;
1639
1640 default:
1641 wxFAIL_MSG( "SCH_EDIT_FRAME::CreateNewText() unknown layer type" );
1642 return nullptr;
1643 }
1644
1645 textItem->SetParent( schematic );
1646
1647 textItem->SetTextSize( VECTOR2I( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
1648
1649 if( aType != LAYER_NETCLASS_REFS )
1650 {
1651 // Must be after SetTextSize()
1652 textItem->SetBold( m_lastTextBold );
1653 textItem->SetItalic( m_lastTextItalic );
1654 }
1655
1656 if( labelItem )
1657 {
1658 labelItem->SetSpinStyle( m_lastTextOrientation );
1659 }
1660 else
1661 {
1664 textItem->SetTextAngle( m_lastTextAngle );
1665 }
1666
1667 textItem->SetFlags( IS_NEW | IS_MOVING );
1668
1669 if( !labelItem )
1670 {
1671 DIALOG_TEXT_PROPERTIES dlg( m_frame, textItem );
1672
1673 // QuasiModal required for syntax help and Scintilla auto-complete
1674 if( dlg.ShowQuasiModal() != wxID_OK )
1675 {
1676 delete textItem;
1677 return nullptr;
1678 }
1679 }
1680 else if( !netName.IsEmpty() )
1681 {
1682 // Auto-create from attached wire
1683 textItem->SetText( netName );
1684 }
1685 else
1686 {
1687 DIALOG_LABEL_PROPERTIES dlg( m_frame, static_cast<SCH_LABEL_BASE*>( textItem ) );
1688
1689 // QuasiModal required for syntax help and Scintilla auto-complete
1690 if( dlg.ShowQuasiModal() != wxID_OK )
1691 {
1692 delete labelItem;
1693 return nullptr;
1694 }
1695 }
1696
1697 wxString text = textItem->GetText();
1698
1699 if( textItem->Type() != SCH_DIRECTIVE_LABEL_T && NoPrintableChars( text ) )
1700 {
1701 delete textItem;
1702 return nullptr;
1703 }
1704
1705 if( aType != LAYER_NETCLASS_REFS )
1706 {
1707 m_lastTextBold = textItem->IsBold();
1708 m_lastTextItalic = textItem->IsItalic();
1709 }
1710
1711 if( labelItem )
1712 {
1713 m_lastTextOrientation = labelItem->GetSpinStyle();
1714 }
1715 else
1716 {
1717 m_lastTextHJustify = textItem->GetHorizJustify();
1718 m_lastTextVJustify = textItem->GetVertJustify();
1719 m_lastTextAngle = textItem->GetTextAngle();
1720 }
1721
1722 if( aType == LAYER_GLOBLABEL || aType == LAYER_HIERLABEL )
1723 {
1724 m_lastGlobalLabelShape = labelItem->GetShape();
1726 }
1727 else if( aType == LAYER_NETCLASS_REFS )
1728 {
1729 m_lastNetClassFlagShape = labelItem->GetShape();
1730 }
1731
1732 return textItem;
1733}
1734
1736{
1737 SCHEMATIC_SETTINGS& settings = aSheet->Schematic()->Settings();
1738 SCH_SHEET_PIN* pin = new SCH_SHEET_PIN( aSheet );
1739
1740 pin->SetFlags( IS_NEW | IS_MOVING );
1741 pin->SetText( std::to_string( aSheet->GetPins().size() + 1 ) );
1742 pin->SetTextSize( VECTOR2I( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
1743 pin->SetPosition( aPosition );
1744 pin->ClearSelected();
1745
1746 m_lastSheetPinType = pin->GetShape();
1747
1748 return pin;
1749}
1750
1751
1753{
1754 SCH_ITEM* item = nullptr;
1757 bool ignorePrimePosition = false;
1758 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
1759 SCH_SHEET* sheet = nullptr;
1760 wxString description;
1761
1762 if( m_inDrawingTool )
1763 return 0;
1764
1766
1767 bool isText = aEvent.IsAction( &EE_ACTIONS::placeSchematicText );
1768 bool isGlobalLabel = aEvent.IsAction( &EE_ACTIONS::placeGlobalLabel );
1769 bool isHierLabel = aEvent.IsAction( &EE_ACTIONS::placeHierLabel );
1770 bool isClassLabel = aEvent.IsAction( &EE_ACTIONS::placeClassLabel );
1771 bool isNetLabel = aEvent.IsAction( &EE_ACTIONS::placeLabel );
1772 bool isSheetPin = aEvent.IsAction( &EE_ACTIONS::placeSheetPin );
1773
1774 GRID_HELPER_GRIDS snapGrid = isText ? GRID_TEXT : GRID_CONNECTABLE;
1775
1776 // If we have a selected sheet use it, otherwise try to get one under the cursor
1777 if( isSheetPin )
1778 sheet = dynamic_cast<SCH_SHEET*>( m_selectionTool->GetSelection().Front() );
1779
1781
1782 m_frame->PushTool( aEvent );
1783
1784 auto setCursor =
1785 [&]()
1786 {
1787 if( item )
1788 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PLACE );
1789 else if( isText )
1790 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::TEXT );
1791 else if( isGlobalLabel )
1792 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_GLOBAL );
1793 else if( isNetLabel )
1794 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_NET );
1795 else if( isClassLabel )
1796 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_NET ); // JEY TODO: netclass directive cursor
1797 else if( isHierLabel )
1798 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_HIER );
1799 else
1800 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1801 };
1802
1803 auto updatePreview =
1804 [&]()
1805 {
1807 m_view->AddToPreview( item->Clone() );
1808 item->RunOnChildren( [&]( SCH_ITEM* aChild )
1809 {
1810 m_view->AddToPreview( aChild->Clone() );
1811 } );
1812 m_frame->SetMsgPanel( item );
1813 };
1814
1815 auto cleanup =
1816 [&]()
1817 {
1820 delete item;
1821 item = nullptr;
1822 };
1823
1824 Activate();
1825
1826 // Must be done after Activate() so that it gets set into the correct context
1827 controls->ShowCursor( true );
1828
1829 // Set initial cursor
1830 setCursor();
1831
1832 if( aEvent.HasPosition() )
1833 {
1834 m_toolMgr->PrimeTool( aEvent.Position() );
1835 }
1836 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate()
1837 && ( isText || isGlobalLabel || isHierLabel || isClassLabel || isNetLabel ) )
1838 {
1839 m_toolMgr->PrimeTool( { 0, 0 } );
1840 ignorePrimePosition = true;
1841 }
1842
1843 // Main loop: keep receiving events
1844 while( TOOL_EVENT* evt = Wait() )
1845 {
1846 setCursor();
1847 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1848 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1849
1850 VECTOR2I cursorPos = controls->GetMousePosition();
1851 cursorPos = grid.BestSnapAnchor( cursorPos, snapGrid, item );
1852 controls->ForceCursorPosition( true, cursorPos );
1853
1854 // The tool hotkey is interpreted as a click when drawing
1855 bool isSyntheticClick = item && evt->IsActivate() && evt->HasPosition()
1856 && evt->Matches( aEvent );
1857
1858 if( evt->IsCancelInteractive() || evt->IsAction( &ACTIONS::undo ) )
1859 {
1861
1862 if( item )
1863 {
1864 cleanup();
1865 }
1866 else
1867 {
1868 m_frame->PopTool( aEvent );
1869 break;
1870 }
1871 }
1872 else if( evt->IsActivate() && !isSyntheticClick )
1873 {
1874 if( item && evt->IsMoveTool() )
1875 {
1876 // we're already moving our own item; ignore the move tool
1877 evt->SetPassEvent( false );
1878 continue;
1879 }
1880
1881 if( item )
1882 {
1883 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel item creation." ) );
1884 evt->SetPassEvent( false );
1885 continue;
1886 }
1887
1888 if( evt->IsPointEditor() )
1889 {
1890 // don't exit (the point editor runs in the background)
1891 }
1892 else if( evt->IsMoveTool() )
1893 {
1894 // leave ourselves on the stack so we come back after the move
1895 break;
1896 }
1897 else
1898 {
1899 m_frame->PopTool( aEvent );
1900 break;
1901 }
1902 }
1903 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) || isSyntheticClick )
1904 {
1905 // First click creates...
1906 if( !item )
1907 {
1909
1910 if( isText )
1911 {
1912 item = createNewText( cursorPos, LAYER_NOTES );
1913 description = _( "Add Text" );
1914 }
1915 else if( isHierLabel )
1916 {
1917 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
1918 {
1919 auto pin = static_cast<SCH_HIERLABEL*>(
1920 m_dialogSyncSheetPin->GetPlacementTemplate() );
1921 SCH_HIERLABEL* label = new SCH_HIERLABEL( cursorPos );
1922 SCHEMATIC* schematic = getModel<SCHEMATIC>();
1923 label->SetText( pin->GetText() );
1924 label->SetShape( pin->GetShape() );
1926 label->SetParent( schematic );
1927 label->SetBold( m_lastTextBold );
1928 label->SetItalic( m_lastTextItalic );
1930 label->SetTextSize( VECTOR2I( schematic->Settings().m_DefaultTextSize,
1931 schematic->Settings().m_DefaultTextSize ) );
1932 label->SetFlags( IS_NEW | IS_MOVING );
1933 item = label;
1934 }
1935 else
1936 {
1937 item = createNewText( cursorPos, LAYER_HIERLABEL );
1938 }
1939
1940 description = _( "Add Hierarchical Label" );
1941 }
1942 else if( isNetLabel )
1943 {
1944 item = createNewText( cursorPos, LAYER_LOCLABEL );
1945 description = _( "Add Label" );
1946 }
1947 else if( isGlobalLabel )
1948 {
1949 item = createNewText( cursorPos, LAYER_GLOBLABEL );
1950 description = _( "Add Label" );
1951 }
1952 else if( isClassLabel )
1953 {
1954 item = createNewText( cursorPos, LAYER_NETCLASS_REFS );
1955 description = _( "Add Label" );
1956 }
1957 else if( isSheetPin )
1958 {
1959 EDA_ITEM* i = nullptr;
1960
1961 // If we didn't have a sheet selected, try to find one under the cursor
1962 if( !sheet && m_selectionTool->SelectPoint( cursorPos, { SCH_SHEET_T }, &i ) )
1963 sheet = dynamic_cast<SCH_SHEET*>( i );
1964
1965 if( !sheet )
1966 {
1967 m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( m_frame );
1968 m_statusPopup->SetText( _( "Click over a sheet." ) );
1970 + wxPoint( 20, 20 ) );
1971 m_statusPopup->PopupFor( 2000 );
1972 item = nullptr;
1973 }
1974 else
1975 {
1976 item = createNewSheetPin( sheet, cursorPos );
1977
1978 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
1979 {
1980 auto label = static_cast<SCH_HIERLABEL*>(
1981 m_dialogSyncSheetPin->GetPlacementTemplate() );
1982 auto pin = static_cast<SCH_HIERLABEL*>( item );
1983 pin->SetText( label->GetText() );
1984 pin->SetShape( label->GetShape() );
1985 }
1986 }
1987
1988 description = _( "Add Sheet Pin" );
1989 }
1990
1991 // If we started with a hotkey which has a position then warp back to that.
1992 // Otherwise update to the current mouse position pinned inside the autoscroll
1993 // boundaries.
1994 if( evt->IsPrime() && !ignorePrimePosition )
1995 {
1996 cursorPos = grid.Align( evt->Position() );
1997 getViewControls()->WarpMouseCursor( cursorPos, true );
1998 }
1999 else
2000 {
2002 cursorPos = getViewControls()->GetMousePosition();
2003 cursorPos = grid.BestSnapAnchor( cursorPos, snapGrid, item );
2004 }
2005
2006 if( item )
2007 {
2008 item->SetPosition( cursorPos );
2009
2010 item->SetFlags( IS_NEW | IS_MOVING );
2011 item->AutoplaceFields( nullptr, false /* aManual */ );
2012 updatePreview();
2015
2016 // update the cursor so it looks correct before another event
2017 setCursor();
2018 }
2019
2020 controls->SetCursorPosition( cursorPos, false );
2021 }
2022 else // ... and second click places:
2023 {
2024 SCH_COMMIT commit( m_toolMgr );
2025
2026 item->ClearFlags( IS_MOVING );
2027
2028 if( item->IsConnectable() )
2030
2031 if( isSheetPin )
2032 {
2033 // Sheet pins are owned by their parent sheet.
2034 commit.Modify( sheet, m_frame->GetScreen() );
2035 sheet->AddPin( (SCH_SHEET_PIN*) item );
2036 }
2037 else
2038 {
2040 m_frame->AddToScreen( item, m_frame->GetScreen() );
2041 commit.Added( item, m_frame->GetScreen() );
2042 }
2043
2044 item->AutoplaceFields( m_frame->GetScreen(), false /* aManual */ );
2045
2046 commit.Push( description );
2047
2049
2050 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
2051 {
2052 m_frame->PopTool( aEvent );
2054 m_dialogSyncSheetPin->EndPlaceItem( item );
2055 m_dialogSyncSheetPin->Show( true );
2056 break;
2057 }
2058 else
2059 {
2060 item = nullptr;
2061 }
2062
2063 if( isSheetPin )
2064 {
2065 item = createNewSheetPin( sheet, cursorPos );
2066 item->SetPosition( cursorPos );
2069 }
2070 }
2071 }
2072 else if( evt->IsClick( BUT_RIGHT ) )
2073 {
2074 // Warp after context menu only if dragging...
2075 if( !item )
2077
2078 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
2079 }
2080 else if( item && evt->IsSelectionEvent() )
2081 {
2082 // This happens if our text was replaced out from under us by ConvertTextType()
2084
2085 if( selection.GetSize() == 1 )
2086 {
2087 item = (SCH_ITEM*) selection.Front();
2088 updatePreview();
2089 }
2090 else
2091 {
2092 item = nullptr;
2093 }
2094 }
2095 else if( evt->IsAction( &ACTIONS::duplicate )
2096 || evt->IsAction( &EE_ACTIONS::repeatDrawItem ) )
2097 {
2098 if( item )
2099 {
2100 // This doesn't really make sense; we'll just end up dragging a stack of
2101 // objects so we ignore the duplicate and just carry on.
2102 wxBell();
2103 continue;
2104 }
2105
2106 // Exit. The duplicate will run in its own loop.
2107 m_frame->PopTool( aEvent );
2108 break;
2109 }
2110 else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
2111 {
2112 item->SetPosition( cursorPos );
2113 item->AutoplaceFields( /* aScreen */ nullptr, /* aManual */ false );
2114 updatePreview();
2115 }
2116 else if( item && evt->IsAction( &ACTIONS::doDelete ) )
2117 {
2118 cleanup();
2119 }
2120 else if( evt->IsAction( &ACTIONS::redo ) )
2121 {
2122 wxBell();
2123 }
2124 else
2125 {
2126 evt->SetPassEvent();
2127 }
2128
2129 // Enable autopanning and cursor capture only when there is an item to be placed
2130 controls->SetAutoPan( item != nullptr );
2131 controls->CaptureCursor( item != nullptr );
2132 }
2133
2134 controls->SetAutoPan( false );
2135 controls->CaptureCursor( false );
2136 controls->ForceCursorPosition( false );
2137 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2138
2139 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
2140 {
2141 m_dialogSyncSheetPin->EndPlaceItem( nullptr );
2142 m_dialogSyncSheetPin->Show( true );
2143 }
2144
2145 return 0;
2146}
2147
2148
2150{
2151 SCHEMATIC* schematic = getModel<SCHEMATIC>();
2152 SCHEMATIC_SETTINGS& sch_settings = schematic->Settings();
2153 SCH_SHAPE* item = nullptr;
2154 bool isTextBox = aEvent.IsAction( &EE_ACTIONS::drawTextBox );
2155 SHAPE_T type = aEvent.Parameter<SHAPE_T>();
2156 wxString description;
2157
2158 if( m_inDrawingTool )
2159 return 0;
2160
2162
2165 VECTOR2I cursorPos;
2166
2167 // We might be running as the same shape in another co-routine. Make sure that one
2168 // gets whacked.
2170
2172
2173 m_frame->PushTool( aEvent );
2174
2175 auto setCursor =
2176 [&]()
2177 {
2178 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2179 };
2180
2181 auto cleanup =
2182 [&] ()
2183 {
2186 delete item;
2187 item = nullptr;
2188 };
2189
2190 Activate();
2191
2192 // Must be done after Activate() so that it gets set into the correct context
2193 getViewControls()->ShowCursor( true );
2194
2195 // Set initial cursor
2196 setCursor();
2197
2198 if( aEvent.HasPosition() )
2199 m_toolMgr->PrimeTool( aEvent.Position() );
2200
2201 // Main loop: keep receiving events
2202 while( TOOL_EVENT* evt = Wait() )
2203 {
2204 setCursor();
2205 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2206 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2207
2208 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
2209 controls->ForceCursorPosition( true, cursorPos );
2210
2211 // The tool hotkey is interpreted as a click when drawing
2212 bool isSyntheticClick = item && evt->IsActivate() && evt->HasPosition()
2213 && evt->Matches( aEvent );
2214
2215 if( evt->IsCancelInteractive() || ( item && evt->IsAction( &ACTIONS::undo ) ) )
2216 {
2217 if( item )
2218 {
2219 cleanup();
2220 }
2221 else
2222 {
2223 m_frame->PopTool( aEvent );
2224 break;
2225 }
2226 }
2227 else if( evt->IsActivate() && !isSyntheticClick )
2228 {
2229 if( item && evt->IsMoveTool() )
2230 {
2231 // we're already drawing our own item; ignore the move tool
2232 evt->SetPassEvent( false );
2233 continue;
2234 }
2235
2236 if( item )
2237 cleanup();
2238
2239 if( evt->IsPointEditor() )
2240 {
2241 // don't exit (the point editor runs in the background)
2242 }
2243 else if( evt->IsMoveTool() )
2244 {
2245 // leave ourselves on the stack so we come back after the move
2246 break;
2247 }
2248 else
2249 {
2250 m_frame->PopTool( aEvent );
2251 break;
2252 }
2253 }
2254 else if( evt->IsClick( BUT_LEFT ) && !item )
2255 {
2257
2258 if( isTextBox )
2259 {
2261
2262 textbox->SetTextSize( VECTOR2I( sch_settings.m_DefaultTextSize,
2263 sch_settings.m_DefaultTextSize ) );
2264
2265 // Must come after SetTextSize()
2266 textbox->SetBold( m_lastTextBold );
2267 textbox->SetItalic( m_lastTextItalic );
2268
2269 textbox->SetTextAngle( m_lastTextboxAngle );
2272 textbox->SetStroke( m_lastTextboxStroke );
2274 textbox->SetParent( schematic );
2275
2276 item = textbox;
2277 description = _( "Add Text Box" );
2278 }
2279 else
2280 {
2281 item = new SCH_SHAPE( type, LAYER_NOTES, 0, m_lastFillStyle );
2282
2283 item->SetStroke( m_lastStroke );
2285 item->SetParent( schematic );
2286 description = wxString::Format( _( "Add %s" ), item->GetFriendlyName() );
2287 }
2288
2289 item->SetFlags( IS_NEW );
2290 item->BeginEdit( cursorPos );
2291
2293 m_view->AddToPreview( item->Clone() );
2294 }
2295 else if( item && ( evt->IsClick( BUT_LEFT )
2296 || evt->IsDblClick( BUT_LEFT )
2297 || isSyntheticClick
2298 || evt->IsAction( &ACTIONS::finishInteractive ) ) )
2299 {
2300 if( evt->IsDblClick( BUT_LEFT )
2301 || evt->IsAction( &ACTIONS::finishInteractive )
2302 || !item->ContinueEdit( cursorPos ) )
2303 {
2304 item->EndEdit();
2305 item->ClearEditFlags();
2306 item->SetFlags( IS_NEW );
2307
2308 if( isTextBox )
2309 {
2310 SCH_TEXTBOX* textbox = static_cast<SCH_TEXTBOX*>( item );
2311 DIALOG_TEXT_PROPERTIES dlg( m_frame, textbox );
2312
2313 getViewControls()->SetAutoPan( false );
2314 getViewControls()->CaptureCursor( false );
2315
2316 // QuasiModal required for syntax help and Scintilla auto-complete
2317 if( dlg.ShowQuasiModal() != wxID_OK )
2318 {
2319 cleanup();
2320 continue;
2321 }
2322
2323 m_lastTextBold = textbox->IsBold();
2324 m_lastTextItalic = textbox->IsItalic();
2325 m_lastTextboxAngle = textbox->GetTextAngle();
2328 m_lastTextboxStroke = textbox->GetStroke();
2331 }
2332 else
2333 {
2334 m_lastStroke = item->GetStroke();
2335 m_lastFillStyle = item->GetFillMode();
2336 m_lastFillColor = item->GetFillColor();
2337 }
2338
2339 SCH_COMMIT commit( m_toolMgr );
2340 commit.Add( item, m_frame->GetScreen() );
2341 commit.Push( wxString::Format( _( "Draw %s" ), item->GetClass() ) );
2342
2344 item = nullptr;
2345
2348 }
2349 }
2350 else if( evt->IsAction( &ACTIONS::duplicate )
2351 || evt->IsAction( &EE_ACTIONS::repeatDrawItem ) )
2352 {
2353 if( item )
2354 {
2355 // This doesn't really make sense; we'll just end up dragging a stack of
2356 // objects so we ignore the duplicate and just carry on.
2357 wxBell();
2358 continue;
2359 }
2360
2361 // Exit. The duplicate will run in its own loop.
2362 m_frame->PopTool( aEvent );
2363 break;
2364 }
2365 else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
2366 {
2367 item->CalcEdit( cursorPos );
2369 m_view->AddToPreview( item->Clone() );
2370 m_frame->SetMsgPanel( item );
2371 }
2372 else if( evt->IsDblClick( BUT_LEFT ) && !item )
2373 {
2375 }
2376 else if( evt->IsClick( BUT_RIGHT ) )
2377 {
2378 // Warp after context menu only if dragging...
2379 if( !item )
2381
2382 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
2383 }
2384 else if( item && evt->IsAction( &ACTIONS::redo ) )
2385 {
2386 wxBell();
2387 }
2388 else
2389 {
2390 evt->SetPassEvent();
2391 }
2392
2393 // Enable autopanning and cursor capture only when there is a shape being drawn
2394 getViewControls()->SetAutoPan( item != nullptr );
2395 getViewControls()->CaptureCursor( item != nullptr );
2396 }
2397
2398 getViewControls()->SetAutoPan( false );
2399 getViewControls()->CaptureCursor( false );
2400 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2401 return 0;
2402}
2403
2404
2406{
2407 if( m_inDrawingTool )
2408 return 0;
2409
2411 SCOPED_SET_RESET<bool> scopedDrawMode( m_drawingRuleArea, true );
2412
2415 VECTOR2I cursorPos;
2416
2417 RULE_AREA_CREATE_HELPER ruleAreaTool( *getView(), m_frame, m_toolMgr );
2418 POLYGON_GEOM_MANAGER polyGeomMgr( ruleAreaTool );
2419 bool started = false;
2420
2421 // We might be running as the same shape in another co-routine. Make sure that one
2422 // gets whacked.
2424
2426
2427 m_frame->PushTool( aEvent );
2428
2429 auto setCursor =
2430 [&]()
2431 {
2432 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2433 };
2434
2435 auto cleanup = [&]()
2436 {
2437 polyGeomMgr.Reset();
2438 started = false;
2439 getViewControls()->SetAutoPan( false );
2440 getViewControls()->CaptureCursor( false );
2442 };
2443
2444 Activate();
2445
2446 // Must be done after Activate() so that it gets set into the correct context
2447 getViewControls()->ShowCursor( true );
2448 //m_controls->ForceCursorPosition( false );
2449
2450 // Set initial cursor
2451 setCursor();
2452
2453 if( aEvent.HasPosition() )
2454 m_toolMgr->PrimeTool( aEvent.Position() );
2455
2456 // Main loop: keep receiving events
2457 while( TOOL_EVENT* evt = Wait() )
2458 {
2459 setCursor();
2460
2461 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2462 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2463
2464 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
2465 controls->ForceCursorPosition( true, cursorPos );
2466
2470
2471 if( evt->IsCancelInteractive() )
2472 {
2473 if( started )
2474 {
2475 cleanup();
2476 }
2477 else
2478 {
2479 m_frame->PopTool( aEvent );
2480
2481 // We've handled the cancel event. Don't cancel other tools
2482 evt->SetPassEvent( false );
2483 break;
2484 }
2485 }
2486 else if( evt->IsActivate() )
2487 {
2488 if( started )
2489 cleanup();
2490
2491 if( evt->IsPointEditor() )
2492 {
2493 // don't exit (the point editor runs in the background)
2494 }
2495 else if( evt->IsMoveTool() )
2496 {
2497 // leave ourselves on the stack so we come back after the move
2498 break;
2499 }
2500 else
2501 {
2502 m_frame->PopTool( aEvent );
2503 break;
2504 }
2505 }
2506 else if( evt->IsClick( BUT_RIGHT ) )
2507 {
2508 if( !started )
2510
2511 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
2512 }
2513 // events that lock in nodes
2514 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
2515 || evt->IsAction( &EE_ACTIONS::closeOutline ) )
2516 {
2517 // Check if it is double click / closing line (so we have to finish the zone)
2518 const bool endPolygon = evt->IsDblClick( BUT_LEFT )
2519 || evt->IsAction( &EE_ACTIONS::closeOutline )
2520 || polyGeomMgr.NewPointClosesOutline( cursorPos );
2521
2522 if( endPolygon )
2523 {
2524 polyGeomMgr.SetFinished();
2525 polyGeomMgr.Reset();
2526
2527 started = false;
2528 getViewControls()->SetAutoPan( false );
2529 getViewControls()->CaptureCursor( false );
2530 }
2531 // adding a corner
2532 else if( polyGeomMgr.AddPoint( cursorPos ) )
2533 {
2534 if( !started )
2535 {
2536 started = true;
2537
2538 getViewControls()->SetAutoPan( true );
2539 getViewControls()->CaptureCursor( true );
2540 }
2541 }
2542 }
2543 else if( started
2544 && ( evt->IsAction( &EE_ACTIONS::deleteLastPoint )
2545 || evt->IsAction( &ACTIONS::doDelete ) || evt->IsAction( &ACTIONS::undo ) ) )
2546 {
2547 if( std::optional<VECTOR2I> last = polyGeomMgr.DeleteLastCorner() )
2548 {
2549 cursorPos = last.value();
2550 getViewControls()->WarpMouseCursor( cursorPos, true );
2551 getViewControls()->ForceCursorPosition( true, cursorPos );
2552 polyGeomMgr.SetCursorPosition( cursorPos );
2553 }
2554 else
2555 {
2556 cleanup();
2557 }
2558 }
2559 else if( started && ( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) )
2560 {
2561 polyGeomMgr.SetCursorPosition( cursorPos );
2562 }
2563 else
2564 {
2565 evt->SetPassEvent();
2566 }
2567
2568 } // end while
2569
2570 getViewControls()->SetAutoPan( false );
2571 getViewControls()->CaptureCursor( false );
2572 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2573 return 0;
2574}
2575
2576
2578{
2579 SCHEMATIC* schematic = getModel<SCHEMATIC>();
2580 SCH_TABLE* table = nullptr;
2581
2582 if( m_inDrawingTool )
2583 return 0;
2584
2586
2589 VECTOR2I cursorPos;
2590
2591 // We might be running as the same shape in another co-routine. Make sure that one
2592 // gets whacked.
2594
2596
2597 m_frame->PushTool( aEvent );
2598
2599 auto setCursor =
2600 [&]()
2601 {
2602 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2603 };
2604
2605 auto cleanup =
2606 [&] ()
2607 {
2610 delete table;
2611 table = nullptr;
2612 };
2613
2614 Activate();
2615
2616 // Must be done after Activate() so that it gets set into the correct context
2617 getViewControls()->ShowCursor( true );
2618
2619 // Set initial cursor
2620 setCursor();
2621
2622 if( aEvent.HasPosition() )
2623 m_toolMgr->PrimeTool( aEvent.Position() );
2624
2625 // Main loop: keep receiving events
2626 while( TOOL_EVENT* evt = Wait() )
2627 {
2628 setCursor();
2629 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2630 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2631
2632 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
2633 controls->ForceCursorPosition( true, cursorPos );
2634
2635 // The tool hotkey is interpreted as a click when drawing
2636 bool isSyntheticClick = table && evt->IsActivate() && evt->HasPosition()
2637 && evt->Matches( aEvent );
2638
2639 if( evt->IsCancelInteractive() || ( table && evt->IsAction( &ACTIONS::undo ) ) )
2640 {
2641 if( table )
2642 {
2643 cleanup();
2644 }
2645 else
2646 {
2647 m_frame->PopTool( aEvent );
2648 break;
2649 }
2650 }
2651 else if( evt->IsActivate() && !isSyntheticClick )
2652 {
2653 if( table && evt->IsMoveTool() )
2654 {
2655 // we're already drawing our own item; ignore the move tool
2656 evt->SetPassEvent( false );
2657 continue;
2658 }
2659
2660 if( table )
2661 cleanup();
2662
2663 if( evt->IsPointEditor() )
2664 {
2665 // don't exit (the point editor runs in the background)
2666 }
2667 else if( evt->IsMoveTool() )
2668 {
2669 // leave ourselves on the stack so we come back after the move
2670 break;
2671 }
2672 else
2673 {
2674 m_frame->PopTool( aEvent );
2675 break;
2676 }
2677 }
2678 else if( evt->IsClick( BUT_LEFT ) && !table )
2679 {
2681
2682 table = new SCH_TABLE( 0 );
2683 table->SetColCount( 1 );
2684
2685 SCH_TABLECELL* tableCell = new SCH_TABLECELL();
2686 int defaultTextSize = schematic->Settings().m_DefaultTextSize;
2687
2688 tableCell->SetTextSize( VECTOR2I( defaultTextSize, defaultTextSize ) );
2689 table->AddCell( tableCell );
2690
2691 table->SetParent( schematic );
2692 table->SetFlags( IS_NEW );
2693 table->SetPosition( cursorPos );
2694
2696 m_view->AddToPreview( table->Clone() );
2697 }
2698 else if( table && ( evt->IsClick( BUT_LEFT )
2699 || evt->IsDblClick( BUT_LEFT )
2700 || isSyntheticClick
2701 || evt->IsAction( &EE_ACTIONS::finishInteractive ) ) )
2702 {
2703 table->ClearEditFlags();
2704 table->SetFlags( IS_NEW );
2705 table->Normalize();
2706
2707 DIALOG_TABLE_PROPERTIES dlg( m_frame, table );
2708
2709 // QuasiModal required for Scintilla auto-complete
2710 if( dlg.ShowQuasiModal() == wxID_OK )
2711 {
2712 SCH_COMMIT commit( m_toolMgr );
2713 commit.Add( table, m_frame->GetScreen() );
2714 commit.Push( _( "Draw Table" ) );
2715
2716 m_selectionTool->AddItemToSel( table );
2718 }
2719 else
2720 {
2721 delete table;
2722 }
2723
2724 table = nullptr;
2726 }
2727 else if( table && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
2728 {
2729 VECTOR2I gridSize = grid.GetGridSize( grid.GetItemGrid( table ) );
2730 int fontSize = schematic->Settings().m_DefaultTextSize;
2731 VECTOR2I origin( table->GetPosition() );
2732 VECTOR2I requestedSize( cursorPos - origin );
2733
2734 int colCount = std::max( 1, requestedSize.x / ( fontSize * 15 ) );
2735 int rowCount = std::max( 1, requestedSize.y / ( fontSize * 2 ) );
2736
2737 VECTOR2I cellSize( std::max( gridSize.x * 5, requestedSize.x / colCount ),
2738 std::max( gridSize.y * 2, requestedSize.y / rowCount ) );
2739
2740 cellSize.x = KiROUND( (double) cellSize.x / gridSize.x ) * gridSize.x;
2741 cellSize.y = KiROUND( (double) cellSize.y / gridSize.y ) * gridSize.y;
2742
2743 table->ClearCells();
2744 table->SetColCount( colCount );
2745
2746 for( int col = 0; col < colCount; ++col )
2747 table->SetColWidth( col, cellSize.x );
2748
2749 for( int row = 0; row < rowCount; ++row )
2750 {
2751 table->SetRowHeight( row, cellSize.y );
2752
2753 for( int col = 0; col < colCount; ++col )
2754 {
2755 SCH_TABLECELL* cell = new SCH_TABLECELL();
2756 int defaultTextSize = schematic->Settings().m_DefaultTextSize;
2757
2758 cell->SetTextSize( VECTOR2I( defaultTextSize, defaultTextSize ) );
2759 cell->SetPosition( origin + VECTOR2I( col * cellSize.x, row * cellSize.y ) );
2760 cell->SetEnd( cell->GetPosition() + cellSize );
2761 table->AddCell( cell );
2762 }
2763 }
2764
2766 m_view->AddToPreview( table->Clone() );
2767 m_frame->SetMsgPanel( table );
2768 }
2769 else if( evt->IsDblClick( BUT_LEFT ) && !table )
2770 {
2772 }
2773 else if( evt->IsClick( BUT_RIGHT ) )
2774 {
2775 // Warp after context menu only if dragging...
2776 if( !table )
2778
2779 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
2780 }
2781 else if( table && evt->IsAction( &ACTIONS::redo ) )
2782 {
2783 wxBell();
2784 }
2785 else
2786 {
2787 evt->SetPassEvent();
2788 }
2789
2790 // Enable autopanning and cursor capture only when there is a shape being drawn
2791 getViewControls()->SetAutoPan( table != nullptr );
2792 getViewControls()->CaptureCursor( table != nullptr );
2793 }
2794
2795 getViewControls()->SetAutoPan( false );
2796 getViewControls()->CaptureCursor( false );
2797 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2798 return 0;
2799}
2800
2801
2803{
2804 bool isDrawSheetCopy = aEvent.IsAction( &EE_ACTIONS::drawSheetFromFile );
2805 bool isDrawSheetFromDesignBlock = aEvent.IsAction( &EE_ACTIONS::drawSheetFromDesignBlock );
2806
2807 DESIGN_BLOCK* designBlock = nullptr;
2808 SCH_SHEET* sheet = nullptr;
2809 wxString filename;
2810
2811 if( isDrawSheetCopy )
2812 {
2813 wxString* ptr = aEvent.Parameter<wxString*>();
2814 wxCHECK( ptr, 0 );
2815
2816 // We own the string if we're importing a sheet
2817 filename = *ptr;
2818 delete ptr;
2819 }
2820 else if( isDrawSheetFromDesignBlock )
2821 {
2822 designBlock = aEvent.Parameter<DESIGN_BLOCK*>();
2823 wxCHECK( designBlock, 0 );
2824 filename = designBlock->GetSchematicFile();
2825 }
2826
2827 if( ( isDrawSheetCopy || isDrawSheetFromDesignBlock ) && !wxFileExists( filename ) )
2828 {
2829 wxMessageBox( wxString::Format( _( "File '%s' does not exist." ), filename ) );
2830 return 0;
2831 }
2832
2833 if( m_inDrawingTool )
2834 return 0;
2835
2837
2839 SCHEMATIC_SETTINGS& schSettings = m_frame->Schematic().Settings();
2842 VECTOR2I cursorPos;
2843
2845
2846 m_frame->PushTool( aEvent );
2847
2848 auto setCursor =
2849 [&]()
2850 {
2851 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2852 };
2853
2854 auto cleanup =
2855 [&] ()
2856 {
2859 delete sheet;
2860 sheet = nullptr;
2861 };
2862
2863 Activate();
2864
2865 // Must be done after Activate() so that it gets set into the correct context
2866 getViewControls()->ShowCursor( true );
2867
2868 // Set initial cursor
2869 setCursor();
2870
2871 if( aEvent.HasPosition() && !( isDrawSheetCopy || isDrawSheetFromDesignBlock ) )
2872 m_toolMgr->PrimeTool( aEvent.Position() );
2873
2874 // Main loop: keep receiving events
2875 while( TOOL_EVENT* evt = Wait() )
2876 {
2877 setCursor();
2878 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2879 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2880
2881 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
2882 controls->ForceCursorPosition( true, cursorPos );
2883
2884 // The tool hotkey is interpreted as a click when drawing
2885 bool isSyntheticClick = sheet && evt->IsActivate() && evt->HasPosition()
2886 && evt->Matches( aEvent );
2887
2888 if( evt->IsCancelInteractive() || ( sheet && evt->IsAction( &ACTIONS::undo ) ) )
2889 {
2891
2892 if( sheet )
2893 {
2894 cleanup();
2895 }
2896 else
2897 {
2898 m_frame->PopTool( aEvent );
2899 break;
2900 }
2901 }
2902 else if( evt->IsActivate() && !isSyntheticClick )
2903 {
2904 if( sheet && evt->IsMoveTool() )
2905 {
2906 // we're already drawing our own item; ignore the move tool
2907 evt->SetPassEvent( false );
2908 continue;
2909 }
2910
2911 if( sheet )
2912 {
2913 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel sheet creation." ) );
2914 evt->SetPassEvent( false );
2915 continue;
2916 }
2917
2918 if( evt->IsPointEditor() )
2919 {
2920 // don't exit (the point editor runs in the background)
2921 }
2922 else if( evt->IsMoveTool() )
2923 {
2924 // leave ourselves on the stack so we come back after the move
2925 break;
2926 }
2927 else
2928 {
2929 m_frame->PopTool( aEvent );
2930 break;
2931 }
2932 }
2933 else if( !sheet && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) ) )
2934 {
2936
2937 if( selection.Size() == 1
2938 && selection.Front()->Type() == SCH_SHEET_T
2939 && selection.Front()->GetBoundingBox().Contains( cursorPos ) )
2940 {
2941 if( evt->IsClick( BUT_LEFT ) )
2942 {
2943 // sheet already selected
2944 continue;
2945 }
2946 else if( evt->IsDblClick( BUT_LEFT ) )
2947 {
2949 m_frame->PopTool( aEvent );
2950 break;
2951 }
2952 }
2953
2955
2956 sheet = new SCH_SHEET( m_frame->GetCurrentSheet().Last(), cursorPos );
2957 sheet->SetScreen( nullptr );
2958
2959 if( isDrawSheetCopy )
2960 {
2961 wxFileName fn( filename );
2962
2963 sheet->GetFields()[SHEETNAME].SetText( fn.GetName() );
2964 sheet->GetFields()[SHEETFILENAME].SetText( fn.GetName() + wxT( "." )
2966 }
2967 else if( isDrawSheetFromDesignBlock )
2968 {
2969 wxFileName fn( filename );
2970
2971 sheet->GetFields()[SHEETNAME].SetText( designBlock->GetLibId().GetLibItemName() );
2972 sheet->GetFields()[SHEETFILENAME].SetText( fn.GetName() + wxT( "." )
2974
2975 std::vector<SCH_FIELD>& sheetFields = sheet->GetFields();
2976
2977 // Copy default fields into the sheet
2978 for( const auto& field : designBlock->GetFields() )
2979 {
2980 SCH_FIELD newField( sheet, sheetFields.size(), field.first );
2981 newField.SetText( field.second );
2982 newField.SetVisible( false );
2983
2984 sheetFields.emplace_back( newField );
2985 }
2986 }
2987 else
2988 {
2989 sheet->GetFields()[SHEETNAME].SetText( wxT( "Untitled Sheet" ) );
2990 sheet->GetFields()[SHEETFILENAME].SetText( wxT( "untitled." )
2992 }
2993
2994 sheet->SetFlags( IS_NEW | IS_MOVING );
2998 sizeSheet( sheet, cursorPos );
2999
3000 SCH_SHEET_LIST hierarchy = m_frame->Schematic().Hierarchy();
3002 instance.push_back( sheet );
3003 wxString pageNumber;
3004
3005 // Don't try to be too clever when assigning the next availabe page number. Just use
3006 // the number of sheets plus one.
3007 pageNumber.Printf( wxT( "%d" ), static_cast<int>( hierarchy.size() ) + 1 );
3008 instance.SetPageNumber( pageNumber );
3009
3011 m_view->AddToPreview( sheet->Clone() );
3012 }
3013 else if( sheet && ( evt->IsClick( BUT_LEFT )
3014 || evt->IsDblClick( BUT_LEFT )
3015 || isSyntheticClick
3016 || evt->IsAction( &ACTIONS::finishInteractive ) ) )
3017 {
3018 getViewControls()->SetAutoPan( false );
3019 getViewControls()->CaptureCursor( false );
3020
3021 if( m_frame->EditSheetProperties( static_cast<SCH_SHEET*>( sheet ),
3022 &m_frame->GetCurrentSheet(), nullptr, nullptr,
3023 nullptr, &filename ) )
3024 {
3026
3027 sheet->AutoplaceFields( /* aScreen */ nullptr, /* aManual */ false );
3028
3029 // Use the commit we were provided or make our own
3030 SCH_COMMIT tempCommit = SCH_COMMIT( m_toolMgr );
3031 SCH_COMMIT& c = evt->Commit() ? *( (SCH_COMMIT*) evt->Commit() ) : tempCommit;
3032
3033 // We need to manually add the sheet to the screen otherwise annotation will not be able to find
3034 // the sheet and its symbols to annotate.
3035 m_frame->AddToScreen( sheet );
3036 c.Added( sheet, m_frame->GetScreen() );
3037
3038 // This convoluted logic means we always annotate unless we are drawing a copy/design block
3039 // and the user has explicitly requested we keep the annotations via checkbox
3041
3042 if( annotate.automatic
3043 && !( ( isDrawSheetCopy || isDrawSheetFromDesignBlock )
3045 {
3046 // Annotation will remove this from selection, but we add it back later
3047 m_selectionTool->AddItemToSel( sheet );
3048
3049 NULL_REPORTER reporter;
3052 (ANNOTATE_ALGO_T) annotate.method, true /* recursive */,
3053 schSettings.m_AnnotateStartNum, true, false, reporter );
3054 }
3055
3056 c.Push( isDrawSheetCopy ? "Import Sheet Copy" : "Draw Sheet" );
3057
3059 m_selectionTool->AddItemToSel( sheet );
3060 }
3061 else
3062 {
3064 delete sheet;
3065 }
3066
3067 sheet = nullptr;
3068 }
3069 else if( evt->IsAction( &ACTIONS::duplicate )
3070 || evt->IsAction( &EE_ACTIONS::repeatDrawItem ) )
3071 {
3072 if( sheet )
3073 {
3074 // This doesn't really make sense; we'll just end up dragging a stack of
3075 // objects so we ignore the duplicate and just carry on.
3076 wxBell();
3077 continue;
3078 }
3079
3080 // Exit. The duplicate will run in its own loop.
3081 m_frame->PopTool( aEvent );
3082 break;
3083 }
3084 else if( sheet && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
3085 {
3086 sizeSheet( sheet, cursorPos );
3088 m_view->AddToPreview( sheet->Clone() );
3089 m_frame->SetMsgPanel( sheet );
3090 }
3091 else if( evt->IsClick( BUT_RIGHT ) )
3092 {
3093 // Warp after context menu only if dragging...
3094 if( !sheet )
3096
3097 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
3098 }
3099 else if( sheet && evt->IsAction( &ACTIONS::redo ) )
3100 {
3101 wxBell();
3102 }
3103 else
3104 {
3105 evt->SetPassEvent();
3106 }
3107
3108 // Enable autopanning and cursor capture only when there is a sheet to be placed
3109 getViewControls()->SetAutoPan( sheet != nullptr );
3110 getViewControls()->CaptureCursor( sheet != nullptr );
3111 }
3112
3113 getViewControls()->SetAutoPan( false );
3114 getViewControls()->CaptureCursor( false );
3115 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
3116
3117 return 0;
3118}
3119
3120
3122{
3123 VECTOR2I pos = aSheet->GetPosition();
3124 VECTOR2I size = aPos - pos;
3125
3126 size.x = std::max( size.x, schIUScale.MilsToIU( MIN_SHEET_WIDTH ) );
3127 size.y = std::max( size.y, schIUScale.MilsToIU( MIN_SHEET_HEIGHT ) );
3128
3130 aSheet->Resize( VECTOR2I( grid.x - pos.x, grid.y - pos.y ) );
3131}
3132
3133
3134int SCH_DRAWING_TOOLS::doSyncSheetsPins( std::list<SCH_SHEET_PATH> sheetPaths )
3135{
3136 if( !sheetPaths.size() )
3137 return 0;
3138
3139 m_dialogSyncSheetPin = std::make_unique<DIALOG_SYNC_SHEET_PINS>(
3140 m_frame, std::move( sheetPaths ),
3141 std::make_shared<SHEET_SYNCHRONIZATION_AGENT>(
3142 [&]( EDA_ITEM* aItem, SCH_SHEET_PATH aPath,
3144 {
3145 SCH_COMMIT commit( m_toolMgr );
3146
3147 if( auto pin = dynamic_cast<SCH_SHEET_PIN*>( aItem ) )
3148 {
3149 commit.Modify( pin->GetParent(), aPath.LastScreen() );
3150 aModify();
3151 commit.Push( _( "Modify sheet pin" ) );
3152 }
3153 else
3154 {
3155 commit.Modify( aItem, aPath.LastScreen() );
3156 aModify();
3157 commit.Push( _( "Modify schematic item" ) );
3158 }
3159
3160 updateItem( aItem, true );
3161 m_frame->OnModify();
3162 },
3163 [&]( EDA_ITEM* aItem, SCH_SHEET_PATH aPath )
3164 {
3166 EE_ACTIONS::changeSheet, &aPath );
3168 selectionTool->UnbrightenItem( aItem );
3169 selectionTool->AddItemToSel( aItem, true );
3171 },
3172 [&]( SCH_SHEET* aItem, SCH_SHEET_PATH aPath,
3174 EDA_ITEM* aTemplate )
3175 {
3176 switch( aOp )
3177 {
3179 {
3180 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
3181 m_dialogSyncSheetPin->Hide();
3182 m_dialogSyncSheetPin->BeginPlaceItem(
3184 aTemplate );
3186 EE_ACTIONS::changeSheet, &aPath );
3188 break;
3189 }
3191 {
3192 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
3193 m_dialogSyncSheetPin->Hide();
3194 m_dialogSyncSheetPin->BeginPlaceItem(
3196 aTemplate );
3198 EE_ACTIONS::changeSheet, &aPath );
3199 m_toolMgr->GetTool<EE_SELECTION_TOOL>()->SyncSelection( {}, nullptr,
3200 { sheet } );
3202 break;
3203 }
3204 }
3205 },
3206 m_toolMgr, m_frame ) );
3207 m_dialogSyncSheetPin->Show( true );
3208 return 0;
3209}
3210
3211
3213{
3214 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( m_selectionTool->GetSelection().Front() );
3215
3216 if( !sheet )
3217 {
3218 VECTOR2I cursorPos = getViewControls()->GetMousePosition();
3219
3220 if( EDA_ITEM* i = nullptr; static_cast<void>(m_selectionTool->SelectPoint( cursorPos, { SCH_SHEET_T }, &i ) ) , i != nullptr )
3221 {
3222 sheet = dynamic_cast<SCH_SHEET*>( i );
3223 }
3224 }
3225
3226 if ( sheet )
3227 {
3229 current.push_back( sheet );
3230 return doSyncSheetsPins( { current } );
3231 }
3232
3233 return 0;
3234}
3235
3236
3238{
3239 static const std::function<void( std::list<SCH_SHEET_PATH>&, SCH_SCREEN*,
3240 std::set<SCH_SCREEN*>&, SCH_SHEET_PATH const& )>
3241 getSheetChildren = []( std::list<SCH_SHEET_PATH>& aPaths, SCH_SCREEN* aScene,
3242 std::set<SCH_SCREEN*>& aVisited, SCH_SHEET_PATH const& aCurPath )
3243 {
3244 if( ! aScene || aVisited.find(aScene) != aVisited.end() )
3245 return ;
3246
3247 std::vector<SCH_ITEM*> sheetChildren;
3248 aScene->GetSheets( &sheetChildren );
3249 aVisited.insert( aScene );
3250
3251 for( SCH_ITEM* child : sheetChildren )
3252 {
3253 SCH_SHEET_PATH cp = aCurPath;
3254 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( child );
3255 cp.push_back( sheet );
3256 aPaths.push_back( cp );
3257 getSheetChildren( aPaths, sheet->GetScreen(), aVisited, cp );
3258 }
3259 };
3260
3261 std::list<SCH_SHEET_PATH> sheetPaths;
3262 std::set<SCH_SCREEN*> visited;
3263 SCH_SHEET_PATH current;
3264 current.push_back( &m_frame->Schematic().Root() );
3265 getSheetChildren( sheetPaths, m_frame->Schematic().Root().GetScreen(), visited, current );
3266 return doSyncSheetsPins( std::move( sheetPaths ) );
3267}
3268
3269
3271{
3272 // clang-format off
3301 // clang-format on
3302}
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:110
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
static TOOL_ACTION cancelInteractive
Definition: actions.h:65
static TOOL_ACTION undo
Definition: actions.h:68
static TOOL_ACTION duplicate
Definition: actions.h:77
static TOOL_ACTION activatePointEditor
Definition: actions.h:221
static TOOL_ACTION doDelete
Definition: actions.h:78
static TOOL_ACTION redo
Definition: actions.h:69
static TOOL_ACTION refreshPreview
Definition: actions.h:149
static TOOL_ACTION finishInteractive
Definition: actions.h:66
constexpr bool Contains(const Vec &aPoint) const
Definition: box2.h:168
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
Definition: commit.h:105
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition: commit.h:86
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:80
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
To be called after this dialog returns from ShowModal().
const wxString & GetSchematicFile() const
Definition: design_block.h:41
const LIB_ID & GetLibId() const
Definition: design_block.h:33
const nlohmann::ordered_map< wxString, wxString > & GetFields() const
Definition: design_block.h:48
std::list< std::unique_ptr< EDA_ITEM > > & GetImportedItems()
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:89
virtual void ClearEditFlags()
Definition: eda_item.h:141
virtual void SetPosition(const VECTOR2I &aPos)
Definition: eda_item.h:244
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:77
EDA_ITEM_FLAGS GetEditFlags() const
Definition: eda_item.h:133
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:127
const KIID m_Uuid
Definition: eda_item.h:489
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:129
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition: eda_item.h:377
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:104
virtual wxString GetFriendlyName() const
Definition: eda_item.cpp:332
virtual EDA_ITEM * Clone() const
Create a duplicate of this item with linked list members set to NULL.
Definition: eda_item.cpp:85
FILL_T GetFillMode() const
Definition: eda_shape.h:114
void SetFillColor(const COLOR4D &aColor)
Definition: eda_shape.h:119
COLOR4D GetFillColor() const
Definition: eda_shape.h:118
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:178
bool IsItalic() const
Definition: eda_text.h:156
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:134
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:506
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:98
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:408
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:187
virtual void SetVisible(bool aVisible)
Definition: eda_text.cpp:377
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition: eda_text.cpp:327
bool IsBold() const
Definition: eda_text.h:171
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition: eda_text.h:190
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:269
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:291
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition: eda_text.cpp:299
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:400
PANEL_DESIGN_BLOCK_CHOOSER m_DesignBlockChooserPanel
PANEL_ANNOTATE m_AnnotatePanel
PANEL_SYM_CHOOSER m_SymChooserPanel
AUTOPLACE_FIELDS m_AutoplaceFields
static TOOL_ACTION drawSheetFromFile
Definition: ee_actions.h:94
static TOOL_ACTION mirrorV
Definition: ee_actions.h:132
static TOOL_ACTION drawSheetFromDesignBlock
Definition: ee_actions.h:95
static TOOL_ACTION placeDesignBlock
Definition: ee_actions.h:82
static TOOL_ACTION properties
Definition: ee_actions.h:135
static TOOL_ACTION addItemsToSel
Selects a list of items (specified as the event parameter)
Definition: ee_actions.h:63
static TOOL_ACTION move
Definition: ee_actions.h:127
static TOOL_ACTION changeSheet
Definition: ee_actions.h:231
static TOOL_ACTION drawTable
Definition: ee_actions.h:104
static TOOL_ACTION syncAllSheetsPins
Definition: ee_actions.h:101
static TOOL_ACTION placeSymbol
Definition: ee_actions.h:79
static TOOL_ACTION clearSelection
Clears the current selection.
Definition: ee_actions.h:56
static TOOL_ACTION drawRuleArea
Definition: ee_actions.h:113
static TOOL_ACTION placeClassLabel
Definition: ee_actions.h:90
static TOOL_ACTION placeNextSymbolUnit
Definition: ee_actions.h:80
static TOOL_ACTION closeOutline
Definition: ee_actions.h:115
static TOOL_ACTION drawCircle
Definition: ee_actions.h:106
static TOOL_ACTION rotateCCW
Definition: ee_actions.h:131
static TOOL_ACTION placePower
Definition: ee_actions.h:81
static TOOL_ACTION deleteLastPoint
Definition: ee_actions.h:114
static TOOL_ACTION placeSheetPin
Definition: ee_actions.h:96
static TOOL_ACTION mirrorH
Definition: ee_actions.h:133
static TOOL_ACTION syncSheetPins
Definition: ee_actions.h:99
static TOOL_ACTION rotateCW
Definition: ee_actions.h:130
static TOOL_ACTION importGraphics
Definition: ee_actions.h:269
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:233
static TOOL_ACTION placeGlobalLabel
Definition: ee_actions.h:91
static TOOL_ACTION placeHierLabel
Definition: ee_actions.h:92
static TOOL_ACTION drawTextBox
Definition: ee_actions.h:103
static TOOL_ACTION drawRectangle
Definition: ee_actions.h:105
static TOOL_ACTION placeImage
Definition: ee_actions.h:110
static TOOL_ACTION enterSheet
Definition: ee_actions.h:232
static TOOL_ACTION placeSchematicText
Definition: ee_actions.h:102
static TOOL_ACTION drawArc
Definition: ee_actions.h:107
static TOOL_ACTION drawSheet
Definition: ee_actions.h:93
static TOOL_ACTION drawBezier
Definition: ee_actions.h:108
static TOOL_ACTION placeLabel
Definition: ee_actions.h:89
static TOOL_ACTION repeatDrawItem
Definition: ee_actions.h:129
static TOOL_ACTION placeBusWireEntry
Definition: ee_actions.h:88
static TOOL_ACTION placeJunction
Definition: ee_actions.h:87
static TOOL_ACTION importSheet
Definition: ee_actions.h:97
static TOOL_ACTION placeNoConnect
Definition: ee_actions.h:86
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition: sch_rtree.h:243
EE_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, bool aPromoteCellSelections=false)
Return either an existing selection (filtered), or the selection at the current cursor position if th...
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.
EE_SELECTION & GetSelection()
A foundation class for a tool operating on a schematic or symbol.
Definition: ee_tool_base.h:48
void updateItem(EDA_ITEM *aItem, bool aUpdateRTree) const
Similar to getView()->Update(), but handles items that are redrawn by their parents and updating the ...
Definition: ee_tool_base.h:109
EE_SELECTION_TOOL * m_selectionTool
Definition: ee_tool_base.h:200
bool Init() override
Init() is called once upon a registration of the tool.
Definition: ee_tool_base.h:64
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
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:299
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:334
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition: view.cpp:1669
void ClearPreview()
Definition: view.cpp:1691
void RecacheAllItems()
Rebuild GAL display lists.
Definition: view.cpp:1435
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1713
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:118
const UTF8 & GetLibItemName() const
Definition: lib_id.h:102
Define a library symbol object.
Definition: lib_symbol.h:78
const LIB_ID & GetLibId() const override
Definition: lib_symbol.h:143
A singleton reporter that reports to nowhere.
Definition: reporter.h:203
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition: pgm_base.cpp:679
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)
Definition: project_sch.cpp:90
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition: project.cpp:129
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.
Holds all the data relating to one schematic.
Definition: schematic.h:77
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:312
SCH_SHEET_LIST Hierarchy() const override
Return the full schematic flattened hierarchical sheet list.
Definition: schematic.cpp:214
SCH_SHEET & Root() const
Definition: schematic.h:125
void AddToScreen(EDA_ITEM *aItem, SCH_SCREEN *aScreen=nullptr)
Add an item to the screen (and view) aScreen is the screen the item is located on,...
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
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.
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
Revert the commit by restoring the modified items state.
Definition: sch_commit.cpp:432
virtual void Revert() override
Definition: sch_commit.cpp:510
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
int PlaceNextSymbolUnit(const TOOL_EVENT &aEvent)
int DrawSheet(const TOOL_EVENT &aEvent)
SPIN_STYLE m_lastTextOrientation
int SyncSheetsPins(const TOOL_EVENT &aEvent)
STROKE_PARAMS m_lastStroke
SCH_TEXT * createNewText(const VECTOR2I &aPosition, int aType)
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 TwoClickPlace(const TOOL_EVENT &aEvent)
SCH_SHEET_PIN * createNewSheetPin(SCH_SHEET *aSheet, const VECTOR2I &aPosition)
int SyncAllSheetsPins(const TOOL_EVENT &aEvent)
wxString findWireLabelDriverName(SCH_LINE *aWire)
int DrawTable(const TOOL_EVENT &aEvent)
GR_TEXT_V_ALIGN_T m_lastTextVJustify
int doSyncSheetsPins(std::list< SCH_SHEET_PATH > aSheets)
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
Schematic editor (Eeschema) main window.
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag and update other data struc...
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void SchematicCleanUp(SCH_COMMIT *aCommit, SCH_SCREEN *aScreen=nullptr)
Perform routine schematic cleaning including breaking wire and buses and deleting identical objects s...
void UpdateHierarchyNavigator(bool aRefreshNetNavigator=true)
Update the hierarchy navigation tree and history.
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:212
void HardRedraw() override
Rebuild the GAL and redraw the screen.
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
DESIGN_BLOCK * GetDesignBlock(const LIB_ID &aLibId, bool aUseCacheLib=false, bool aShowErrorMsg=false)
Load design block from design block library table.
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:603
void FlipBodyStyle(SCH_SYMBOL *aSymbol)
Definition: picksymbol.cpp:176
void SetSheetNumberAndCount()
Set the m_ScreenNumber and m_NumberOfScreens members for screens.
void SelectUnit(SCH_SYMBOL *aSymbol, int aUnit)
Definition: picksymbol.cpp:95
void UpdateDesignBlockOptions()
Design block panel options have changed and the panel needs to be refreshed.
DESIGN_BLOCK_PANE * GetDesignBlockPane() const
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.
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
void SetText(const wxString &aText) override
Definition: sch_field.cpp:1213
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Definition: sch_label.cpp:2031
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:166
virtual bool IsConnectable() const
Definition: sch_item.h:449
SCHEMATIC * Schematic() const
Searches the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:150
int GetUnit() const
Definition: sch_item.h:229
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction)
Definition: sch_item.h:568
virtual void SetUnit(int aUnit)
Definition: sch_item.h:228
virtual void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual)
Definition: sch_item.h:566
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:218
bool IsType(const std::vector< KICAD_T > &aScanTypes) const override
Check whether the item is one of the listed types.
Definition: sch_item.h:181
bool AutoRotateOnPlacement() const
autoRotateOnPlacement
Definition: sch_label.cpp:1402
SPIN_STYLE GetSpinStyle() const
Definition: sch_label.cpp:332
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition: sch_label.h:178
LABEL_FLAG_SHAPE GetShape() const
Definition: sch_label.h:177
void SetAutoRotateOnPlacement(bool autoRotate=true)
setAutoRotateOnPlacement
Definition: sch_label.cpp:1408
std::vector< SCH_FIELD > & GetFields()
Definition: sch_label.h:201
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Definition: sch_label.cpp:297
Tool responsible for drawing/placing items (symbols, wires, buses, labels, etc.)
int AddJunctionsIfNeeded(SCH_COMMIT *aCommit, EE_SELECTION *aSelection)
Handle the addition of junctions to a selection of objects.
int TrimOverLappingWires(SCH_COMMIT *aCommit, EE_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:41
bool IsWire() const
Return true if the line is a wire.
Definition: sch_line.cpp:973
VECTOR2I GetEndPoint() const
Definition: sch_line.h:141
VECTOR2I GetStartPoint() const
Definition: sch_line.h:136
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.
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.
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:108
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:392
bool IsExplicitJunctionAllowed(const VECTOR2I &aPosition) const
Indicates that a juction dot may be placed at the given location.
Definition: sch_screen.cpp:506
void SetPosition(const VECTOR2I &aPos) override
Definition: sch_shape.h:71
void BeginEdit(const VECTOR2I &aStartPoint) override
Begin drawing a symbol library draw item at aPosition.
Definition: sch_shape.h:75
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:78
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: sch_shape.cpp:63
bool ContinueEdit(const VECTOR2I &aPosition) override
Continue an edit in progress at aPosition.
Definition: sch_shape.h:76
void CalcEdit(const VECTOR2I &aPosition) override
Calculate the attributes of an item at aPosition when it is being edited.
Definition: sch_shape.h:77
wxString GetClass() const override
Return the class name.
Definition: sch_shape.h:42
STROKE_PARAMS GetStroke() const override
Definition: sch_shape.h:55
VECTOR2I GetPosition() const override
Definition: sch_shape.h:70
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:57
void SetBorderColor(KIGFX::COLOR4D aColor)
Definition: sch_sheet.h:119
void AddPin(SCH_SHEET_PIN *aSheetPin)
Add aSheetPin to the sheet.
Definition: sch_sheet.cpp:429
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_sheet.cpp:167
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
Definition: sch_sheet.cpp:1023
std::vector< SCH_FIELD > & GetFields()
Definition: sch_sheet.h:93
void SetBackgroundColor(KIGFX::COLOR4D aColor)
Definition: sch_sheet.h:122
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:110
VECTOR2I GetPosition() const override
Definition: sch_sheet.h:400
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:173
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual) override
Definition: sch_sheet.cpp:666
void SetBorderWidth(int aWidth)
Definition: sch_sheet.h:116
void Resize(const VECTOR2I &aSize)
Resize this sheet to aSize and adjust all of the labels accordingly.
Definition: sch_sheet.cpp:1006
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:181
Schematic symbol object.
Definition: sch_symbol.h:104
void ClearAnnotation(const SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear exiting symbol annotation.
const LIB_ID & GetLibId() const override
Definition: sch_symbol.h:193
bool IsMulti() const override
Definition: sch_symbol.h:300
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
Set the selected unit of this symbol on one sheet.
Definition: sch_symbol.cpp:881
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
Definition: sch_symbol.cpp:737
void SetRowHeight(int aRow, int aHeight)
Definition: sch_table.h:122
void SetColCount(int aCount)
Definition: sch_table.h:104
void SetColWidth(int aCol, int aWidth)
Definition: sch_table.h:112
void AddCell(SCH_TABLECELL *aCell)
Definition: sch_table.h:147
VECTOR2I GetPosition() const override
Definition: sch_table.cpp:115
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
Definition: sch_table.h:189
void ClearCells()
Definition: sch_table.h:159
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_table.h:214
void SetPosition(const VECTOR2I &aPos) override
Definition: sch_table.cpp:109
void Normalize()
Definition: sch_table.cpp:149
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:327
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:171
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:100
EDA_ITEM * Front() const
Definition: selection.h:172
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:93
int Size() const
Returns the number of selected parts.
Definition: selection.h:116
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
KIGFX::VIEW_CONTROLS * getViewControls() const
Return the instance of VIEW_CONTROLS object used in the application.
Definition: tool_base.cpp:42
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:218
KIGFX::VIEW * getView() const
Returns the instance of #VIEW object used in the application.
Definition: tool_base.cpp:36
Generic, UI-independent tool event.
Definition: tool_event.h:167
bool HasPosition() const
Definition: tool_event.h:256
bool DisableGridSnapping() const
Definition: tool_event.h:363
const VECTOR2D Position() const
Returns the point where dragging has started.
Definition: tool_event.h:285
bool IsReactivate() const
Definition: tool_event.h:268
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:460
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:511
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:190
This file is part of the common library.
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:401
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:536
#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
std::set< int > GetUnplacedUnitsForSymbol(const SCH_SYMBOL &aSym)
Get a list of unplaced (i.e.
@ 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:42
@ GRID_TEXT
Definition: grid_helper.h:49
@ GRID_GRAPHICS
Definition: grid_helper.h:50
@ GRID_CONNECTABLE
Definition: grid_helper.h:46
static const std::string KiCadSchematicFileExtension
static wxString KiCadSchematicFileWildcard()
@ LAYER_HIERLABEL
Definition: layer_ids.h:361
@ LAYER_GLOBLABEL
Definition: layer_ids.h:360
@ LAYER_NOTES
Definition: layer_ids.h:371
@ LAYER_LOCLABEL
Definition: layer_ids.h:359
@ LAYER_NETCLASS_REFS
Definition: layer_ids.h:368
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: wxgtk/ui.cpp:620
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1060
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.
LABEL_FLAG_SHAPE
Definition: sch_label.h:98
@ F_ROUND
Definition: sch_label.h:107
@ L_INPUT
Definition: sch_label.h:99
ANNOTATE_ORDER_T
Schematic annotation order options.
@ ANNOTATE_SELECTION
Annotate the selection.
ANNOTATE_ALGO_T
Schematic annotation type options.
@ SHEETNAME
Definition: sch_sheet.h:45
@ SHEETFILENAME
Definition: sch_sheet.h:46
#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.
bool NoPrintableChars(const wxString &aString)
Return true if the string is empty or contains only whitespace.
LINE_STYLE
Dashed line types.
Definition: stroke_params.h:46
constexpr int MilsToIU(int mils) const
Definition: base_units.h:93
SCH_SYMBOL * m_Symbol
< Provide a symbol to place
Definition: ee_actions.h:320
LIB_ID LibId
Definition: sch_screen.h:79
Definition for symbol library class.
constexpr 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
Definition: tool_event.h:97
@ TC_COMMAND
Definition: tool_event.h:56
@ MD_SHIFT
Definition: tool_event.h:142
@ BUT_LEFT
Definition: tool_event.h:131
@ BUT_RIGHT
Definition: tool_event.h:132
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
@ SCH_LINE_T
Definition: typeinfo.h:163
@ SCH_NO_CONNECT_T
Definition: typeinfo.h:160
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:171
@ SCH_SHEET_T
Definition: typeinfo.h:174
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:173
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:161
@ SCH_JUNCTION_T
Definition: typeinfo.h:159
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691
Definition of file extensions used in Kicad.