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