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