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-2023 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>
36#include <ee_actions.h>
37#include <sch_edit_frame.h>
38#include <pgm_base.h>
39#include <eeschema_id.h>
40#include <confirm.h>
41#include <view/view_controls.h>
42#include <view/view.h>
43#include <sch_symbol.h>
44#include <sch_no_connect.h>
45#include <sch_line.h>
46#include <sch_junction.h>
47#include <sch_bus_entry.h>
48#include <sch_text.h>
49#include <sch_textbox.h>
50#include <sch_table.h>
51#include <sch_tablecell.h>
52#include <sch_sheet.h>
53#include <sch_sheet_pin.h>
54#include <sch_label.h>
55#include <sch_bitmap.h>
56#include <schematic.h>
57#include <sch_commit.h>
58#include <symbol_library.h>
59#include <eeschema_settings.h>
61#include <dialogs/dialog_text_properties.h>
66#include <string_utils.h>
68#include <wx/filedlg.h>
69
71 EE_TOOL_BASE<SCH_EDIT_FRAME>( "eeschema.InteractiveDrawing" ),
72 m_lastSheetPinType( LABEL_FLAG_SHAPE::L_INPUT ),
73 m_lastGlobalLabelShape( LABEL_FLAG_SHAPE::L_INPUT ),
74 m_lastNetClassFlagShape( LABEL_FLAG_SHAPE::F_ROUND ),
75 m_lastTextOrientation( SPIN_STYLE::RIGHT ),
76 m_lastTextBold( false ),
77 m_lastTextItalic( false ),
78 m_lastTextAngle( ANGLE_0 ),
79 m_lastTextboxAngle( ANGLE_0 ),
80 m_lastTextHJustify( GR_TEXT_H_ALIGN_CENTER ),
81 m_lastTextVJustify( GR_TEXT_V_ALIGN_CENTER ),
82 m_lastTextboxHJustify( GR_TEXT_H_ALIGN_LEFT ),
83 m_lastTextboxVJustify( GR_TEXT_V_ALIGN_TOP ),
84 m_lastFillStyle( FILL_T::NO_FILL ),
85 m_lastTextboxFillStyle( FILL_T::NO_FILL ),
86 m_lastFillColor( COLOR4D::UNSPECIFIED ),
87 m_lastTextboxFillColor( COLOR4D::UNSPECIFIED ),
88 m_lastStroke( 0, LINE_STYLE::DEFAULT, COLOR4D::UNSPECIFIED ),
89 m_lastTextboxStroke( 0, LINE_STYLE::DEFAULT, COLOR4D::UNSPECIFIED ),
90 m_mruPath( wxEmptyString ),
91 m_lastAutoLabelRotateOnPlacement( false ),
92 m_inDrawingTool( false )
93{
94}
95
96
98{
100
101 auto belowRootSheetCondition =
102 [&]( const SELECTION& aSel )
103 {
104 return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
105 };
106
107 CONDITIONAL_MENU& ctxMenu = m_menu.GetMenu();
108 ctxMenu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 150 );
109
110 return true;
111}
112
113
115{
116 SCH_SYMBOL* symbol = aEvent.Parameter<SCH_SYMBOL*>();
118 std::vector<PICKED_SYMBOL>* historyList = nullptr;
119 bool ignorePrimePosition = false;
120 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
121 SCH_SCREEN* screen = m_frame->GetScreen();
122
123 if( m_inDrawingTool )
124 return 0;
125
127
130 VECTOR2I cursorPos;
131
132 // First we need to get all instances of this sheet so we can annotate
133 // whatever symbols we place on all copies
134 SCH_SHEET_LIST hierarchy = m_frame->Schematic().GetSheets();
135 SCH_SHEET_LIST newInstances =
137 newInstances.SortByPageNumbers();
138
139 // Get a list of all references in the schematic to avoid duplicates wherever
140 // they're placed
141 SCH_REFERENCE_LIST existingRefs;
142 hierarchy.GetSymbols( existingRefs );
143 existingRefs.SortByReferenceOnly();
144
145 if( aEvent.IsAction( &EE_ACTIONS::placeSymbol ) )
146 {
147 historyList = &m_symbolHistoryList;
148 }
149 else if (aEvent.IsAction( &EE_ACTIONS::placePower ) )
150 {
151 historyList = &m_powerHistoryList;
152 filter.FilterPowerSymbols( true );
153 }
154 else
155 {
156 wxFAIL_MSG( "PlaceSymbol(): unexpected request" );
157 }
158
159 m_frame->PushTool( aEvent );
160
161 auto addSymbol =
162 [this]( SCH_SYMBOL* aSymbol )
163 {
165 m_selectionTool->AddItemToSel( aSymbol );
166
167 aSymbol->SetFlags( IS_NEW | IS_MOVING );
168
170 m_view->AddToPreview( aSymbol, false ); // Add, but not give ownership
171
172 // Set IS_MOVING again, as AddItemToCommitAndScreen() will have cleared it.
173 aSymbol->SetFlags( IS_MOVING );
175 };
176
177 auto setCursor =
178 [&]()
179 {
180 m_frame->GetCanvas()->SetCurrentCursor( symbol ? KICURSOR::MOVING
181 : KICURSOR::COMPONENT );
182 };
183
184 auto cleanup =
185 [&]()
186 {
189 delete symbol;
190 symbol = nullptr;
191
192 existingRefs.Clear();
193 hierarchy.GetSymbols( existingRefs );
194 existingRefs.SortByReferenceOnly();
195 };
196
197 auto annotate =
198 [&]()
199 {
201
202 // Then we need to annotate all instances by sheet
203 for( SCH_SHEET_PATH& instance : newInstances )
204 {
205 SCH_REFERENCE newReference( symbol, symbol->GetLibSymbolRef().get(), instance );
207 refs.AddItem( newReference );
208
209 if( cfg->m_AnnotatePanel.automatic || newReference.AlwaysAnnotate() )
210 {
214 existingRefs, false, &hierarchy );
215
216 refs.UpdateAnnotation();
217
218 // Update existing refs for next iteration
219 for( size_t i = 0; i < refs.GetCount(); i++ )
220 existingRefs.AddItem( refs[i] );
221 }
222 }
223
225 };
226
227 Activate();
228
229 // Must be done after Activate() so that it gets set into the correct context
230 getViewControls()->ShowCursor( true );
231
232 // Set initial cursor
233 setCursor();
234
235 // Prime the pump
236 if( symbol )
237 {
238 addSymbol( symbol );
239 annotate();
240 getViewControls()->WarpMouseCursor( getViewControls()->GetMousePosition( false ) );
241 }
242 else if( aEvent.HasPosition() )
243 {
244 m_toolMgr->PrimeTool( aEvent.Position() );
245 }
246 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
247 {
248 m_toolMgr->PrimeTool( { 0, 0 } );
249 ignorePrimePosition = true;
250 }
251
252 // Main loop: keep receiving events
253 while( TOOL_EVENT* evt = Wait() )
254 {
255 setCursor();
256 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
257 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
258
259 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
260 controls->ForceCursorPosition( true, cursorPos );
261
262 // The tool hotkey is interpreted as a click when drawing
263 bool isSyntheticClick = symbol && evt->IsActivate() && evt->HasPosition()
264 && evt->Matches( aEvent );
265
266 if( evt->IsCancelInteractive() || ( symbol && evt->IsAction( &ACTIONS::undo ) ) )
267 {
269
270 if( symbol )
271 {
272 cleanup();
273 }
274 else
275 {
276 m_frame->PopTool( aEvent );
277 break;
278 }
279 }
280 else if( evt->IsActivate() && !isSyntheticClick )
281 {
282 if( symbol && evt->IsMoveTool() )
283 {
284 // we're already moving our own item; ignore the move tool
285 evt->SetPassEvent( false );
286 continue;
287 }
288
289 if( symbol )
290 {
291 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel symbol creation." ) );
292 evt->SetPassEvent( false );
293 continue;
294 }
295
296 if( evt->IsMoveTool() )
297 {
298 // leave ourselves on the stack so we come back after the move
299 break;
300 }
301 else
302 {
303 m_frame->PopTool( aEvent );
304 break;
305 }
306 }
307 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) || isSyntheticClick )
308 {
309 if( !symbol )
310 {
312
316
317 std::vector<LIB_SYMBOL*> part_list;
318
319 for( SCH_SHEET_PATH& sheet : sheets )
320 {
321 for( SCH_ITEM* item : sheet.LastScreen()->Items() )
322 {
323 if( item->Type() != SCH_SYMBOL_T )
324 continue;
325
326 SCH_SYMBOL* s = static_cast<SCH_SYMBOL*>( item );
327 LIB_SYMBOL* libSymbol = SchGetLibSymbol( s->GetLibId(), libs, cache );
328
329 if( libSymbol )
330 part_list.push_back( libSymbol );
331 }
332 }
333
334 // Remove redundant parts
335 sort( part_list.begin(), part_list.end() );
336 part_list.erase( unique( part_list.begin(), part_list.end() ), part_list.end() );
337
338 std::vector<PICKED_SYMBOL> alreadyPlaced;
339 for( LIB_SYMBOL* libSymbol : part_list )
340 {
341 PICKED_SYMBOL pickedSymbol;
342 pickedSymbol.LibId = libSymbol->GetLibId();
343 alreadyPlaced.push_back( pickedSymbol );
344 }
345
346 // Pick the symbol to be placed
347 bool footprintPreviews = m_frame->eeconfig()->m_Appearance.footprint_preview;
348 PICKED_SYMBOL sel = m_frame->PickSymbolFromLibrary( &filter, *historyList,
349 alreadyPlaced,
350 footprintPreviews );
351
352 LIB_SYMBOL* libSymbol = sel.LibId.IsValid() ? m_frame->GetLibSymbol( sel.LibId )
353 : nullptr;
354
355 if( !libSymbol )
356 continue;
357
358 // If we started with a hotkey which has a position then warp back to that.
359 // Otherwise update to the current mouse position pinned inside the autoscroll
360 // boundaries.
361 if( evt->IsPrime() && !ignorePrimePosition )
362 {
363 cursorPos = grid.Align( evt->Position(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
364 getViewControls()->WarpMouseCursor( cursorPos, true );
365 }
366 else
367 {
369 cursorPos = grid.Align( getViewControls()->GetMousePosition(),
370 GRID_HELPER_GRIDS::GRID_CONNECTABLE );
371 }
372
373 symbol = new SCH_SYMBOL( *libSymbol, &m_frame->GetCurrentSheet(), sel, cursorPos,
374 &m_frame->Schematic() );
375 addSymbol( symbol );
376 annotate();
377
378 // Update the list of references for the next symbol placement.
379 SCH_REFERENCE placedSymbolReference( symbol, symbol->GetLibSymbolRef().get(),
381 existingRefs.AddItem( placedSymbolReference );
382 existingRefs.SortByReferenceOnly();
383
385 symbol->AutoplaceFields( /* aScreen */ nullptr, /* aManual */ false );
386
387 // Update cursor now that we have a symbol
388 setCursor();
389 }
390 else
391 {
393 m_frame->AddToScreen( symbol, screen );
394
396 symbol->AutoplaceFields( screen, false /* aManual */ );
397
399
400 SCH_COMMIT commit( m_toolMgr );
401 commit.Added( symbol, screen );
402
404 lwbTool->TrimOverLappingWires( &commit, &m_selectionTool->GetSelection() );
405 lwbTool->AddJunctionsIfNeeded( &commit, &m_selectionTool->GetSelection() );
406
407 commit.Push( _( "Add Symbol" ) );
408
409 SCH_SYMBOL* nextSymbol = nullptr;
410
413 {
414 int new_unit = symbol->GetUnit();
415
417 && symbol->GetUnit() < symbol->GetUnitCount() )
418 {
419 new_unit++;
420 }
421 else
422 {
423 new_unit = 1;
424 }
425
426 // We are either stepping to the next unit or next symbol
427 if( m_frame->eeconfig()->m_SymChooserPanel.keep_symbol || new_unit > 1 )
428 {
429 nextSymbol = static_cast<SCH_SYMBOL*>( symbol->Duplicate() );
430 nextSymbol->SetUnit( new_unit );
431 nextSymbol->SetUnitSelection( new_unit );
432
433 // Start new annotation sequence at first unit
434 if( new_unit == 1 )
435 nextSymbol->ClearAnnotation( nullptr, false );
436
437 addSymbol( nextSymbol );
438 symbol = nextSymbol;
439 annotate();
440
441 // Update the list of references for the next symbol placement.
442 SCH_REFERENCE placedSymbolReference( symbol,
443 symbol->GetLibSymbolRef().get(),
445 existingRefs.AddItem( placedSymbolReference );
446 existingRefs.SortByReferenceOnly();
447 }
448 }
449
450 symbol = nextSymbol;
451 }
452 }
453 else if( evt->IsClick( BUT_RIGHT ) )
454 {
455 // Warp after context menu only if dragging...
456 if( !symbol )
458
460 }
461 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
462 {
463 if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_UNIT
464 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_UNIT_END )
465 {
466 int unit = *evt->GetCommandId() - ID_POPUP_SCH_SELECT_UNIT;
467
468 if( symbol )
469 {
470 m_frame->SelectUnit( symbol, unit );
472 }
473 }
474 }
475 else if( evt->IsAction( &ACTIONS::duplicate )
476 || evt->IsAction( &EE_ACTIONS::repeatDrawItem ) )
477 {
478 if( symbol )
479 {
480 // This doesn't really make sense; we'll just end up dragging a stack of
481 // objects so we ignore the duplicate and just carry on.
482 wxBell();
483 continue;
484 }
485
486 // Exit. The duplicate will run in its own loop.
487 m_frame->PopTool( aEvent );
488 break;
489 }
490 else if( symbol && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
491 {
492 symbol->SetPosition( cursorPos );
494 m_view->AddToPreview( symbol, false ); // Add, but not give ownership
495 m_frame->SetMsgPanel( symbol );
496 }
497 else if( symbol && evt->IsAction( &ACTIONS::doDelete ) )
498 {
499 cleanup();
500 }
501 else if( symbol && evt->IsAction( &ACTIONS::redo ) )
502 {
503 wxBell();
504 }
505 else
506 {
507 evt->SetPassEvent();
508 }
509
510 // Enable autopanning and cursor capture only when there is a symbol to be placed
511 getViewControls()->SetAutoPan( symbol != nullptr );
512 getViewControls()->CaptureCursor( symbol != nullptr );
513 }
514
515 getViewControls()->SetAutoPan( false );
516 getViewControls()->CaptureCursor( false );
517 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
518
519 return 0;
520}
521
522
524{
525 SCH_BITMAP* image = aEvent.Parameter<SCH_BITMAP*>();
526 bool immediateMode = image != nullptr;
527 bool ignorePrimePosition = false;
528 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
529
530 if( m_inDrawingTool )
531 return 0;
532
534
537 VECTOR2I cursorPos;
538
540
541 // Add all the drawable symbols to preview
542 if( image )
543 {
544 image->SetPosition( getViewControls()->GetCursorPosition() );
546 m_view->AddToPreview( image, false ); // Add, but not give ownership
547 }
548
549 m_frame->PushTool( aEvent );
550
551 auto setCursor =
552 [&]()
553 {
554 if( image )
555 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
556 else
557 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
558 };
559
560 auto cleanup =
561 [&] ()
562 {
566 delete image;
567 image = nullptr;
568 };
569
570 Activate();
571
572 // Must be done after Activate() so that it gets set into the correct context
573 getViewControls()->ShowCursor( true );
574
575 // Set initial cursor
576 setCursor();
577
578 // Prime the pump
579 if( image )
580 {
582 }
583 else if( aEvent.HasPosition() )
584 {
585 m_toolMgr->PrimeTool( aEvent.Position() );
586 }
587 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
588 {
589 m_toolMgr->PrimeTool( { 0, 0 } );
590 ignorePrimePosition = true;
591 }
592
593 // Main loop: keep receiving events
594 while( TOOL_EVENT* evt = Wait() )
595 {
596 setCursor();
597 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
598 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
599
600 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
601 controls->ForceCursorPosition( true, cursorPos );
602
603 // The tool hotkey is interpreted as a click when drawing
604 bool isSyntheticClick = image && evt->IsActivate() && evt->HasPosition()
605 && evt->Matches( aEvent );
606
607 if( evt->IsCancelInteractive() || ( image && evt->IsAction( &ACTIONS::undo ) ) )
608 {
610
611 if( image )
612 {
613 cleanup();
614 }
615 else
616 {
617 m_frame->PopTool( aEvent );
618 break;
619 }
620
621 if( immediateMode )
622 {
623 m_frame->PopTool( aEvent );
624 break;
625 }
626 }
627 else if( evt->IsActivate() && !isSyntheticClick )
628 {
629 if( image && evt->IsMoveTool() )
630 {
631 // we're already moving our own item; ignore the move tool
632 evt->SetPassEvent( false );
633 continue;
634 }
635
636 if( image )
637 {
638 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel image creation." ) );
639 evt->SetPassEvent( false );
640 continue;
641 }
642
643 if( evt->IsMoveTool() )
644 {
645 // leave ourselves on the stack so we come back after the move
646 break;
647 }
648 else
649 {
650 m_frame->PopTool( aEvent );
651 break;
652 }
653 }
654 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) || isSyntheticClick )
655 {
656 if( !image )
657 {
659
660 wxFileDialog dlg( m_frame, _( "Choose Image" ), m_mruPath, wxEmptyString,
661 _( "Image Files" ) + wxS( " " ) + wxImage::GetImageExtWildcard(),
662 wxFD_OPEN );
663
664 if( dlg.ShowModal() != wxID_OK )
665 continue;
666
667 // If we started with a hotkey which has a position then warp back to that.
668 // Otherwise update to the current mouse position pinned inside the autoscroll
669 // boundaries.
670 if( evt->IsPrime() && !ignorePrimePosition )
671 {
672 cursorPos = grid.Align( evt->Position() );
673 getViewControls()->WarpMouseCursor( cursorPos, true );
674 }
675 else
676 {
678 cursorPos = getViewControls()->GetMousePosition();
679 }
680
681 wxString fullFilename = dlg.GetPath();
682 m_mruPath = wxPathOnly( fullFilename );
683
684 if( wxFileExists( fullFilename ) )
685 image = new SCH_BITMAP( cursorPos );
686
687 if( !image || !image->ReadImageFile( fullFilename ) )
688 {
689 wxMessageBox( _( "Could not load image from '%s'." ), fullFilename );
690 delete image;
691 image = nullptr;
692 continue;
693 }
694
695 image->SetFlags( IS_NEW | IS_MOVING );
696
698
700 m_view->AddToPreview( image, false ); // Add, but not give ownership
701 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
702
704
705 getViewControls()->SetCursorPosition( cursorPos, false );
706 setCursor();
707 }
708 else
709 {
710 SCH_COMMIT commit( m_toolMgr );
711 commit.Add( image, m_frame->GetScreen() );
712 commit.Push( _( "Add Image" ) );
713
714 image = nullptr;
716
718
719 if( immediateMode )
720 {
721 m_frame->PopTool( aEvent );
722 break;
723 }
724 }
725 }
726 else if( evt->IsClick( BUT_RIGHT ) )
727 {
728 // Warp after context menu only if dragging...
729 if( !image )
731
733 }
734 else if( evt->IsAction( &ACTIONS::duplicate )
735 || evt->IsAction( &EE_ACTIONS::repeatDrawItem ) )
736 {
737 if( image )
738 {
739 // This doesn't really make sense; we'll just end up dragging a stack of
740 // objects so we ignore the duplicate and just carry on.
741 wxBell();
742 continue;
743 }
744
745 // Exit. The duplicate will run in its own loop.
746 m_frame->PopTool( aEvent );
747 break;
748 }
749 else if( image && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
750 {
751 image->SetPosition( cursorPos );
753 m_view->AddToPreview( image, false ); // Add, but not give ownership
754 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
756 }
757 else if( image && evt->IsAction( &ACTIONS::doDelete ) )
758 {
759 cleanup();
760 }
761 else if( image && evt->IsAction( &ACTIONS::redo ) )
762 {
763 wxBell();
764 }
765 else
766 {
767 evt->SetPassEvent();
768 }
769
770 // Enable autopanning and cursor capture only when there is an image to be placed
771 getViewControls()->SetAutoPan( image != nullptr );
772 getViewControls()->CaptureCursor( image != nullptr );
773 }
774
775 getViewControls()->SetAutoPan( false );
776 getViewControls()->CaptureCursor( false );
777 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
778
779 return 0;
780}
781
782
784{
785 if( m_inDrawingTool )
786 return 0;
787
789
790 // Note: PlaceImportedGraphics() will convert PCB_SHAPE_T and PCB_TEXT_T to footprint
791 // items if needed
793 int dlgResult = dlg.ShowModal();
794
795 std::list<std::unique_ptr<EDA_ITEM>>& list = dlg.GetImportedItems();
796
797 if( dlgResult != wxID_OK )
798 return 0;
799
800 // Ensure the list is not empty:
801 if( list.empty() )
802 {
803 wxMessageBox( _( "No graphic items found in file." ) );
804 return 0;
805 }
806
808
810 std::vector<SCH_ITEM*> newItems; // all new items, including group
811 std::vector<SCH_ITEM*> selectedItems; // the group, or newItems if no group
812 EE_SELECTION preview;
813 SCH_COMMIT commit( m_toolMgr );
814
815 for( std::unique_ptr<EDA_ITEM>& ptr : list )
816 {
817 SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( ptr.get() );
818 wxCHECK2( item, continue );
819
820 newItems.push_back( item );
821 selectedItems.push_back( item );
822 preview.Add( item );
823
824 ptr.release();
825 }
826
827 if( !dlg.IsPlacementInteractive() )
828 {
829 // Place the imported drawings
830 for( SCH_ITEM* item : newItems )
831 commit.Add(item, m_frame->GetScreen());
832
833 commit.Push( _( "Import Graphic" ) );
834 return 0;
835 }
836
837 m_view->Add( &preview );
838
839 // Clear the current selection then select the drawings so that edit tools work on them
841
842 EDA_ITEMS selItems( selectedItems.begin(), selectedItems.end() );
844
845 m_frame->PushTool( aEvent );
846
847 auto setCursor = [&]()
848 {
849 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
850 };
851
852 Activate();
853 // Must be done after Activate() so that it gets set into the correct context
854 controls->ShowCursor( true );
855 controls->ForceCursorPosition( false );
856 // Set initial cursor
857 setCursor();
858
859 //SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::DXF );
861
862 // Now move the new items to the current cursor position:
863 VECTOR2I cursorPos = controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
864 VECTOR2I delta = cursorPos;
865 VECTOR2I currentOffset;
866
867 for( SCH_ITEM* item : selectedItems )
868 item->Move( delta );
869
870 currentOffset += delta;
871
872 m_view->Update( &preview );
873
874 // Main loop: keep receiving events
875 while( TOOL_EVENT* evt = Wait() )
876 {
877 setCursor();
878
879 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
880 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
881
882 cursorPos = grid.Align( controls->GetMousePosition(), GRID_GRAPHICS );
883 controls->ForceCursorPosition( true, cursorPos );
884
885 if( evt->IsCancelInteractive() || evt->IsActivate() )
886 {
888
889 for( SCH_ITEM* item : newItems )
890 delete item;
891
892 break;
893 }
894 else if( evt->IsMotion() )
895 {
896 delta = cursorPos - currentOffset;
897
898 for( SCH_ITEM* item : selectedItems )
899 item->Move( delta );
900
901 currentOffset += delta;
902
903 m_view->Update( &preview );
904 }
905 else if( evt->IsClick( BUT_RIGHT ) )
906 {
908 }
909 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
910 {
911 // Place the imported drawings
912 for( SCH_ITEM* item : newItems )
913 commit.Add( item, m_frame->GetScreen() );
914
915 commit.Push( _( "Import Graphic" ) );
916 break; // This is a one-shot command, not a tool
917 }
918 else
919 {
920 evt->SetPassEvent();
921 }
922 }
923
924 preview.Clear();
925 m_view->Remove( &preview );
926
927 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
928 controls->ForceCursorPosition( false );
929
930 m_frame->PopTool( aEvent );
931
932 return 0;
933}
934
935
937{
938 VECTOR2I cursorPos;
939 KICAD_T type = aEvent.Parameter<KICAD_T>();
942 SCH_ITEM* previewItem;
943 bool loggedInfoBarError = false;
944 wxString description;
945 SCH_SCREEN* screen = m_frame->GetScreen();
946 bool allowRepeat = false; // Set to true to allow new item repetition
947
948 if( m_inDrawingTool )
949 return 0;
950
952
953 if( type == SCH_JUNCTION_T && aEvent.HasPosition() )
954 {
956 SCH_LINE* wire = dynamic_cast<SCH_LINE*>( selection.Front() );
957
958 if( wire )
959 {
960 SEG seg( wire->GetStartPoint(), wire->GetEndPoint() );
961 VECTOR2I nearest = seg.NearestPoint( getViewControls()->GetCursorPosition() );
962 getViewControls()->SetCrossHairCursorPosition( nearest, false );
963 getViewControls()->WarpMouseCursor( getViewControls()->GetCursorPosition(), true );
964 }
965 }
966
967 switch( type )
968 {
969 case SCH_NO_CONNECT_T:
970 previewItem = new SCH_NO_CONNECT( cursorPos );
971 previewItem->SetParent( screen );
972 description = _( "Add No Connect Flag" );
973 allowRepeat = true;
974 break;
975
976 case SCH_JUNCTION_T:
977 previewItem = new SCH_JUNCTION( cursorPos );
978 previewItem->SetParent( screen );
979 description = _( "Add Junction" );
980 break;
981
983 previewItem = new SCH_BUS_WIRE_ENTRY( cursorPos );
984 previewItem->SetParent( screen );
985 description = _( "Add Wire to Bus Entry" );
986 allowRepeat = true;
987 break;
988
989 default:
990 wxASSERT_MSG( false, "Unknown item type in SCH_DRAWING_TOOLS::SingleClickPlace" );
991 return 0;
992 }
993
995
996 cursorPos = aEvent.HasPosition() ? aEvent.Position() : controls->GetMousePosition();
997
998 m_frame->PushTool( aEvent );
999
1000 auto setCursor =
1001 [&]()
1002 {
1003 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PLACE );
1004 };
1005
1006 Activate();
1007
1008 // Must be done after Activate() so that it gets set into the correct context
1009 getViewControls()->ShowCursor( true );
1010
1011 // Set initial cursor
1012 setCursor();
1013
1015 m_view->AddToPreview( previewItem->Clone() );
1016
1017 // Prime the pump
1018 if( aEvent.HasPosition() && type != SCH_SHEET_PIN_T )
1019 m_toolMgr->PrimeTool( aEvent.Position() );
1020 else
1022
1023 // Main loop: keep receiving events
1024 while( TOOL_EVENT* evt = Wait() )
1025 {
1026 setCursor();
1027 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1028 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1029
1030 cursorPos = evt->IsPrime() ? evt->Position() : controls->GetMousePosition();
1031 cursorPos = grid.BestSnapAnchor( cursorPos, grid.GetItemGrid( previewItem ), nullptr );
1032 controls->ForceCursorPosition( true, cursorPos );
1033
1034 if( evt->IsCancelInteractive() )
1035 {
1036 m_frame->PopTool( aEvent );
1037 break;
1038 }
1039 else if( evt->IsActivate() )
1040 {
1041 if( evt->IsMoveTool() )
1042 {
1043 // leave ourselves on the stack so we come back after the move
1044 break;
1045 }
1046 else
1047 {
1048 m_frame->PopTool( aEvent );
1049 break;
1050 }
1051 }
1052 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) )
1053 {
1054 if( !screen->GetItem( cursorPos, 0, type ) )
1055 {
1056 if( type == SCH_JUNCTION_T )
1057 {
1058 if( !screen->IsExplicitJunctionAllowed( cursorPos ) )
1059 {
1060 m_frame->ShowInfoBarError( _( "Junction location contains no joinable "
1061 "wires and/or pins." ) );
1062 loggedInfoBarError = true;
1063 continue;
1064 }
1065 else if( loggedInfoBarError )
1066 {
1068 }
1069 }
1070
1071 SCH_ITEM* newItem = static_cast<SCH_ITEM*>( previewItem->Clone() );
1072 const_cast<KIID&>( newItem->m_Uuid ) = KIID();
1073 newItem->SetPosition( cursorPos );
1074 newItem->SetFlags( IS_NEW );
1075 m_frame->AddToScreen( newItem, screen );
1076
1077 if( allowRepeat )
1078 m_frame->SaveCopyForRepeatItem( newItem );
1079
1080 SCH_COMMIT commit( m_toolMgr );
1081 commit.Added( newItem, screen );
1082
1083 m_frame->SchematicCleanUp( &commit );
1084
1085 commit.Push( description );
1086 }
1087
1088 if( evt->IsDblClick( BUT_LEFT ) || type == SCH_SHEET_PIN_T ) // Finish tool.
1089 {
1090 m_frame->PopTool( aEvent );
1091 break;
1092 }
1093 }
1094 else if( evt->IsClick( BUT_RIGHT ) )
1095 {
1097 }
1098 else if( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() )
1099 {
1100 previewItem->SetPosition( cursorPos );
1102 m_view->AddToPreview( previewItem->Clone() );
1103 m_frame->SetMsgPanel( previewItem );
1104 }
1105 else if( evt->Category() == TC_COMMAND )
1106 {
1107 if( ( type == SCH_BUS_WIRE_ENTRY_T ) && ( evt->IsAction( &EE_ACTIONS::rotateCW )
1108 || evt->IsAction( &EE_ACTIONS::rotateCCW )
1109 || evt->IsAction( &EE_ACTIONS::mirrorV )
1110 || evt->IsAction( &EE_ACTIONS::mirrorH ) ) )
1111 {
1112 SCH_BUS_ENTRY_BASE* busItem = static_cast<SCH_BUS_ENTRY_BASE*>( previewItem );
1113
1114 // The bus entries only rotate in one direction
1115 if( evt->IsAction( &EE_ACTIONS::rotateCW )
1116 || evt->IsAction( &EE_ACTIONS::rotateCCW ) )
1117 {
1118 busItem->Rotate( busItem->GetPosition() );
1119 }
1120 else if( evt->IsAction( &EE_ACTIONS::mirrorV ) )
1121 {
1122 busItem->MirrorVertically( busItem->GetPosition().y );
1123 }
1124 else if( evt->IsAction( &EE_ACTIONS::mirrorH ) )
1125 {
1126 busItem->MirrorHorizontally( busItem->GetPosition().x );
1127 }
1128
1130 m_view->AddToPreview( previewItem->Clone() );
1131 }
1132 else if( evt->IsAction( &EE_ACTIONS::properties ) )
1133 {
1134 switch( type )
1135 {
1137 {
1138 std::deque<SCH_ITEM*> strokeItems;
1139 strokeItems.push_back( previewItem );
1140
1141 DIALOG_WIRE_BUS_PROPERTIES dlg( m_frame, strokeItems );
1142 }
1143 break;
1144
1145 case SCH_JUNCTION_T:
1146 {
1147 std::deque<SCH_JUNCTION*> junctions;
1148 junctions.push_back( static_cast<SCH_JUNCTION*>( previewItem ) );
1149
1150 DIALOG_JUNCTION_PROPS dlg( m_frame, junctions );
1151 }
1152 break;
1153 default:
1154 // Do nothing
1155 break;
1156 }
1157
1159 m_view->AddToPreview( previewItem->Clone() );
1160 }
1161 else
1162 {
1163 evt->SetPassEvent();
1164 }
1165 }
1166 else
1167 {
1168 evt->SetPassEvent();
1169 }
1170 }
1171
1172 delete previewItem;
1174
1175 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1176 controls->ForceCursorPosition( false );
1177
1178 return 0;
1179}
1180
1181
1183{
1184 for( SCH_ITEM* item : m_frame->GetScreen()->Items().Overlapping( SCH_LINE_T, aPosition ) )
1185 {
1186 SCH_LINE* line = static_cast<SCH_LINE*>( item );
1187
1188 if( line->GetEditFlags() & STRUCT_DELETED )
1189 continue;
1190
1191 if( line->IsWire() )
1192 return line;
1193 }
1194
1195 return nullptr;
1196}
1197
1198
1200{
1201 SCHEMATIC* schematic = getModel<SCHEMATIC>();
1202 SCHEMATIC_SETTINGS& settings = schematic->Settings();
1203 SCH_TEXT* textItem = nullptr;
1204 SCH_LABEL_BASE* labelItem = nullptr;
1205 wxString netName;
1206
1207 switch( aType )
1208 {
1209 case LAYER_NOTES:
1210 textItem = new SCH_TEXT( aPosition );
1211 break;
1212
1213 case LAYER_LOCLABEL:
1214 labelItem = new SCH_LABEL( aPosition );
1215 textItem = labelItem;
1216
1217 if( SCH_LINE* wire = findWire( aPosition ) )
1218 netName = wire->GetNetname( m_frame->GetCurrentSheet() );
1219
1220 break;
1221
1223 labelItem = new SCH_DIRECTIVE_LABEL( aPosition );
1224 labelItem->SetShape( m_lastNetClassFlagShape );
1225 labelItem->GetFields().emplace_back( SCH_FIELD( {0,0}, 0, labelItem, wxT( "Netclass" ) ) );
1226 labelItem->GetFields().back().SetItalic( true );
1227 labelItem->GetFields().back().SetVisible( true );
1228 textItem = labelItem;
1229 break;
1230
1231 case LAYER_HIERLABEL:
1232 labelItem = new SCH_HIERLABEL( aPosition );
1233 labelItem->SetShape( m_lastGlobalLabelShape );
1235 textItem = labelItem;
1236 break;
1237
1238 case LAYER_GLOBLABEL:
1239 labelItem = new SCH_GLOBALLABEL( aPosition );
1240 labelItem->SetShape( m_lastGlobalLabelShape );
1241 labelItem->GetFields()[0].SetVisible( settings.m_IntersheetRefsShow );
1243 textItem = labelItem;
1244
1245 if( SCH_LINE* wire = findWire( aPosition ) )
1246 netName = wire->GetNetname( m_frame->GetCurrentSheet() );
1247
1248 break;
1249
1250 default:
1251 wxFAIL_MSG( "SCH_EDIT_FRAME::CreateNewText() unknown layer type" );
1252 return nullptr;
1253 }
1254
1255 textItem->SetParent( schematic );
1256
1257 textItem->SetTextSize( VECTOR2I( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
1258
1259 if( aType != LAYER_NETCLASS_REFS )
1260 {
1261 // Must be after SetTextSize()
1262 textItem->SetBold( m_lastTextBold );
1263 textItem->SetItalic( m_lastTextItalic );
1264 }
1265
1266 if( labelItem )
1267 {
1268 labelItem->SetSpinStyle( m_lastTextOrientation );
1269 }
1270 else
1271 {
1274 textItem->SetTextAngle( m_lastTextAngle );
1275 }
1276
1277 textItem->SetFlags( IS_NEW | IS_MOVING );
1278
1279 if( !labelItem )
1280 {
1281 DIALOG_TEXT_PROPERTIES dlg( m_frame, textItem );
1282
1283 // QuasiModal required for syntax help and Scintilla auto-complete
1284 if( dlg.ShowQuasiModal() != wxID_OK )
1285 {
1286 delete textItem;
1287 return nullptr;
1288 }
1289 }
1290 else if( !netName.IsEmpty() )
1291 {
1292 // Auto-create from attached wire
1293 textItem->SetText( netName );
1294 }
1295 else
1296 {
1297 DIALOG_LABEL_PROPERTIES dlg( m_frame, static_cast<SCH_LABEL_BASE*>( textItem ) );
1298
1299 // Must be quasi modal for syntax help
1300 if( dlg.ShowQuasiModal() != wxID_OK )
1301 {
1302 delete labelItem;
1303 return nullptr;
1304 }
1305 }
1306
1307 wxString text = textItem->GetText();
1308
1309 if( textItem->Type() != SCH_DIRECTIVE_LABEL_T && NoPrintableChars( text ) )
1310 {
1311 delete textItem;
1312 return nullptr;
1313 }
1314
1315 if( aType != LAYER_NETCLASS_REFS )
1316 {
1317 m_lastTextBold = textItem->IsBold();
1318 m_lastTextItalic = textItem->IsItalic();
1319 }
1320
1321 if( labelItem )
1322 {
1323 m_lastTextOrientation = labelItem->GetSpinStyle();
1324 }
1325 else
1326 {
1327 m_lastTextHJustify = textItem->GetHorizJustify();
1328 m_lastTextVJustify = textItem->GetVertJustify();
1329 m_lastTextAngle = textItem->GetTextAngle();
1330 }
1331
1332 if( aType == LAYER_GLOBLABEL || aType == LAYER_HIERLABEL )
1333 {
1334 m_lastGlobalLabelShape = labelItem->GetShape();
1336 }
1337 else if( aType == LAYER_NETCLASS_REFS )
1338 {
1339 m_lastNetClassFlagShape = labelItem->GetShape();
1340 }
1341
1342 return textItem;
1343}
1344
1346{
1347 SCHEMATIC_SETTINGS& settings = aSheet->Schematic()->Settings();
1348 SCH_SHEET_PIN* pin = new SCH_SHEET_PIN( aSheet );
1349
1350 pin->SetFlags( IS_NEW | IS_MOVING );
1351 pin->SetText( std::to_string( aSheet->GetPins().size() + 1 ) );
1352 pin->SetTextSize( VECTOR2I( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
1353 pin->SetPosition( aPosition );
1354 pin->ClearSelected();
1355
1356 m_lastSheetPinType = pin->GetShape();
1357
1358 return pin;
1359}
1360
1361
1363{
1364 SCH_ITEM* item = nullptr;
1367 bool ignorePrimePosition = false;
1368 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
1369 SCH_SHEET* sheet = nullptr;
1370 wxString description;
1371
1372 if( m_inDrawingTool )
1373 return 0;
1374
1376
1377 bool isText = aEvent.IsAction( &EE_ACTIONS::placeSchematicText );
1378 bool isGlobalLabel = aEvent.IsAction( &EE_ACTIONS::placeGlobalLabel );
1379 bool isHierLabel = aEvent.IsAction( &EE_ACTIONS::placeHierLabel );
1380 bool isClassLabel = aEvent.IsAction( &EE_ACTIONS::placeClassLabel );
1381 bool isNetLabel = aEvent.IsAction( &EE_ACTIONS::placeLabel );
1382 bool isSheetPin = aEvent.IsAction( &EE_ACTIONS::placeSheetPin );
1383
1384 GRID_HELPER_GRIDS snapGrid = isText ? GRID_TEXT : GRID_CONNECTABLE;
1385
1386 // If we have a selected sheet use it, otherwise try to get one under the cursor
1387 if( isSheetPin )
1388 sheet = dynamic_cast<SCH_SHEET*>( m_selectionTool->GetSelection().Front() );
1389
1391
1392 m_frame->PushTool( aEvent );
1393
1394 auto setCursor =
1395 [&]()
1396 {
1397 if( item )
1398 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PLACE );
1399 else if( isText )
1400 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::TEXT );
1401 else if( isGlobalLabel )
1402 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_GLOBAL );
1403 else if( isNetLabel )
1404 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_NET );
1405 else if( isClassLabel )
1406 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_NET ); // JEY TODO: netclass directive cursor
1407 else if( isHierLabel )
1408 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_HIER );
1409 else
1410 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1411 };
1412
1413 auto updatePreview =
1414 [&]()
1415 {
1417 m_view->AddToPreview( item->Clone() );
1418 item->RunOnChildren( [&]( SCH_ITEM* aChild )
1419 {
1420 m_view->AddToPreview( aChild->Clone() );
1421 } );
1422 m_frame->SetMsgPanel( item );
1423 };
1424
1425 auto cleanup =
1426 [&]()
1427 {
1430 delete item;
1431 item = nullptr;
1432 };
1433
1434 Activate();
1435
1436 // Must be done after Activate() so that it gets set into the correct context
1437 controls->ShowCursor( true );
1438
1439 // Set initial cursor
1440 setCursor();
1441
1442 if( aEvent.HasPosition() )
1443 {
1444 m_toolMgr->PrimeTool( aEvent.Position() );
1445 }
1446 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate()
1447 && ( isText || isGlobalLabel || isHierLabel || isClassLabel || isNetLabel ) )
1448 {
1449 m_toolMgr->PrimeTool( { 0, 0 } );
1450 ignorePrimePosition = true;
1451 }
1452
1453 // Main loop: keep receiving events
1454 while( TOOL_EVENT* evt = Wait() )
1455 {
1456 setCursor();
1457 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1458 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1459
1460 VECTOR2I cursorPos = controls->GetMousePosition();
1461 cursorPos = grid.BestSnapAnchor( cursorPos, snapGrid, item );
1462 controls->ForceCursorPosition( true, cursorPos );
1463
1464 // The tool hotkey is interpreted as a click when drawing
1465 bool isSyntheticClick = item && evt->IsActivate() && evt->HasPosition()
1466 && evt->Matches( aEvent );
1467
1468 if( evt->IsCancelInteractive() || evt->IsAction( &ACTIONS::undo ) )
1469 {
1471
1472 if( item )
1473 {
1474 cleanup();
1475 }
1476 else
1477 {
1478 m_frame->PopTool( aEvent );
1479 break;
1480 }
1481 }
1482 else if( evt->IsActivate() && !isSyntheticClick )
1483 {
1484 if( item && evt->IsMoveTool() )
1485 {
1486 // we're already moving our own item; ignore the move tool
1487 evt->SetPassEvent( false );
1488 continue;
1489 }
1490
1491 if( item )
1492 {
1493 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel item creation." ) );
1494 evt->SetPassEvent( false );
1495 continue;
1496 }
1497
1498 if( evt->IsPointEditor() )
1499 {
1500 // don't exit (the point editor runs in the background)
1501 }
1502 else if( evt->IsMoveTool() )
1503 {
1504 // leave ourselves on the stack so we come back after the move
1505 break;
1506 }
1507 else
1508 {
1509 m_frame->PopTool( aEvent );
1510 break;
1511 }
1512 }
1513 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) || isSyntheticClick )
1514 {
1515 // First click creates...
1516 if( !item )
1517 {
1519
1520 if( isText )
1521 {
1522 item = createNewText( cursorPos, LAYER_NOTES );
1523 description = _( "Add Text" );
1524 }
1525 else if( isHierLabel )
1526 {
1527 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
1528 {
1529 auto pin = static_cast<SCH_HIERLABEL*>(
1530 m_dialogSyncSheetPin->GetPlacementTemplate() );
1531 SCH_HIERLABEL* label = new SCH_HIERLABEL( cursorPos );
1532 SCHEMATIC* schematic = getModel<SCHEMATIC>();
1533 label->SetText( pin->GetText() );
1534 label->SetShape( pin->GetShape() );
1536 label->SetParent( schematic );
1537 label->SetBold( m_lastTextBold );
1538 label->SetItalic( m_lastTextItalic );
1540 label->SetTextSize( VECTOR2I( schematic->Settings().m_DefaultTextSize,
1541 schematic->Settings().m_DefaultTextSize ) );
1542 label->SetFlags( IS_NEW | IS_MOVING );
1543 item = label;
1544 }
1545 else
1546 {
1547 item = createNewText( cursorPos, LAYER_HIERLABEL );
1548 }
1549
1550 description = _( "Add Hierarchical Label" );
1551 }
1552 else if( isNetLabel )
1553 {
1554 item = createNewText( cursorPos, LAYER_LOCLABEL );
1555 description = _( "Add Label" );
1556 }
1557 else if( isGlobalLabel )
1558 {
1559 item = createNewText( cursorPos, LAYER_GLOBLABEL );
1560 description = _( "Add Label" );
1561 }
1562 else if( isClassLabel )
1563 {
1564 item = createNewText( cursorPos, LAYER_NETCLASS_REFS );
1565 description = _( "Add Label" );
1566 }
1567 else if( isSheetPin )
1568 {
1569 EDA_ITEM* i = nullptr;
1570
1571 // If we didn't have a sheet selected, try to find one under the cursor
1572 if( !sheet && m_selectionTool->SelectPoint( cursorPos, { SCH_SHEET_T }, &i ) )
1573 sheet = dynamic_cast<SCH_SHEET*>( i );
1574
1575 if( !sheet )
1576 {
1577 m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( m_frame );
1578 m_statusPopup->SetText( _( "Click over a sheet." ) );
1580 + wxPoint( 20, 20 ) );
1581 m_statusPopup->PopupFor( 2000 );
1582 item = nullptr;
1583 }
1584 else
1585 {
1586 item = createNewSheetPin( sheet, cursorPos );
1587
1588 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
1589 {
1590 auto label = static_cast<SCH_HIERLABEL*>(
1591 m_dialogSyncSheetPin->GetPlacementTemplate() );
1592 auto pin = static_cast<SCH_HIERLABEL*>( item );
1593 pin->SetText( label->GetText() );
1594 pin->SetShape( label->GetShape() );
1595 }
1596 }
1597
1598 description = _( "Add Sheet Pin" );
1599 }
1600
1601 // If we started with a hotkey which has a position then warp back to that.
1602 // Otherwise update to the current mouse position pinned inside the autoscroll
1603 // boundaries.
1604 if( evt->IsPrime() && !ignorePrimePosition )
1605 {
1606 cursorPos = grid.Align( evt->Position() );
1607 getViewControls()->WarpMouseCursor( cursorPos, true );
1608 }
1609 else
1610 {
1612 cursorPos = getViewControls()->GetMousePosition();
1613 cursorPos = grid.BestSnapAnchor( cursorPos, snapGrid, item );
1614 }
1615
1616 if( item )
1617 {
1618 item->SetPosition( cursorPos );
1619
1620 item->SetFlags( IS_NEW | IS_MOVING );
1621 item->AutoplaceFields( nullptr, false /* aManual */ );
1622 updatePreview();
1625
1626 // update the cursor so it looks correct before another event
1627 setCursor();
1628 }
1629
1630 controls->SetCursorPosition( cursorPos, false );
1631 }
1632 else // ... and second click places:
1633 {
1634 SCH_COMMIT commit( m_toolMgr );
1635
1636 item->ClearFlags( IS_MOVING );
1637
1638 if( item->IsConnectable() )
1640
1641 if( isSheetPin )
1642 {
1643 // Sheet pins are owned by their parent sheet.
1644 commit.Modify( sheet, m_frame->GetScreen() );
1645 sheet->AddPin( (SCH_SHEET_PIN*) item );
1646 }
1647 else
1648 {
1650 m_frame->AddToScreen( item, m_frame->GetScreen() );
1651 commit.Added( item, m_frame->GetScreen() );
1652 }
1653
1654 item->AutoplaceFields( m_frame->GetScreen(), false /* aManual */ );
1655
1656 commit.Push( description );
1657
1659
1660 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
1661 {
1662 m_dialogSyncSheetPin->EndPlaceItem( item );
1663 m_dialogSyncSheetPin->Show( true );
1664 break;
1665 }
1666 else
1667 {
1668 item = nullptr;
1669 }
1670
1671 if( isSheetPin )
1672 {
1673 item = createNewSheetPin( sheet, cursorPos );
1674 item->SetPosition( cursorPos );
1677 }
1678 }
1679 }
1680 else if( evt->IsClick( BUT_RIGHT ) )
1681 {
1682 // Warp after context menu only if dragging...
1683 if( !item )
1685
1687 }
1688 else if( item && evt->IsSelectionEvent() )
1689 {
1690 // This happens if our text was replaced out from under us by ConvertTextType()
1692
1693 if( selection.GetSize() == 1 )
1694 {
1695 item = (SCH_ITEM*) selection.Front();
1696 updatePreview();
1697 }
1698 else
1699 {
1700 item = nullptr;
1701 }
1702 }
1703 else if( evt->IsAction( &ACTIONS::duplicate )
1704 || evt->IsAction( &EE_ACTIONS::repeatDrawItem ) )
1705 {
1706 if( item )
1707 {
1708 // This doesn't really make sense; we'll just end up dragging a stack of
1709 // objects so we ignore the duplicate and just carry on.
1710 wxBell();
1711 continue;
1712 }
1713
1714 // Exit. The duplicate will run in its own loop.
1715 m_frame->PopTool( aEvent );
1716 break;
1717 }
1718 else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
1719 {
1720 item->SetPosition( cursorPos );
1721 item->AutoplaceFields( /* aScreen */ nullptr, /* aManual */ false );
1722 updatePreview();
1723 }
1724 else if( item && evt->IsAction( &ACTIONS::doDelete ) )
1725 {
1726 cleanup();
1727 }
1728 else if( evt->IsAction( &ACTIONS::redo ) )
1729 {
1730 wxBell();
1731 }
1732 else
1733 {
1734 evt->SetPassEvent();
1735 }
1736
1737 // Enable autopanning and cursor capture only when there is an item to be placed
1738 controls->SetAutoPan( item != nullptr );
1739 controls->CaptureCursor( item != nullptr );
1740 }
1741
1742 controls->SetAutoPan( false );
1743 controls->CaptureCursor( false );
1744 controls->ForceCursorPosition( false );
1745 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1746
1747 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
1748 {
1749 m_dialogSyncSheetPin->EndPlaceItem( nullptr );
1750 m_dialogSyncSheetPin->Show( true );
1751 }
1752
1753 return 0;
1754}
1755
1756
1758{
1759 SCHEMATIC* schematic = getModel<SCHEMATIC>();
1760 SCHEMATIC_SETTINGS& sch_settings = schematic->Settings();
1761 SCH_SHAPE* item = nullptr;
1762 bool isTextBox = aEvent.IsAction( &EE_ACTIONS::drawTextBox );
1763 SHAPE_T type = aEvent.Parameter<SHAPE_T>();
1764 wxString description;
1765
1766 if( m_inDrawingTool )
1767 return 0;
1768
1770
1773 VECTOR2I cursorPos;
1774
1775 // We might be running as the same shape in another co-routine. Make sure that one
1776 // gets whacked.
1778
1780
1781 m_frame->PushTool( aEvent );
1782
1783 auto setCursor =
1784 [&]()
1785 {
1786 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1787 };
1788
1789 auto cleanup =
1790 [&] ()
1791 {
1794 delete item;
1795 item = nullptr;
1796 };
1797
1798 Activate();
1799
1800 // Must be done after Activate() so that it gets set into the correct context
1801 getViewControls()->ShowCursor( true );
1802
1803 // Set initial cursor
1804 setCursor();
1805
1806 if( aEvent.HasPosition() )
1807 m_toolMgr->PrimeTool( aEvent.Position() );
1808
1809 // Main loop: keep receiving events
1810 while( TOOL_EVENT* evt = Wait() )
1811 {
1812 setCursor();
1813 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1814 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1815
1816 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
1817 controls->ForceCursorPosition( true, cursorPos );
1818
1819 // The tool hotkey is interpreted as a click when drawing
1820 bool isSyntheticClick = item && evt->IsActivate() && evt->HasPosition()
1821 && evt->Matches( aEvent );
1822
1823 if( evt->IsCancelInteractive() || ( item && evt->IsAction( &ACTIONS::undo ) ) )
1824 {
1825 if( item )
1826 {
1827 cleanup();
1828 }
1829 else
1830 {
1831 m_frame->PopTool( aEvent );
1832 break;
1833 }
1834 }
1835 else if( evt->IsActivate() && !isSyntheticClick )
1836 {
1837 if( item && evt->IsMoveTool() )
1838 {
1839 // we're already drawing our own item; ignore the move tool
1840 evt->SetPassEvent( false );
1841 continue;
1842 }
1843
1844 if( item )
1845 cleanup();
1846
1847 if( evt->IsPointEditor() )
1848 {
1849 // don't exit (the point editor runs in the background)
1850 }
1851 else if( evt->IsMoveTool() )
1852 {
1853 // leave ourselves on the stack so we come back after the move
1854 break;
1855 }
1856 else
1857 {
1858 m_frame->PopTool( aEvent );
1859 break;
1860 }
1861 }
1862 else if( evt->IsClick( BUT_LEFT ) && !item )
1863 {
1865
1866 if( isTextBox )
1867 {
1868 SCH_TEXTBOX* textbox = new SCH_TEXTBOX( 0, m_lastTextboxFillStyle );
1869
1870 textbox->SetTextSize( VECTOR2I( sch_settings.m_DefaultTextSize,
1871 sch_settings.m_DefaultTextSize ) );
1872
1873 // Must come after SetTextSize()
1874 textbox->SetBold( m_lastTextBold );
1875 textbox->SetItalic( m_lastTextItalic );
1876
1877 textbox->SetTextAngle( m_lastTextboxAngle );
1880 textbox->SetStroke( m_lastTextboxStroke );
1882 textbox->SetParent( schematic );
1883
1884 item = textbox;
1885 description = _( "Add Text Box" );
1886 }
1887 else
1888 {
1889 item = new SCH_SHAPE( type, 0, m_lastFillStyle );
1890
1891 item->SetStroke( m_lastStroke );
1893 item->SetParent( schematic );
1894 description = wxString::Format( _( "Add %s" ), item->EDA_SHAPE::GetFriendlyName() );
1895 }
1896
1897 item->SetFlags( IS_NEW );
1898 item->BeginEdit( cursorPos );
1899
1901 m_view->AddToPreview( item->Clone() );
1902 }
1903 else if( item && ( evt->IsClick( BUT_LEFT )
1904 || evt->IsDblClick( BUT_LEFT )
1905 || isSyntheticClick
1906 || evt->IsAction( &ACTIONS::finishInteractive ) ) )
1907 {
1908 if( evt->IsDblClick( BUT_LEFT )
1909 || evt->IsAction( &ACTIONS::finishInteractive )
1910 || !item->ContinueEdit( cursorPos ) )
1911 {
1912 item->EndEdit();
1913 item->ClearEditFlags();
1914 item->SetFlags( IS_NEW );
1915
1916 if( isTextBox )
1917 {
1918 SCH_TEXTBOX* textbox = static_cast<SCH_TEXTBOX*>( item );
1919 DIALOG_TEXT_PROPERTIES dlg( m_frame, textbox );
1920
1921 getViewControls()->SetAutoPan( false );
1922 getViewControls()->CaptureCursor( false );
1923
1924 // QuasiModal required for syntax help and Scintilla auto-complete
1925 if( dlg.ShowQuasiModal() != wxID_OK )
1926 {
1927 cleanup();
1928 continue;
1929 }
1930
1931 m_lastTextBold = textbox->IsBold();
1932 m_lastTextItalic = textbox->IsItalic();
1933 m_lastTextboxAngle = textbox->GetTextAngle();
1936 m_lastTextboxStroke = textbox->GetStroke();
1939 }
1940 else
1941 {
1942 m_lastStroke = item->GetStroke();
1943 m_lastFillStyle = item->GetFillMode();
1944 m_lastFillColor = item->GetFillColor();
1945 }
1946
1947 SCH_COMMIT commit( m_toolMgr );
1948 commit.Add( item, m_frame->GetScreen() );
1949 commit.Push( wxString::Format( _( "Draw %s" ), item->GetClass() ) );
1950
1952 item = nullptr;
1953
1956 }
1957 }
1958 else if( evt->IsAction( &ACTIONS::duplicate )
1959 || evt->IsAction( &EE_ACTIONS::repeatDrawItem ) )
1960 {
1961 if( item )
1962 {
1963 // This doesn't really make sense; we'll just end up dragging a stack of
1964 // objects so we ignore the duplicate and just carry on.
1965 wxBell();
1966 continue;
1967 }
1968
1969 // Exit. The duplicate will run in its own loop.
1970 m_frame->PopTool( aEvent );
1971 break;
1972 }
1973 else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
1974 {
1975 item->CalcEdit( cursorPos );
1977 m_view->AddToPreview( item->Clone() );
1978 m_frame->SetMsgPanel( item );
1979 }
1980 else if( evt->IsDblClick( BUT_LEFT ) && !item )
1981 {
1983 }
1984 else if( evt->IsClick( BUT_RIGHT ) )
1985 {
1986 // Warp after context menu only if dragging...
1987 if( !item )
1989
1991 }
1992 else if( item && evt->IsAction( &ACTIONS::redo ) )
1993 {
1994 wxBell();
1995 }
1996 else
1997 {
1998 evt->SetPassEvent();
1999 }
2000
2001 // Enable autopanning and cursor capture only when there is a shape being drawn
2002 getViewControls()->SetAutoPan( item != nullptr );
2003 getViewControls()->CaptureCursor( item != nullptr );
2004 }
2005
2006 getViewControls()->SetAutoPan( false );
2007 getViewControls()->CaptureCursor( false );
2008 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2009 return 0;
2010}
2011
2012
2014{
2015 SCH_SHEET_LIST fullHierarchy = m_frame->Schematic().GetFullHierarchy();
2016 SCH_SHEET_LIST instances = fullHierarchy.FindAllSheetsForScreen( aAddedSheet.LastScreen() );
2017
2018 long pageNo;
2019 long addedSheetPageNo;
2020
2021 if( aAddedSheet.GetPageNumber().ToLong( &addedSheetPageNo ) )
2022 pageNo = addedSheetPageNo + 1;
2023 else
2024 pageNo = (signed)( fullHierarchy.size() - instances.size() + 1 );
2025
2026 for( SCH_SHEET_PATH& sheet : instances )
2027 {
2028 if( sheet == aAddedSheet )
2029 continue;
2030
2031 sheet.SetPageNumber( wxString::Format( wxS( "%ld" ), pageNo++ ) );
2032 }
2033}
2034
2035
2037{
2038 SCHEMATIC* schematic = getModel<SCHEMATIC>();
2039 SCH_TABLE* table = nullptr;
2040
2041 if( m_inDrawingTool )
2042 return 0;
2043
2045
2048 VECTOR2I cursorPos;
2049
2050 // We might be running as the same shape in another co-routine. Make sure that one
2051 // gets whacked.
2053
2055
2056 m_frame->PushTool( aEvent );
2057
2058 auto setCursor =
2059 [&]()
2060 {
2061 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2062 };
2063
2064 auto cleanup =
2065 [&] ()
2066 {
2069 delete table;
2070 table = nullptr;
2071 };
2072
2073 Activate();
2074
2075 // Must be done after Activate() so that it gets set into the correct context
2076 getViewControls()->ShowCursor( true );
2077
2078 // Set initial cursor
2079 setCursor();
2080
2081 if( aEvent.HasPosition() )
2082 m_toolMgr->PrimeTool( aEvent.Position() );
2083
2084 // Main loop: keep receiving events
2085 while( TOOL_EVENT* evt = Wait() )
2086 {
2087 setCursor();
2088 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2089 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2090
2091 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
2092 controls->ForceCursorPosition( true, cursorPos );
2093
2094 // The tool hotkey is interpreted as a click when drawing
2095 bool isSyntheticClick = table && evt->IsActivate() && evt->HasPosition()
2096 && evt->Matches( aEvent );
2097
2098 if( evt->IsCancelInteractive() || ( table && evt->IsAction( &ACTIONS::undo ) ) )
2099 {
2100 if( table )
2101 {
2102 cleanup();
2103 }
2104 else
2105 {
2106 m_frame->PopTool( aEvent );
2107 break;
2108 }
2109 }
2110 else if( evt->IsActivate() && !isSyntheticClick )
2111 {
2112 if( table && evt->IsMoveTool() )
2113 {
2114 // we're already drawing our own item; ignore the move tool
2115 evt->SetPassEvent( false );
2116 continue;
2117 }
2118
2119 if( table )
2120 cleanup();
2121
2122 if( evt->IsPointEditor() )
2123 {
2124 // don't exit (the point editor runs in the background)
2125 }
2126 else if( evt->IsMoveTool() )
2127 {
2128 // leave ourselves on the stack so we come back after the move
2129 break;
2130 }
2131 else
2132 {
2133 m_frame->PopTool( aEvent );
2134 break;
2135 }
2136 }
2137 else if( evt->IsClick( BUT_LEFT ) && !table )
2138 {
2140
2141 table = new SCH_TABLE( 0 );
2142 table->SetColCount( 1 );
2143 table->AddCell( new SCH_TABLECELL() );
2144
2145 table->SetParent( schematic );
2146 table->SetFlags( IS_NEW );
2147 table->SetPosition( cursorPos );
2148
2150 m_view->AddToPreview( table->Clone() );
2151 }
2152 else if( table && ( evt->IsClick( BUT_LEFT )
2153 || evt->IsDblClick( BUT_LEFT )
2154 || isSyntheticClick
2155 || evt->IsAction( &EE_ACTIONS::finishInteractive ) ) )
2156 {
2157 table->ClearEditFlags();
2158 table->SetFlags( IS_NEW );
2159 table->Normalize();
2160
2161 SCH_COMMIT commit( m_toolMgr );
2162 commit.Add( table, m_frame->GetScreen() );
2163 commit.Push( _( "Draw Table" ) );
2164
2165 m_selectionTool->AddItemToSel( table );
2166 table = nullptr;
2167
2170 }
2171 else if( table && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
2172 {
2173 VECTOR2I gridSize = grid.GetGridSize( grid.GetItemGrid( table ) );
2174 int fontSize = schematic->Settings().m_DefaultTextSize;
2175 VECTOR2I origin( table->GetPosition() );
2176 VECTOR2I requestedSize( cursorPos - origin );
2177
2178 int colCount = std::max( 1, requestedSize.x / ( fontSize * 15 ) );
2179 int rowCount = std::max( 1, requestedSize.y / ( fontSize * 2 ) );
2180
2181 VECTOR2I cellSize( std::max( gridSize.x * 5, requestedSize.x / colCount ),
2182 std::max( gridSize.y * 2, requestedSize.y / rowCount ) );
2183
2184 cellSize.x = KiROUND( (double) cellSize.x / gridSize.x ) * gridSize.x;
2185 cellSize.y = KiROUND( (double) cellSize.y / gridSize.y ) * gridSize.y;
2186
2187 table->ClearCells();
2188 table->SetColCount( colCount );
2189
2190 for( int col = 0; col < colCount; ++col )
2191 table->SetColWidth( col, cellSize.x );
2192
2193 for( int row = 0; row < rowCount; ++row )
2194 {
2195 table->SetRowHeight( row, cellSize.y );
2196
2197 for( int col = 0; col < colCount; ++col )
2198 {
2199 SCH_TABLECELL* cell = new SCH_TABLECELL();
2200 cell->SetPosition( origin + VECTOR2I( col * cellSize.x, row * cellSize.y ) );
2201 cell->SetEnd( cell->GetPosition() + cellSize );
2202 table->AddCell( cell );
2203 }
2204 }
2205
2207 m_view->AddToPreview( table->Clone() );
2208 m_frame->SetMsgPanel( table );
2209 }
2210 else if( evt->IsDblClick( BUT_LEFT ) && !table )
2211 {
2213 }
2214 else if( evt->IsClick( BUT_RIGHT ) )
2215 {
2216 // Warp after context menu only if dragging...
2217 if( !table )
2219
2221 }
2222 else if( table && evt->IsAction( &ACTIONS::redo ) )
2223 {
2224 wxBell();
2225 }
2226 else
2227 {
2228 evt->SetPassEvent();
2229 }
2230
2231 // Enable autopanning and cursor capture only when there is a shape being drawn
2232 getViewControls()->SetAutoPan( table != nullptr );
2233 getViewControls()->CaptureCursor( table != nullptr );
2234 }
2235
2236 getViewControls()->SetAutoPan( false );
2237 getViewControls()->CaptureCursor( false );
2238 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2239 return 0;
2240}
2241
2242
2244{
2245 SCH_SHEET* sheet = nullptr;
2246
2247 if( m_inDrawingTool )
2248 return 0;
2249
2251
2254 VECTOR2I cursorPos;
2255
2257
2258 m_frame->PushTool( aEvent );
2259
2260 auto setCursor =
2261 [&]()
2262 {
2263 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2264 };
2265
2266 auto cleanup =
2267 [&] ()
2268 {
2271 delete sheet;
2272 sheet = nullptr;
2273 };
2274
2275 Activate();
2276
2277 // Must be done after Activate() so that it gets set into the correct context
2278 getViewControls()->ShowCursor( true );
2279
2280 // Set initial cursor
2281 setCursor();
2282
2283 if( aEvent.HasPosition() )
2284 m_toolMgr->PrimeTool( aEvent.Position() );
2285
2286 // Main loop: keep receiving events
2287 while( TOOL_EVENT* evt = Wait() )
2288 {
2289 setCursor();
2290 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2291 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2292
2293 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
2294 controls->ForceCursorPosition( true, cursorPos );
2295
2296 // The tool hotkey is interpreted as a click when drawing
2297 bool isSyntheticClick = sheet && evt->IsActivate() && evt->HasPosition()
2298 && evt->Matches( aEvent );
2299
2300 if( evt->IsCancelInteractive() || ( sheet && evt->IsAction( &ACTIONS::undo ) ) )
2301 {
2303
2304 if( sheet )
2305 {
2306 cleanup();
2307 }
2308 else
2309 {
2310 m_frame->PopTool( aEvent );
2311 break;
2312 }
2313 }
2314 else if( evt->IsActivate() && !isSyntheticClick )
2315 {
2316 if( sheet && evt->IsMoveTool() )
2317 {
2318 // we're already drawing our own item; ignore the move tool
2319 evt->SetPassEvent( false );
2320 continue;
2321 }
2322
2323 if( sheet )
2324 {
2325 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel sheet creation." ) );
2326 evt->SetPassEvent( false );
2327 continue;
2328 }
2329
2330 if( evt->IsPointEditor() )
2331 {
2332 // don't exit (the point editor runs in the background)
2333 }
2334 else if( evt->IsMoveTool() )
2335 {
2336 // leave ourselves on the stack so we come back after the move
2337 break;
2338 }
2339 else
2340 {
2341 m_frame->PopTool( aEvent );
2342 break;
2343 }
2344 }
2345 else if( !sheet && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) ) )
2346 {
2349
2350 if( selection.Size() == 1
2351 && selection.Front()->Type() == SCH_SHEET_T
2352 && selection.Front()->GetBoundingBox().Contains( cursorPos ) )
2353 {
2354 if( evt->IsClick( BUT_LEFT ) )
2355 {
2356 // sheet already selected
2357 continue;
2358 }
2359 else if( evt->IsDblClick( BUT_LEFT ) )
2360 {
2362 break;
2363 }
2364 }
2365
2367
2368 sheet = new SCH_SHEET( m_frame->GetCurrentSheet().Last(), cursorPos );
2369 sheet->SetFlags( IS_NEW | IS_MOVING );
2370 sheet->SetScreen( nullptr );
2374 sheet->GetFields()[ SHEETNAME ].SetText( "Untitled Sheet" );
2375 sheet->GetFields()[ SHEETFILENAME ].SetText( "untitled." + FILEEXT::KiCadSchematicFileExtension );
2376 sizeSheet( sheet, cursorPos );
2377
2379 m_view->AddToPreview( sheet->Clone() );
2380 }
2381 else if( sheet && ( evt->IsClick( BUT_LEFT )
2382 || evt->IsDblClick( BUT_LEFT )
2383 || isSyntheticClick
2384 || evt->IsAction( &ACTIONS::finishInteractive ) ) )
2385 {
2386 getViewControls()->SetAutoPan( false );
2387 getViewControls()->CaptureCursor( false );
2388
2389 if( m_frame->EditSheetProperties( static_cast<SCH_SHEET*>( sheet ),
2390 &m_frame->GetCurrentSheet(), nullptr ) )
2391 {
2393
2394 sheet->AutoplaceFields( /* aScreen */ nullptr, /* aManual */ false );
2395
2396 SCH_COMMIT commit( m_toolMgr );
2397 commit.Add( sheet, m_frame->GetScreen() );
2398 commit.Push( "Draw Sheet" );
2399
2401 newPath.push_back( sheet );
2403
2405 m_selectionTool->AddItemToSel( sheet );
2406 }
2407 else
2408 {
2410 delete sheet;
2411 }
2412
2413 sheet = nullptr;
2414 }
2415 else if( evt->IsAction( &ACTIONS::duplicate )
2416 || evt->IsAction( &EE_ACTIONS::repeatDrawItem ) )
2417 {
2418 if( sheet )
2419 {
2420 // This doesn't really make sense; we'll just end up dragging a stack of
2421 // objects so we ignore the duplicate and just carry on.
2422 wxBell();
2423 continue;
2424 }
2425
2426 // Exit. The duplicate will run in its own loop.
2427 m_frame->PopTool( aEvent );
2428 break;
2429 }
2430 else if( sheet && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
2431 {
2432 sizeSheet( sheet, cursorPos );
2434 m_view->AddToPreview( sheet->Clone() );
2435 m_frame->SetMsgPanel( sheet );
2436 }
2437 else if( evt->IsClick( BUT_RIGHT ) )
2438 {
2439 // Warp after context menu only if dragging...
2440 if( !sheet )
2442
2444 }
2445 else if( sheet && evt->IsAction( &ACTIONS::redo ) )
2446 {
2447 wxBell();
2448 }
2449 else
2450 {
2451 evt->SetPassEvent();
2452 }
2453
2454 // Enable autopanning and cursor capture only when there is a sheet to be placed
2455 getViewControls()->SetAutoPan( sheet != nullptr );
2456 getViewControls()->CaptureCursor( sheet != nullptr );
2457 }
2458
2459 getViewControls()->SetAutoPan( false );
2460 getViewControls()->CaptureCursor( false );
2461 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2462
2463 return 0;
2464}
2465
2466
2468{
2469 VECTOR2I pos = aSheet->GetPosition();
2470 VECTOR2I size = aPos - pos;
2471
2472 size.x = std::max( size.x, schIUScale.MilsToIU( MIN_SHEET_WIDTH ) );
2473 size.y = std::max( size.y, schIUScale.MilsToIU( MIN_SHEET_HEIGHT ) );
2474
2476 aSheet->Resize( VECTOR2I( grid.x - pos.x, grid.y - pos.y ) );
2477}
2478
2479
2480int SCH_DRAWING_TOOLS::doSyncSheetsPins( std::list<SCH_SHEET_PATH> sheetPaths )
2481{
2482 if( !sheetPaths.size() )
2483 return 0;
2484
2485 m_dialogSyncSheetPin = std::make_unique<DIALOG_SYNC_SHEET_PINS>(
2486 m_frame, std::move( sheetPaths ),
2487 std::make_shared<SHEET_SYNCHRONIZATION_AGENT>(
2488 [&]( EDA_ITEM* aItem, SCH_SHEET_PATH aPath,
2490 {
2491 SCH_COMMIT commit( m_toolMgr );
2492
2493 if( auto pin = dynamic_cast<SCH_SHEET_PIN*>( aItem ) )
2494 {
2495 commit.Modify( pin->GetParent(), aPath.LastScreen() );
2496 aModify();
2497 commit.Push( _( "Modify sch item" ) );
2498 }
2499 else
2500 {
2501 commit.Modify( aItem, aPath.LastScreen() );
2502 aModify();
2503 commit.Push( _( "Modify sch item" ), SKIP_CONNECTIVITY );
2504 }
2505
2506 updateItem( aItem, true );
2507 m_frame->OnModify();
2508 },
2509 [&]( EDA_ITEM* aItem, SCH_SHEET_PATH aPath )
2510 {
2512 EE_ACTIONS::changeSheet, &aPath );
2514 selectionTool->UnbrightenItem( aItem );
2515 selectionTool->AddItemToSel( aItem, true );
2517 },
2518 [&]( SCH_SHEET* aItem, SCH_SHEET_PATH aPath,
2520 EDA_ITEM* aTemplate )
2521 {
2522 switch( aOp )
2523 {
2525 {
2526 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
2527 m_dialogSyncSheetPin->Hide();
2528 m_dialogSyncSheetPin->BeginPlaceItem(
2530 aTemplate );
2532 EE_ACTIONS::changeSheet, &aPath );
2534 break;
2535 }
2537 {
2538 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
2539 m_dialogSyncSheetPin->Hide();
2540 m_dialogSyncSheetPin->BeginPlaceItem(
2542 aTemplate );
2544 EE_ACTIONS::changeSheet, &aPath );
2545 m_toolMgr->GetTool<EE_SELECTION_TOOL>()->SyncSelection( {}, nullptr,
2546 { sheet } );
2548 break;
2549 }
2550 }
2551 },
2552 m_toolMgr, m_frame ) );
2553 m_dialogSyncSheetPin->Show( true );
2554 return 0;
2555}
2556
2557
2559{
2560 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( m_selectionTool->GetSelection().Front() );
2561
2562 if( !sheet )
2563 {
2564 VECTOR2I cursorPos = getViewControls()->GetMousePosition();
2565
2566 if( EDA_ITEM* i = nullptr; static_cast<void>(m_selectionTool->SelectPoint( cursorPos, { SCH_SHEET_T }, &i ) ) , i != nullptr )
2567 {
2568 sheet = dynamic_cast<SCH_SHEET*>( i );
2569 }
2570 }
2571
2572 if ( sheet )
2573 {
2575 current.push_back( sheet );
2576 return doSyncSheetsPins( { current } );
2577 }
2578
2579 return 0;
2580}
2581
2582
2584{
2585 static const std::function<void( std::list<SCH_SHEET_PATH>&, SCH_SCREEN*,
2586 std::set<SCH_SCREEN*>&, SCH_SHEET_PATH const& )>
2587 getSheetChildren = []( std::list<SCH_SHEET_PATH>& aPaths, SCH_SCREEN* aScene,
2588 std::set<SCH_SCREEN*>& aVisited, SCH_SHEET_PATH const& aCurPath )
2589 {
2590 if( ! aScene || aVisited.find(aScene) != aVisited.end() )
2591 return ;
2592
2593 std::vector<SCH_ITEM*> sheetChildren;
2594 aScene->GetSheets( &sheetChildren );
2595 aVisited.insert( aScene );
2596
2597 for( SCH_ITEM* child : sheetChildren )
2598 {
2599 SCH_SHEET_PATH cp = aCurPath;
2600 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( child );
2601 cp.push_back( sheet );
2602 aPaths.push_back( cp );
2603 getSheetChildren( aPaths, sheet->GetScreen(), aVisited, cp );
2604 }
2605 };
2606
2607 std::list<SCH_SHEET_PATH> sheetPaths;
2608 std::set<SCH_SCREEN*> visited;
2609 SCH_SHEET_PATH current;
2610 current.push_back( &m_frame->Schematic().Root() );
2611 getSheetChildren( sheetPaths, m_frame->Schematic().Root().GetScreen(), visited, current );
2612 return doSyncSheetsPins( sheetPaths );
2613}
2614
2615
2617{
2639}
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:111
static TOOL_ACTION cancelInteractive
Definition: actions.h:63
static TOOL_ACTION undo
Definition: actions.h:66
static TOOL_ACTION duplicate
Definition: actions.h:74
static TOOL_ACTION activatePointEditor
Definition: actions.h:201
static TOOL_ACTION doDelete
Definition: actions.h:75
static TOOL_ACTION redo
Definition: actions.h:67
static TOOL_ACTION refreshPreview
Definition: actions.h:133
static TOOL_ACTION finishInteractive
Definition: actions.h:64
bool Contains(const Vec &aPoint) const
Definition: box2.h:142
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.
std::list< std::unique_ptr< EDA_ITEM > > & GetImportedItems()
int ShowQuasiModal()
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:85
virtual void SetPosition(const VECTOR2I &aPos)
Definition: eda_item.h:240
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:74
EDA_ITEM_FLAGS GetEditFlags() const
Definition: eda_item.h:129
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:123
const KIID m_Uuid
Definition: eda_item.h:482
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:125
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition: eda_item.h:372
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
virtual EDA_ITEM * Clone() const
Create a duplicate of this item with linked list members set to NULL.
Definition: eda_item.cpp:82
void ClearEditFlags()
Definition: eda_item.h:137
FILL_T GetFillMode() const
Definition: eda_shape.h:101
void SetFillColor(const COLOR4D &aColor)
Definition: eda_shape.h:106
COLOR4D GetFillColor() const
Definition: eda_shape.h:105
void SetEnd(const VECTOR2I &aEnd)
Definition: eda_shape.h:155
bool IsItalic() const
Definition: eda_text.h:141
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:131
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition: eda_text.cpp:374
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:95
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:276
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:161
void SetBold(bool aBold)
Definition: eda_text.cpp:221
bool IsBold() const
Definition: eda_text.h:145
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition: eda_text.h:164
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:183
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:205
void SetItalic(bool aItalic)
Definition: eda_text.cpp:213
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:268
PANEL_ANNOTATE m_AnnotatePanel
PANEL_SYM_CHOOSER m_SymChooserPanel
AUTOPLACE_FIELDS m_AutoplaceFields
static TOOL_ACTION mirrorV
Definition: ee_actions.h:123
static TOOL_ACTION properties
Definition: ee_actions.h:126
static TOOL_ACTION addItemsToSel
Selects a list of items (specified as the event parameter)
Definition: ee_actions.h:63
static TOOL_ACTION changeSheet
Definition: ee_actions.h:215
static TOOL_ACTION drawTable
Definition: ee_actions.h:99
static TOOL_ACTION syncAllSheetsPins
Definition: ee_actions.h:96
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 placeClassLabel
Definition: ee_actions.h:88
static TOOL_ACTION drawCircle
Definition: ee_actions.h:101
static TOOL_ACTION rotateCCW
Definition: ee_actions.h:122
static TOOL_ACTION placePower
Definition: ee_actions.h:80
static TOOL_ACTION placeSheetPin
Definition: ee_actions.h:92
static TOOL_ACTION mirrorH
Definition: ee_actions.h:124
static TOOL_ACTION syncSheetPins
Definition: ee_actions.h:94
static TOOL_ACTION rotateCW
Definition: ee_actions.h:121
static TOOL_ACTION importGraphics
Definition: ee_actions.h:252
static TOOL_ACTION leaveSheet
Definition: ee_actions.h:217
static TOOL_ACTION placeGlobalLabel
Definition: ee_actions.h:89
static TOOL_ACTION placeHierLabel
Definition: ee_actions.h:90
static TOOL_ACTION drawTextBox
Definition: ee_actions.h:98
static TOOL_ACTION drawRectangle
Definition: ee_actions.h:100
static TOOL_ACTION placeImage
Definition: ee_actions.h:104
static TOOL_ACTION enterSheet
Definition: ee_actions.h:216
static TOOL_ACTION placeSchematicText
Definition: ee_actions.h:97
static TOOL_ACTION drawArc
Definition: ee_actions.h:102
static TOOL_ACTION drawSheet
Definition: ee_actions.h:91
static TOOL_ACTION placeLabel
Definition: ee_actions.h:87
static TOOL_ACTION repeatDrawItem
Definition: ee_actions.h:120
static TOOL_ACTION placeBusWireEntry
Definition: ee_actions.h:86
static TOOL_ACTION placeJunction
Definition: ee_actions.h:85
static TOOL_ACTION placeNoConnect
Definition: ee_actions.h:84
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition: sch_rtree.h:243
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:315
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:354
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:1636
void ClearPreview()
Definition: view.cpp:1658
void RecacheAllItems()
Rebuild GAL display lists.
Definition: view.cpp:1415
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1680
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
Define a library symbol object.
Definition: lib_symbol.h:99
static SYMBOL_LIB_TABLE * SchSymbolLibTable(PROJECT *aProject)
Accessor for project symbol library table.
static SYMBOL_LIBS * SchLibs(PROJECT *aProject)
Definition: project_sch.cpp:90
These settings were stored in SCH_BASE_FRAME previously.
Holds all the data relating to one schematic.
Definition: schematic.h:75
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:287
SCH_SHEET_LIST & GetFullHierarchy() const
Return the full schematic flattened hierarchical sheet list.
Definition: schematic.cpp:592
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:100
SCH_SHEET & Root() const
Definition: schematic.h:105
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:49
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:41
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) 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:367
STROKE_PARAMS m_lastTextboxStroke
GR_TEXT_V_ALIGN_T m_lastTextboxVJustify
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
void initSharedInstancePageNumbers(const SCH_SHEET_PATH &aAddedSheet)
Set up handlers for various events.
std::vector< PICKED_SYMBOL > m_powerHistoryList
int SingleClickPlace(const TOOL_EVENT &aEvent)
SCH_LINE * findWire(const VECTOR2I &aPosition)
void sizeSheet(SCH_SHEET *aSheet, const VECTOR2I &aPos)
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
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)
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...
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
void SelectUnit(SCH_SYMBOL *aSymbol, int aUnit)
Definition: picksymbol.cpp:93
bool EditSheetProperties(SCH_SHEET *aSheet, SCH_SHEET_PATH *aHierarchy, bool *aClearAnnotationNewItems)
Edit an existing sheet or add a new sheet to the schematic.
Definition: sheet.cpp:591
void UpdateHierarchyNavigator()
Update the hierarchy navigation tree and history.
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:52
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Definition: sch_label.cpp:1947
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:165
virtual bool IsConnectable() const
Definition: sch_item.h:389
SCHEMATIC * Schematic() const
Searches the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:113
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction)
Definition: sch_item.h:490
virtual void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual)
Definition: sch_item.h:488
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:94
bool AutoRotateOnPlacement() const
autoRotateOnPlacement
Definition: sch_label.cpp:1408
SPIN_STYLE GetSpinStyle() const
Definition: sch_label.cpp:372
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition: sch_label.h:168
LABEL_FLAG_SHAPE GetShape() const
Definition: sch_label.h:167
void SetAutoRotateOnPlacement(bool autoRotate=true)
setAutoRotateOnPlacement
Definition: sch_label.cpp:1413
std::vector< SCH_FIELD > & GetFields()
Definition: sch_label.h:191
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Definition: sch_label.cpp:337
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:40
bool IsWire() const
Return true if the line is a wire.
Definition: sch_line.cpp:985
VECTOR2I GetEndPoint() const
Definition: sch_line.h:145
VECTOR2I GetStartPoint() const
Definition: sch_line.h:140
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:109
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:389
bool IsExplicitJunctionAllowed(const VECTOR2I &aPosition) const
Indicates that a juction dot may be placed at the given location.
Definition: sch_screen.cpp:703
void SetPosition(const VECTOR2I &aPos) override
Definition: sch_shape.h:78
void CalcEdit(const VECTOR2I &aPosition)
Definition: sch_shape.h:84
bool ContinueEdit(const VECTOR2I &aPosition)
Definition: sch_shape.h:83
void BeginEdit(const VECTOR2I &aStartPoint)
Definition: sch_shape.h:82
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_shape.cpp:46
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: sch_shape.cpp:63
void EndEdit()
Definition: sch_shape.h:85
wxString GetClass() const override
Return the class name.
Definition: sch_shape.h:42
STROKE_PARAMS GetStroke() const override
Definition: sch_shape.h:64
VECTOR2I GetPosition() const override
Definition: sch_shape.h:77
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()
wxString GetPageNumber() const
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:372
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_sheet.cpp:156
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
Definition: sch_sheet.cpp:952
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:375
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:162
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual) override
Definition: sch_sheet.cpp:609
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:935
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:181
Schematic symbol object.
Definition: sch_symbol.h:109
int GetUnitCount() const
Return the number of units per package of the symbol.
Definition: sch_symbol.cpp:483
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual) override
Automatically orient all the fields in the symbol.
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_symbol.h:814
int GetUnit() const
Definition: sch_symbol.h:258
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
void ClearAnnotation(const SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear exiting symbol annotation.
void SetUnit(int aUnit)
Change the unit number to aUnit.
Definition: sch_symbol.cpp:452
const LIB_ID & GetLibId() const
Definition: sch_symbol.h:203
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
Set the selected unit of this symbol on one sheet.
Definition: sch_symbol.cpp:892
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:222
void SetRowHeight(int aRow, int aHeight)
Definition: sch_table.h:123
void SetColCount(int aCount)
Definition: sch_table.h:105
void SetColWidth(int aCol, int aWidth)
Definition: sch_table.h:113
void AddCell(SCH_TABLECELL *aCell)
Definition: sch_table.h:148
VECTOR2I GetPosition() const override
Definition: sch_table.cpp:117
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
Definition: sch_table.h:190
void ClearCells()
Definition: sch_table.h:160
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_table.h:209
void SetPosition(const VECTOR2I &aPos) override
Definition: sch_table.cpp:111
void Normalize()
Definition: sch_table.cpp:137
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:269
int AddItemToSel(const TOOL_EVENT &aEvent)
void UnbrightenItem(EDA_ITEM *aItem)
virtual void Add(EDA_ITEM *aItem)
Definition: selection.cpp:42
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition: selection.h:99
EDA_ITEM * Front() const
Definition: selection.h:208
virtual void Clear() override
Remove all the stored items from the group.
Definition: selection.h:92
int Size() const
Returns the number of selected parts.
Definition: selection.h:115
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:216
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).
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:145
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:230
void VetoContextMenuMouseWarp()
Disable mouse warping after the current context menu is closed.
Definition: tool_manager.h:517
CONDITIONAL_MENU & GetMenu()
Definition: tool_menu.cpp:44
void ShowContextMenu(SELECTION &aSelection)
Helper function to set and immediately show a CONDITIONAL_MENU in concert with the given SELECTION.
Definition: tool_menu.cpp:57
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: wx_infobar.cpp:187
This file is part of the common library.
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:435
std::vector< EDA_ITEM * > EDA_ITEMS
Define list of drawing items for screens.
Definition: eda_item.h:529
#define IS_NEW
New item, just created.
#define STRUCT_DELETED
flag indication structures to be erased
#define IS_MOVING
Item being moved.
SHAPE_T
Definition: eda_shape.h:42
FILL_T
Definition: eda_shape.h:54
@ ID_POPUP_SCH_SELECT_UNIT
Definition: eeschema_id.h:82
@ ID_POPUP_SCH_SELECT_UNIT_END
Definition: eeschema_id.h:86
GRID_HELPER_GRIDS
Definition: grid_helper.h:37
@ GRID_TEXT
Definition: grid_helper.h:44
@ GRID_GRAPHICS
Definition: grid_helper.h:45
@ GRID_CONNECTABLE
Definition: grid_helper.h:41
static const std::string KiCadSchematicFileExtension
@ LAYER_HIERLABEL
Definition: layer_ids.h:360
@ LAYER_GLOBLABEL
Definition: layer_ids.h:359
@ LAYER_NOTES
Definition: layer_ids.h:369
@ LAYER_LOCLABEL
Definition: layer_ids.h:358
@ LAYER_NETCLASS_REFS
Definition: layer_ids.h:367
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition: gtk/ui.cpp:594
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.
#define SKIP_CONNECTIVITY
Definition: sch_commit.h:43
LABEL_FLAG_SHAPE
Definition: sch_label.h:91
@ F_ROUND
Definition: sch_label.h:100
@ L_INPUT
Definition: sch_label.h:92
ANNOTATE_ORDER_T
Schematic annotation order options.
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.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:119
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:48
constexpr int MilsToIU(int mils) const
Definition: base_units.h:94
LIB_ID LibId
Definition: sch_screen.h:80
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:148
@ SCH_NO_CONNECT_T
Definition: typeinfo.h:145
@ SCH_SYMBOL_T
Definition: typeinfo.h:160
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:158
@ SCH_SHEET_T
Definition: typeinfo.h:162
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:161
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:146
@ SCH_JUNCTION_T
Definition: typeinfo.h:144
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588
Definition of file extensions used in Kicad.