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