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