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, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <eda_shape.h>
22#include <tool/tool_manager.h>
23#include "sch_sheet_path.h"
24#include <limits>
25#include <memory>
26#include <set>
27#include <unordered_set>
28
29#include <advanced_config.h>
31#include <kiplatform/ui.h>
32#include <optional>
33#include <project_sch.h>
41#include <sch_actions.h>
42#include <sch_tool_utils.h>
43#include <sch_edit_frame.h>
44#include <widgets/wx_infobar.h>
45#include <pgm_base.h>
46#include <design_block.h>
48#include <eeschema_id.h>
49#include <confirm.h>
50#include <view/view_controls.h>
51#include <view/view.h>
52#include <sch_symbol.h>
53#include <sch_no_connect.h>
54#include <sch_group.h>
55#include <sch_line.h>
56#include <sch_junction.h>
57#include <sch_bus_entry.h>
58#include <sch_table.h>
59#include <sch_tablecell.h>
60#include <sch_sheet.h>
61#include <sch_sheet_pin.h>
62#include <sch_label.h>
63#include <sch_bitmap.h>
64#include <schematic.h>
65#include <sch_commit.h>
66#include <scoped_set_reset.h>
68#include <eeschema_settings.h>
75#include <string_utils.h>
77#include <wx/filedlg.h>
78#include <wx/msgdlg.h>
79
80
82
83
101
102
104{
106
107 auto belowRootSheetCondition =
108 [this]( const SELECTION& aSel )
109 {
110 return m_frame->GetCurrentSheet().Last() != &m_frame->Schematic().Root();
111 };
112
113 // some interactive drawing tools can undo the last point
114 auto canUndoPoint =
115 [this]( const SELECTION& aSel )
116 {
117 return ( m_mode == MODE::RULE_AREA );
118 };
119
120 auto inDrawingRuleArea =
121 [this]( const SELECTION& aSel )
122 {
123 return m_mode == MODE::RULE_AREA;
124 };
125
126 CONDITIONAL_MENU& ctxMenu = m_menu->GetMenu();
127
128 // clang-format off
129 ctxMenu.AddItem( SCH_ACTIONS::leaveSheet, belowRootSheetCondition, 150 );
130 ctxMenu.AddItem( SCH_ACTIONS::closeOutline, inDrawingRuleArea, 200 );
131 ctxMenu.AddItem( ACTIONS::deleteLastPoint, canUndoPoint, 200 );
132 // clang-format on
133
134 return true;
135}
136
137
139{
141
142 SCH_SYMBOL* symbol = toolParams.m_Symbol;
143
144 // If we get a parameterised symbol, we probably just want to place that and get out of the placement tool,
145 // rather than popping up the chooser afterwards. A multi-unit symbol may still request that its remaining
146 // units be placed before the tool exits.
147 bool placeOneOnly = symbol != nullptr;
148
150 std::vector<PICKED_SYMBOL>* historyList = nullptr;
151 bool ignorePrimePosition = false;
152 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
153 SCHEMATIC_SETTINGS& schSettings = m_frame->Schematic().Settings();
154 SCH_SCREEN* screen = m_frame->GetScreen();
155 bool keepSymbol = false;
156 bool placeAllUnits = toolParams.m_PlaceAllUnits;
157
158 if( m_inDrawingTool )
159 return 0;
160
162
165 VECTOR2I cursorPos;
166
167 // First we need to get all instances of this sheet so we can annotate whatever symbols we place on all copies
168 SCH_SHEET_LIST hierarchy = m_frame->Schematic().Hierarchy();
169 SCH_SHEET_LIST newInstances = hierarchy.FindAllSheetsForScreen( m_frame->GetCurrentSheet().LastScreen() );
170 newInstances.SortByPageNumbers();
171
172 // Get a list of all references in the schematic to avoid duplicates wherever they're placed
173 SCH_REFERENCE_LIST existingRefs;
174 hierarchy.GetSymbols( existingRefs, SYMBOL_FILTER_ALL );
175 existingRefs.SortByReferenceOnly();
176
177 if( aEvent.IsAction( &SCH_ACTIONS::placeSymbol ) )
178 {
179 historyList = &m_symbolHistoryList;
180 }
181 else if (aEvent.IsAction( &SCH_ACTIONS::placePower ) )
182 {
183 historyList = &m_powerHistoryList;
184 filter.FilterPowerSymbols( true );
185 }
186 else
187 {
188 wxFAIL_MSG( "PlaceSymbol(): unexpected request" );
189 }
190
191 TOOL_EVENT originalEvent = aEvent; // This can change out from under us when the event loop runs
192 SCOPED_TOOL_PUSHER raii( m_frame, originalEvent );
193
194 auto addSymbol =
195 [this]( SCH_SYMBOL* aSymbol )
196 {
198 m_selectionTool->AddItemToSel( aSymbol );
199
200 aSymbol->SetFlags( IS_NEW | IS_MOVING );
201
202 m_view->ClearPreview();
203 m_view->AddToPreview( aSymbol, false ); // Add, but not give ownership
204
205 // Set IS_MOVING again, as AddItemToCommitAndScreen() will have cleared it.
206 aSymbol->SetFlags( IS_MOVING );
207 m_toolMgr->PostAction( ACTIONS::refreshPreview );
208 };
209
210 auto setCursor =
211 [&]()
212 {
213 m_frame->GetCanvas()->SetCurrentCursor( symbol ? KICURSOR::MOVING : KICURSOR::COMPONENT );
214 };
215
216 auto cleanup =
217 [&]()
218 {
220 m_view->ClearPreview();
221 delete symbol;
222 symbol = nullptr;
223
224 existingRefs.Clear();
225 hierarchy.GetSymbols( existingRefs, SYMBOL_FILTER_ALL );
226 existingRefs.SortByReferenceOnly();
227 };
228
229 auto annotate =
230 [&]()
231 {
232 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
233
234 // Then we need to annotate all instances by sheet
235 for( SCH_SHEET_PATH& instance : newInstances )
236 {
237 SCH_REFERENCE newReference( symbol, instance );
239 refs.AddItem( newReference );
240 refs.SetRefDesTracker( schSettings.m_refDesTracker );
241
242 if( cfg->m_AnnotatePanel.automatic || newReference.AlwaysAnnotate() )
243 {
245 (ANNOTATE_ALGO_T) schSettings.m_AnnotateMethod,
246 schSettings.m_AnnotateStartNum, existingRefs, false,
247 &hierarchy );
248
249 refs.UpdateAnnotation();
250
251 // Update existing refs for next iteration
252 for( size_t i = 0; i < refs.GetCount(); i++ )
253 existingRefs.AddItem( refs[i] );
254 }
255 }
256
257 m_frame->GetCurrentSheet().UpdateAllScreenReferences();
258 };
259
260 Activate();
261
262 // Must be done after Activate() so that it gets set into the correct context
263 getViewControls()->ShowCursor( true );
264
265 // Set initial cursor
266 setCursor();
267
268 // Prime the pump
269 if( symbol )
270 {
271 addSymbol( symbol );
272
273 if( toolParams.m_Reannotate )
274 annotate();
275
276 // Seed the placed-reference list so multi-unit stepping sees this symbol's first unit
277 // as taken. The chooser path seeds it when it builds the symbol; this path bypasses
278 // that branch.
279 SCH_REFERENCE placedSymbolReference( symbol, m_frame->GetCurrentSheet() );
280 existingRefs.AddItem( placedSymbolReference );
281 existingRefs.SortByReferenceOnly();
282
283 getViewControls()->WarpMouseCursor( getViewControls()->GetMousePosition( false ) );
284 }
285 else if( aEvent.HasPosition() )
286 {
287 m_toolMgr->PrimeTool( aEvent.Position() );
288 }
289 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
290 {
291 m_toolMgr->PrimeTool( { 0, 0 } );
292 ignorePrimePosition = true;
293 }
294
295 // Main loop: keep receiving events
296 while( TOOL_EVENT* evt = Wait() )
297 {
298 setCursor();
299 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
300 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
301
302 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
303 controls->ForceCursorPosition( true, cursorPos );
304
305 // The tool hotkey is interpreted as a click when drawing
306 bool isSyntheticClick = symbol && evt->IsActivate() && evt->HasPosition() && evt->Matches( aEvent );
307
308 if( evt->IsCancelInteractive() || ( symbol && evt->IsAction( &ACTIONS::undo ) ) )
309 {
310 m_frame->GetInfoBar()->Dismiss();
311
312 if( symbol )
313 {
314 cleanup();
315
316 if( keepSymbol )
317 {
318 // Re-enter symbol chooser
319 m_toolMgr->PostAction( ACTIONS::cursorClick );
320 }
321 }
322 else
323 {
324 break;
325 }
326 }
327 else if( evt->IsActivate() && !isSyntheticClick )
328 {
329 if( symbol && evt->IsMoveTool() )
330 {
331 // we're already moving our own item; ignore the move tool
332 evt->SetPassEvent( false );
333 continue;
334 }
335
336 if( symbol )
337 {
338 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel symbol creation." ) );
339 evt->SetPassEvent( false );
340 continue;
341 }
342
343 if( evt->IsMoveTool() )
344 {
345 // Make sure we come back after the move tool runs
346 frame()->PushTool( originalEvent );
347 }
348
349 break;
350 }
351 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
352 || isSyntheticClick
353 || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick ) )
354 {
355 if( !symbol )
356 {
358
361
362 std::set<UTF8> unique_libid;
363 std::vector<PICKED_SYMBOL> alreadyPlaced;
364
365 for( SCH_SHEET_PATH& sheet : hierarchy )
366 {
367 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
368 {
369 SCH_SYMBOL* s = static_cast<SCH_SYMBOL*>( item );
370
371 if( !unique_libid.insert( s->GetLibId().Format() ).second )
372 continue;
373
374 LIB_SYMBOL* libSymbol = SchGetLibSymbol( s->GetLibId(), libs, cache );
375
376 if( libSymbol )
377 {
378 if( libSymbol->IsPower() != filter.GetFilterPowerSymbols() )
379 continue;
380
381 PICKED_SYMBOL pickedSymbol;
382 pickedSymbol.LibId = libSymbol->GetLibId();
383 alreadyPlaced.push_back( pickedSymbol );
384 }
385 }
386 }
387
388 // Pick the symbol to be placed
389 bool footprintPreviews = m_frame->eeconfig()->m_Appearance.footprint_preview;
390 PICKED_SYMBOL sel = m_frame->PickSymbolFromLibrary( &filter, *historyList, alreadyPlaced,
391 footprintPreviews );
392
393 keepSymbol = sel.KeepSymbol;
394 placeAllUnits = sel.PlaceAllUnits;
395
396 LIB_SYMBOL* libSymbol = sel.LibId.IsValid() ? m_frame->GetLibSymbol( sel.LibId ) : nullptr;
397
398 if( !libSymbol )
399 continue;
400
401 // If we started with a hotkey which has a position then warp back to that.
402 // Otherwise update to the current mouse position pinned inside the autoscroll
403 // boundaries.
404 if( evt->IsPrime() && !ignorePrimePosition )
405 {
406 cursorPos = grid.Align( evt->Position(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
407 getViewControls()->WarpMouseCursor( cursorPos, true );
408 }
409 else
410 {
412 cursorPos = grid.Align( getViewControls()->GetMousePosition(),
414 }
415
416 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
417
418 // Only convert between power symbol types. Regular (non-power) symbols must
419 // never be promoted to power symbols just because the default is set to
420 // Global or Local. The preference's Default option means "follow the symbol
421 // definition" and any conversion only applies to symbols that are already
422 // power symbols.
423 if( libSymbol->IsPower()
424 && !libSymbol->IsLocalPower()
426 {
427 libSymbol->SetLocalPower();
428 wxString keywords = libSymbol->GetKeyWords();
429
430 // Adjust the KiCad library default fields to match the new power symbol type
431 if( keywords.Contains( wxT( "global power" ) ) )
432 {
433 keywords.Replace( wxT( "global power" ), wxT( "local power" ) );
434 libSymbol->SetKeyWords( keywords );
435 }
436
437 wxString desc = libSymbol->GetDescription();
438
439 if( desc.Contains( wxT( "global label" ) ) )
440 {
441 desc.Replace( wxT( "global label" ), wxT( "local label" ) );
442 libSymbol->SetDescription( desc );
443 }
444 }
445 else if( libSymbol->IsPower()
446 && !libSymbol->IsGlobalPower()
448 {
449 // We do not currently have local power symbols in the KiCad library, so
450 // don't update any fields
451 libSymbol->SetGlobalPower();
452 }
453
454 symbol = new SCH_SYMBOL( *libSymbol, &m_frame->GetCurrentSheet(), sel, cursorPos,
455 &m_frame->Schematic() );
456 addSymbol( symbol );
457 annotate();
458
459 // Update the list of references for the next symbol placement.
460 SCH_REFERENCE placedSymbolReference( symbol, m_frame->GetCurrentSheet() );
461 existingRefs.AddItem( placedSymbolReference );
462 existingRefs.SortByReferenceOnly();
463
464 if( m_frame->eeconfig()->m_AutoplaceFields.enable )
465 {
466 // Not placed yet, so pass a nullptr screen reference
467 symbol->AutoplaceFields( nullptr, AUTOPLACE_AUTO );
468 }
469
470 // Update cursor now that we have a symbol
471 setCursor();
472 }
473 else
474 {
475 m_view->ClearPreview();
476 m_frame->AddToScreen( symbol, screen );
477
478 if( m_frame->eeconfig()->m_AutoplaceFields.enable )
479 symbol->AutoplaceFields( screen, AUTOPLACE_AUTO );
480
481 m_frame->SaveCopyForRepeatItem( symbol );
482
483 SCH_COMMIT commit( m_toolMgr );
484 commit.Added( symbol, screen );
485
487 lwbTool->TrimOverLappingWires( &commit, &m_selectionTool->GetSelection() );
488 lwbTool->AddJunctionsIfNeeded( &commit, &m_selectionTool->GetSelection() );
489
490 commit.Push( _( "Place Symbol" ) );
491
492 // A preselected single-unit symbol exits here rather than re-opening the
493 // chooser. Multi-unit placement must fall through to the unit continuation
494 // below, which exits once the units are exhausted.
495 if( placeOneOnly && !placeAllUnits )
496 break;
497
498 SCH_SYMBOL* nextSymbol = nullptr;
499
500 if( keepSymbol || placeAllUnits )
501 {
502 SCH_REFERENCE currentReference( symbol, m_frame->GetCurrentSheet() );
503 SCHEMATIC& schematic = m_frame->Schematic();
504
505 if( placeAllUnits )
506 {
507 // For unannotated references all U?-prefix symbols share the same ref
508 // string regardless of the library symbol they originate from. Only
509 // consider units already used by THIS library symbol when stepping
510 // through units, so different multi-unit parts that share a reference
511 // prefix do not collide pre-annotation.
512 const wxString currentRefStr = currentReference.GetRef();
513 const bool isUnannotated = !currentRefStr.IsEmpty() && currentRefStr.Last() == '?';
514 const LIB_ID symLibId = symbol->GetLibId();
515
516 auto unitOccupied =
517 [&]( int aUnit ) -> bool
518 {
519 if( !isUnannotated )
520 {
521 SCH_REFERENCE candidate = currentReference;
522 candidate.SetUnit( aUnit );
523 return schematic.Contains( candidate );
524 }
525
526 return IsUnannotatedUnitOccupied( existingRefs, currentRefStr, symLibId, aUnit );
527 };
528
529 while( currentReference.GetUnit() <= symbol->GetUnitCount()
530 && unitOccupied( currentReference.GetUnit() ) )
531 {
532 currentReference.SetUnit( currentReference.GetUnit() + 1 );
533 }
534
535 if( currentReference.GetUnit() > symbol->GetUnitCount() )
536 {
537 currentReference.SetUnit( 1 );
538 }
539 }
540
541 // We are either stepping to the next unit or next symbol
542 if( keepSymbol || currentReference.GetUnit() > 1 )
543 {
544 nextSymbol = static_cast<SCH_SYMBOL*>( symbol->Duplicate( IGNORE_PARENT_GROUP ) );
545 nextSymbol->SetUnit( currentReference.GetUnit() );
546 nextSymbol->SetUnitSelection( currentReference.GetUnit() );
547
548 addSymbol( nextSymbol );
549 symbol = nextSymbol;
550
551 if( currentReference.GetUnit() == 1 )
552 annotate();
553
554 // Update the list of references for the next symbol placement.
555 SCH_REFERENCE placedSymbolReference( symbol, m_frame->GetCurrentSheet() );
556 existingRefs.AddItem( placedSymbolReference );
557 existingRefs.SortByReferenceOnly();
558 }
559 }
560
561 symbol = nextSymbol;
562
563 // A preselected multi-unit symbol leaves the tool once its last unit is placed.
564 if( placeOneOnly && !symbol )
565 break;
566 }
567 }
568 else if( evt->IsClick( BUT_RIGHT ) )
569 {
570 // Warp after context menu only if dragging...
571 if( !symbol )
572 m_toolMgr->VetoContextMenuMouseWarp();
573
574 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
575 }
576 else if( evt->Category() == TC_COMMAND && evt->Action() == TA_CHOICE_MENU_CHOICE )
577 {
578 if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_UNIT
579 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_UNIT_END )
580 {
581 int unit = *evt->GetCommandId() - ID_POPUP_SCH_SELECT_UNIT;
582
583 if( symbol )
584 {
585 m_frame->SelectUnit( symbol, unit );
586 m_toolMgr->PostAction( ACTIONS::refreshPreview );
587 }
588 }
589 else if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_BODY_STYLE
590 && *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_BODY_STYLE_END )
591 {
592 int bodyStyle = ( *evt->GetCommandId() - ID_POPUP_SCH_SELECT_BODY_STYLE ) + 1;
593
594 if( symbol && symbol->GetBodyStyle() != bodyStyle )
595 {
596 m_frame->SelectBodyStyle( symbol, bodyStyle );
597 m_toolMgr->PostAction( ACTIONS::refreshPreview );
598 }
599 }
600 }
601 else if( evt->IsAction( &ACTIONS::duplicate )
602 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem )
603 || evt->IsAction( &ACTIONS::paste ) )
604 {
605 if( symbol )
606 {
607 wxBell();
608 continue;
609 }
610
611 // Exit. The duplicate/repeat/paste will run in its own loop.
612 evt->SetPassEvent();
613 break;
614 }
615 else if( symbol && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
616 {
617 symbol->SetPosition( cursorPos );
618 m_view->ClearPreview();
619 m_view->AddToPreview( symbol, false ); // Add, but not give ownership
620 m_frame->SetMsgPanel( symbol );
621 }
622 else if( symbol && evt->IsAction( &ACTIONS::doDelete ) )
623 {
624 cleanup();
625 }
626 else if( symbol && ( evt->IsAction( &ACTIONS::redo )
627 || evt->IsAction( &SCH_ACTIONS::editWithLibEdit )
628 || evt->IsAction( &SCH_ACTIONS::changeSymbol ) ) )
629 {
630 wxBell();
631 }
632 else if( symbol
633 && ( evt->IsAction( &SCH_ACTIONS::properties ) || evt->IsAction( &SCH_ACTIONS::editReference )
634 || evt->IsAction( &SCH_ACTIONS::editValue ) || evt->IsAction( &SCH_ACTIONS::editFootprint )
635 || evt->IsAction( &SCH_ACTIONS::autoplaceFields ) || evt->IsAction( &SCH_ACTIONS::cycleBodyStyle )
636 || evt->IsAction( &SCH_ACTIONS::setExcludeFromBOM )
637 || evt->IsAction( &SCH_ACTIONS::setExcludeFromBoard )
638 || evt->IsAction( &SCH_ACTIONS::setExcludeFromSim )
639 || evt->IsAction( &SCH_ACTIONS::setExcludeFromPosFiles ) || evt->IsAction( &SCH_ACTIONS::setDNP )
640 || evt->IsAction( &SCH_ACTIONS::rotateCW ) || evt->IsAction( &SCH_ACTIONS::rotateCCW )
641 || evt->IsAction( &SCH_ACTIONS::mirrorV ) || evt->IsAction( &SCH_ACTIONS::mirrorH ) ) )
642 {
643 m_toolMgr->PostAction( ACTIONS::refreshPreview );
644 evt->SetPassEvent();
645 }
646 else
647 {
648 evt->SetPassEvent();
649 }
650
651 // Enable autopanning and cursor capture only when there is a symbol to be placed
652 getViewControls()->SetAutoPan( symbol != nullptr );
653 getViewControls()->CaptureCursor( symbol != nullptr );
654 }
655
656 getViewControls()->SetAutoPan( false );
657 getViewControls()->CaptureCursor( false );
658 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
659
660 return 0;
661}
662
663
665{
667 SCH_SYMBOL* symbol = params.m_Symbol;
668 int requestedUnit = params.m_Unit;
669
670 // TODO: get from selection
671 if( !symbol )
672 {
673 static const std::vector<KICAD_T> symbolTypes = { SCH_SYMBOL_T };
674 SCH_SELECTION& selection = m_selectionTool->RequestSelection( symbolTypes );
675
676 if( selection.Size() != 1 )
677 {
678 m_frame->ShowInfoBarMsg( _( "Select a single symbol to place the next unit." ) );
679 return 0;
680 }
681
682 wxCHECK( selection.Front()->Type() == SCH_SYMBOL_T, 0 );
683 symbol = static_cast<SCH_SYMBOL*>( selection.Front() );
684 }
685
686 if( !symbol )
687 return 0;
688
689 if( !symbol->IsMultiUnit() )
690 {
691 m_frame->ShowInfoBarMsg( _( "This symbol has only one unit." ) );
692 return 0;
693 }
694
695 const std::set<int> missingUnits = GetUnplacedUnitsForSymbol( *symbol );
696
697 if( missingUnits.empty() )
698 {
699 m_frame->ShowInfoBarMsg( _( "All units of this symbol are already placed." ) );
700 return 0;
701 }
702
703 int nextMissing;
704
705 if( requestedUnit > 0 )
706 {
707 if( missingUnits.count( requestedUnit ) == 0 )
708 {
709 m_frame->ShowInfoBarMsg( _( "Requested unit already placed." ) );
710 return 0;
711 }
712
713 nextMissing = requestedUnit;
714 }
715 else
716 {
717 // Find the lowest unit number that is missing
718 nextMissing = *std::min_element( missingUnits.begin(), missingUnits.end() );
719 }
720
721 std::unique_ptr<SCH_SYMBOL> newSymbol = std::make_unique<SCH_SYMBOL>( *symbol );
722 const SCH_SHEET_PATH& sheetPath = m_frame->GetCurrentSheet();
723
724 // Use SetUnitSelection(int) to update ALL instance references at once.
725 // This is important for shared sheets where the same screen is used by multiple
726 // sheet instances - we want the new symbol unit to appear correctly on all instances.
727 newSymbol->SetUnitSelection( nextMissing );
728 newSymbol->SetUnit( nextMissing );
729 newSymbol->SetRefProp( symbol->GetRef( &sheetPath, false ) );
730
731 // Post the new symbol - don't reannotate it - we set the reference ourselves
732 m_toolMgr->PostAction( SCH_ACTIONS::placeSymbol, SCH_ACTIONS::PLACE_SYMBOL_PARAMS{ newSymbol.release(), false } );
733 return 0;
734}
735
736
744static std::optional<VECTOR2I> designBlockAnchor( const std::vector<SCH_ITEM*>& aItems )
745{
746 std::optional<VECTOR2I> connectionAnchor;
747 std::optional<VECTOR2I> positionAnchor;
748
749 auto keepTopLeft =
750 []( std::optional<VECTOR2I>& aBest, const VECTOR2I& aCandidate )
751 {
752 if( !aBest || aCandidate.y < aBest->y || ( aCandidate.y == aBest->y && aCandidate.x < aBest->x ) )
753 aBest = aCandidate;
754 };
755
756 for( SCH_ITEM* item : aItems )
757 {
758 if( item->Type() == SCH_GROUP_T )
759 continue;
760
761 for( const VECTOR2I& pt : item->GetConnectionPoints() )
762 keepTopLeft( connectionAnchor, pt );
763
764 keepTopLeft( positionAnchor, item->GetPosition() );
765 }
766
767 return connectionAnchor ? connectionAnchor : positionAnchor;
768}
769
770
772{
773 if( m_inDrawingTool )
774 return 0;
775
777
778 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
779 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
780 SCHEMATIC_SETTINGS& schSettings = m_frame->Schematic().Settings();
781 SCH_SCREEN* screen = m_frame->GetScreen();
782 SCH_SHEET_PATH& sheetPath = m_frame->GetCurrentSheet();
783
786 VECTOR2I cursorPos;
787
788 // Guard to reset forced cursor positioning on exit, regardless of error path
789 struct RESET_FORCED_CURSOR_GUARD
790 {
791 KIGFX::VIEW_CONTROLS* m_controls;
792
793 ~RESET_FORCED_CURSOR_GUARD()
794 {
795 m_controls->ForceCursorPosition( false );
796 }
797 };
798
799 RESET_FORCED_CURSOR_GUARD forcedCursorGuard{ controls };
800
801 if( !cfg || !common_settings )
802 return 0;
803
804 bool placingDesignBlock = aEvent.IsAction( &SCH_ACTIONS::placeDesignBlock );
805
806 std::unique_ptr<DESIGN_BLOCK> designBlock;
807 wxString sheetFileName = wxEmptyString;
808
809 if( placingDesignBlock )
810 {
811 SCH_DESIGN_BLOCK_PANE* designBlockPane = m_frame->GetDesignBlockPane();
812
813 if( designBlockPane->GetSelectedLibId().IsValid() )
814 {
815 designBlock.reset( designBlockPane->GetDesignBlock( designBlockPane->GetSelectedLibId(), true, true ) );
816
817 if( !designBlock )
818 return 0;
819
820 sheetFileName = designBlock->GetSchematicFile();
821
822 if( sheetFileName.IsEmpty() || !wxFileExists( sheetFileName ) )
823 {
824 m_frame->ShowInfoBarError( _( "Design block has no schematic to place." ), true );
825 return 0;
826 }
827 }
828 }
829 else
830 {
831 wxString* importSourceFile = aEvent.Parameter<wxString*>();
832
833 if( importSourceFile != nullptr )
834 sheetFileName = *importSourceFile;
835 }
836
837 auto setCursor =
838 [&]()
839 {
840 m_frame->GetCanvas()->SetCurrentCursor( designBlock ? KICURSOR::MOVING
842 };
843
844 auto placeSheetContents =
845 [&]()
846 {
847 SCH_COMMIT commit( m_toolMgr );
848 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
849
850 EDA_ITEMS newItems;
851 bool keepAnnotations = cfg->m_DesignBlockChooserPanel.keep_annotations;
852 bool placeAsGroup = cfg->m_DesignBlockChooserPanel.place_as_group;
853 bool screenWasModified = screen->IsContentModified();
854
855 selectionTool->ClearSelection();
856
857 // Remember existing items so we only select and commit imported items.
858 std::unordered_set<EDA_ITEM*> existingItems;
859
860 for( EDA_ITEM* item : screen->Items() )
861 existingItems.insert( item );
862
863 if( !m_frame->LoadSheetFromFile( sheetPath.Last(), &sheetPath, sheetFileName, true,
864 placingDesignBlock ) )
865 {
866 return false;
867 }
868
869 m_frame->SetSheetNumberAndCount();
870
871 m_frame->SyncView();
872 m_frame->OnModify();
873 m_frame->HardRedraw(); // Full reinit of the current screen and the display.
874
875 SCH_GROUP* group = nullptr;
876
877 if( placeAsGroup )
878 {
879 group = new SCH_GROUP( screen );
880
881 wxString baseName;
882
883 if( designBlock )
884 {
885 baseName = designBlock->GetLibId().GetLibItemName().wx_str();
886 group->SetDesignBlockLibId( designBlock->GetLibId() );
887 }
888 else
889 {
890 baseName = wxFileName( sheetFileName ).GetName();
891 }
892
893 group->SetName( UniqueGroupName( screen, baseName ) );
894 }
895
896 bool autoAnnotate = !keepAnnotations && cfg->m_AnnotatePanel.automatic;
897
898 // Select all new items
899 for( EDA_ITEM* item : screen->Items() )
900 {
901 if( !existingItems.contains( item ) )
902 {
903 // When auto-annotating, preserve original refs so that
904 // AnnotateSymbols can build correct locked groups for
905 // multi-unit symbols before assigning new references.
906 // Clearing first would leave locked groups empty, causing
907 // units from different same-value arrays to get mixed.
908 if( item->Type() == SCH_SYMBOL_T && !keepAnnotations && !autoAnnotate )
909 static_cast<SCH_SYMBOL*>( item )->ClearAnnotation( &sheetPath, false );
910
911 if( item->Type() == SCH_LINE_T )
912 item->SetFlags( STARTPOINT | ENDPOINT );
913
914 if( !item->GetParentGroup() )
915 {
916 if( placeAsGroup )
917 group->AddItem( item );
918
919 newItems.emplace_back( item );
920 }
921
922 commit.Added( item, screen );
923 }
924 }
925
926 if( placeAsGroup )
927 {
928 commit.Add( group, screen );
929 selectionTool->AddItemToSel( group );
930 }
931 else
932 {
933 selectionTool->AddItemsToSel( &newItems, true );
934 }
935
936 cursorPos = grid.Align( controls->GetMousePosition(),
937 grid.GetSelectionGrid( selectionTool->GetSelection() ) );
938 controls->ForceCursorPosition( true, cursorPos );
939
940 std::vector<SCH_ITEM*> blockItems = FlattenGroups( newItems );
941 std::optional<VECTOR2I> anchorPos = designBlockAnchor( blockItems );
942 VECTOR2I delta = anchorPos ? cursorPos - *anchorPos : VECTOR2I( 0, 0 );
943
944 // Will all be SCH_ITEMs as these were pulled from the screen->Items()
945 for( EDA_ITEM* item : newItems )
946 static_cast<SCH_ITEM*>( item )->Move( delta );
947
948 if( !keepAnnotations || placingDesignBlock )
949 {
950 if( autoAnnotate )
951 {
953 m_frame->AnnotateSymbols( &commit, ANNOTATE_SELECTION,
955 (ANNOTATE_ALGO_T) schSettings.m_AnnotateMethod,
956 true /* recursive */,
957 schSettings.m_AnnotateStartNum,
958 true /* aResetAnnotation */,
959 false, false, reporter );
960 }
961
962 // Annotation will clear selection, so we need to restore it
963 for( EDA_ITEM* item : newItems )
964 {
965 if( item->Type() == SCH_LINE_T )
966 item->SetFlags( STARTPOINT | ENDPOINT );
967 }
968
969 if( placeAsGroup )
970 selectionTool->AddItemToSel( group );
971 else
972 selectionTool->AddItemsToSel( &newItems, true );
973 }
974
975 // IS_NEW is what makes the move tool use the reference point set below, and
976 // IS_MOVING stops the selection tool replacing it on the way there.
977 for( SCH_ITEM* item : blockItems )
978 item->SetFlags( IS_NEW | IS_MOVING );
979
980 if( group )
981 group->SetFlags( IS_NEW | IS_MOVING );
982
983 selectionTool->GetSelection().SetReferencePoint( cursorPos );
984
985 // Start moving selection, cancel undoes the insertion
986 bool placed = m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit );
987
988 // Update our cursor position to the new location in case we're placing repeated copies
989 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
990
991 if( placed )
992 {
993 commit.Push( placingDesignBlock ? _( "Add Design Block" )
994 : _( "Import Schematic Sheet Content" ) );
995 }
996 else
997 {
998 commit.Revert();
999 screen->SetContentModified( screenWasModified );
1000 }
1001
1002 selectionTool->RebuildSelection();
1003 m_frame->UpdateHierarchyNavigator();
1004
1005 return placed;
1006 };
1007
1008 // Whether we are placing the sheet as a sheet, or as its contents, we need to get a filename
1009 // if we weren't provided one
1010 if( sheetFileName.IsEmpty() )
1011 {
1012 wxString path;
1013 wxString file;
1014
1015 if (!placingDesignBlock)
1016 {
1017 if( sheetFileName.IsEmpty() )
1018 {
1019 path = wxPathOnly( m_frame->Prj().GetProjectFullName() );
1020 file = wxEmptyString;
1021 }
1022 else
1023 {
1024 path = wxPathOnly( sheetFileName );
1025 file = wxFileName( sheetFileName ).GetFullName();
1026 }
1027
1028 // Open file chooser dialog even if we have been provided a file so the user
1029 // can select the options they want
1030 wxFileDialog dlg( m_frame, _( "Choose Schematic" ), path, file,
1031 FILEEXT::KiCadSchematicFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
1032
1033 FILEDLG_IMPORT_SHEET_CONTENTS dlgHook( cfg );
1034 dlg.SetCustomizeHook( dlgHook );
1035
1037
1038 if( dlg.ShowModal() == wxID_CANCEL )
1039 return 0;
1040
1041 sheetFileName = dlg.GetPath();
1042
1043 m_frame->GetDesignBlockPane()->UpdateCheckboxes();
1044 }
1045
1046 if( sheetFileName.IsEmpty() )
1047 return 0;
1048 }
1049
1050 // If we're placing sheet contents, we don't even want to run our tool loop, just add the items
1051 // to the canvas and run the move tool
1053 {
1054 while( placeSheetContents() && cfg->m_DesignBlockChooserPanel.repeated_placement )
1055 {}
1056
1057 m_toolMgr->RunAction( ACTIONS::selectionClear );
1058 m_view->ClearPreview();
1059 return 0;
1060 }
1061
1062 // We're placing a sheet as a sheet, we need to run a small tool loop to get the starting
1063 // coordinate of the sheet drawing
1064 SCOPED_TOOL_PUSHER raii( m_frame, aEvent );
1065
1066 Activate();
1067
1068 // Must be done after Activate() so that it gets set into the correct context
1069 getViewControls()->ShowCursor( true );
1070
1071 // Set initial cursor
1072 setCursor();
1073
1074 if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
1075 m_toolMgr->PrimeTool( { 0, 0 } );
1076
1077 // Main loop: keep receiving events
1078 while( TOOL_EVENT* evt = Wait() )
1079 {
1080 setCursor();
1081 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1082 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1083
1084 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
1085 controls->ForceCursorPosition( true, cursorPos );
1086
1087 // The tool hotkey is interpreted as a click when drawing
1088 bool isSyntheticClick = designBlock && evt->IsActivate() && evt->HasPosition() && evt->Matches( aEvent );
1089
1090 if( evt->IsCancelInteractive() || ( designBlock && evt->IsAction( &ACTIONS::undo ) ) )
1091 {
1092 m_frame->GetInfoBar()->Dismiss();
1093 break;
1094 }
1095 else if( evt->IsActivate() && !isSyntheticClick )
1096 {
1097 m_frame->GetInfoBar()->Dismiss();
1098 break;
1099 }
1100 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
1101 || isSyntheticClick
1102 || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick ) )
1103 {
1104 if( placingDesignBlock )
1105 {
1106 // drawSheet must delete designBlock
1107 m_toolMgr->PostAction( SCH_ACTIONS::drawSheetFromDesignBlock, designBlock.release() );
1108 }
1109 else
1110 {
1111 // drawSheet must delete sheetFileName
1112 m_toolMgr->PostAction( SCH_ACTIONS::drawSheetFromFile, new wxString( sheetFileName ) );
1113 }
1114
1115 break;
1116 }
1117 else if( evt->IsClick( BUT_RIGHT ) )
1118 {
1119 // Warp after context menu only if dragging...
1120 if( !designBlock )
1121 m_toolMgr->VetoContextMenuMouseWarp();
1122
1123 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
1124 }
1125 else if( evt->IsAction( &ACTIONS::duplicate )
1126 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem ) )
1127 {
1128 wxBell();
1129 }
1130 else
1131 {
1132 evt->SetPassEvent();
1133 }
1134 }
1135
1136 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1137 return 0;
1138}
1139
1140
1142{
1143 SCH_BITMAP* image = aEvent.Parameter<SCH_BITMAP*>();
1144 bool immediateMode = image != nullptr;
1145 bool ignorePrimePosition = false;
1146 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
1147
1148 if( m_inDrawingTool )
1149 return 0;
1150
1152
1155 VECTOR2I cursorPos;
1156
1157 m_toolMgr->RunAction( ACTIONS::selectionClear );
1158
1159 // Add all the drawable symbols to preview
1160 if( image )
1161 {
1162 image->SetPosition( getViewControls()->GetCursorPosition() );
1163 m_view->ClearPreview();
1164 m_view->AddToPreview( image, false ); // Add, but not give ownership
1165 }
1166
1167 TOOL_EVENT originalEvent = aEvent; // This can change out from under us when the event loop runs
1168 SCOPED_TOOL_PUSHER raii( m_frame, originalEvent );
1169
1170 auto setCursor =
1171 [&]()
1172 {
1173 if( image )
1174 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::MOVING );
1175 else
1176 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1177 };
1178
1179 auto cleanup =
1180 [&]()
1181 {
1182 m_toolMgr->RunAction( ACTIONS::selectionClear );
1183 m_view->ClearPreview();
1184 m_view->RecacheAllItems();
1185 delete image;
1186 image = nullptr;
1187 };
1188
1189 Activate();
1190
1191 // Must be done after Activate() so that it gets set into the correct context
1192 getViewControls()->ShowCursor( true );
1193
1194 // Set initial cursor
1195 setCursor();
1196
1197 // Prime the pump
1198 if( image )
1199 {
1200 m_toolMgr->PostAction( ACTIONS::refreshPreview );
1201 }
1202 else if( aEvent.HasPosition() )
1203 {
1204 m_toolMgr->PrimeTool( aEvent.Position() );
1205 }
1206 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate() )
1207 {
1208 m_toolMgr->PrimeTool( { 0, 0 } );
1209 ignorePrimePosition = true;
1210 }
1211
1212 // Main loop: keep receiving events
1213 while( TOOL_EVENT* evt = Wait() )
1214 {
1215 setCursor();
1216 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1217 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1218
1219 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
1220 controls->ForceCursorPosition( true, cursorPos );
1221
1222 // The tool hotkey is interpreted as a click when drawing
1223 bool isSyntheticClick = image && evt->IsActivate() && evt->HasPosition() && evt->Matches( aEvent );
1224
1225 if( evt->IsCancelInteractive() || ( image && evt->IsAction( &ACTIONS::undo ) ) )
1226 {
1227 m_frame->GetInfoBar()->Dismiss();
1228
1229 if( image )
1230 cleanup();
1231 else
1232 break;
1233
1234 if( immediateMode )
1235 break;
1236 }
1237 else if( evt->IsActivate() && !isSyntheticClick )
1238 {
1239 if( image && evt->IsMoveTool() )
1240 {
1241 // we're already moving our own item; ignore the move tool
1242 evt->SetPassEvent( false );
1243 continue;
1244 }
1245
1246 if( image )
1247 {
1248 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel image creation." ) );
1249 evt->SetPassEvent( false );
1250 continue;
1251 }
1252
1253 if( evt->IsMoveTool() )
1254 {
1255 // Make sure we come back after the move tool is done
1256 m_frame->PushTool( originalEvent );
1257 }
1258
1259 break;
1260 }
1261 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
1262 || isSyntheticClick
1263 || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick ) )
1264 {
1265 if( !image )
1266 {
1267 m_toolMgr->RunAction( ACTIONS::selectionClear );
1268
1269 wxFileDialog dlg( m_frame, _( "Choose Image" ), m_mruPath, wxEmptyString, FILEEXT::ImageFileWildcard(),
1270 wxFD_OPEN );
1271
1273
1274 bool cancelled = false;
1275
1277 [&]()
1278 {
1279 cancelled = dlg.ShowModal() != wxID_OK;
1280 } );
1281
1282 if( cancelled )
1283 continue;
1284
1285 // If we started with a hotkey which has a position then warp back to that.
1286 // Otherwise update to the current mouse position pinned inside the autoscroll
1287 // boundaries.
1288 if( evt->IsPrime() && !ignorePrimePosition )
1289 {
1290 cursorPos = grid.Align( evt->Position() );
1291 getViewControls()->WarpMouseCursor( cursorPos, true );
1292 }
1293 else
1294 {
1296 cursorPos = getViewControls()->GetMousePosition();
1297 }
1298
1299 wxString fullFilename = dlg.GetPath();
1300 m_mruPath = wxPathOnly( fullFilename );
1301
1302 if( wxFileExists( fullFilename ) )
1303 image = new SCH_BITMAP( cursorPos );
1304
1305 if( !image || !image->GetReferenceImage().ReadImageFile( fullFilename ) )
1306 {
1307 wxMessageBox( wxString::Format( _( "Could not load image from '%s'." ), fullFilename ) );
1308 delete image;
1309 image = nullptr;
1310 continue;
1311 }
1312
1313 image->SetFlags( IS_NEW | IS_MOVING );
1314
1315 m_frame->SaveCopyForRepeatItem( image );
1316
1317 m_view->ClearPreview();
1318 m_view->AddToPreview( image, false ); // Add, but not give ownership
1319 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
1320
1321 m_selectionTool->AddItemToSel( image );
1322
1323 getViewControls()->SetCursorPosition( cursorPos, false );
1324 setCursor();
1325 }
1326 else
1327 {
1328 SCH_COMMIT commit( m_toolMgr );
1329 commit.Add( image, m_frame->GetScreen() );
1330 commit.Push( _( "Place Image" ) );
1331
1332 image = nullptr;
1334
1335 m_view->ClearPreview();
1336
1337 if( immediateMode )
1338 break;
1339 }
1340 }
1341 else if( evt->IsClick( BUT_RIGHT ) )
1342 {
1343 // Warp after context menu only if dragging...
1344 if( !image )
1345 m_toolMgr->VetoContextMenuMouseWarp();
1346
1347 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
1348 }
1349 else if( evt->IsAction( &ACTIONS::duplicate )
1350 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem )
1351 || evt->IsAction( &ACTIONS::paste ) )
1352 {
1353 if( image )
1354 {
1355 // This doesn't really make sense; we'll just end up dragging a stack of
1356 // objects so we ignore the duplicate and just carry on.
1357 wxBell();
1358 continue;
1359 }
1360
1361 // Exit. The duplicate/repeat/paste will run in its own loop.
1362 evt->SetPassEvent();
1363 break;
1364 }
1365 else if( image && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
1366 {
1367 image->SetPosition( cursorPos );
1368 m_view->ClearPreview();
1369 m_view->AddToPreview( image, false ); // Add, but not give ownership
1370 m_view->RecacheAllItems(); // Bitmaps are cached in Opengl
1371 m_frame->SetMsgPanel( image );
1372 }
1373 else if( image && evt->IsAction( &ACTIONS::doDelete ) )
1374 {
1375 cleanup();
1376 }
1377 else if( image && evt->IsAction( &ACTIONS::redo ) )
1378 {
1379 wxBell();
1380 }
1381 else
1382 {
1383 evt->SetPassEvent();
1384 }
1385
1386 // Enable autopanning and cursor capture only when there is an image to be placed
1387 getViewControls()->SetAutoPan( image != nullptr );
1388 getViewControls()->CaptureCursor( image != nullptr );
1389 }
1390
1391 getViewControls()->SetAutoPan( false );
1392 getViewControls()->CaptureCursor( false );
1393 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1394
1395 return 0;
1396}
1397
1398
1400{
1401 VECTOR2I cursorPos;
1402 KICAD_T type = aEvent.Parameter<KICAD_T>();
1405 SCH_ITEM* previewItem;
1406 bool loggedInfoBarError = false;
1407 wxString description;
1408 SCH_SCREEN* screen = m_frame->GetScreen();
1409 bool allowRepeat = false; // Set to true to allow new item repetition
1410
1411 if( m_inDrawingTool )
1412 return 0;
1413
1415
1416 if( type == SCH_JUNCTION_T && aEvent.HasPosition() )
1417 {
1418 SCH_SELECTION& selection = m_selectionTool->GetSelection();
1419 SCH_LINE* wire = dynamic_cast<SCH_LINE*>( selection.Front() );
1420
1421 if( wire )
1422 {
1423 SEG seg( wire->GetStartPoint(), wire->GetEndPoint() );
1424 VECTOR2I nearest = seg.NearestPoint( getViewControls()->GetCursorPosition() );
1425 getViewControls()->SetCrossHairCursorPosition( nearest, false );
1426 getViewControls()->WarpMouseCursor( getViewControls()->GetCursorPosition(), true );
1427 }
1428 }
1429
1430 switch( type )
1431 {
1432 case SCH_NO_CONNECT_T:
1433 previewItem = new SCH_NO_CONNECT( cursorPos );
1434 previewItem->SetParent( screen );
1435 description = _( "Add No Connect Flag" );
1436 allowRepeat = true;
1437 break;
1438
1439 case SCH_JUNCTION_T:
1440 previewItem = new SCH_JUNCTION( cursorPos );
1441 previewItem->SetParent( screen );
1442 description = _( "Add Junction" );
1443 break;
1444
1446 previewItem = new SCH_BUS_WIRE_ENTRY( cursorPos );
1447 previewItem->SetParent( screen );
1448 description = _( "Add Wire to Bus Entry" );
1449 allowRepeat = true;
1450 break;
1451
1452 default:
1453 wxASSERT_MSG( false, "Unknown item type in SCH_DRAWING_TOOLS::SingleClickPlace" );
1454 return 0;
1455 }
1456
1457 m_toolMgr->RunAction( ACTIONS::selectionClear );
1458
1459 cursorPos = aEvent.HasPosition() ? aEvent.Position() : controls->GetMousePosition();
1460
1461 TOOL_EVENT originalEvent = aEvent; // This can change out from under us when the event loop runs
1462 SCOPED_TOOL_PUSHER raii( m_frame, originalEvent );
1463
1464 auto setCursor =
1465 [&]()
1466 {
1467 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PLACE );
1468 };
1469
1470 Activate();
1471
1472 // Must be done after Activate() so that it gets set into the correct context
1473 getViewControls()->ShowCursor( true );
1474
1475 // Set initial cursor
1476 setCursor();
1477
1478 m_view->ClearPreview();
1479 m_view->AddToPreview( previewItem->Clone() );
1480
1481 // Prime the pump
1482 if( aEvent.HasPosition() && type != SCH_SHEET_PIN_T )
1483 m_toolMgr->PrimeTool( aEvent.Position() );
1484 else
1485 m_toolMgr->PostAction( ACTIONS::refreshPreview );
1486
1487 // Main loop: keep receiving events
1488 while( TOOL_EVENT* evt = Wait() )
1489 {
1490 setCursor();
1491 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
1492 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
1493
1494 cursorPos = evt->IsPrime() ? evt->Position() : controls->GetMousePosition();
1495 cursorPos = grid.ResolveSnap( cursorPos, grid.GetItemGrid( previewItem ), nullptr ).position;
1496 controls->ForceCursorPosition( true, cursorPos );
1497
1498 if( evt->IsCancelInteractive() )
1499 {
1500 break;
1501 }
1502 else if( evt->IsActivate() )
1503 {
1504 if( evt->IsMoveTool() )
1505 {
1506 // Make sure we come back after the move tool runs
1507 frame()->PushTool( originalEvent );
1508 }
1509
1510 break;
1511 }
1512 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
1513 || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick ) )
1514 {
1515 if( SCH_ITEM* existingItem = screen->GetItem( cursorPos, 0, type ) )
1516 {
1517 // No connects can be "toggled"/removed by clicking on them again
1518 // It helps with not having to fight pin selection ambiguity
1519 if( type == SCH_NO_CONNECT_T )
1520 {
1521 SCH_COMMIT commit( m_toolMgr );
1522 commit.Removed( existingItem, screen );
1523 m_frame->RemoveFromScreen( existingItem, screen );
1524 commit.Push( _( "Remove No Connect Flag" ) );
1525 }
1526 }
1527 else
1528 {
1529 if( type == SCH_JUNCTION_T )
1530 {
1531 if( !screen->IsExplicitJunctionAllowed( cursorPos ) )
1532 {
1533 m_frame->ShowInfoBarError( _( "Junction location contains no joinable wires and/or pins." ) );
1534 loggedInfoBarError = true;
1535 continue;
1536 }
1537 else if( loggedInfoBarError )
1538 {
1539 m_frame->GetInfoBar()->Dismiss();
1540 }
1541 }
1542
1543 if( type == SCH_JUNCTION_T )
1544 {
1545 SCH_COMMIT commit( m_toolMgr );
1547 lwbTool->AddJunction( &commit, screen, cursorPos );
1548
1549 m_frame->Schematic().CleanUp( &commit );
1550
1551 commit.Push( description );
1552 }
1553 else
1554 {
1555 SCH_ITEM* newItem = static_cast<SCH_ITEM*>( previewItem->Clone() );
1556 const_cast<KIID&>( newItem->m_Uuid ) = KIID();
1557 newItem->SetPosition( cursorPos );
1558 newItem->SetFlags( IS_NEW );
1559 m_frame->AddToScreen( newItem, screen );
1560
1561 if( allowRepeat )
1562 m_frame->SaveCopyForRepeatItem( newItem );
1563
1564 SCH_COMMIT commit( m_toolMgr );
1565 commit.Added( newItem, screen );
1566
1567 m_frame->Schematic().CleanUp( &commit );
1568
1569 commit.Push( description );
1570 }
1571 }
1572
1573 if( evt->IsDblClick( BUT_LEFT )
1574 || evt->IsAction( &ACTIONS::cursorDblClick )
1575 || type == SCH_SHEET_PIN_T ) // Finish tool.
1576 {
1577 break;
1578 }
1579 }
1580 else if( evt->IsClick( BUT_RIGHT ) )
1581 {
1582 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
1583 }
1584 else if( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() )
1585 {
1586 previewItem->SetPosition( cursorPos );
1587 m_view->ClearPreview();
1588 m_view->AddToPreview( previewItem->Clone() );
1589 m_frame->SetMsgPanel( previewItem );
1590 }
1591 else if( evt->Category() == TC_COMMAND )
1592 {
1593 if( ( type == SCH_BUS_WIRE_ENTRY_T ) && ( evt->IsAction( &SCH_ACTIONS::rotateCW )
1594 || evt->IsAction( &SCH_ACTIONS::rotateCCW )
1595 || evt->IsAction( &SCH_ACTIONS::mirrorV )
1596 || evt->IsAction( &SCH_ACTIONS::mirrorH ) ) )
1597 {
1598 SCH_BUS_ENTRY_BASE* busItem = static_cast<SCH_BUS_ENTRY_BASE*>( previewItem );
1599
1600 if( evt->IsAction( &SCH_ACTIONS::rotateCW ) )
1601 {
1602 busItem->Rotate( busItem->GetPosition(), false );
1603 }
1604 else if( evt->IsAction( &SCH_ACTIONS::rotateCCW ) )
1605 {
1606 busItem->Rotate( busItem->GetPosition(), true );
1607 }
1608 else if( evt->IsAction( &SCH_ACTIONS::mirrorV ) )
1609 {
1610 busItem->MirrorVertically( busItem->GetPosition().y );
1611 }
1612 else if( evt->IsAction( &SCH_ACTIONS::mirrorH ) )
1613 {
1614 busItem->MirrorHorizontally( busItem->GetPosition().x );
1615 }
1616
1617 m_view->ClearPreview();
1618 m_view->AddToPreview( previewItem->Clone() );
1619 }
1620 else if( evt->IsAction( &SCH_ACTIONS::properties ) )
1621 {
1622 switch( type )
1623 {
1625 {
1626 std::deque<SCH_ITEM*> strokeItems;
1627 strokeItems.push_back( previewItem );
1628
1629 DIALOG_WIRE_BUS_PROPERTIES dlg( m_frame, strokeItems );
1630
1632 [&]()
1633 {
1634 dlg.ShowModal();
1635 } );
1636
1637 break;
1638 }
1639
1640 case SCH_JUNCTION_T:
1641 {
1642 std::deque<SCH_JUNCTION*> junctions;
1643 junctions.push_back( static_cast<SCH_JUNCTION*>( previewItem ) );
1644
1645 DIALOG_JUNCTION_PROPS dlg( m_frame, junctions );
1646
1648 [&]()
1649 {
1650 dlg.ShowModal();
1651 } );
1652
1653 break;
1654 }
1655
1656 default:
1657 // Do nothing
1658 break;
1659 }
1660
1661 m_view->ClearPreview();
1662 m_view->AddToPreview( previewItem->Clone() );
1663 }
1664 else
1665 {
1666 evt->SetPassEvent();
1667 }
1668 }
1669 else
1670 {
1671 evt->SetPassEvent();
1672 }
1673 }
1674
1675 delete previewItem;
1676 m_view->ClearPreview();
1677
1678 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
1679 controls->ForceCursorPosition( false );
1680
1681 return 0;
1682}
1683
1684
1686{
1687 for( SCH_ITEM* item : m_frame->GetScreen()->Items().Overlapping( SCH_LINE_T, aPosition ) )
1688 {
1689 SCH_LINE* line = static_cast<SCH_LINE*>( item );
1690
1691 if( line->GetEditFlags() & STRUCT_DELETED )
1692 continue;
1693
1694 if( line->IsWire() )
1695 return line;
1696 }
1697
1698 return nullptr;
1699}
1700
1701
1703{
1704 wxASSERT( aWire->IsWire() );
1705
1706 SCH_SHEET_PATH sheetPath = m_frame->GetCurrentSheet();
1707
1708 const auto labelDriverName = []( const auto& aConnection ) -> wxString
1709 {
1710 SCH_ITEM* driver = aConnection.Driver();
1711
1712 if( driver && driver->IsType( { SCH_LABEL_T, SCH_GLOBAL_LABEL_T } ) )
1713 return aConnection.LocalName();
1714
1715 return wxEmptyString;
1716 };
1717
1718 if( ADVANCED_CFG::GetCfg().m_ConnectivityEngine )
1719 {
1720 const auto connection = m_frame->Schematic().Connectivity().Connection( aWire->m_Uuid, sheetPath.PathRef() );
1721 return connection ? labelDriverName( *connection ) : wxString();
1722 }
1723
1724 const SCH_CONNECTION* wireConnection = aWire->Connection( &sheetPath );
1725 return wireConnection ? labelDriverName( *wireConnection ) : wxString();
1726}
1727
1728
1729bool SCH_DRAWING_TOOLS::createNewLabel( const VECTOR2I& aPosition, int aType,
1730 std::list<std::unique_ptr<SCH_LABEL_BASE>>& aLabelList )
1731{
1732 SCHEMATIC* schematic = getModel<SCHEMATIC>();
1733 SCHEMATIC_SETTINGS& settings = schematic->Settings();
1734 SCH_LABEL_BASE* labelItem = nullptr;
1735 SCH_GLOBALLABEL* globalLabel = nullptr;
1736 wxString netName;
1737
1738 switch( aType )
1739 {
1740 case LAYER_LOCLABEL:
1741 labelItem = new SCH_LABEL( aPosition );
1742
1743 if( SCH_LINE* wire = findWire( aPosition ) )
1744 netName = findWireLabelDriverName( wire );
1745
1746 break;
1747
1749 labelItem = new SCH_DIRECTIVE_LABEL( aPosition );
1750 labelItem->SetShape( m_lastNetClassFlagShape );
1751 labelItem->GetFields().emplace_back( labelItem, FIELD_T::USER, wxT( "Netclass" ) );
1752 labelItem->GetFields().emplace_back( labelItem, FIELD_T::USER, wxT( "Component Class" ) );
1753 labelItem->GetFields().back().SetItalic( true );
1754 labelItem->GetFields().back().SetVisible( true );
1755 break;
1756
1757 case LAYER_HIERLABEL:
1758 labelItem = new SCH_HIERLABEL( aPosition );
1759 labelItem->SetShape( m_lastGlobalLabelShape );
1761 break;
1762
1763 case LAYER_GLOBLABEL:
1764 globalLabel = new SCH_GLOBALLABEL( aPosition );
1765 globalLabel->SetShape( m_lastGlobalLabelShape );
1768 labelItem = globalLabel;
1769
1770 if( SCH_LINE* wire = findWire( aPosition ) )
1771 netName = findWireLabelDriverName( wire );
1772
1773 break;
1774
1775 default:
1776 wxFAIL_MSG( "SCH_DRAWING_TOOLS::createNewLabel() unknown label type" );
1777 return false;
1778 }
1779
1780 // The normal parent is the current screen for these labels, set by SCH_SCREEN::Append()
1781 // but it is also used during placement for SCH_HIERLABEL before beeing appended
1782 labelItem->SetParent( m_frame->GetScreen() );
1783
1784 labelItem->SetTextSize( VECTOR2I( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
1785
1786 if( aType != LAYER_NETCLASS_REFS )
1787 {
1788 // Must be after SetTextSize()
1789 labelItem->SetBold( m_lastTextBold );
1790 labelItem->SetItalic( m_lastTextItalic );
1791 }
1792
1793 labelItem->SetSpinStyle( m_lastTextOrientation );
1794 labelItem->SetFlags( IS_NEW | IS_MOVING );
1795
1796 if( !netName.IsEmpty() )
1797 {
1798 // Auto-create from attached wire
1799 labelItem->SetText( netName );
1800 }
1801 else
1802 {
1803 DIALOG_LABEL_PROPERTIES dlg( m_frame, labelItem, true );
1804
1805 dlg.SetLabelList( &aLabelList );
1806
1807 // QuasiModal required for syntax help and Scintilla auto-complete
1808 if( dlg.ShowQuasiModal() != wxID_OK )
1809 {
1811 delete labelItem;
1812 return false;
1813 }
1814 }
1815
1816 if( aType != LAYER_NETCLASS_REFS )
1817 {
1818 m_lastTextBold = labelItem->IsBold();
1819 m_lastTextItalic = labelItem->IsItalic();
1820 }
1821
1822 m_lastTextOrientation = labelItem->GetSpinStyle();
1823
1824 if( aType == LAYER_GLOBLABEL || aType == LAYER_HIERLABEL )
1825 {
1826 m_lastGlobalLabelShape = labelItem->GetShape();
1828 }
1829 else if( aType == LAYER_NETCLASS_REFS )
1830 {
1831 m_lastNetClassFlagShape = labelItem->GetShape();
1832 }
1833
1834 if( aLabelList.empty() )
1835 aLabelList.push_back( std::unique_ptr<SCH_LABEL_BASE>( labelItem ) );
1836 else // DIALOG_LABEL_PROPERTIES already filled in aLabelList; labelItem is extraneous to needs
1837 delete labelItem;
1838
1839 return true;
1840}
1841
1842
1844{
1845 SCHEMATIC* schematic = getModel<SCHEMATIC>();
1846 SCHEMATIC_SETTINGS& settings = schematic->Settings();
1847 SCH_TEXT* textItem = nullptr;
1848
1849 textItem = new SCH_TEXT( aPosition );
1850 textItem->SetParent( schematic );
1851 textItem->SetTextSize( VECTOR2I( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
1852 // Must be after SetTextSize()
1853 textItem->SetBold( m_lastTextBold );
1854 textItem->SetItalic( m_lastTextItalic );
1857 textItem->SetTextAngle( m_lastTextAngle );
1858 textItem->SetFlags( IS_NEW | IS_MOVING );
1859
1860 DIALOG_TEXT_PROPERTIES dlg( m_frame, textItem );
1861
1862 // QuasiModal required for syntax help and Scintilla auto-complete
1863 if( dlg.ShowQuasiModal() != wxID_OK )
1864 {
1865 delete textItem;
1866 return nullptr;
1867 }
1868
1869 m_lastTextBold = textItem->IsBold();
1870 m_lastTextItalic = textItem->IsItalic();
1871 m_lastTextHJustify = textItem->GetHorizJustify();
1872 m_lastTextVJustify = textItem->GetVertJustify();
1873 m_lastTextAngle = textItem->GetTextAngle();
1874 return textItem;
1875}
1876
1877
1879{
1880 SCHEMATIC_SETTINGS& settings = aSheet->Schematic()->Settings();
1881 SCH_SHEET_PIN* pin = new SCH_SHEET_PIN( aSheet );
1882
1883 pin->SetFlags( IS_NEW | IS_MOVING );
1884 pin->SetText( std::to_string( aSheet->GetPins().size() + 1 ) );
1885 pin->SetTextSize( VECTOR2I( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
1886 pin->SetPosition( aPosition );
1887 pin->ClearSelected();
1888
1889 m_lastSheetPinType = pin->GetShape();
1890
1891 return pin;
1892}
1893
1894
1896 const VECTOR2I& aPosition,
1897 SCH_HIERLABEL* aLabel )
1898{
1899 auto pin = createNewSheetPin( aSheet, aPosition );
1900 pin->SetText( aLabel->GetText() );
1901 pin->SetShape( aLabel->GetShape() );
1902 return pin;
1903}
1904
1905
1907{
1908 SCH_ITEM* item = nullptr;
1911 bool ignorePrimePosition = false;
1912 COMMON_SETTINGS* common_settings = Pgm().GetCommonSettings();
1913 SCH_SHEET* sheet = nullptr;
1914 wxString description;
1915
1916 std::list<std::unique_ptr<SCH_LABEL_BASE>> itemsToPlace;
1917
1918 if( m_inDrawingTool )
1919 return 0;
1920
1922
1923 bool isText = aEvent.IsAction( &SCH_ACTIONS::placeSchematicText );
1924 bool isGlobalLabel = aEvent.IsAction( &SCH_ACTIONS::placeGlobalLabel );
1925 bool isHierLabel = aEvent.IsAction( &SCH_ACTIONS::placeHierLabel );
1926 bool isClassLabel = aEvent.IsAction( &SCH_ACTIONS::placeClassLabel );
1927 bool isNetLabel = aEvent.IsAction( &SCH_ACTIONS::placeLabel );
1928 bool isSheetPin = aEvent.IsAction( &SCH_ACTIONS::placeSheetPin );
1929
1930 GRID_HELPER_GRIDS snapGrid = isText ? GRID_TEXT : GRID_CONNECTABLE;
1931
1932 // If we have a selected sheet use it, otherwise try to get one under the cursor
1933 if( isSheetPin )
1934 sheet = dynamic_cast<SCH_SHEET*>( m_selectionTool->GetSelection().Front() );
1935
1936 m_toolMgr->RunAction( ACTIONS::selectionClear );
1937
1938 TOOL_EVENT originalEvent = aEvent; // This can change out from under us when the event loop runs
1939 SCOPED_TOOL_PUSHER raii( m_frame, originalEvent );
1940
1941 auto setCursor =
1942 [&]()
1943 {
1944 if( item )
1945 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PLACE );
1946 else if( isText )
1947 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::TEXT );
1948 else if( isGlobalLabel )
1949 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_GLOBAL );
1950 else if( isNetLabel || isClassLabel )
1951 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_NET );
1952 else if( isHierLabel )
1953 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::LABEL_HIER );
1954 else
1955 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
1956 };
1957
1958 auto updatePreview =
1959 [&]()
1960 {
1961 m_view->ClearPreview();
1962 m_view->AddToPreview( item, false );
1963 item->RunOnChildren( [&]( SCH_ITEM* aChild )
1964 {
1965 m_view->AddToPreview( aChild, false );
1966 },
1968 m_frame->SetMsgPanel( item );
1969 };
1970
1971 auto cleanup =
1972 [&]()
1973 {
1974 m_toolMgr->RunAction( ACTIONS::selectionClear );
1975 m_view->ClearPreview();
1976 delete item;
1977 item = nullptr;
1978
1979 while( !itemsToPlace.empty() )
1980 itemsToPlace.erase( itemsToPlace.begin() );
1981 };
1982
1983 auto prepItemForPlacement =
1984 [&]( SCH_ITEM* aItem, const VECTOR2I& cursorPos )
1985 {
1986 item->SetPosition( cursorPos );
1987
1988 item->SetFlags( IS_NEW | IS_MOVING );
1989
1990 // Not placed yet, so pass a nullptr screen reference
1991 item->AutoplaceFields( nullptr, AUTOPLACE_AUTO );
1992
1993 updatePreview();
1994 m_selectionTool->ClearSelection( true );
1995 m_selectionTool->AddItemToSel( item );
1996 m_toolMgr->PostAction( ACTIONS::refreshPreview );
1997
1998 // update the cursor so it looks correct before another event
1999 setCursor();
2000 };
2001
2002 Activate();
2003
2004 // Must be done after Activate() so that it gets set into the correct context
2005 controls->ShowCursor( true );
2006
2007 // Set initial cursor
2008 setCursor();
2009
2010 if( aEvent.HasPosition() )
2011 {
2012 m_toolMgr->PrimeTool( aEvent.Position() );
2013 }
2014 else if( common_settings->m_Input.immediate_actions && !aEvent.IsReactivate()
2015 && ( isText || isGlobalLabel || isHierLabel || isClassLabel || isNetLabel ) )
2016 {
2017 m_toolMgr->PrimeTool( { 0, 0 } );
2018 ignorePrimePosition = true;
2019 }
2020
2021 SCH_COMMIT commit( m_toolMgr );
2022
2023 // Main loop: keep receiving events
2024 while( TOOL_EVENT* evt = Wait() )
2025 {
2026 setCursor();
2027 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2028 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2029
2030 VECTOR2I cursorPos = controls->GetMousePosition();
2031 cursorPos = grid.ResolveSnap( cursorPos, snapGrid, item ).position;
2032 controls->ForceCursorPosition( true, cursorPos );
2033
2034 // The tool hotkey is interpreted as a click when drawing
2035 bool isSyntheticClick = item && evt->IsActivate() && evt->HasPosition() && evt->Matches( aEvent );
2036
2037 if( evt->IsCancelInteractive() || evt->IsAction( &ACTIONS::undo ) )
2038 {
2039 m_frame->GetInfoBar()->Dismiss();
2040
2041 if( item )
2042 cleanup();
2043 else
2044 break;
2045 }
2046 else if( evt->IsActivate() && !isSyntheticClick )
2047 {
2048 if( item && evt->IsMoveTool() )
2049 {
2050 // we're already moving our own item; ignore the move tool
2051 evt->SetPassEvent( false );
2052 continue;
2053 }
2054
2055 if( item )
2056 {
2057 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel item creation." ) );
2058 evt->SetPassEvent( false );
2059 continue;
2060 }
2061
2062 if( evt->IsPointEditor() )
2063 {
2064 // don't exit (the point editor runs in the background)
2065 continue;
2066 }
2067
2068 if( evt->IsMoveTool() )
2069 {
2070 // Make sure we come back after the move tool runs
2071 frame()->PushTool( originalEvent );
2072 }
2073
2074 break;
2075 }
2076 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
2077 || isSyntheticClick
2078 || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick ) )
2079 {
2080 PLACE_NEXT:
2081 // First click creates...
2082 if( !item )
2083 {
2084 m_toolMgr->RunAction( ACTIONS::selectionClear );
2085
2086 if( isText )
2087 {
2088 item = createNewText( cursorPos );
2089 description = _( "Add Text" );
2090 }
2091 else if( isHierLabel )
2092 {
2093 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
2094 {
2095 auto pin = static_cast<SCH_HIERLABEL*>( m_dialogSyncSheetPin->GetPlacementTemplate() );
2096 SCH_HIERLABEL* label = new SCH_HIERLABEL( cursorPos );
2097 SCHEMATIC* schematic = getModel<SCHEMATIC>();
2098 label->SetText( pin->GetText() );
2099 label->SetShape( pin->GetShape() );
2101 label->SetParent( schematic );
2102 label->SetBold( m_lastTextBold );
2103 label->SetItalic( m_lastTextItalic );
2105 label->SetTextSize( VECTOR2I( schematic->Settings().m_DefaultTextSize,
2106 schematic->Settings().m_DefaultTextSize ) );
2107 label->SetFlags( IS_NEW | IS_MOVING );
2108 itemsToPlace.push_back( std::unique_ptr<SCH_LABEL_BASE>( label ) );
2109 }
2110 else
2111 {
2112 createNewLabel( cursorPos, LAYER_HIERLABEL, itemsToPlace );
2113 }
2114
2115 description = _( "Add Hierarchical Label" );
2116 }
2117 else if( isNetLabel )
2118 {
2119 createNewLabel( cursorPos, LAYER_LOCLABEL, itemsToPlace );
2120 description = _( "Add Label" );
2121 }
2122 else if( isGlobalLabel )
2123 {
2124 createNewLabel( cursorPos, LAYER_GLOBLABEL, itemsToPlace );
2125 description = _( "Add Label" );
2126 }
2127 else if( isClassLabel )
2128 {
2129 createNewLabel( cursorPos, LAYER_NETCLASS_REFS, itemsToPlace );
2130 description = _( "Add Label" );
2131 }
2132 else if( isSheetPin )
2133 {
2134 EDA_ITEM* i = nullptr;
2135
2136 // If we didn't have a sheet selected, try to find one under the cursor
2137 if( !sheet && m_selectionTool->SelectPoint( cursorPos, { SCH_SHEET_T }, &i ) )
2138 sheet = dynamic_cast<SCH_SHEET*>( i );
2139
2140 if( !sheet )
2141 {
2142 m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( m_frame );
2143 m_statusPopup->SetText( _( "Click over a sheet." ) );
2144 m_statusPopup->Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
2145 m_statusPopup->PopupFor( 2000 );
2146 item = nullptr;
2147 }
2148 else
2149 {
2150 // User is using the 'Sync Sheet Pins' tool
2151 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
2152 {
2153 item = createNewSheetPinFromLabel( sheet, cursorPos,
2154 m_dialogSyncSheetPin->GetPlacementTemplate() );
2155 }
2156 else
2157 {
2158 // User is using the 'Place Sheet Pins' tool
2159 SCH_HIERLABEL* label = importHierLabel( sheet );
2160
2161 if( !label )
2162 {
2163 m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( m_frame );
2164 m_statusPopup->SetText( _( "No new hierarchical labels found." ) );
2165 m_statusPopup->Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
2166 m_statusPopup->PopupFor( 2000 );
2167 item = nullptr;
2168 break;
2169 }
2170
2171 item = createNewSheetPinFromLabel( sheet, cursorPos, label );
2172 }
2173 }
2174
2175 description = _( "Add Sheet Pin" );
2176 }
2177
2178 // If we started with a hotkey which has a position then warp back to that.
2179 // Otherwise update to the current mouse position pinned inside the autoscroll
2180 // boundaries.
2181 if( evt->IsPrime() && !ignorePrimePosition )
2182 {
2183 cursorPos = grid.Align( evt->Position() );
2184 getViewControls()->WarpMouseCursor( cursorPos, true );
2185 }
2186 else
2187 {
2189 cursorPos = getViewControls()->GetMousePosition();
2190 cursorPos = grid.ResolveSnap( cursorPos, snapGrid, item ).position;
2191 }
2192
2193 if( !itemsToPlace.empty() )
2194 {
2195 item = itemsToPlace.front().release();
2196 itemsToPlace.pop_front();
2197 }
2198
2199 if( item )
2200 prepItemForPlacement( item, cursorPos );
2201
2202 if( m_frame->GetMoveWarpsCursor() )
2203 controls->SetCursorPosition( cursorPos, false );
2204
2205 m_toolMgr->PostAction( ACTIONS::refreshPreview );
2206 }
2207 else // ... and second click places:
2208 {
2209 item->ClearFlags( IS_MOVING );
2210
2211 if( item->IsConnectable() )
2212 m_frame->AutoRotateItem( m_frame->GetScreen(), item );
2213
2214 if( isSheetPin && sheet )
2215 {
2216 // Sheet pins are owned by their parent sheet.
2217 commit.Modify( sheet, m_frame->GetScreen() );
2218 sheet->AddPin( (SCH_SHEET_PIN*) item );
2219 }
2220 else
2221 {
2222 m_frame->SaveCopyForRepeatItem( item );
2223 m_frame->AddToScreen( item, m_frame->GetScreen() );
2224 commit.Added( item, m_frame->GetScreen() );
2225 }
2226
2227 item->AutoplaceFields( m_frame->GetScreen(), AUTOPLACE_AUTO );
2228
2229 commit.Push( description );
2230
2231 m_view->ClearPreview();
2232
2233 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->GetPlacementTemplate() )
2234 {
2235 m_dialogSyncSheetPin->EndPlaceItem( item );
2236
2237 if( m_dialogSyncSheetPin->CanPlaceMore() )
2238 {
2239 item = nullptr;
2240 goto PLACE_NEXT;
2241 }
2242
2243 m_toolMgr->RunAction( ACTIONS::selectionClear );
2244 m_dialogSyncSheetPin->Show( true );
2245 break;
2246 }
2247
2248 item = nullptr;
2249
2250 if( isSheetPin && sheet )
2251 {
2252 SCH_HIERLABEL* label = importHierLabel( sheet );
2253
2254 if( !label )
2255 {
2256 m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( m_frame );
2257 m_statusPopup->SetText( _( "No new hierarchical labels found." ) );
2258 m_statusPopup->Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
2259 m_statusPopup->PopupFor( 2000 );
2260 break;
2261 }
2262
2263 item = createNewSheetPinFromLabel( sheet, cursorPos, label );
2264 }
2265 else if( !itemsToPlace.empty() )
2266 {
2267 item = itemsToPlace.front().release();
2268 itemsToPlace.pop_front();
2269 prepItemForPlacement( item, cursorPos );
2270 }
2271 }
2272 }
2273 else if( evt->IsClick( BUT_RIGHT ) )
2274 {
2275 // Warp after context menu only if dragging...
2276 if( !item )
2277 m_toolMgr->VetoContextMenuMouseWarp();
2278
2279 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
2280 }
2281 else if( item && evt->IsSelectionEvent() )
2282 {
2283 // This happens if our text was replaced out from under us by ConvertTextType()
2284 SCH_SELECTION& selection = m_selectionTool->GetSelection();
2285
2286 if( selection.GetSize() == 1 )
2287 {
2288 item = (SCH_ITEM*) selection.Front();
2289 updatePreview();
2290 }
2291 else
2292 {
2293 item = nullptr;
2294 }
2295 }
2296 else if( evt->IsAction( &ACTIONS::increment ) )
2297 {
2298 if( evt->HasParameter() )
2299 m_toolMgr->RunSynchronousAction( ACTIONS::increment, &commit, evt->Parameter<ACTIONS::INCREMENT>() );
2300 else
2301 m_toolMgr->RunSynchronousAction( ACTIONS::increment, &commit, ACTIONS::INCREMENT { 1, 0 } );
2302 }
2303 else if( evt->IsAction( &ACTIONS::duplicate )
2304 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem )
2305 || evt->IsAction( &ACTIONS::paste ) )
2306 {
2307 if( item )
2308 {
2309 wxBell();
2310 continue;
2311 }
2312
2313 // Exit. The duplicate/repeat/paste will run in its own loop.
2314 evt->SetPassEvent();
2315 break;
2316 }
2317 else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
2318 {
2319 item->CalcEdit( cursorPos );
2320 m_view->ClearPreview();
2321 m_view->AddToPreview( item->Clone() );
2322 m_frame->SetMsgPanel( item );
2323 }
2324 else if( item && evt->IsAction( &ACTIONS::doDelete ) )
2325 {
2326 cleanup();
2327 }
2328 else if( evt->IsAction( &ACTIONS::redo ) )
2329 {
2330 wxBell();
2331 }
2332 else if( item && ( evt->IsAction( &SCH_ACTIONS::toDLabel )
2333 || evt->IsAction( &SCH_ACTIONS::toGLabel )
2334 || evt->IsAction( &SCH_ACTIONS::toHLabel )
2335 || evt->IsAction( &SCH_ACTIONS::toLabel )
2336 || evt->IsAction( &SCH_ACTIONS::toText )
2337 || evt->IsAction( &SCH_ACTIONS::toTextBox ) ) )
2338 {
2339 wxBell();
2340 }
2341 else if( item && ( evt->IsAction( &SCH_ACTIONS::properties )
2342 || evt->IsAction( &SCH_ACTIONS::autoplaceFields )
2343 || evt->IsAction( &SCH_ACTIONS::rotateCW )
2344 || evt->IsAction( &SCH_ACTIONS::rotateCCW )
2345 || evt->IsAction( &SCH_ACTIONS::mirrorV )
2346 || evt->IsAction( &SCH_ACTIONS::mirrorH ) ) )
2347 {
2348 m_toolMgr->PostAction( ACTIONS::refreshPreview );
2349 evt->SetPassEvent();
2350 }
2351 else
2352 {
2353 evt->SetPassEvent();
2354 }
2355
2356 // Enable autopanning and cursor capture only when there is an item to be placed
2357 controls->SetAutoPan( item != nullptr );
2358 controls->CaptureCursor( item != nullptr );
2359 }
2360
2361 controls->SetAutoPan( false );
2362 controls->CaptureCursor( false );
2363 controls->ForceCursorPosition( false );
2364 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2365
2366 if( m_dialogSyncSheetPin && m_dialogSyncSheetPin->CanPlaceMore() )
2367 {
2368 m_dialogSyncSheetPin->EndPlacement();
2369 m_dialogSyncSheetPin->Show( true );
2370 }
2371
2372 return 0;
2373}
2374
2375
2377{
2378 if( m_inDrawingTool )
2379 return 0;
2380
2382 SCOPED_DRAW_MODE scopedDrawMode( m_mode, MODE::RULE_AREA );
2383
2386 VECTOR2I cursorPos;
2387
2388 RULE_AREA_CREATE_HELPER ruleAreaTool( *getView(), m_frame, m_toolMgr );
2389 POLYGON_GEOM_MANAGER polyGeomMgr( ruleAreaTool );
2390 bool started = false;
2391
2392 // We might be running as the same shape in another co-routine. Make sure that one
2393 // gets whacked.
2394 m_toolMgr->DeactivateTool();
2395
2396 m_toolMgr->RunAction( ACTIONS::selectionClear );
2397
2398 TOOL_EVENT originalEvent = aEvent; // This can change out from under us when the event loop runs
2399 SCOPED_TOOL_PUSHER raii( m_frame, originalEvent );
2400
2401 auto setCursor =
2402 [&]()
2403 {
2404 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2405 };
2406
2407 auto cleanup =
2408 [&]()
2409 {
2410 polyGeomMgr.Reset();
2411 started = false;
2412 getViewControls()->SetAutoPan( false );
2413 getViewControls()->CaptureCursor( false );
2414 m_toolMgr->RunAction( ACTIONS::selectionClear );
2415 };
2416
2417 Activate();
2418
2419 // Must be done after Activate() so that it gets set into the correct context
2420 getViewControls()->ShowCursor( true );
2421 //m_controls->ForceCursorPosition( false );
2422
2423 // Set initial cursor
2424 setCursor();
2425
2426 if( aEvent.HasPosition() )
2427 m_toolMgr->PrimeTool( aEvent.Position() );
2428
2429 // Main loop: keep receiving events
2430 while( TOOL_EVENT* evt = Wait() )
2431 {
2432 setCursor();
2433
2434 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2435 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2436
2437 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
2438 controls->ForceCursorPosition( true, cursorPos );
2439
2440 polyGeomMgr.SetLeaderMode( m_frame->eeconfig()->m_Drawing.line_mode == LINE_MODE_FREE ? LEADER_MODE::DIRECT
2442
2443 if( evt->IsCancelInteractive() )
2444 {
2445 if( started )
2446 {
2447 cleanup();
2448 }
2449 else
2450 {
2451 // We've handled the cancel event. Don't cancel other tools
2452 evt->SetPassEvent( false );
2453 break;
2454 }
2455 }
2456 else if( evt->IsActivate() )
2457 {
2458 if( started )
2459 cleanup();
2460
2461 if( evt->IsPointEditor() )
2462 {
2463 // don't exit (the point editor runs in the background)
2464 continue;
2465 }
2466
2467 if( evt->IsMoveTool() )
2468 {
2469 // Make sure we come back after the move tool runs
2470 frame()->PushTool( originalEvent );
2471 }
2472
2473 break;
2474 }
2475 else if( evt->IsClick( BUT_RIGHT ) )
2476 {
2477 if( !started )
2478 m_toolMgr->VetoContextMenuMouseWarp();
2479
2480 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
2481 }
2482 // events that lock in nodes
2483 else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
2484 || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick )
2485 || evt->IsAction( &SCH_ACTIONS::closeOutline ) )
2486 {
2487 // Check if it is double click / closing line (so we have to finish the zone)
2488 const bool endPolygon = evt->IsDblClick( BUT_LEFT )
2489 || evt->IsAction( &ACTIONS::cursorDblClick )
2490 || evt->IsAction( &SCH_ACTIONS::closeOutline )
2491 || polyGeomMgr.NewPointClosesOutline( cursorPos );
2492
2493 if( endPolygon )
2494 {
2495 polyGeomMgr.SetFinished();
2496 polyGeomMgr.Reset();
2497
2498 started = false;
2499 getViewControls()->SetAutoPan( false );
2500 getViewControls()->CaptureCursor( false );
2501 }
2502 // adding a corner
2503 else if( polyGeomMgr.AddPoint( cursorPos ) )
2504 {
2505 if( !started )
2506 {
2507 started = true;
2508
2509 getViewControls()->SetAutoPan( true );
2510 getViewControls()->CaptureCursor( true );
2511 }
2512 }
2513 }
2514 else if( started && ( evt->IsAction( &ACTIONS::deleteLastPoint )
2515 || evt->IsAction( &ACTIONS::doDelete )
2516 || evt->IsAction( &ACTIONS::undo ) ) )
2517 {
2518 if( std::optional<VECTOR2I> last = polyGeomMgr.DeleteLastCorner() )
2519 {
2520 cursorPos = last.value();
2521 getViewControls()->WarpMouseCursor( cursorPos, true );
2522 getViewControls()->ForceCursorPosition( true, cursorPos );
2523 polyGeomMgr.SetCursorPosition( cursorPos );
2524 }
2525 else
2526 {
2527 cleanup();
2528 }
2529 }
2530 else if( started && ( evt->IsMotion()
2531 || evt->IsAction( &ACTIONS::refreshPreview )
2532 || evt->IsDrag( BUT_LEFT ) ) )
2533 {
2534 polyGeomMgr.SetCursorPosition( cursorPos );
2535 }
2536 else if( evt->IsAction( &ACTIONS::duplicate )
2537 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem )
2538 || evt->IsAction( &ACTIONS::paste ) )
2539 {
2540 if( started )
2541 {
2542 wxBell();
2543 continue;
2544 }
2545
2546 // Exit. The duplicate/repeat/paste will run in its own loop.
2547 evt->SetPassEvent();
2548 break;
2549 }
2550 else
2551 {
2552 evt->SetPassEvent();
2553 }
2554
2555 } // end while
2556
2557 getViewControls()->SetAutoPan( false );
2558 getViewControls()->CaptureCursor( false );
2559 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2560 return 0;
2561}
2562
2563
2565{
2566 SCHEMATIC* schematic = getModel<SCHEMATIC>();
2567 SCH_TABLE* table = nullptr;
2568
2569 if( m_inDrawingTool )
2570 return 0;
2571
2573
2576 VECTOR2I cursorPos;
2577
2578 // We might be running as the same shape in another co-routine. Make sure that one
2579 // gets whacked.
2580 m_toolMgr->DeactivateTool();
2581
2582 m_toolMgr->RunAction( ACTIONS::selectionClear );
2583
2584 TOOL_EVENT originalEvent = aEvent; // This can change out from under us when the event loop runs
2585 SCOPED_TOOL_PUSHER raii( m_frame, originalEvent );
2586
2587 auto setCursor =
2588 [&]()
2589 {
2590 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2591 };
2592
2593 auto cleanup =
2594 [&] ()
2595 {
2596 m_toolMgr->RunAction( ACTIONS::selectionClear );
2597 m_view->ClearPreview();
2598 delete table;
2599 table = nullptr;
2600 };
2601
2602 Activate();
2603
2604 // Must be done after Activate() so that it gets set into the correct context
2605 getViewControls()->ShowCursor( true );
2606
2607 // Set initial cursor
2608 setCursor();
2609
2610 if( aEvent.HasPosition() )
2611 m_toolMgr->PrimeTool( aEvent.Position() );
2612
2613 // Main loop: keep receiving events
2614 while( TOOL_EVENT* evt = Wait() )
2615 {
2616 setCursor();
2617 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2618 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2619
2620 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
2621 controls->ForceCursorPosition( true, cursorPos );
2622
2623 // The tool hotkey is interpreted as a click when drawing
2624 bool isSyntheticClick = table && evt->IsActivate() && evt->HasPosition() && evt->Matches( aEvent );
2625
2626 if( evt->IsCancelInteractive() || ( table && evt->IsAction( &ACTIONS::undo ) ) )
2627 {
2628 if( table )
2629 cleanup();
2630 else
2631 break;
2632 }
2633 else if( evt->IsActivate() && !isSyntheticClick )
2634 {
2635 if( table && evt->IsMoveTool() )
2636 {
2637 // we're already drawing our own item; ignore the move tool
2638 evt->SetPassEvent( false );
2639 continue;
2640 }
2641
2642 if( table )
2643 cleanup();
2644
2645 if( evt->IsPointEditor() )
2646 {
2647 // don't exit (the point editor runs in the background)
2648 continue;
2649 }
2650
2651 if( evt->IsMoveTool() )
2652 {
2653 // Make sure we come back after the move tool runs
2654 frame()->PushTool( originalEvent );
2655 }
2656
2657 break;
2658 }
2659 else if( !table && ( evt->IsClick( BUT_LEFT )
2660 || evt->IsAction( &ACTIONS::cursorClick ) ) )
2661 {
2662 m_toolMgr->RunAction( ACTIONS::selectionClear );
2663
2664 table = new SCH_TABLE( 0 );
2665 table->SetColCount( 1 );
2666
2667 SCH_TABLECELL* tableCell = new SCH_TABLECELL();
2668 int defaultTextSize = schematic->Settings().m_DefaultTextSize;
2669
2670 tableCell->SetTextSize( VECTOR2I( defaultTextSize, defaultTextSize ) );
2671 table->AddCell( tableCell );
2672
2673 table->SetParent( schematic );
2674 table->SetFlags( IS_NEW );
2675 table->SetPosition( cursorPos );
2676
2677 m_view->ClearPreview();
2678 m_view->AddToPreview( table->Clone() );
2679 }
2680 else if( table && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
2681 || isSyntheticClick
2682 || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick )
2683 || evt->IsAction( &SCH_ACTIONS::finishInteractive ) ) )
2684 {
2685 table->ClearEditFlags();
2686 table->SetFlags( IS_NEW );
2687 table->Normalize();
2688
2690
2691 // QuasiModal required for Scintilla auto-complete
2692 if( dlg.ShowQuasiModal() == wxID_OK )
2693 {
2694 SCH_COMMIT commit( m_toolMgr );
2695 commit.Add( table, m_frame->GetScreen() );
2696 commit.Push( _( "Draw Table" ) );
2697
2698 m_selectionTool->AddItemToSel( table );
2700 }
2701 else
2702 {
2703 delete table;
2704 }
2705
2706 table = nullptr;
2707 m_view->ClearPreview();
2708 }
2709 else if( table && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
2710 {
2711 VECTOR2I gridSize = grid.GetGridSize( grid.GetItemGrid( table ) );
2712 int fontSize = schematic->Settings().m_DefaultTextSize;
2713 VECTOR2I origin( table->GetPosition() );
2714 VECTOR2I requestedSize( cursorPos - origin );
2715
2716 int colCount = std::max( 1, requestedSize.x / ( fontSize * 15 ) );
2717 int rowCount = std::max( 1, requestedSize.y / ( fontSize * 2 ) );
2718
2719 VECTOR2I cellSize( std::max( gridSize.x * 5, requestedSize.x / colCount ),
2720 std::max( gridSize.y * 2, requestedSize.y / rowCount ) );
2721
2722 cellSize.x = KiROUND( (double) cellSize.x / gridSize.x ) * gridSize.x;
2723 cellSize.y = KiROUND( (double) cellSize.y / gridSize.y ) * gridSize.y;
2724
2725 table->ClearCells();
2726 table->SetColCount( colCount );
2727
2728 for( int col = 0; col < colCount; ++col )
2729 table->SetColWidth( col, cellSize.x );
2730
2731 for( int row = 0; row < rowCount; ++row )
2732 {
2733 table->SetRowHeight( row, cellSize.y );
2734
2735 for( int col = 0; col < colCount; ++col )
2736 {
2737 SCH_TABLECELL* cell = new SCH_TABLECELL();
2738 int defaultTextSize = schematic->Settings().m_DefaultTextSize;
2739
2740 cell->SetTextSize( VECTOR2I( defaultTextSize, defaultTextSize ) );
2741 cell->SetPosition( origin + VECTOR2I( col * cellSize.x, row * cellSize.y ) );
2742 cell->SetEnd( cell->GetPosition() + cellSize );
2743 table->AddCell( cell );
2744 }
2745 }
2746
2747 m_view->ClearPreview();
2748 m_view->AddToPreview( table->Clone() );
2749 m_frame->SetMsgPanel( table );
2750 }
2751 else if( !table && ( evt->IsDblClick( BUT_LEFT )
2752 || evt->IsAction( &ACTIONS::cursorDblClick ) ) )
2753 {
2754 m_toolMgr->RunAction( SCH_ACTIONS::properties );
2755 }
2756 else if( evt->IsClick( BUT_RIGHT ) )
2757 {
2758 // Warp after context menu only if dragging...
2759 if( !table )
2760 m_toolMgr->VetoContextMenuMouseWarp();
2761
2762 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
2763 }
2764 else if( evt->IsAction( &ACTIONS::duplicate )
2765 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem )
2766 || evt->IsAction( &ACTIONS::paste ) )
2767 {
2768 if( table )
2769 {
2770 wxBell();
2771 continue;
2772 }
2773
2774 // Exit. The duplicate/repeat/paste will run in its own loop.
2775 evt->SetPassEvent();
2776 break;
2777 }
2778 else if( table && evt->IsAction( &ACTIONS::redo ) )
2779 {
2780 wxBell();
2781 }
2782 else
2783 {
2784 evt->SetPassEvent();
2785 }
2786
2787 // Enable autopanning and cursor capture only when there is a shape being drawn
2788 getViewControls()->SetAutoPan( table != nullptr );
2789 getViewControls()->CaptureCursor( table != nullptr );
2790 }
2791
2792 getViewControls()->SetAutoPan( false );
2793 getViewControls()->CaptureCursor( false );
2794 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
2795 return 0;
2796}
2797
2798
2800{
2801 bool isDrawSheetCopy = aEvent.IsAction( &SCH_ACTIONS::drawSheetFromFile );
2802 bool isDrawSheetFromDesignBlock = aEvent.IsAction( &SCH_ACTIONS::drawSheetFromDesignBlock );
2803
2804 std::unique_ptr<DESIGN_BLOCK> designBlock;
2805
2806 SCH_SHEET* sheet = nullptr;
2807 wxString filename;
2808 SCH_GROUP* sheetGroup = nullptr;
2809
2810 if( isDrawSheetCopy )
2811 {
2812 wxString* ptr = aEvent.Parameter<wxString*>();
2813 wxCHECK( ptr, 0 );
2814
2815 // We own the string if we're importing a sheet
2816 filename = *ptr;
2817 delete ptr;
2818 }
2819 else if( isDrawSheetFromDesignBlock )
2820 {
2821 designBlock.reset( aEvent.Parameter<DESIGN_BLOCK*>() );
2822 wxCHECK( designBlock, 0 );
2823 filename = designBlock->GetSchematicFile();
2824 }
2825
2826 if( ( isDrawSheetCopy || isDrawSheetFromDesignBlock ) && !wxFileExists( filename ) )
2827 {
2828 wxMessageBox( wxString::Format( _( "File '%s' does not exist." ), filename ) );
2829 return 0;
2830 }
2831
2832 if( m_inDrawingTool )
2833 return 0;
2834
2836
2837 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
2838 SCHEMATIC_SETTINGS& schSettings = m_frame->Schematic().Settings();
2841 VECTOR2I cursorPos;
2842 bool startedWithDrag = false; // Track if initial sheet placement started with a drag
2843
2844 m_toolMgr->RunAction( ACTIONS::selectionClear );
2845
2846 TOOL_EVENT originalEvent = aEvent; // This can change out from under us when the event loop runs
2847 SCOPED_TOOL_PUSHER raii( m_frame, originalEvent );
2848
2849 auto setCursor =
2850 [&]()
2851 {
2852 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::PENCIL );
2853 };
2854
2855 auto cleanup =
2856 [&] ()
2857 {
2858 m_toolMgr->RunAction( ACTIONS::selectionClear );
2859 m_view->ClearPreview();
2860 delete sheet;
2861 sheet = nullptr;
2862 };
2863
2864 Activate();
2865
2866 // Must be done after Activate() so that it gets set into the correct context
2867 getViewControls()->ShowCursor( true );
2868
2869 // Set initial cursor
2870 setCursor();
2871
2872 if( aEvent.HasPosition() && !( isDrawSheetCopy || isDrawSheetFromDesignBlock ) )
2873 m_toolMgr->PrimeTool( aEvent.Position() );
2874
2875 // Main loop: keep receiving events
2876 while( TOOL_EVENT* evt = Wait() )
2877 {
2878 setCursor();
2879 grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
2880 grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
2881
2882 cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_GRAPHICS );
2883 controls->ForceCursorPosition( true, cursorPos );
2884
2885 // The tool hotkey is interpreted as a click when drawing
2886 bool isSyntheticClick = sheet && evt->IsActivate() && evt->HasPosition()
2887 && evt->Matches( aEvent );
2888
2889 if( evt->IsCancelInteractive() || ( sheet && evt->IsAction( &ACTIONS::undo ) ) )
2890 {
2891 m_frame->GetInfoBar()->Dismiss();
2892
2893 if( sheet )
2894 cleanup();
2895 else
2896 break;
2897 }
2898 else if( evt->IsActivate() && !isSyntheticClick )
2899 {
2900 if( sheet && evt->IsMoveTool() )
2901 {
2902 // we're already drawing our own item; ignore the move tool
2903 evt->SetPassEvent( false );
2904 continue;
2905 }
2906
2907 if( sheet )
2908 {
2909 m_frame->ShowInfoBarMsg( _( "Press <ESC> to cancel sheet creation." ) );
2910 evt->SetPassEvent( false );
2911 continue;
2912 }
2913
2914 if( evt->IsPointEditor() )
2915 {
2916 // don't exit (the point editor runs in the background)
2917 continue;
2918 }
2919
2920 if( evt->IsMoveTool() )
2921 {
2922 // Make sure we come back after the move tool runs
2923 frame()->PushTool( originalEvent );
2924 }
2925
2926 break;
2927 }
2928 else if( !sheet && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
2929 || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick )
2930 || evt->IsDrag( BUT_LEFT ) ) )
2931 {
2932 SCH_SELECTION& selection = m_selectionTool->GetSelection();
2933
2934 if( selection.Size() == 1
2935 && selection.Front()->Type() == SCH_SHEET_T
2936 && selection.Front()->GetBoundingBox().Contains( cursorPos ) )
2937 {
2938 if( evt->IsClick( BUT_LEFT ) || evt->IsAction( &ACTIONS::cursorClick ) )
2939 {
2940 // sheet already selected
2941 continue;
2942 }
2943 else if( evt->IsDblClick( BUT_LEFT ) || evt->IsAction( &ACTIONS::cursorDblClick ) )
2944 {
2945 m_toolMgr->PostAction( SCH_ACTIONS::enterSheet );
2946 break;
2947 }
2948 }
2949
2950 m_toolMgr->RunAction( ACTIONS::selectionClear );
2951
2952 VECTOR2I sheetPos = evt->IsDrag( BUT_LEFT )
2953 ? grid.Align( evt->DragOrigin(), GRID_HELPER_GRIDS::GRID_GRAPHICS )
2954 : cursorPos;
2955
2956 // Remember whether this sheet was initiated with a drag so we can treat mouse-up as
2957 // the terminating (second) click.
2958 startedWithDrag = evt->IsDrag( BUT_LEFT );
2959
2960 sheet = new SCH_SHEET( m_frame->GetCurrentSheet().Last(), sheetPos );
2961 sheet->SetScreen( nullptr );
2962
2963 wxString ext = wxString( "." ) + FILEEXT::KiCadSchematicFileExtension;
2964
2965 if( isDrawSheetCopy )
2966 {
2967 wxFileName fn( filename );
2968
2969 sheet->GetField( FIELD_T::SHEET_NAME )->SetText( fn.GetName() );
2970 sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( fn.GetName() + ext );
2971 }
2972 else if( isDrawSheetFromDesignBlock )
2973 {
2974 wxString sn = UniqueSheetName( m_frame->GetScreen(), designBlock->GetLibId().GetLibItemName() );
2975 wxFileName fn( filename );
2976
2977 sheet->GetField( FIELD_T::SHEET_NAME )->SetText( sn );
2978 sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( fn.GetName() + ext );
2979
2980 std::vector<SCH_FIELD>& sheetFields = sheet->GetFields();
2981
2982 // Copy default fields into the sheet
2983 for( const auto& [fieldName, fieldValue] : designBlock->GetFields() )
2984 {
2985 sheetFields.emplace_back( sheet, FIELD_T::USER, fieldName );
2986 sheetFields.back().SetText( fieldValue );
2987 sheetFields.back().SetTextPos( sheet->GetPosition() );
2988 sheetFields.back().SetVisible( false );
2989 }
2990 }
2991 else
2992 {
2993 sheet->GetField( FIELD_T::SHEET_NAME )->SetText( wxT( "Untitled Sheet" ) );
2994 sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( wxT( "untitled" ) + ext );
2995 }
2996
2997 sheet->SetFlags( IS_NEW | IS_MOVING );
2998 sheet->SetBorderWidth( schIUScale.MilsToIU( cfg->m_Drawing.default_line_thickness ) );
3001 sizeSheet( sheet, cursorPos );
3002
3003 SCH_SHEET_LIST hierarchy = m_frame->Schematic().Hierarchy();
3004 SCH_SHEET_PATH instance = m_frame->GetCurrentSheet();
3005 instance.push_back( sheet );
3006 wxString pageNumber = hierarchy.GetNextPageNumber();
3007 instance.SetPageNumber( pageNumber );
3008
3009 m_view->ClearPreview();
3010 m_view->AddToPreview( sheet->Clone() );
3011 }
3012 else if( sheet && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
3013 || isSyntheticClick
3014 || evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick )
3015 || evt->IsAction( &ACTIONS::finishInteractive )
3016 || ( startedWithDrag && evt->IsMouseUp( BUT_LEFT ) ) ) )
3017 {
3018 getViewControls()->SetAutoPan( false );
3019 getViewControls()->CaptureCursor( false );
3020
3021 if( m_frame->EditSheetProperties( sheet, &m_frame->GetCurrentSheet(), nullptr, nullptr, nullptr,
3022 &filename ) )
3023 {
3024 m_view->ClearPreview();
3025
3026 if( ( isDrawSheetCopy || isDrawSheetFromDesignBlock ) && cfg->m_Drawing.auto_place_sheet_pins )
3028
3029 sheet->AutoplaceFields( m_frame->GetScreen(), AUTOPLACE_AUTO );
3030
3031 // Use the commit we were provided or make our own
3032 SCH_COMMIT tempCommit = SCH_COMMIT( m_toolMgr );
3033 SCH_COMMIT& c = evt->Commit() ? *( (SCH_COMMIT*) evt->Commit() ) : tempCommit;
3034
3035 // We need to manually add the sheet to the screen otherwise annotation will not be able to find
3036 // the sheet and its symbols to annotate.
3037 m_frame->AddToScreen( sheet );
3038 c.Added( sheet, m_frame->GetScreen() );
3039
3040 // Refresh the hierarchy so the new sheet and its symbols are found during annotation.
3041 // The cached hierarchy was built before this sheet was added.
3042 m_frame->Schematic().RefreshHierarchy();
3043
3044 if( cfg->m_AnnotatePanel.automatic && !( ( isDrawSheetCopy || isDrawSheetFromDesignBlock )
3046 {
3047 // Annotation will remove this from selection, but we add it back later
3048 m_selectionTool->AddItemToSel( sheet );
3049
3051
3052 m_frame->AnnotateSymbols( &c, ANNOTATE_SELECTION,
3054 (ANNOTATE_ALGO_T) schSettings.m_AnnotateMethod, true, /* recursive */
3055 schSettings.m_AnnotateStartNum, true, /* reset */
3056 false, /* regroup */
3057 false, /* repair */
3058 reporter );
3059 }
3060
3061 if( isDrawSheetFromDesignBlock && cfg->m_DesignBlockChooserPanel.place_as_group )
3062 {
3063 SCH_SCREEN* screen = m_frame->GetScreen();
3064
3065 sheetGroup = new SCH_GROUP( screen );
3066 sheetGroup->SetName( UniqueGroupName( screen, designBlock->GetLibId().GetLibItemName() ) );
3067 sheetGroup->SetDesignBlockLibId( designBlock->GetLibId() );
3068 c.Add( sheetGroup, screen );
3069 c.Modify( sheet, screen, RECURSE_MODE::NO_RECURSE );
3070 sheetGroup->AddItem( sheet );
3071 }
3072
3073 c.Push( isDrawSheetCopy ? "Import Sheet Copy" : "Draw Sheet" );
3074
3075 if( sheetGroup )
3076 m_selectionTool->AddItemToSel( sheetGroup );
3077 else
3078 m_selectionTool->AddItemToSel( sheet );
3079
3080 if( ( isDrawSheetCopy || isDrawSheetFromDesignBlock )
3082 {
3083 break;
3084 }
3085 }
3086 else
3087 {
3088 m_view->ClearPreview();
3089 delete sheet;
3090 }
3091
3092 sheet = nullptr;
3093 }
3094 else if( evt->IsAction( &ACTIONS::duplicate )
3095 || evt->IsAction( &SCH_ACTIONS::repeatDrawItem )
3096 || evt->IsAction( &ACTIONS::paste ) )
3097 {
3098 if( sheet )
3099 {
3100 wxBell();
3101 continue;
3102 }
3103
3104 // Exit. The duplicate/repeat/paste will run in its own loop.
3105 evt->SetPassEvent();
3106 break;
3107 }
3108 else if( sheet && ( evt->IsAction( &ACTIONS::refreshPreview )
3109 || evt->IsMotion()
3110 || evt->IsDrag( BUT_LEFT ) ) )
3111 {
3112 sizeSheet( sheet, cursorPos );
3113 m_view->ClearPreview();
3114 m_view->AddToPreview( sheet->Clone() );
3115 m_frame->SetMsgPanel( sheet );
3116 }
3117 else if( evt->IsClick( BUT_RIGHT ) )
3118 {
3119 // Warp after context menu only if dragging...
3120 if( !sheet )
3121 m_toolMgr->VetoContextMenuMouseWarp();
3122
3123 m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
3124 }
3125 else if( sheet && evt->IsAction( &ACTIONS::redo ) )
3126 {
3127 wxBell();
3128 }
3129 else
3130 {
3131 evt->SetPassEvent();
3132 }
3133
3134 // Enable autopanning and cursor capture only when there is a sheet to be placed
3135 getViewControls()->SetAutoPan( sheet != nullptr );
3136 getViewControls()->CaptureCursor( sheet != nullptr );
3137 }
3138
3139 getViewControls()->SetAutoPan( false );
3140 getViewControls()->CaptureCursor( false );
3141 m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
3142
3143 return 0;
3144}
3145
3146
3148{
3149 VECTOR2I pos = aSheet->GetPosition();
3150 VECTOR2I size = aPos - pos;
3152
3153 size.x = std::max( size.x, minSize.x );
3154 size.y = std::max( size.y, minSize.y );
3155
3156 VECTOR2I grid = m_frame->GetNearestGridPosition( pos + size );
3157 VECTOR2I gridSize = getView()->GetGAL()->GetGridSize();
3158
3159 // Keep the corner on-grid without letting inward rounding violate the minimum size.
3160 if( grid.x - pos.x < minSize.x )
3161 grid.x += gridSize.x;
3162
3163 if( grid.y - pos.y < minSize.y )
3164 grid.y += gridSize.y;
3165
3166 aSheet->Resize( VECTOR2I( grid.x - pos.x, grid.y - pos.y ) );
3167}
3168
3169
3170int SCH_DRAWING_TOOLS::doSyncSheetsPins( std::list<SCH_SHEET_PATH> sheetPaths, SCH_SHEET* aInitialSheet )
3171{
3172 if( !sheetPaths.size() )
3173 return 0;
3174
3175 m_dialogSyncSheetPin = std::make_unique<DIALOG_SYNC_SHEET_PINS>(
3176 m_frame, std::move( sheetPaths ),
3177 std::make_shared<SHEET_SYNCHRONIZATION_AGENT>(
3178 [&]( EDA_ITEM* aItem, SCH_SHEET_PATH aPath,
3180 {
3181 SCH_COMMIT commit( m_toolMgr );
3182
3183 if( auto pin = dynamic_cast<SCH_SHEET_PIN*>( aItem ) )
3184 {
3185 commit.Modify( pin->GetParent(), aPath.LastScreen() );
3186 aModify();
3187 commit.Push( _( "Modify Sheet Pin" ) );
3188 }
3189 else
3190 {
3191 commit.Modify( aItem, aPath.LastScreen() );
3192 aModify();
3193 commit.Push( _( "Modify Schematic Item" ) );
3194 }
3195
3196 // The push already updated the R-tree and republished connectivity
3197 updateItem( aItem, false );
3198 m_frame->OnModify();
3199 },
3200 [&]( EDA_ITEM* aItem, SCH_SHEET_PATH aPath )
3201 {
3202 m_frame->GetToolManager()->RunAction<SCH_SHEET_PATH*>( SCH_ACTIONS::changeSheet, &aPath );
3203 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
3204 selectionTool->UnbrightenItem( aItem );
3205 selectionTool->AddItemToSel( aItem, true );
3206 m_toolMgr->RunAction( ACTIONS::doDelete );
3207 },
3208 [&]( SCH_SHEET* aItem, SCH_SHEET_PATH aPath,
3210 std::set<EDA_ITEM*> aTemplates )
3211 {
3212 switch( aOp )
3213 {
3215 {
3216 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
3217 m_dialogSyncSheetPin->Hide();
3218 m_dialogSyncSheetPin->PreparePlacementTemplate(
3220 m_frame->GetToolManager()->RunAction<SCH_SHEET_PATH*>( SCH_ACTIONS::changeSheet, &aPath );
3222 break;
3223 }
3225 {
3226 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
3227 m_dialogSyncSheetPin->Hide();
3228 m_dialogSyncSheetPin->PreparePlacementTemplate(
3230 m_frame->GetToolManager()->RunAction<SCH_SHEET_PATH*>( SCH_ACTIONS::changeSheet, &aPath );
3231 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->SyncSelection( {}, nullptr, { sheet } );
3233 break;
3234 }
3235 }
3236 },
3237 m_toolMgr, m_frame ),
3238 aInitialSheet );
3239 m_dialogSyncSheetPin->Show( true );
3240 return 0;
3241}
3242
3243
3245{
3246 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( m_selectionTool->GetSelection().Front() );
3247
3248 if( !sheet )
3249 {
3250 VECTOR2I cursorPos = getViewControls()->GetMousePosition();
3251
3252 if( EDA_ITEM* i = nullptr; static_cast<void>(m_selectionTool->SelectPoint( cursorPos, { SCH_SHEET_T }, &i ) ) , i != nullptr )
3253 {
3254 sheet = dynamic_cast<SCH_SHEET*>( i );
3255 }
3256 }
3257
3258 if ( sheet )
3259 {
3260 SCH_SHEET_PATH current = m_frame->GetCurrentSheet();
3261 current.push_back( sheet );
3262 return doSyncSheetsPins( { current } );
3263 }
3264
3265 return 0;
3266}
3267
3268
3270{
3271 if( m_inDrawingTool )
3272 return 0;
3273
3275
3276 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( m_selectionTool->GetSelection().Front() );
3277
3278 if( !sheet )
3279 return 0;
3280
3281 std::vector<SCH_HIERLABEL*> labels = GetUnplacedSheetPinLabels( *sheet );
3282
3283 if( labels.empty() )
3284 {
3285 SCOPED_TOOL_PUSHER raii( m_frame, aEvent );
3286
3287 m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( m_frame );
3288 m_statusPopup->SetText( _( "No new hierarchical labels found." ) );
3289 m_statusPopup->Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
3290 m_statusPopup->PopupFor( 2000 );
3291 m_toolMgr->RunAction( ACTIONS::selectionClear );
3292 m_view->ClearPreview();
3293 return 0;
3294 }
3295
3296 m_toolMgr->RunAction( ACTIONS::selectionClear );
3297
3298 SCH_COMMIT commit( m_toolMgr );
3299 commit.Modify( sheet, m_frame->GetScreen() );
3300
3301 AutoPlaceSheetPins( sheet, labels );
3302
3303 commit.Push( _( "Auto-place Sheet Pins" ) );
3304 return 0;
3305}
3306
3307
3309{
3310 static const std::function<void( std::list<SCH_SHEET_PATH>&, SCH_SCREEN*, std::set<SCH_SCREEN*>&,
3311 SCH_SHEET_PATH const& )> getSheetChildren =
3312 []( std::list<SCH_SHEET_PATH>& aPaths, SCH_SCREEN* aScene, std::set<SCH_SCREEN*>& aVisited,
3313 SCH_SHEET_PATH const& aCurPath )
3314 {
3315 if( ! aScene || aVisited.find(aScene) != aVisited.end() )
3316 return ;
3317
3318 std::vector<SCH_ITEM*> sheetChildren;
3319 aScene->GetSheets( &sheetChildren );
3320 aVisited.insert( aScene );
3321
3322 for( SCH_ITEM* child : sheetChildren )
3323 {
3324 SCH_SHEET_PATH cp = aCurPath;
3325 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( child );
3326 cp.push_back( sheet );
3327 aPaths.push_back( cp );
3328 getSheetChildren( aPaths, sheet->GetScreen(), aVisited, cp );
3329 }
3330 };
3331
3332 std::list<SCH_SHEET_PATH> sheetPaths;
3333 std::set<SCH_SCREEN*> visited;
3334
3335 // Build sheet paths for each top-level sheet (don't include virtual root in paths)
3336 std::vector<SCH_SHEET*> topLevelSheets = m_frame->Schematic().GetTopLevelSheets();
3337
3338 for( SCH_SHEET* topSheet : topLevelSheets )
3339 {
3340 if( topSheet && topSheet->GetScreen() )
3341 {
3342 SCH_SHEET_PATH current;
3343 current.push_back( topSheet );
3344 getSheetChildren( sheetPaths, topSheet->GetScreen(), visited, current );
3345 }
3346 }
3347
3348 if( sheetPaths.size() == 0 )
3349 {
3350 m_frame->ShowInfoBarMsg( _( "No sub schematic found in the current project" ) );
3351 return 0;
3352 }
3353
3354 // If a sheet is currently selected, pre-select its tab in the dialog
3355 SCH_SHEET* selectedSheet = dynamic_cast<SCH_SHEET*>( m_selectionTool->GetSelection().Front() );
3356
3357 return doSyncSheetsPins( std::move( sheetPaths ), selectedSheet );
3358}
3359
3361{
3362 if( !aSheet->GetScreen() )
3363 return nullptr;
3364
3365 std::vector<SCH_HIERLABEL*> labels;
3366
3367 for( EDA_ITEM* item : aSheet->GetScreen()->Items().OfType( SCH_HIER_LABEL_T ) )
3368 {
3369 SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( item );
3370 labels.push_back( label );
3371 }
3372
3373 std::sort( labels.begin(), labels.end(),
3374 []( const SCH_HIERLABEL* label1, const SCH_HIERLABEL* label2 )
3375 {
3376 return StrNumCmp( label1->GetText(), label2->GetText(), true ) < 0;
3377 } );
3378
3379 for( SCH_HIERLABEL* label : labels )
3380 {
3381 if( !aSheet->HasPin( label->GetText() ) )
3382 return label;
3383 }
3384
3385 return nullptr;
3386}
3387
3388
3390{
3391 // clang-format off
3415 // clang-format on
3416}
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:130
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
static TOOL_ACTION paste
Definition actions.h:76
static TOOL_ACTION deleteLastPoint
Definition actions.h:271
static TOOL_ACTION cursorDblClick
Definition actions.h:177
static TOOL_ACTION undo
Definition actions.h:71
static TOOL_ACTION duplicate
Definition actions.h:80
static TOOL_ACTION activatePointEditor
Definition actions.h:268
static TOOL_ACTION doDelete
Definition actions.h:81
static TOOL_ACTION cursorClick
Definition actions.h:176
static TOOL_ACTION redo
Definition actions.h:72
static TOOL_ACTION increment
Definition actions.h:90
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
static TOOL_ACTION refreshPreview
Definition actions.h:155
static TOOL_ACTION finishInteractive
Definition actions.h:69
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
PANEL_DESIGN_BLOCK_CHOOSER m_DesignBlockChooserPanel
bool IsContentModified() const
Definition base_screen.h:56
void SetContentModified(bool aModified=true)
Definition base_screen.h:55
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:165
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition commit.h:80
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:102
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:74
COMMIT & Removed(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been removed.
Definition commit.h:92
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, wxString *aErrorMsg=nullptr)
Load design block from design block library table.
void SetLabelList(std::list< std::unique_ptr< SCH_LABEL_BASE > > *aLabelList)
FIELDS_GRID_TABLE * GetFieldsGridTable()
int ShowModal() override
void SetDesignBlockLibId(const LIB_ID &aLibId)
Definition eda_group.h:101
void AddItem(EDA_ITEM *aItem)
Add item to group.
Definition eda_group.cpp:58
void SetName(const wxString &aName)
Definition eda_group.h:76
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
virtual void SetPosition(const VECTOR2I &aPos)
Definition eda_item.h:349
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:270
EDA_ITEM_FLAGS GetEditFlags() const
Definition eda_item.h:170
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:158
const KIID m_Uuid
Definition eda_item.h:599
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:160
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition eda_item.h:484
virtual EDA_ITEM * Clone() const
Create a duplicate of this item with linked list members set to NULL.
Definition eda_item.cpp:278
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
virtual void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:337
bool IsItalic() const
Definition eda_text.h:200
virtual void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:512
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:118
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:378
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:239
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:347
virtual EDA_ANGLE GetTextAngle() const
Definition eda_text.h:178
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition eda_text.cpp:310
bool IsBold() const
Definition eda_text.h:215
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:242
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:236
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:268
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:290
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:370
PANEL_ANNOTATE m_AnnotatePanel
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:248
const VECTOR2D & GetGridSize() const
Return the grid size.
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.
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
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:224
Definition kiid.h:46
LEGACY_SYMBOL_LIB * GetCacheLibrary()
Object used to load, save, search, and otherwise manipulate symbol library files.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
UTF8 Format() const
Definition lib_id.cpp:132
Define a library symbol object.
Definition lib_symbol.h:114
wxString GetDescription() const override
Get the Description field text value *‍/.
Definition lib_symbol.h:202
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:190
wxString GetKeyWords() const override
Definition lib_symbol.h:220
void SetGlobalPower()
bool IsPower() const override
void SetDescription(const wxString &aDescription)
Set the Description field text value.
void SetKeyWords(const wxString &aKeyWords)
bool IsLocalPower() const override
void SetLocalPower()
bool IsGlobalPower() const override
A singleton reporter that reports to nowhere.
Definition reporter.h:267
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:562
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_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
static LEGACY_SYMBOL_LIBS * LegacySchLibs(PROJECT *aProject)
Returns the list of symbol libraries from a legacy (pre-5.x) design This is only used from the remapp...
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:149
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:85
static TOOL_ACTION placeSheetPin
Definition sch_actions.h:91
static TOOL_ACTION placeNextSymbolUnit
Definition sch_actions.h:73
static TOOL_ACTION editValue
static TOOL_ACTION setExcludeFromBOM
static TOOL_ACTION mirrorV
static TOOL_ACTION drawSheetFromFile
Definition sch_actions.h:89
static TOOL_ACTION placeGlobalLabel
Definition sch_actions.h:86
static TOOL_ACTION autoplaceFields
static TOOL_ACTION changeSymbol
static TOOL_ACTION syncAllSheetsPins
Definition sch_actions.h:97
static TOOL_ACTION closeOutline
static TOOL_ACTION drawSheet
Definition sch_actions.h:88
static TOOL_ACTION properties
static TOOL_ACTION editReference
static TOOL_ACTION leaveSheet
static TOOL_ACTION autoplaceAllSheetPins
Definition sch_actions.h:92
static TOOL_ACTION placeHierLabel
Definition sch_actions.h:87
static TOOL_ACTION placeLabel
Definition sch_actions.h:84
static TOOL_ACTION toText
static TOOL_ACTION placeBusWireEntry
Definition sch_actions.h:83
static TOOL_ACTION toHLabel
static TOOL_ACTION rotateCW
static TOOL_ACTION importSheet
Definition sch_actions.h:93
static TOOL_ACTION setExcludeFromSim
static TOOL_ACTION toLabel
static TOOL_ACTION placeJunction
Definition sch_actions.h:82
static TOOL_ACTION setDNP
static TOOL_ACTION drawRuleArea
static TOOL_ACTION placeSymbol
Definition sch_actions.h:72
static TOOL_ACTION placeImage
static TOOL_ACTION editWithLibEdit
static TOOL_ACTION toDLabel
static TOOL_ACTION setExcludeFromPosFiles
static TOOL_ACTION cycleBodyStyle
static TOOL_ACTION drawSheetFromDesignBlock
Definition sch_actions.h:90
static TOOL_ACTION mirrorH
static TOOL_ACTION placeDesignBlock
Definition sch_actions.h:75
static TOOL_ACTION drawTable
static TOOL_ACTION placeSchematicText
Definition sch_actions.h:98
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:81
static TOOL_ACTION toGLabel
static TOOL_ACTION setExcludeFromBoard
static TOOL_ACTION move
static TOOL_ACTION syncSheetPins
Definition sch_actions.h:95
static TOOL_ACTION placePower
Definition sch_actions.h:74
Object to handle a bitmap image that can be inserted in a schematic.
Definition sch_bitmap.h:36
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.
Commit for the schematic and symbol editors.
Definition sch_commit.h:54
void Revert() override
Revert the commit by restoring the modified items state.
void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
int ImportSheet(const TOOL_EVENT &aEvent)
int doSyncSheetsPins(std::list< SCH_SHEET_PATH > aSheets, SCH_SHEET *aInitialSheet=nullptr)
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)
std::vector< PICKED_SYMBOL > m_powerHistoryList
int SingleClickPlace(const TOOL_EVENT &aEvent)
SCH_LINE * findWire(const VECTOR2I &aPosition)
void sizeSheet(SCH_SHEET *aSheet, const VECTOR2I &aPos)
LABEL_FLAG_SHAPE m_lastGlobalLabelShape
LABEL_FLAG_SHAPE m_lastNetClassFlagShape
GR_TEXT_H_ALIGN_T m_lastTextHJustify
int 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)
Gets the (global) label name driving this wire, if it is driven by a label.
int DrawTable(const TOOL_EVENT &aEvent)
GR_TEXT_V_ALIGN_T m_lastTextVJustify
LABEL_FLAG_SHAPE m_lastSheetPinType
MODE
The possible drawing modes of SCH_DRAWING_TOOLS.
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
Set up handlers for various 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)
Try finding any hierlabel that does not have a sheet pin associated with it.
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:48
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
virtual bool IsConnectable() const
Definition sch_item.h:550
virtual void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo)
Definition sch_item.h:681
virtual void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode)
Definition sch_item.h:683
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:302
virtual void CalcEdit(const VECTOR2I &aPosition)
Calculate the attributes of an item at aPosition when it is being edited.
Definition sch_item.h:490
virtual void SetUnit(int aUnit)
Definition sch_item.h:242
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:580
bool IsType(const std::vector< KICAD_T > &aScanTypes) const override
Check whether the item is one of the listed types.
Definition sch_item.h:185
bool AutoRotateOnPlacement() const
autoRotateOnPlacement
SPIN_STYLE GetSpinStyle() const
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition sch_label.h:179
LABEL_FLAG_SHAPE GetShape() const
Definition sch_label.h:178
void SetAutoRotateOnPlacement(bool autoRotate=true)
std::vector< SCH_FIELD > & GetFields()
Definition sch_label.h:210
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:39
bool IsWire() const
Return true if the line is a wire.
VECTOR2I GetEndPoint() const
Definition sch_line.h:145
VECTOR2I GetStartPoint() const
Definition sch_line.h:136
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
void SortByReferenceOnly()
Sort the list of references by reference.
void ReannotateByOptions(ANNOTATE_ORDER_T aSortOption, ANNOTATE_ALGO_T aAlgoOption, int aStartNumber, const SCH_REFERENCE_LIST &aAdditionalRefs, bool aStartAtCurrent, SCH_SHEET_LIST *aHierarchy)
Forces reannotation of the provided references.
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)
wxString GetRef() const
int GetUnit() const
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:122
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)
Clear current selection event handler.
void RebuildSelection()
Rebuild the selection from the EDA_ITEMs' selection flags.
SCH_SELECTION & GetSelection()
void SetPosition(const VECTOR2I &aPos) override
Definition sch_shape.h:89
VECTOR2I GetPosition() const override
Definition sch_shape.h:88
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.
wxString GetNextPageNumber() const
void GetSymbols(SCH_REFERENCE_LIST &aReferences, SYMBOL_FILTER aSymbolFilter, 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.
const KIID_PATH & PathRef() const
Borrow the cached path until this sheet path is modified or destroyed.
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:48
void SetBorderColor(KIGFX::COLOR4D aColor)
Definition sch_sheet.h:160
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:91
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
void SetBackgroundColor(KIGFX::COLOR4D aColor)
Definition sch_sheet.h:163
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:151
VECTOR2I GetPosition() const override
Definition sch_sheet.h:512
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.
void SetBorderWidth(int aWidth)
Definition sch_sheet.h:157
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:249
Schematic symbol object.
Definition sch_symbol.h:75
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:165
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:38
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition seg.cpp:599
int AddItemsToSel(const TOOL_EVENT &aEvent)
int AddItemToSel(const TOOL_EVENT &aEvent)
void UnbrightenItem(EDA_ITEM *aItem)
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition selection.h:104
EDA_ITEM * Front() const
Definition selection.h:176
int Size() const
Returns the number of selected parts.
Definition selection.h:120
void SetReferencePoint(const VECTOR2I &aP)
Spin style for labels of all kinds on schematics.
Definition sch_label.h:38
An interface to the global shared library manager that is schematic-specific and linked to one projec...
Helper object to filter a list of libraries.
SCH_EDIT_FRAME * getModel() const
Definition tool_base.h:195
KIGFX::VIEW_CONTROLS * getViewControls() const
Definition tool_base.cpp:40
KIGFX::VIEW * getView() const
Definition tool_base.cpp:34
Generic, UI-independent tool event.
Definition tool_event.h:167
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:256
const VECTOR2D Position() const
Return mouse cursor position in world coordinates.
Definition tool_event.h:289
bool IsReactivate() const
Control whether the tool is first being pushed to the stack or being reactivated after a pause.
Definition tool_event.h:269
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:484
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:81
@ PLACE
Definition cursors.h:95
@ LABEL_GLOBAL
Definition cursors.h:79
@ MOVING
Definition cursors.h:45
@ LABEL_NET
Definition cursors.h:77
@ ARROW
Definition cursors.h:43
@ LABEL_HIER
Definition cursors.h:93
@ PENCIL
Definition cursors.h:49
const int minSize
Push and Shove router track width and via size dialog.
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
@ NO_RECURSE
Definition eda_item.h:52
#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 IS_MOVING
Item being moved.
#define STARTPOINT
When a line is selected, these flags indicate which.
SCOPED_SET_RESET< EE_GRAPHIC_TOOL::MODE > SCOPED_DRAW_MODE
@ ID_POPUP_SCH_SELECT_UNIT
Definition eeschema_id.h:81
@ ID_POPUP_SCH_SELECT_BODY_STYLE
Definition eeschema_id.h:91
@ ID_POPUP_SCH_SELECT_BODY_STYLE_END
Definition eeschema_id.h:93
@ ID_POPUP_SCH_SELECT_UNIT_END
Definition eeschema_id.h:85
@ LINE_MODE_FREE
@ DEG45
45 Degree only
@ DIRECT
Unconstrained point-to-point.
GRID_HELPER_GRIDS
Definition grid_helper.h:55
@ GRID_TEXT
Definition grid_helper.h:62
@ GRID_GRAPHICS
Definition grid_helper.h:63
@ GRID_CONNECTABLE
Definition grid_helper.h:59
static const std::string KiCadSchematicFileExtension
static wxString ImageFileWildcard()
static wxString KiCadSchematicFileWildcard()
@ LAYER_HIERLABEL
Definition layer_ids.h:485
@ LAYER_GLOBLABEL
Definition layer_ids.h:484
@ LAYER_LOCLABEL
Definition layer_ids.h:483
@ LAYER_NETCLASS_REFS
Definition layer_ids.h:492
Definition for symbol library class.
wxPoint GetMousePosition()
Returns the mouse position in screen coordinates.
Definition wxgtk/ui.cpp:958
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:640
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
LIB_SYMBOL * SchGetLibSymbol(const LIB_ID &aLibId, SYMBOL_LIBRARY_ADAPTER *aLibMgr, LEGACY_SYMBOL_LIB *aCacheLib, wxWindow *aParent, bool aShowErrorMsg)
Load symbol from symbol library table.
static std::optional< VECTOR2I > designBlockAnchor(const std::vector< SCH_ITEM * > &aItems)
Pick the point a placed design block hangs from.
Class to handle a set of SCH_ITEMs.
@ AUTOPLACE_AUTO
Definition sch_item.h:75
std::vector< EDA_ITEM * > EDA_ITEMS
LABEL_FLAG_SHAPE
Label and flag shapes used with text objects.
Definition sch_label.h:97
@ F_ROUND
Definition sch_label.h:106
@ L_INPUT
Definition sch_label.h:98
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:41
#define MIN_SHEET_WIDTH
Definition sch_sheet.h:40
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
@ SYMBOL_FILTER_ALL
wxString UniqueGroupName(SCH_SCREEN *aScreen, const wxString &aBaseName)
Return aBaseName, or aBaseName + smallest free integer if a group with that name already exists on aS...
bool IsUnannotatedUnitOccupied(const SCH_REFERENCE_LIST &aRefs, const wxString &aRef, const LIB_ID &aLibId, int aUnit)
Decide whether aUnit of an unannotated multi-unit symbol is already placed.
std::set< int > GetUnplacedUnitsForSymbol(const SCH_SYMBOL &aSym)
Get a list of unplaced (i.e.
void AutoPlaceSheetPins(SCH_SHEET *aSheet, const std::vector< SCH_HIERLABEL * > &aLabels)
Import and auto-place sheet pins for the given labels, growing the sheet as needed.
std::vector< SCH_ITEM * > FlattenGroups(const EDA_ITEMS &aItems)
Return the given items with the members of any group added, recursively.
std::vector< SCH_HIERLABEL * > GetUnplacedSheetPinLabels(const SCH_SHEET &aSheet)
Return one sheet hierarchical label per name that does not already have a sheet pin.
wxString UniqueSheetName(SCH_SCREEN *aScreen, const wxString &aBaseName)
Return aBaseName, or aBaseName + smallest free integer if a sheet with that name already exists on aS...
Increment event parameters.
Definition actions.h:329
bool PlaceAllUnits
Definition sch_screen.h:89
bool m_Reannotate
If a symbol is provide, reannotate it?
bool m_PlaceAllUnits
For a preselected multi-unit symbol, keep placing remaining units instead of exiting.
SCH_SYMBOL * m_Symbol
Provide a symbol to place.
int m_Unit
Unit number to place; 0 means next available unit.
SCH_SYMBOL * m_Symbol
Symbol used as reference for unit placement.
@ USER
The field ID hasn't been set yet; field is invalid.
@ INTERSHEET_REFS
Global label cross-reference page numbers.
std::string path
IbisParser parser & reporter
KIBIS_PIN * pin
int delta
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_CENTER
@ TA_CHOICE_MENU_CHOICE
Context menu choice.
Definition tool_event.h:94
@ MD_SHIFT
Definition tool_event.h:139
@ TC_COMMAND
Definition tool_event.h:53
@ BUT_LEFT
Definition tool_event.h:128
@ BUT_RIGHT
Definition tool_event.h:129
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ SCH_GROUP_T
Definition typeinfo.h:169
@ SCH_LINE_T
Definition typeinfo.h:159
@ SCH_NO_CONNECT_T
Definition typeinfo.h:156
@ SCH_SYMBOL_T
Definition typeinfo.h:168
@ SCH_SHEET_T
Definition typeinfo.h:171
@ SCH_HIER_LABEL_T
Definition typeinfo.h:165
@ SCH_SHEET_PIN_T
Definition typeinfo.h:170
@ SCH_BUS_WIRE_ENTRY_T
Definition typeinfo.h:157
@ SCH_JUNCTION_T
Definition typeinfo.h:155
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
Definition of file extensions used in Kicad.