KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_editor_control.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2019-2023 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
22
23#include <algorithm>
24
25#include <wx_filename.h>
26#include <wx/clipbrd.h>
27#include <wx/buffer.h>
28#include <wx/filedlg.h>
29#include <wx/filefn.h>
30#include <wx/imagpng.h>
31#include <wx/log.h>
32#include <wx/log.h>
33#include <wx/msgdlg.h>
34#include <wx/mstream.h>
35#include <wx/textdlg.h>
36#include <wx/treectrl.h>
37
39#include <core/base64.h>
40#include <clipboard.h>
41#include <confirm.h>
42#include <connection_graph.h>
43#include <design_block.h>
54#include <project_rescue.h>
55#include <erc/erc.h>
56#include <invoke_sch_dialog.h>
57#include <locale_io.h>
58#include <string_utils.h>
59#include <kiway.h>
60#include <kiplatform/ui.h>
62#include <paths.h>
63#include <pgm_base.h>
66#include <project_sch.h>
68#include <richio.h>
70#include <sch_edit_frame.h>
72#include <sch_bitmap.h>
73#include <sch_group.h>
74#include <sch_line.h>
75#include <sch_junction.h>
76#include <sch_bus_entry.h>
77#include <sch_shape.h>
78#include <sch_painter.h>
79#include <sch_sheet_pin.h>
80#include <sch_table.h>
81#include <sch_tablecell.h>
82#include <sch_label.h>
83#include <sch_commit.h>
84#include <sim/simulator_frame.h>
86#include <symbol_viewer_frame.h>
87#include <tool/picker_tool.h>
88#include <tool/tool_manager.h>
89#include <tools/sch_actions.h>
90#include <tools/sch_selection.h>
96#include <view/view_controls.h>
97#include <widgets/wx_infobar.h>
103#include <view/view.h>
104#include <zoom_defines.h>
106#include <gal/gal_print.h>
108
114static const wxChar traceSchPaste[] = wxT( "KICAD_SCH_PASTE" );
115
116namespace
117{
118constexpr int clipboardMaxBitmapSize = 4096;
119constexpr double clipboardBboxInflation = 0.02; // Small padding around selection
120
121
122std::vector<SCH_ITEM*> collectSelectionItems( const SCH_SELECTION& aSelection )
123{
124 std::vector<SCH_ITEM*> items;
125 items.reserve( aSelection.GetSize() );
126
127 for( EDA_ITEM* item : aSelection.GetItems() )
128 {
129 SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( item );
130
131 if( schItem )
132 items.push_back( schItem );
133 }
134
135 return items;
136}
137
138
139BOX2I expandedSelectionBox( const SCH_SELECTION& aSelection )
140{
141 BOX2I bbox = aSelection.GetBoundingBox();
142
143 if( bbox.GetWidth() > 0 && bbox.GetHeight() > 0 )
144 bbox.Inflate( bbox.GetWidth() * clipboardBboxInflation,
145 bbox.GetHeight() * clipboardBboxInflation );
146
147 return bbox;
148}
149
150
151bool generateHtmlFromPngData( const wxMemoryBuffer& aPngData, wxMemoryBuffer& aHtmlBuffer )
152{
153 if( aPngData.GetDataLen() == 0 )
154 return false;
155
156 std::vector<uint8_t> pngVec( static_cast<const uint8_t*>( aPngData.GetData() ),
157 static_cast<const uint8_t*>( aPngData.GetData() ) + aPngData.GetDataLen() );
158
159 std::vector<uint8_t> base64Data;
160 base64::encode( pngVec, base64Data );
161
162 std::string html = "<img src=\"data:image/png;base64,";
163 html.append( reinterpret_cast<const char*>( base64Data.data() ), base64Data.size() );
164 html.append( "\" />" );
165
166 aHtmlBuffer.SetDataLen( 0 );
167 aHtmlBuffer.AppendData( html.data(), html.size() );
168
169 return true;
170}
171
172
173bool plotSelectionToSvg( SCH_EDIT_FRAME* aFrame, const SCH_SELECTION& aSelection, const BOX2I& aBBox,
174 wxMemoryBuffer& aBuffer )
175{
176 SCH_RENDER_SETTINGS renderSettings( *aFrame->GetRenderSettings() );
177 renderSettings.LoadColors( aFrame->GetColorSettings() );
178 renderSettings.SetDefaultFont( aFrame->eeconfig()->m_Appearance.default_font );
179 renderSettings.m_ShowHiddenPins = false;
180 renderSettings.m_ShowHiddenFields = false;
181
182 std::unique_ptr<SVG_PLOTTER> plotter = std::make_unique<SVG_PLOTTER>();
183 plotter->SetRenderSettings( &renderSettings );
184
185 PAGE_INFO pageInfo = aFrame->GetScreen()->GetPageSettings();
186 pageInfo.SetWidthMils( schIUScale.IUToMils( aBBox.GetWidth() ) );
187 pageInfo.SetHeightMils( schIUScale.IUToMils( aBBox.GetHeight() ) );
188
189 plotter->SetPageSettings( pageInfo );
190 plotter->SetColorMode( true );
191
192 VECTOR2I plot_offset = aBBox.GetOrigin();
193 plotter->SetViewport( plot_offset, schIUScale.IU_PER_MILS / 10, 1.0, false );
194 plotter->SetCreator( wxT( "Eeschema-SVG" ) );
195
196 wxFileName tempFile( wxFileName::CreateTempFileName( wxS( "kicad_svg" ) ) );
197
198 if( !plotter->OpenFile( tempFile.GetFullPath() ) )
199 {
200 wxRemoveFile( tempFile.GetFullPath() );
201 return false;
202 }
203
204 LOCALE_IO toggle;
205 SCH_PLOT_OPTS plotOpts;
206 plotOpts.m_plotHopOver = aFrame->Schematic().Settings().GetHopOverScale() > 0.0;
207
208 plotter->StartPlot( wxT( "1" ) );
209 aFrame->GetScreen()->Plot( plotter.get(), plotOpts, collectSelectionItems( aSelection ) );
210 plotter->EndPlot();
211 plotter.reset();
212
213 bool ok = LoadFileToMemory( tempFile.GetFullPath(), aBuffer );
214 wxRemoveFile( tempFile.GetFullPath() );
215 return ok;
216}
217
218
224wxImage renderSelectionToBitmap( SCH_EDIT_FRAME* aFrame, const SCH_SELECTION& aSelection, const BOX2I& aBBox,
225 int aWidth, int aHeight, bool aUseAlpha, bool aIncludeDrawingSheet )
226{
227 wxImage image( aWidth, aHeight, false );
228 image.SetAlpha();
229
230 double actualPPI_x = (double) aWidth / schIUScale.IUTomm( aBBox.GetWidth() ) * 25.4;
231 double actualPPI_y = (double) aHeight / schIUScale.IUTomm( aBBox.GetHeight() ) * 25.4;
232 double actualPPI = std::max( actualPPI_x, actualPPI_y );
233
234 VECTOR2D pageSizeIn( (double) aWidth / actualPPI, (double) aHeight / actualPPI );
235
236 {
239
240 std::unique_ptr<KIGFX::CAIRO_PRINT_GAL> gal = KIGFX::CAIRO_PRINT_GAL::Create( options, &image, actualPPI );
241
242 if( !gal )
243 return wxImage();
244
245 KIGFX::PRINT_CONTEXT* printCtx = gal->GetPrintCtx();
246 std::unique_ptr<KIGFX::SCH_PAINTER> painter = std::make_unique<KIGFX::SCH_PAINTER>( gal.get() );
247 std::unique_ptr<KIGFX::VIEW> view = std::make_unique<KIGFX::VIEW>();
248
249 painter->SetSchematic( &aFrame->Schematic() );
250 view->SetGAL( gal.get() );
251 view->SetPainter( painter.get() );
252 view->SetScaleLimits( ZOOM_MAX_LIMIT_EESCHEMA, ZOOM_MIN_LIMIT_EESCHEMA );
253 view->SetScale( 1.0 );
254
255 gal->SetWorldUnitLength( SCH_WORLD_UNIT );
256 gal->SetSheetSize( pageSizeIn );
257 gal->SetNativePaperSize( pageSizeIn, printCtx->HasNativeLandscapeRotation() );
258
259 // Clone items and add to view
260 std::vector<std::unique_ptr<SCH_ITEM>> clonedItems;
261 clonedItems.reserve( aSelection.GetSize() );
262
263 for( EDA_ITEM* item : aSelection.GetItems() )
264 {
265 SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( item );
266
267 if( !schItem )
268 continue;
269
270 SCH_ITEM* clone = static_cast<SCH_ITEM*>( schItem->Clone() );
271 clonedItems.emplace_back( clone );
272 view->Add( clone );
273 }
274
275 SCH_RENDER_SETTINGS* dstSettings = painter->GetSettings();
276 *dstSettings = *aFrame->GetRenderSettings();
277 dstSettings->m_ShowPinsElectricalType = false;
278 dstSettings->LoadColors( aFrame->GetColorSettings( false ) );
280 dstSettings->SetDefaultFont( aFrame->eeconfig()->m_Appearance.default_font );
281 dstSettings->SetIsPrinting( true );
282
283 if( aUseAlpha )
284 dstSettings->SetBackgroundColor( COLOR4D::CLEAR );
285
286 for( int i = 0; i < KIGFX::VIEW::VIEW_MAX_LAYERS; ++i )
287 {
288 view->SetLayerVisible( i, true );
289 view->SetLayerTarget( i, KIGFX::TARGET_NONCACHED );
290 }
291
292 view->SetLayerVisible( LAYER_DRAWINGSHEET, aIncludeDrawingSheet );
293
294 // Create and add drawing sheet proxy view item if requested
295 std::unique_ptr<DS_PROXY_VIEW_ITEM> drawingSheet;
296
297 if( aIncludeDrawingSheet )
298 {
299 SCH_SCREEN* screen = aFrame->GetScreen();
300
301 drawingSheet.reset( new DS_PROXY_VIEW_ITEM( schIUScale, &screen->GetPageSettings(),
302 &screen->Schematic()->Project(), &screen->GetTitleBlock(),
303 screen->Schematic()->GetProperties() ) );
304 drawingSheet->SetPageNumber( TO_UTF8( screen->GetPageNumber() ) );
305 drawingSheet->SetSheetCount( screen->GetPageCount() );
306 drawingSheet->SetFileName( TO_UTF8( screen->GetFileName() ) );
307 drawingSheet->SetColorLayer( LAYER_SCHEMATIC_DRAWINGSHEET );
308 drawingSheet->SetPageBorderColorLayer( LAYER_SCHEMATIC_PAGE_LIMITS );
309 drawingSheet->SetIsFirstPage( screen->GetVirtualPageNumber() == 1 );
310 drawingSheet->SetSheetName( TO_UTF8( aFrame->GetScreenDesc() ) );
311 drawingSheet->SetSheetPath( TO_UTF8( aFrame->GetFullScreenDesc() ) );
312
313 wxString currentVariant = screen->Schematic()->GetCurrentVariant();
314 wxString variantDesc = screen->Schematic()->GetVariantDescription( currentVariant );
315 drawingSheet->SetVariantName( TO_UTF8( currentVariant ) );
316 drawingSheet->SetVariantDesc( TO_UTF8( variantDesc ) );
317
318 view->Add( drawingSheet.get() );
319 }
320
321 view->SetCenter( aBBox.Centre() );
322 view->UseDrawPriority( true );
323
324 gal->SetClearColor( dstSettings->GetBackgroundColor() );
325 gal->ClearScreen();
326
327 {
328 KIGFX::GAL_DRAWING_CONTEXT ctx( gal.get() );
329 view->Redraw();
330 }
331 }
332
333 return image;
334}
335
336
337wxImage renderSelectionToImageForClipboard( SCH_EDIT_FRAME* aFrame, const SCH_SELECTION& aSelection,
338 const BOX2I& aBBox, bool aUseAlpha, bool aIncludeDrawingSheet )
339{
340 const double c_targetPPI = 300;
341 const double c_targetPixelsPerMM = c_targetPPI / 25.4;
342
343 VECTOR2I size = aBBox.GetSize();
344
345 if( size.x <= 0 || size.y <= 0 )
346 return wxImage();
347
348 int bitmapWidth = KiROUND( schIUScale.IUTomm( size.x ) * c_targetPixelsPerMM );
349 int bitmapHeight = KiROUND( schIUScale.IUTomm( size.y ) * c_targetPixelsPerMM );
350
351 // Clamp to maximum size while preserving aspect ratio
352 if( bitmapWidth > clipboardMaxBitmapSize || bitmapHeight > clipboardMaxBitmapSize )
353 {
354 double scaleDown = (double) clipboardMaxBitmapSize / std::max( bitmapWidth, bitmapHeight );
355 bitmapWidth = KiROUND( bitmapWidth * scaleDown );
356 bitmapHeight = KiROUND( bitmapHeight * scaleDown );
357 }
358
359 if( bitmapWidth <= 0 || bitmapHeight <= 0 )
360 return wxImage();
361
362 wxImage result = renderSelectionToBitmap( aFrame, aSelection, aBBox, bitmapWidth, bitmapHeight, aUseAlpha,
363 aIncludeDrawingSheet );
364
365 return result;
366}
367} // namespace
368
369
371{
372 m_frame->NewProject();
373 return 0;
374}
375
376
378{
379 m_frame->LoadProject();
380 return 0;
381}
382
383
385{
386 m_frame->SaveProject();
387 return 0;
388}
389
390
392{
393 m_frame->SaveProject( true );
394 return 0;
395}
396
397
399{
400 SCH_SHEET* curr_sheet = m_frame->GetCurrentSheet().Last();
401 wxFileName curr_fn = curr_sheet->GetFileName();
402 wxFileDialog dlg( m_frame, _( "Schematic Files" ), curr_fn.GetPath(), curr_fn.GetFullName(),
403 FILEEXT::KiCadSchematicFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
404
406
407 if( dlg.ShowModal() == wxID_CANCEL )
408 return false;
409
410 wxString newFilename = EnsureFileExtension( dlg.GetPath(), FILEEXT::KiCadSchematicFileExtension );
411
412 m_frame->saveSchematicFile( curr_sheet, newFilename );
413 return 0;
414}
415
416
418{
419 SCHEMATIC& schematic = m_frame->Schematic();
420 SCH_SHEET& root = schematic.Root();
421
422 // Save original sheet path to restore if user cancels
423 SCH_SHEET_PATH originalSheet = m_frame->GetCurrentSheet();
424 bool wasOnSubsheet = ( m_frame->GetCurrentSheet().Last() != &root );
425
426 // Navigate to root sheet first (needed for proper reload), but don't repaint yet
427 if( wasOnSubsheet )
428 {
429 // Use the properly constructed root sheet path from the hierarchy
430 // (manually pushing root creates a path with empty KIID which causes assertions)
431 SCH_SHEET_PATH rootSheetPath = schematic.Hierarchy().at( 0 );
432
433 m_frame->GetToolManager()->RunAction<SCH_SHEET_PATH*>( SCH_ACTIONS::changeSheet,
434 &rootSheetPath );
435 // Don't call wxSafeYield() here - avoid repainting the root sheet before the dialog
436 }
437
438 wxString msg;
439 msg.Printf( _( "Revert '%s' (and all sub-sheets) to last version saved?" ), schematic.GetFileName() );
440
441 if( !IsOK( m_frame, msg ) )
442 {
443 // User cancelled - navigate back to original sheet
444 if( wasOnSubsheet )
445 {
446 m_frame->GetToolManager()->RunAction<SCH_SHEET_PATH*>( SCH_ACTIONS::changeSheet,
447 &originalSheet );
448 wxSafeYield();
449 }
450
451 return false;
452 }
453
454 SCH_SCREENS screenList( schematic.Root() );
455
456 for( SCH_SCREEN* screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
457 screen->SetContentModified( false ); // do not prompt the user for changes
458
459 m_frame->ReleaseFile();
460 m_frame->OpenProjectFiles( std::vector<wxString>( 1, schematic.GetFileName() ), KICTL_REVERT );
461
462 return 0;
463}
464
465
467{
468 m_frame->ShowSchematicSetupDialog();
469 return 0;
470}
471
472
474{
475 PICKED_ITEMS_LIST undoCmd;
477 ITEM_PICKER wrapper( m_frame->GetScreen(), undoItem, UNDO_REDO::PAGESETTINGS );
478
479 undoCmd.PushItem( wrapper );
480 undoCmd.SetDescription( _( "Page Settings" ) );
481 m_frame->SaveCopyInUndoList( undoCmd, UNDO_REDO::PAGESETTINGS, false );
482
483 DIALOG_EESCHEMA_PAGE_SETTINGS dlg( m_frame, m_frame->Schematic().GetEmbeddedFiles(),
486
487 if( dlg.ShowModal() == wxID_OK )
488 {
489 // Update text variables
490 m_frame->GetCanvas()->GetView()->MarkDirty();
491 m_frame->GetCanvas()->GetView()->UpdateAllItems( KIGFX::REPAINT );
492 m_frame->GetCanvas()->Refresh();
493
494 m_frame->OnModify();
495 }
496 else
497 {
498 m_frame->RollbackSchematicFromUndo();
499 }
500
501 return 0;
502}
503
504
506{
507 SCH_SCREENS schematic( m_frame->Schematic().Root() );
508
509 if( schematic.HasNoFullyDefinedLibIds() )
510 RescueLegacyProject( true );
511 else
513
514 return 0;
515}
516
517
518bool SCH_EDITOR_CONTROL::RescueLegacyProject( bool aRunningOnDemand )
519{
520 LEGACY_RESCUER rescuer( m_frame->Prj(), &m_frame->Schematic(), &m_frame->GetCurrentSheet(),
521 m_frame->GetCanvas()->GetBackend() );
522
523 return rescueProject( rescuer, aRunningOnDemand );
524}
525
526
528{
529 SYMBOL_LIB_TABLE_RESCUER rescuer( m_frame->Prj(), &m_frame->Schematic(), &m_frame->GetCurrentSheet(),
530 m_frame->GetCanvas()->GetBackend() );
531
532 return rescueProject( rescuer, aRunningOnDemand );
533}
534
535
536bool SCH_EDITOR_CONTROL::rescueProject( RESCUER& aRescuer, bool aRunningOnDemand )
537{
538 if( !RESCUER::RescueProject( m_frame, aRescuer, aRunningOnDemand ) )
539 return false;
540
541 if( aRescuer.GetCandidateCount() )
542 {
543 KIWAY_PLAYER* viewer = m_frame->Kiway().Player( FRAME_SCH_VIEWER, false );
544
545 if( viewer )
546 static_cast<SYMBOL_VIEWER_FRAME*>( viewer )->ReCreateLibList();
547
548 if( aRunningOnDemand )
549 {
550 SCH_SCREENS schematic( m_frame->Schematic().Root() );
551
552 schematic.UpdateSymbolLinks();
553 m_frame->RecalculateConnections( nullptr, GLOBAL_CLEANUP );
554 }
555
556 m_frame->ClearUndoRedoList();
557 m_frame->SyncView();
558 m_frame->GetCanvas()->Refresh();
559 m_frame->OnModify();
560 }
561
562 return true;
563}
564
565
567{
568 DIALOG_SYMBOL_REMAP dlgRemap( m_frame );
569
570 dlgRemap.ShowQuasiModal();
571
572 m_frame->GetCanvas()->Refresh( true );
573
574 return 0;
575}
576
577
579{
580 DIALOG_PRINT dlg( m_frame );
581
582 dlg.ShowModal();
583
584 return 0;
585}
586
587
589{
591
592 dlg.ShowModal();
593
594 return 0;
595}
596
597
599{
600 m_frame->Schematic().OnSchSelectionChanged();
601 doCrossProbeSchToPcb( aEvent, false );
602 return 0;
603}
604
605
607{
608 doCrossProbeSchToPcb( aEvent, true );
609 return 0;
610}
611
612
613void SCH_EDITOR_CONTROL::doCrossProbeSchToPcb( const TOOL_EVENT& aEvent, bool aForce )
614{
615 // Don't get in an infinite loop SCH -> PCB -> SCH -> PCB -> SCH -> ...
616 if( m_probingPcbToSch || m_frame->IsSyncingSelection() )
617 return;
618
619 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
620 SCH_SELECTION& selection = aForce ? selTool->RequestSelection() : selTool->GetSelection();
621
622 m_frame->SendSelectItemsToPcb( selection.GetItemsSortedBySelectionOrder(), aForce );
623}
624
625
627{
628 bool savePowerSymbols = false;
629 bool map = false;
631 wxString targetLib;
632 wxString msg;
633
634 targetLib = m_frame->SelectLibrary( _( "Export Symbols" ), _( "Export symbols to library:" ),
635 { { _( "Include power symbols in export" ), &savePowerSymbols },
636 { _( "Update schematic symbols to link to exported symbols" ), &map }
637 } );
638
639 if( targetLib.empty() )
640 return 0;
641
642 SCH_SHEET_LIST sheets = m_frame->Schematic().BuildSheetListSortedByPageNumbers();
643 SCH_REFERENCE_LIST symbols;
644 sheets.GetSymbols( symbols, savePowerSymbols ? SYMBOL_FILTER_ALL : SYMBOL_FILTER_NON_POWER );
645
646 std::map<LIB_ID, LIB_SYMBOL*> libSymbols;
647 std::map<LIB_ID, std::vector<SCH_SYMBOL*>> symbolMap;
648
649 for( size_t i = 0; i < symbols.GetCount(); ++i )
650 {
651 SCH_SYMBOL* symbol = symbols[i].GetSymbol();
652 LIB_SYMBOL* libSymbol = symbol->GetLibSymbolRef().get();
653 LIB_ID id = libSymbol->GetLibId();
654
655 if( libSymbols.count( id ) )
656 {
657 wxASSERT_MSG( libSymbols[id]->Compare( *libSymbol, ~SCH_ITEM::COMPARE_FLAGS::UUID ) == 0,
658 "Two symbols have the same LIB_ID but are different!" );
659 }
660 else
661 {
662 libSymbols[id] = libSymbol;
663 }
664
665 symbolMap[id].emplace_back( symbol );
666 }
667
668 bool append = false;
669 SCH_COMMIT commit( m_frame );
671
672 auto optRow = adapter->GetRow( targetLib );
673 wxCHECK( optRow, 0 );
674 const LIBRARY_TABLE_ROW* row = *optRow;
675
676 SCH_IO_MGR::SCH_FILE_T type = SCH_IO_MGR::EnumFromStr( row->Type() );
677 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( type ) );
678
679 wxFileName dest = LIBRARY_MANAGER::GetFullURI( row );
680 dest.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
681
682 for( const std::pair<const LIB_ID, LIB_SYMBOL*>& it : libSymbols )
683 {
684 LIB_SYMBOL* origSym = it.second;
685 LIB_SYMBOL* newSym = origSym->Flatten().release();
686
687 try
688 {
689 pi->SaveSymbol( dest.GetFullPath(), newSym );
690 }
691 catch( const IO_ERROR& ioe )
692 {
693 msg.Printf( _( "Error saving symbol %s to library '%s'." ), newSym->GetName(), row->Nickname() );
694 msg += wxS( "\n\n" ) + ioe.What();
695 wxLogWarning( msg );
696 return 0;
697 }
698
699 if( map )
700 {
701 LIB_ID id = it.first;
702 id.SetLibNickname( targetLib );
703
704 for( SCH_SYMBOL* symbol : symbolMap[it.first] )
705 {
706 SCH_SCREEN* parentScreen = static_cast<SCH_SCREEN*>( symbol->GetParent() );
707
708 wxCHECK2( parentScreen, continue );
709
710 commit.Modify( symbol, parentScreen, RECURSE_MODE::NO_RECURSE );
711 symbol->SetLibId( id );
712 append = true;
713 }
714 }
715 }
716
717 if( append )
718 {
719 std::set<SCH_SCREEN*> processedScreens;
720
721 for( SCH_SHEET_PATH& sheet : sheets )
722 {
723 SCH_SCREEN* screen = sheet.LastScreen();
724
725 if( processedScreens.find( ( screen ) ) == processedScreens.end() )
726 {
727 processedScreens.insert( screen );
728 screen->UpdateSymbolLinks();
729 }
730 }
731
732 commit.Push( wxS( "Update Library Identifiers" ) );
733 }
734
735 return 0;
736}
737
738
739#define HITTEST_THRESHOLD_PIXELS 5
740
742{
743 PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
744 KIWAY_PLAYER* sim_player = m_frame->Kiway().Player( FRAME_SIMULATOR, false );
745 SIMULATOR_FRAME* sim_Frame = static_cast<SIMULATOR_FRAME*>( sim_player );
746
747 if( !sim_Frame ) // Defensive coding; shouldn't happen.
748 return 0;
749
750 if( wxWindow* blocking_win = sim_Frame->Kiway().GetBlockingDialog() )
751 blocking_win->Close( true );
752
753 // Deactivate other tools; particularly important if another PICKER is currently running
754 Activate();
755
757 picker->SetSnapping( false );
758 picker->ClearHandlers();
759
760 picker->SetClickHandler(
761 [this]( const VECTOR2D& aPosition )
762 {
763 KIWAY_PLAYER* player = m_frame->Kiway().Player( FRAME_SIMULATOR, false );
764 SIMULATOR_FRAME* simFrame = static_cast<SIMULATOR_FRAME*>( player );
765 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
766
767 // We do not really want to keep an item selected in schematic,
768 // so clear the current selection
769 selTool->ClearSelection();
770
771 EDA_ITEM* item = selTool->GetNode( aPosition );
772 SCH_SHEET_PATH& sheet = m_frame->GetCurrentSheet();
773 wxString variant = m_frame->Schematic().GetCurrentVariant();
774
775 if( !item )
776 return false;
777
778 if( item->Type() == SCH_PIN_T )
779 {
780 SCH_PIN* schPin = static_cast<SCH_PIN*>( item );
781 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( schPin->GetParentSymbol() );
782 SCH_PIN* libPin = schPin->GetLibPin();
783
784 if( !symbol || !libPin )
785 return false;
786
787 try
788 {
790 SIM_LIB_MGR mgr( &m_frame->Prj() );
791
792 std::vector<EMBEDDED_FILES*> embeddedFilesStack;
793 embeddedFilesStack.push_back( m_frame->Schematic().GetEmbeddedFiles() );
794
795 if( EMBEDDED_FILES* symbolEmbeddedFile = symbol->GetEmbeddedFiles() )
796 embeddedFilesStack.push_back( symbolEmbeddedFile );
797
798 mgr.SetFilesStack( std::move( embeddedFilesStack ) );
799
800 SIM_MODEL& model = mgr.CreateModel( &sheet, *symbol, true, 0, variant, reporter ).model;
801
802 if( reporter.HasMessage() )
803 THROW_IO_ERROR( reporter.GetMessages() );
804
805 SPICE_ITEM spiceItem;
806 spiceItem.refName = symbol->GetRef( &sheet ).ToStdString();
807 std::vector<std::string> currentNames = model.SpiceGenerator().CurrentNames( spiceItem );
808
809 if( currentNames.size() == 0 )
810 {
811 return true;
812 }
813 else if( currentNames.size() == 1 )
814 {
815 if( simFrame )
816 simFrame->AddCurrentTrace( currentNames.at( 0 ) );
817
818 return true;
819 }
820
821 int modelPinIndex = model.FindModelPinIndex( libPin->GetNumber().ToStdString() );
822
823 if( modelPinIndex != SIM_MODEL_PIN::NOT_CONNECTED )
824 {
825 wxString name = currentNames.at( modelPinIndex );
826
827 if( simFrame )
828 simFrame->AddCurrentTrace( name );
829 }
830 }
831 catch( const IO_ERROR& e )
832 {
834 }
835 }
836 else if( item->IsType( { SCH_ITEM_LOCATE_WIRE_T } ) || item->IsType( { SCH_JUNCTION_T } ) )
837 {
838 if( SCH_CONNECTION* conn = static_cast<SCH_ITEM*>( item )->Connection() )
839 {
840 wxString spiceNet = UnescapeString( conn->Name() );
842
843 if( simFrame )
844 simFrame->AddVoltageTrace( wxString::Format( "V(%s)", spiceNet ) );
845 }
846 }
847
848 return true;
849 } );
850
851 picker->SetMotionHandler(
852 [this]( const VECTOR2D& aPos )
853 {
854 SCH_COLLECTOR collector;
855 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
856 collector.Collect( m_frame->GetScreen(), { SCH_ITEM_LOCATE_WIRE_T,
857 SCH_PIN_T,
858 SCH_SHEET_PIN_T }, aPos );
859
860 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
861 selectionTool->GuessSelectionCandidates( collector, aPos );
862
863 EDA_ITEM* item = collector.GetCount() == 1 ? collector[0] : nullptr;
864 SCH_LINE* wire = dynamic_cast<SCH_LINE*>( item );
865
866 const SCH_CONNECTION* conn = nullptr;
867
868 if( wire )
869 {
870 item = nullptr;
871 conn = wire->Connection();
872 }
873
874 if( item && item->Type() == SCH_PIN_T )
875 m_toolMgr->GetTool<PICKER_TOOL>()->SetCursor( KICURSOR::CURRENT_PROBE );
876 else
877 m_toolMgr->GetTool<PICKER_TOOL>()->SetCursor( KICURSOR::VOLTAGE_PROBE );
878
879 if( m_pickerItem != item )
880 {
881 if( m_pickerItem )
882 selectionTool->UnbrightenItem( m_pickerItem );
883
884 m_pickerItem = item;
885
886 if( m_pickerItem )
887 selectionTool->BrightenItem( m_pickerItem );
888 }
889
890 wxString connectionName = ( conn ) ? conn->Name() : wxString( wxS( "" ) );
891
892 if( m_frame->GetHighlightedConnection() != connectionName )
893 {
894 m_frame->SetHighlightedConnection( connectionName );
895
896 TOOL_EVENT dummyEvent;
897 UpdateNetHighlighting( dummyEvent );
898 }
899 } );
900
901 picker->SetFinalizeHandler(
902 [this]( const int& aFinalState )
903 {
904 if( m_pickerItem )
905 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
906
907 if( !m_frame->GetHighlightedConnection().IsEmpty() )
908 {
909 m_frame->SetHighlightedConnection( wxEmptyString );
910
911 TOOL_EVENT dummyEvent;
912 UpdateNetHighlighting( dummyEvent );
913 }
914
915 // Wake the selection tool after exiting to ensure the cursor gets updated
916 // and deselect previous selection from simulator to avoid any issue
917 // ( avoid crash in some cases when the SimProbe tool is deselected )
918 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
919 selectionTool->ClearSelection();
921 } );
922
923 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
924
925 return 0;
926}
927
928
930{
931 PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
932
933 // Deactivate other tools; particularly important if another PICKER is currently running
934 Activate();
935
936 picker->SetCursor( KICURSOR::TUNE );
937 picker->SetSnapping( false );
938 picker->ClearHandlers();
939
940 picker->SetClickHandler(
941 [this]( const VECTOR2D& aPosition )
942 {
943 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
944 EDA_ITEM* item = nullptr;
945 selTool->SelectPoint( aPosition, { SCH_SYMBOL_T, SCH_FIELD_T }, &item );
946
947 if( !item )
948 return false;
949
950 if( item->Type() != SCH_SYMBOL_T )
951 {
952 item = item->GetParent();
953
954 if( item->Type() != SCH_SYMBOL_T )
955 return false;
956 }
957
958 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
959 SCH_SHEET_PATH sheetPath = symbol->Schematic()->CurrentSheet();
960 KIWAY_PLAYER* simFrame = m_frame->Kiway().Player( FRAME_SIMULATOR, false );
961
962 if( simFrame )
963 {
964 if( wxWindow* blocking_win = simFrame->Kiway().GetBlockingDialog() )
965 blocking_win->Close( true );
966
967 static_cast<SIMULATOR_FRAME*>( simFrame )->AddTuner( sheetPath, symbol );
968 }
969
970 // We do not really want to keep a symbol selected in schematic,
971 // so clear the current selection
972 selTool->ClearSelection();
973 return true;
974 } );
975
976 picker->SetMotionHandler(
977 [this]( const VECTOR2D& aPos )
978 {
979 SCH_COLLECTOR collector;
980 collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
981 collector.Collect( m_frame->GetScreen(), { SCH_SYMBOL_T, SCH_FIELD_T }, aPos );
982
983 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
984 selectionTool->GuessSelectionCandidates( collector, aPos );
985
986 EDA_ITEM* item = collector.GetCount() == 1 ? collector[0] : nullptr;
987
988 if( item && item->Type() == SCH_FIELD_T )
989 item = static_cast<SCH_FIELD*>( item )->GetParentSymbol();
990
991 if( m_pickerItem != item )
992 {
993 if( m_pickerItem )
994 selectionTool->UnbrightenItem( m_pickerItem );
995
996 m_pickerItem = item;
997
998 if( m_pickerItem )
999 selectionTool->BrightenItem( m_pickerItem );
1000 }
1001 } );
1002
1003 picker->SetFinalizeHandler(
1004 [this]( const int& aFinalState )
1005 {
1006 if( m_pickerItem )
1007 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
1008
1009 // Wake the selection tool after exiting to ensure the cursor gets updated
1010 // and deselect previous selection from simulator to avoid any issue
1011 // ( avoid crash in some cases when the SimTune tool is deselected )
1012 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1013 selectionTool->ClearSelection();
1015 } );
1016
1017 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
1018
1019 return 0;
1020}
1021
1022
1023// A singleton reference for clearing the highlight
1025
1026
1027static bool highlightNet( TOOL_MANAGER* aToolMgr, const VECTOR2D& aPosition )
1028{
1029 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "highlightNet: pos=(%f,%f) clear=%d", aPosition.x, aPosition.y,
1030 ( aPosition == CLEAR ) );
1031 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( aToolMgr->GetToolHolder() );
1032 SCH_SELECTION_TOOL* selTool = aToolMgr->GetTool<SCH_SELECTION_TOOL>();
1033 SCH_EDITOR_CONTROL* editorControl = aToolMgr->GetTool<SCH_EDITOR_CONTROL>();
1034 SCH_CONNECTION* conn = nullptr;
1035 SCH_ITEM* item = nullptr;
1036 bool retVal = true;
1037
1038 if( aPosition != CLEAR )
1039 {
1040 ERC_TESTER erc( &editFrame->Schematic() );
1041
1042 if( erc.TestDuplicateSheetNames( false ) > 0 )
1043 {
1044 wxMessageBox( _( "Error: duplicate sub-sheet names found in current sheet." ) );
1045 retVal = false;
1046 }
1047 else
1048 {
1049 item = static_cast<SCH_ITEM*>( selTool->GetNode( aPosition ) );
1050 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "highlightNet: item=%p type=%d", (void*) item,
1051 item ? (int) item->Type() : -1 );
1052 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item );
1053
1054 if( item )
1055 {
1056 if( item->IsConnectivityDirty() )
1057 editFrame->RecalculateConnections( nullptr, NO_CLEANUP );
1058
1059 if( item->Type() == SCH_FIELD_T )
1060 symbol = dynamic_cast<SCH_SYMBOL*>( item->GetParent() );
1061
1062 if( symbol && symbol->GetLibSymbolRef() && symbol->GetLibSymbolRef()->IsPower() )
1063 {
1064 std::vector<SCH_PIN*> pins = symbol->GetPins();
1065
1066 if( pins.size() == 1 )
1067 conn = pins[0]->Connection();
1068 }
1069 else
1070 {
1071 conn = item->Connection();
1072 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "highlightNet: conn=%p name=%s",
1073 (void*) conn, conn ? conn->Name() : wxString( "" ) );
1074 }
1075 }
1076 }
1077 }
1078
1079 wxString connName = ( conn ) ? conn->Name() : wxString( wxS( "" ) );
1080
1081 if( !conn )
1082 {
1083 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "highlightNet: no connection under cursor" );
1084 editFrame->SetStatusText( wxT( "" ) );
1085 editFrame->SendCrossProbeClearHighlight();
1086 editFrame->SetHighlightedConnection( wxEmptyString );
1087 // Also clear any highlighted net chain so ESC or clicking empty space clears both modes
1088 editFrame->SetHighlightedNetChain( wxEmptyString );
1089 editorControl->SetHighlightBusMembers( false );
1090 }
1091 else
1092 {
1093 NET_NAVIGATOR_ITEM_DATA itemData( editFrame->GetCurrentSheet(), item );
1094
1095 if( connName != editFrame->GetHighlightedConnection() )
1096 {
1097 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "highlightNet: setting highlighted connection to %s",
1098 connName );
1099 editorControl->SetHighlightBusMembers( false );
1100 // Clear any previous chain highlight when switching to net highlight
1101 editFrame->SetHighlightedNetChain( wxEmptyString );
1102 editFrame->SetCrossProbeConnection( conn );
1103 editFrame->SetHighlightedConnection( connName, &itemData );
1104 }
1105 else
1106 {
1107 // Same net requested again. Try to expand to the containing chain if available.
1108 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "highlightNet: same net re-invoked; trying to expand to chain" );
1109 CONNECTION_GRAPH* graph = editFrame ? editFrame->Schematic().ConnectionGraph() : nullptr;
1110
1111 if( graph )
1112 {
1113 // An empty chain list is valid; rely on the explicit built flag.
1114 if( !graph->NetChainsBuilt() )
1115 {
1116 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "highlightNet: chains not built; rebuilding before expand" );
1117 SCH_SHEET_LIST sheets = editFrame->Schematic().Hierarchy();
1118 graph->Recalculate( sheets, /*aUnconditional=*/true );
1119 }
1120
1121 if( SCH_NETCHAIN* sig = graph->GetNetChainForNet( connName ) )
1122 {
1123 // Only switch if this net is indeed part of a multi-net chain or any chain
1124 wxString chainName = sig->GetName();
1125 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "highlightNet: expanding to chain '%s' (nets=%zu)",
1126 chainName, sig->GetNets().size() );
1127 editFrame->SetHighlightedConnection( wxEmptyString );
1128 editFrame->SetHighlightedNetChain( chainName );
1129 editorControl->SetHighlightBusMembers( false );
1130 }
1131 else
1132 {
1133 // Fallback to previous behavior: toggle bus members
1134 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "highlightNet: no chain found; toggling bus members" );
1135 editorControl->SetHighlightBusMembers( !editorControl->GetHighlightBusMembers() );
1136
1137 if( item != editFrame->GetSelectedNetNavigatorItem() )
1138 editFrame->SelectNetNavigatorItem( &itemData );
1139 }
1140 }
1141 else
1142 {
1143 // No graph; fallback to toggling bus members
1144 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "highlightNet: no graph; toggling bus members" );
1145 editorControl->SetHighlightBusMembers( !editorControl->GetHighlightBusMembers() );
1146
1147 if( item != editFrame->GetSelectedNetNavigatorItem() )
1148 editFrame->SelectNetNavigatorItem( &itemData );
1149 }
1150 }
1151 }
1152
1153 editFrame->UpdateNetHighlightStatus();
1154
1156 editorControl->UpdateNetHighlighting( dummy );
1157 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "highlightNet: done" );
1158
1159 return retVal;
1160}
1161
1162
1164{
1166 VECTOR2D cursorPos = controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
1167
1168 highlightNet( m_toolMgr, cursorPos );
1169
1170 return 0;
1171}
1172
1173
1175{
1177 VECTOR2D cursorPos = controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
1178 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_toolMgr->GetToolHolder() );
1179 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1180 SCH_ITEM* item = static_cast<SCH_ITEM*>( selTool->GetNode( cursorPos ) );
1181 wxString netChainName;
1182 CONNECTION_GRAPH* graph = editFrame ? editFrame->Schematic().ConnectionGraph() : nullptr;
1183
1184 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "HighlightNetChain: cursor=(%f,%f) gridSnap=%d",
1185 cursorPos.x, cursorPos.y, !aEvent.DisableGridSnapping() );
1186 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "HighlightNetChain: item=%p type=%d",
1187 (void*) item, item ? (int) item->Type() : -1 );
1188
1189 if( graph && !graph->NetChainsBuilt() )
1190 {
1191 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "HighlightNetChain: chains not built; calling Recalculate(unconditional=true)" );
1192 SCH_SHEET_LIST sheets = editFrame->Schematic().Hierarchy();
1193 graph->Recalculate( sheets, /*aUnconditional=*/true );
1194 }
1195
1196 if( item )
1197 {
1198 SCH_CONNECTION* conn = item->Connection();
1199 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "HighlightNetChain: conn=%p name=%s",
1200 (void*) conn, conn ? conn->Name() : wxString( "" ) );
1201
1202 if( conn )
1203 {
1204 SCH_NETCHAIN* sig = graph ? graph->GetNetChainForNet( conn->Name() ) : nullptr;
1205
1206 if( sig )
1207 {
1208 netChainName = sig->GetName();
1209 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "HighlightNetChain: found chain=%s", netChainName );
1210 }
1211 else
1212 {
1213 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "HighlightNetChain: no chain for net=%s; falling back to net highlight", conn->Name() );
1214 editFrame->SetHighlightedNetChain( wxEmptyString );
1215 editFrame->SetHighlightedConnection( conn->Name() );
1216 }
1217 }
1218 }
1219
1220 if( !netChainName.IsEmpty() )
1221 {
1222 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "HighlightNetChain: SetHighlightedNetChain(%s)", netChainName );
1223 editFrame->SetHighlightedConnection( wxEmptyString );
1224 editFrame->SetHighlightedNetChain( netChainName );
1225
1226 // Cross-probe the chain's member nets to the PCB so the chain highlights there too.
1227 // The PCB side interprets the first member as the net to highlight; in a chain-aware
1228 // PCB build, all members will be included in a single highlight event.
1229 if( graph )
1230 {
1231 if( SCH_NETCHAIN* chain = graph->GetNetChainByName( netChainName ) )
1232 {
1233 const auto& nets = chain->GetNets();
1234
1235 if( !nets.empty() )
1236 editFrame->SendCrossProbeNetName( *nets.begin() );
1237 }
1238 }
1239 }
1240 editFrame->UpdateNetHighlightStatus();
1243 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "HighlightNetChain: UpdateNetHighlighting done" );
1244
1245 return 0;
1246}
1247
1249{
1250 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_toolMgr->GetToolHolder() );
1251 if( !editFrame )
1252 return 0;
1253
1254 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1256 VECTOR2D cursorPos = controls->GetCursorPosition( !aEvent.DisableGridSnapping() );
1257
1258 SCH_ITEM* target = nullptr;
1259
1260 // Prefer current selection; otherwise, use item under cursor
1261 if( selTool && selTool->GetSelection().GetSize() == 1 )
1262 target = static_cast<SCH_ITEM*>( selTool->GetSelection().Front() );
1263 else if( selTool )
1264 target = static_cast<SCH_ITEM*>( selTool->GetNode( cursorPos ) );
1265
1266 if( !target )
1267 return 0;
1268
1269 SCH_CONNECTION* conn = target->Connection();
1270 if( !conn )
1271 return 0;
1272
1273 SCHEMATIC& schematic = editFrame->Schematic();
1274 SCH_SCREEN* screen = editFrame->GetCurrentSheet().LastScreen();
1275
1276 // Find any 2-pin symbols that bridge this connection's net into another net and disable propagation
1277 int disabled = 0;
1278
1279 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
1280 {
1281 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1282 std::vector<SCH_PIN*> pins = symbol->GetPins( &schematic.CurrentSheet() );
1283
1284 if( pins.size() != 2 )
1285 continue;
1286
1287 SCH_PIN* pa = pins[0];
1288 SCH_PIN* pb = pins[1];
1289
1290 SCH_CONNECTION* ca = pa->Connection();
1291 SCH_CONNECTION* cb = pb->Connection();
1292
1293 if( !ca || !cb )
1294 continue;
1295
1296 // If either side matches the selected net and the other side is a different net,
1297 // this symbol is bridging the selected net into its chain.
1298 if( ( ca->Name() == conn->Name() && cb->Name() != conn->Name() )
1299 || ( cb->Name() == conn->Name() && ca->Name() != conn->Name() ) )
1300 {
1302 {
1304 disabled++;
1305 }
1306 }
1307 }
1308
1309 if( disabled > 0 )
1310 {
1311 // Rebuild connectivity/chains so the change takes effect
1312 CONNECTION_GRAPH* graph = schematic.ConnectionGraph();
1313 if( graph )
1314 {
1315 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "RemoveFromNetChain: disabled=%d, rebuilding chains", disabled );
1316 SCH_SHEET_LIST sheets = schematic.Hierarchy();
1317 graph->Recalculate( sheets, /*aUnconditional=*/true );
1318 m_frame->GetCanvas()->Refresh();
1319 }
1320 }
1321
1322 return 0;
1323}
1324
1325
1327{
1329 // Also clear any highlighted chain explicitly
1330 if( m_frame )
1331 m_frame->SetHighlightedNetChain( wxEmptyString );
1332
1333 return 0;
1334}
1335
1336
1338{
1339 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1340 SCHEMATIC& schematic = m_frame->Schematic();
1341 SCH_SCREEN* screen = m_frame->GetCurrentSheet().LastScreen();
1342
1343 std::vector<std::pair<SCH_CONNECTION*, VECTOR2D>> selectedConns;
1344
1345 for( EDA_ITEM* item : selectionTool->GetSelection() )
1346 {
1347 SCH_CONNECTION* conn = static_cast<SCH_ITEM*>( item )->Connection();
1348
1349 if( !conn )
1350 continue;
1351
1352 selectedConns.emplace_back( conn, item->GetPosition() );
1353 }
1354
1355 if( selectedConns.empty() )
1356 {
1357 m_frame->ShowInfoBarError( _( "No nets selected." ) );
1358 return 0;
1359 }
1360
1361 // Remove selection in favor of highlighting so the whole net is highlighted
1362 selectionTool->ClearSelection();
1363
1364 const auto getNetNamePattern =
1365 []( const SCH_CONNECTION& aConn ) -> std::optional<wxString>
1366 {
1367 wxString netName = aConn.Name();
1368
1369 if( aConn.IsBus() )
1370 {
1371 wxString prefix;
1372
1373 if( NET_SETTINGS::ParseBusVector( netName, &prefix, nullptr ) )
1374 return prefix + wxT( "*" );
1375 else if( NET_SETTINGS::ParseBusGroup( netName, &prefix, nullptr ) )
1376 return prefix + wxT( ".*" );
1377 }
1378 else if( !aConn.Driver() || CONNECTION_SUBGRAPH::GetDriverPriority( aConn.Driver() )
1380 {
1381 return std::nullopt;
1382 }
1383
1384 return netName;
1385 };
1386
1387 std::set<wxString> netNames;
1388
1389 for( const auto& [conn, pos] : selectedConns )
1390 {
1391 std::optional<wxString> netNamePattern = getNetNamePattern( *conn );
1392
1393 if( !netNamePattern )
1394 {
1395 // This is a choice, we can also allow some un-labeled nets as long as some are labeled.
1396 m_frame->ShowInfoBarError( _( "All selected nets must be labeled to assign a netclass." ) );
1397 return 0;
1398 }
1399
1400 netNames.insert( *netNamePattern );
1401 }
1402
1403 wxCHECK( !netNames.empty(), 0 );
1404
1405 DIALOG_ASSIGN_NETCLASS dlg( m_frame, netNames, schematic.GetNetClassAssignmentCandidates(),
1406 [&]( const std::vector<wxString>& aNetNames )
1407 {
1408 for( SCH_ITEM* item : screen->Items() )
1409 {
1410 bool redraw = item->IsBrightened();
1411 SCH_CONNECTION* itemConn = item->Connection();
1412
1413 if( itemConn && alg::contains( aNetNames, itemConn->Name() ) )
1414 item->SetBrightened();
1415 else
1416 item->ClearBrightened();
1417
1418 redraw |= item->IsBrightened();
1419
1420 if( item->Type() == SCH_SYMBOL_T )
1421 {
1422 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1423
1424 redraw |= symbol->HasBrightenedPins();
1425
1426 symbol->ClearBrightenedPins();
1427
1428 for( SCH_PIN* pin : symbol->GetPins() )
1429 {
1430 SCH_CONNECTION* pin_conn = pin->Connection();
1431
1432 if( pin_conn && alg::contains( aNetNames, pin_conn->Name() ) )
1433 {
1434 pin->SetBrightened();
1435 redraw = true;
1436 }
1437 }
1438 }
1439 else if( item->Type() == SCH_SHEET_T )
1440 {
1441 for( SCH_SHEET_PIN* pin : static_cast<SCH_SHEET*>( item )->GetPins() )
1442 {
1443 SCH_CONNECTION* pin_conn = pin->Connection();
1444
1445 redraw |= pin->IsBrightened();
1446
1447 if( pin_conn && alg::contains( aNetNames, pin_conn->Name() ) )
1448 pin->SetBrightened();
1449 else
1450 pin->ClearBrightened();
1451
1452 redraw |= pin->IsBrightened();
1453 }
1454 }
1455
1456 if( redraw )
1457 getView()->Update( item, KIGFX::VIEW_UPDATE_FLAGS::REPAINT );
1458 }
1459
1460 m_frame->GetCanvas()->ForceRefresh();
1461 } );
1462
1463 if( dlg.ShowModal() )
1464 {
1465 getView()->UpdateAllItemsConditionally(
1466 [&]( KIGFX::VIEW_ITEM* aItem ) -> int
1467 {
1468 int flags = 0;
1469
1470 auto invalidateTextVars =
1471 [&flags]( EDA_TEXT* text )
1472 {
1473 if( text->HasTextVars() )
1474 {
1475 text->ClearRenderCache();
1476 text->ClearBoundingBoxCache();
1478 }
1479 };
1480
1481 // Netclass coloured items
1482 //
1483 if( dynamic_cast<SCH_LINE*>( aItem ) )
1484 flags |= KIGFX::REPAINT;
1485 else if( dynamic_cast<SCH_JUNCTION*>( aItem ) )
1486 flags |= KIGFX::REPAINT;
1487 else if( dynamic_cast<SCH_BUS_ENTRY_BASE*>( aItem ) )
1488 flags |= KIGFX::REPAINT;
1489
1490 // Items that might reference an item's netclass name
1491 //
1492 if( SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aItem ) )
1493 {
1494 item->RunOnChildren(
1495 [&invalidateTextVars]( SCH_ITEM* aChild )
1496 {
1497 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aChild ) )
1498 invalidateTextVars( text );
1499 },
1501
1502 if( flags & KIGFX::GEOMETRY )
1503 m_frame->GetScreen()->Update( item, false ); // Refresh RTree
1504 }
1505
1506 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem ) )
1507 invalidateTextVars( text );
1508
1509 return flags;
1510 } );
1511 }
1512
1513 highlightNet( m_toolMgr, CLEAR );
1514 return 0;
1515}
1516
1517
1519{
1520 SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1521
1522 if( !selectionTool )
1523 return 0;
1524
1525 wxString netName;
1526
1527 for( EDA_ITEM* item : selectionTool->GetSelection() )
1528 {
1529 if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( item ) )
1530 {
1531 if( SCH_CONNECTION* conn = schItem->Connection() )
1532 {
1533 if( !conn->GetNetName().IsEmpty() )
1534 {
1535 netName = conn->GetNetName();
1536 break;
1537 }
1538 }
1539 }
1540 }
1541
1542 if( netName.IsEmpty() )
1543 netName = m_frame->GetHighlightedConnection();
1544
1545 if( netName.IsEmpty() )
1546 {
1547 m_frame->ShowInfoBarError( _( "No connected net selected." ) );
1548 return 0;
1549 }
1550
1551 m_frame->FindNetInInspector( netName );
1552
1553 return 0;
1554}
1555
1556
1558{
1559 wxCHECK( m_frame, 0 );
1560
1561 const SCH_SHEET_PATH& sheetPath = m_frame->GetCurrentSheet();
1562 SCH_SCREEN* screen = m_frame->GetCurrentSheet().LastScreen();
1563 CONNECTION_GRAPH* connectionGraph = m_frame->Schematic().ConnectionGraph();
1564 wxString selectedName = m_frame->GetHighlightedConnection();
1565
1566 std::set<wxString> connNames;
1567 std::vector<EDA_ITEM*> itemsToRedraw;
1568
1569 wxCHECK( screen && connectionGraph, 0 );
1570
1571 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "UpdateNetHighlighting: highlightedConn='%s' highlightedSignal='%s'",
1572 selectedName, m_frame->GetHighlightedNetChain() );
1573
1574 if( !selectedName.IsEmpty() )
1575 {
1576 connNames.emplace( selectedName );
1577
1578 // Highlight both label forms together: {MIXED_BUS} and its expansion {FOO BAR HAM EGGS}.
1579 for( const wxString& equivalent : connectionGraph->GetEquivalentBusNames( selectedName ) )
1580 connNames.emplace( equivalent );
1581
1582 if( CONNECTION_SUBGRAPH* sg = connectionGraph->FindSubgraphByName( selectedName, sheetPath ) )
1583 {
1585 {
1586 for( const SCH_ITEM* item : sg->GetItems() )
1587 {
1588 wxCHECK2( item, continue );
1589
1590 if( SCH_CONNECTION* connection = item->Connection() )
1591 {
1592 for( const std::shared_ptr<SCH_CONNECTION>& member : connection->AllMembers() )
1593 {
1594 if( member )
1595 connNames.emplace( member->Name() );
1596 }
1597 }
1598 }
1599 }
1600 }
1601
1602 // Place all bus names that are connected to the selected net in the set, regardless of
1603 // their sheet. This ensures that nets that are connected to a bus on a different sheet
1604 // get their buses highlighted as well.
1605 for( const wxString& connName : std::vector<wxString>( connNames.begin(), connNames.end() ) )
1606 {
1607 for( CONNECTION_SUBGRAPH* sg : connectionGraph->GetAllSubgraphs( connName ) )
1608 {
1609 for( const auto& [_, bus_sgs] : sg->GetBusParents() )
1610 {
1611 for( CONNECTION_SUBGRAPH* bus_sg : bus_sgs )
1612 connNames.emplace( bus_sg->GetNetName() );
1613 }
1614 }
1615 }
1616 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "UpdateNetHighlighting: connNames after connection='%zu'", connNames.size() );
1617 }
1618
1619 if( !m_frame->GetHighlightedNetChain().IsEmpty() )
1620 {
1621 if( SCH_NETCHAIN* sig = connectionGraph->GetNetChainByName( m_frame->GetHighlightedNetChain() ) )
1622 {
1623 for( const wxString& n : sig->GetNets() )
1624 connNames.emplace( n );
1625 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "UpdateNetHighlighting: added %zu nets from chain '%s'",
1626 sig->GetNets().size(), m_frame->GetHighlightedNetChain() );
1627 }
1628 }
1629
1630 for( SCH_ITEM* item : screen->Items() )
1631 {
1632 if( !item || !item->IsConnectable() )
1633 continue;
1634
1635 SCH_ITEM* redrawItem = nullptr;
1636
1637 if( item->Type() == SCH_SYMBOL_T )
1638 {
1639 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1640
1641 for( SCH_PIN* pin : symbol->GetPins() )
1642 {
1643 SCH_CONNECTION* pin_conn = pin->Connection();
1644
1645 if( pin_conn )
1646 {
1647 if( !pin->IsBrightened() && connNames.count( pin_conn->Name() ) )
1648 {
1649 pin->SetBrightened();
1650 redrawItem = symbol;
1651 }
1652 else if( pin->IsBrightened() && !connNames.count( pin_conn->Name() ) )
1653 {
1654 pin->ClearBrightened();
1655 redrawItem = symbol;
1656 }
1657 }
1658 else if( pin->IsBrightened() )
1659 {
1660 pin->ClearBrightened();
1661 redrawItem = symbol;
1662 }
1663 }
1664
1665 if( symbol->IsPower() && symbol->GetPins().size() )
1666 {
1667 SCH_CONNECTION* pinConn = symbol->GetPins()[0]->Connection();
1668
1670 {
1671 SCH_FIELD* field = symbol->GetField( id );
1672
1673 if( !field->IsVisible() )
1674 continue;
1675
1676 if( pinConn )
1677 {
1678 if( !field->IsBrightened() && connNames.count( pinConn->Name() ) )
1679 {
1680 field->SetBrightened();
1681 redrawItem = symbol;
1682 }
1683 else if( field->IsBrightened() && !connNames.count( pinConn->Name() ) )
1684 {
1685 field->ClearBrightened();
1686 redrawItem = symbol;
1687 }
1688 }
1689 else if( field->IsBrightened() )
1690 {
1691 field->ClearBrightened();
1692 redrawItem = symbol;
1693 }
1694 }
1695 }
1696 }
1697 else if( item->Type() == SCH_SHEET_T )
1698 {
1699 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1700
1701 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
1702 {
1703 wxCHECK2( pin, continue );
1704
1705 SCH_CONNECTION* pin_conn = pin->Connection();
1706
1707 if( pin_conn )
1708 {
1709 if( !pin->IsBrightened() && connNames.count( pin_conn->Name() ) )
1710 {
1711 pin->SetBrightened();
1712 redrawItem = sheet;
1713 }
1714 else if( pin->IsBrightened() && !connNames.count( pin_conn->Name() ) )
1715 {
1716 pin->ClearBrightened();
1717 redrawItem = sheet;
1718 }
1719 }
1720 else if( pin->IsBrightened() )
1721 {
1722 pin->ClearBrightened();
1723 redrawItem = sheet;
1724 }
1725 }
1726 }
1727 else
1728 {
1729 SCH_CONNECTION* itemConn = item->Connection();
1730
1731 if( itemConn )
1732 {
1733 if( !item->IsBrightened() && connNames.count( itemConn->Name() ) )
1734 {
1735 item->SetBrightened();
1736 redrawItem = item;
1737 }
1738 else if( item->IsBrightened() && !connNames.count( itemConn->Name() ) )
1739 {
1740 item->ClearBrightened();
1741 redrawItem = item;
1742 }
1743 }
1744 else if( item->IsBrightened() )
1745 {
1746 item->ClearBrightened();
1747 redrawItem = item;
1748 }
1749 }
1750
1751 if( redrawItem )
1752 itemsToRedraw.push_back( redrawItem );
1753 }
1754
1755 if( itemsToRedraw.size() )
1756 {
1757 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "UpdateNetHighlighting: itemsToRedraw=%zu", itemsToRedraw.size() );
1758 // Be sure highlight change will be redrawn
1759 KIGFX::VIEW* view = getView();
1760
1761 for( EDA_ITEM* redrawItem : itemsToRedraw )
1763
1764 m_frame->GetCanvas()->Refresh();
1765 }
1766
1767 return 0;
1768}
1769
1770
1772{
1773 PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
1774
1775 // Deactivate other tools; particularly important if another PICKER is currently running
1776 Activate();
1777
1778 picker->SetCursor( KICURSOR::BULLSEYE );
1779 picker->SetSnapping( false );
1780 picker->ClearHandlers();
1781
1782 picker->SetClickHandler(
1783 [this]( const VECTOR2D& aPos )
1784 {
1785 return highlightNet( m_toolMgr, aPos );
1786 } );
1787
1788 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
1789
1790 return 0;
1791}
1792
1793
1795{
1796 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_toolMgr->GetToolHolder() );
1797 auto ids = aEvent.Parameter<std::pair<wxString, wxString>>();
1798 wxString oldStr = ids.first;
1799 wxString newStr = ids.second;
1800 KIID oldPin( oldStr );
1801 KIID newPin( newStr );
1802 wxString sig = editFrame->GetHighlightedNetChain();
1803
1804 if( !sig.IsEmpty() )
1805 editFrame->Schematic().ConnectionGraph()->ReplaceNetChainTerminalPin( sig, oldPin, newPin );
1806
1807 return 0;
1808}
1809
1810
1812{
1813 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1814 SCH_ITEM* item = static_cast<SCH_ITEM*>( selTool->GetSelection().Front() );
1815 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( item );
1816
1817 if( !pin || !pin->Connection() )
1818 return 0;
1819
1820 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_toolMgr->GetToolHolder() );
1821 CONNECTION_GRAPH* graph = editFrame->Schematic().ConnectionGraph();
1822
1823 if( SCH_NETCHAIN* sig = graph->GetNetChainForNet( pin->Connection()->Name() ) )
1824 {
1825 wxString newName = wxGetTextFromUser( _( "Net chain name:" ), _( "Name Net Chain" ), sig->GetName() );
1826
1827 if( !newName.IsEmpty() && newName != sig->GetName() )
1828 {
1829 sig->SetName( newName );
1830
1831 editFrame->SetHighlightedNetChain( newName );
1834 editFrame->UpdateNetHighlightStatus();
1835 }
1836 }
1837
1838 return 0;
1839}
1840
1842{
1843 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1844 auto& selection = selTool->GetSelection();
1845
1846 if( selection.GetSize() != 2 )
1847 return 0;
1848
1849 SCH_PIN* pinA = dynamic_cast<SCH_PIN*>( static_cast<SCH_ITEM*>( selection[0] ) );
1850 SCH_PIN* pinB = dynamic_cast<SCH_PIN*>( static_cast<SCH_ITEM*>( selection[1] ) );
1851
1852 if( !pinA || !pinB )
1853 return 0;
1854
1855 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_toolMgr->GetToolHolder() );
1856 CONNECTION_GRAPH* graph = editFrame->Schematic().ConnectionGraph();
1857
1858 SCH_NETCHAIN* potential = graph->FindPotentialNetChainBetweenPins( pinA, pinB );
1859 if( !potential )
1860 {
1861 DisplayError( editFrame, _( "No potential net chain connects the selected pins." ) );
1862 return 0;
1863 }
1864
1865 // Build default suggestion name
1866 wxString suggestion = wxString::Format( wxS( "%s_%s" ), pinA->GetParentSymbol()->GetRef( &editFrame->GetCurrentSheet() ), pinB->GetParentSymbol()->GetRef( &editFrame->GetCurrentSheet() ) );
1867
1868 // Compose display text for dialog
1869 wxString msg = wxString::Format( _( "Create Net Chain between %s:%s and %s:%s" ),
1870 pinA->GetParentSymbol()->GetRef( &editFrame->GetCurrentSheet() ), pinA->GetNumber(),
1871 pinB->GetParentSymbol()->GetRef( &editFrame->GetCurrentSheet() ), pinB->GetNumber() );
1872
1873 // Temporary highlight preview: highlight all nets in potential (reuse SetHighlightedNetChain with temp name)
1874 // We use the potential's current name as a temporary highlight identifier
1875 wxString prevHighlightedChain = editFrame->GetHighlightedNetChain();
1876 wxString prevHighlightedConn = editFrame->GetHighlightedConnection();
1877
1878 editFrame->SetHighlightedConnection( wxEmptyString );
1879 editFrame->SetHighlightedNetChain( potential->GetName() );
1882 editFrame->UpdateNetHighlightStatus();
1883
1884 // Zoom to bounding box of the two pins (union) expanded slightly
1885 BOX2I bbox = pinA->GetBoundingBox();
1886 bbox.Merge( pinB->GetBoundingBox() );
1887 // Expand by 25% for context
1888 int dx = bbox.GetWidth() / 4; if( dx < 100 ) dx = 100;
1889 int dy = bbox.GetHeight() / 4; if( dy < 100 ) dy = 100;
1890 bbox.Inflate( dx, dy );
1891 if( auto canvas = editFrame->GetCanvas() )
1892 {
1893 canvas->GetView()->SetCenter( bbox.GetCenter() );
1894 // Compute scale so bbox roughly fits viewport height
1895 auto view = canvas->GetView();
1896 if( view )
1897 {
1898 BOX2D viewBox = view->GetBoundary();
1899 double scaleX = (double) viewBox.GetWidth() / (double) bbox.GetWidth();
1900 double scaleY = (double) viewBox.GetHeight() / (double) bbox.GetHeight();
1901 double scale = std::min( scaleX, scaleY );
1902 if( scale > 0 )
1903 view->SetScale( scale );
1904 }
1905 }
1906
1907 wxString name = wxGetTextFromUser( msg, _( "Create Net Chain" ), suggestion, editFrame );
1908 if( name.IsEmpty() )
1909 {
1910 // Restore previous highlight state
1911 editFrame->SetHighlightedNetChain( prevHighlightedChain );
1912 editFrame->SetHighlightedConnection( prevHighlightedConn );
1914 editFrame->UpdateNetHighlightStatus();
1915 return 0; // cancelled
1916 }
1917
1918 if( graph->CreateNetChainFromPotential( potential, name ) )
1919 {
1920 // Replace temporary highlight with new chain name
1921 editFrame->SetHighlightedNetChain( name );
1922 editFrame->SetHighlightedConnection( wxEmptyString );
1924 editFrame->UpdateNetHighlightStatus();
1925 editFrame->Refresh();
1926 }
1927
1928 return 0;
1929}
1930
1931
1933{
1934 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_toolMgr->GetToolHolder() );
1935
1936 CONNECTION_GRAPH* graph = editFrame->Schematic().ConnectionGraph();
1937
1938 if( graph && graph->GetPotentialNetChains().empty() )
1939 {
1940 SCH_SHEET_LIST sheets = editFrame->Schematic().Hierarchy();
1941 graph->Recalculate( sheets, true );
1942 }
1943
1945
1946 if( SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>() )
1947 {
1948 const SCH_SELECTION& sel = selTool->GetSelection();
1949
1950 std::vector<SCH_SYMBOL*> symbols;
1951
1952 for( EDA_ITEM* item : sel )
1953 {
1954 if( SCH_SYMBOL* sym = dynamic_cast<SCH_SYMBOL*>( static_cast<SCH_ITEM*>( item ) ) )
1955 symbols.push_back( sym );
1956 }
1957
1958 if( symbols.size() >= 1 )
1959 hint.fromRef = symbols[0]->GetRef( &editFrame->GetCurrentSheet() );
1960
1961 if( symbols.size() >= 2 )
1962 hint.toRef = symbols[1]->GetRef( &editFrame->GetCurrentSheet() );
1963
1964 // Single pin or single wire/bus → use its connection's net name as the focus hint.
1965 if( symbols.empty() && sel.GetSize() == 1 )
1966 {
1967 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( sel.Front() );
1968
1969 if( SCH_PIN* pin = dynamic_cast<SCH_PIN*>( schItem ) )
1970 {
1971 if( pin->Connection() )
1972 hint.netName = pin->Connection()->Name();
1973 }
1974 else if( schItem
1975 && schItem->Type() == SCH_LINE_T
1976 && schItem->IsType( { SCH_ITEM_LOCATE_WIRE_T, SCH_ITEM_LOCATE_BUS_T } )
1977 && schItem->Connection() )
1978 {
1979 hint.netName = schItem->Connection()->Name();
1980 }
1981 }
1982 }
1983
1984 DIALOG_CREATE_NET_CHAIN dlg( editFrame, hint );
1985 dlg.ShowModal();
1986
1987 return 0;
1988}
1989
1990
1992{
1993 wxCHECK( m_frame, 0 );
1994
1995 if( m_frame->GetUndoCommandCount() <= 0 )
1996 return 0;
1997
1998 // Inform tools that undo command was issued
1999 m_toolMgr->ProcessEvent( { TC_MESSAGE, TA_UNDO_REDO_PRE, AS_GLOBAL } );
2000
2001 // Get the old list
2002 PICKED_ITEMS_LIST* undo_list = m_frame->PopCommandFromUndoList();
2003
2004 wxCHECK( undo_list, 0 );
2005
2006 m_frame->PutDataInPreviousState( undo_list );
2007
2008 // Now push the old command to the RedoList
2009 undo_list->ReversePickersListOrder();
2010 m_frame->PushCommandToRedoList( undo_list );
2011
2012 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->RebuildSelection();
2013
2014 m_frame->GetCanvas()->Refresh();
2015 m_frame->OnModify();
2016
2017 return 0;
2018}
2019
2020
2022{
2023 wxCHECK( m_frame, 0 );
2024
2025 if( m_frame->GetRedoCommandCount() == 0 )
2026 return 0;
2027
2028 // Inform tools that undo command was issued
2029 m_toolMgr->ProcessEvent( { TC_MESSAGE, TA_UNDO_REDO_PRE, AS_GLOBAL } );
2030
2031 /* Get the old list */
2032 PICKED_ITEMS_LIST* list = m_frame->PopCommandFromRedoList();
2033
2034 wxCHECK( list, 0 );
2035
2036 /* Redo the command: */
2037 m_frame->PutDataInPreviousState( list );
2038
2039 /* Put the old list in UndoList */
2040 list->ReversePickersListOrder();
2041 m_frame->PushCommandToUndoList( list );
2042
2043 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->RebuildSelection();
2044
2045 m_frame->GetCanvas()->Refresh();
2046 m_frame->OnModify();
2047
2048 return 0;
2049}
2050
2051
2052bool SCH_EDITOR_CONTROL::doCopy( bool aUseDuplicateClipboard )
2053{
2054 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
2055 SCH_SELECTION& selection = selTool->RequestSelection();
2056 SCHEMATIC& schematic = m_frame->Schematic();
2057
2058 if( selection.Empty() )
2059 return false;
2060
2061 if( aUseDuplicateClipboard )
2062 m_duplicateIsHoverSelection = selection.IsHover();
2063
2064 selection.SetScreen( m_frame->GetScreen() );
2066
2067 for( EDA_ITEM* item : selection.GetItems() )
2068 {
2069 if( item->Type() == SCH_SHEET_T )
2070 {
2071 SCH_SHEET* sheet = (SCH_SHEET*) item;
2072 m_supplementaryClipboard[sheet->GetFileName()] = sheet->GetScreen();
2073 }
2074 else if( item->Type() == SCH_FIELD_T && selection.IsHover() )
2075 {
2076 // Most of the time the user is trying to duplicate the parent symbol
2077 // and the field text is in it
2078 selection.Add( item->GetParent() );
2079 }
2080 else if( item->Type() == SCH_MARKER_T )
2081 {
2082 // Don't let the markers be copied
2083 selection.Remove( item );
2084 }
2085 else if( item->Type() == SCH_GROUP_T )
2086 {
2087 // Groups need to have all their items selected
2088 static_cast<SCH_ITEM*>( item )->RunOnChildren(
2089 [&]( EDA_ITEM* aChild )
2090 {
2091 selection.Add( aChild );
2092 },
2094 }
2095 }
2096
2097 bool result = true;
2098 STRING_FORMATTER formatter;
2099 SCH_IO_KICAD_SEXPR plugin;
2100 SCH_SHEET_PATH selPath = m_frame->GetCurrentSheet();
2101
2102 plugin.Format( &selection, &selPath, schematic, &formatter, true );
2103
2104 std::string prettyData = formatter.GetString();
2105 KICAD_FORMAT::Prettify( prettyData, KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES );
2106
2107 if( !aUseDuplicateClipboard )
2108 {
2109 wxLogNull doNotLog; // disable logging of failed clipboard actions
2110
2111 result &= wxTheClipboard->Open();
2112
2113 if( result )
2114 {
2115 wxDataObjectComposite* data = new wxDataObjectComposite();
2116
2117 // Add KiCad data
2118 wxCustomDataObject* kicadObj = new wxCustomDataObject( wxDataFormat( "application/kicad" ) );
2119 kicadObj->SetData( prettyData.size(), prettyData.data() );
2120 data->Add( kicadObj );
2121
2122 BOX2I selectionBox = expandedSelectionBox( selection );
2123
2124 if( selectionBox.GetWidth() > 0 && selectionBox.GetHeight() > 0 )
2125 {
2126 // Add bitmap data (encoded once, used for both PNG clipboard and HTML)
2127 wxImage image = renderSelectionToImageForClipboard( m_frame, selection, selectionBox, true, false );
2128 wxMemoryBuffer pngBuffer;
2129
2130 if( image.IsOk() && EncodeImageToPng( image, pngBuffer ) )
2131 {
2132 AddPngToClipboardData( data, pngBuffer, &image );
2133
2134 // Add HTML with embedded base64 PNG for pasting into documents
2135 wxMemoryBuffer htmlBuffer;
2136
2137 if( generateHtmlFromPngData( pngBuffer, htmlBuffer ) )
2138 {
2139 wxCustomDataObject* htmlObj = new wxCustomDataObject( wxDF_HTML );
2140 htmlObj->SetData( htmlBuffer.GetDataLen(), htmlBuffer.GetData() );
2141 data->Add( htmlObj );
2142 }
2143 }
2144 else
2145 {
2146 wxLogDebug( wxS( "Failed to generate bitmap for clipboard" ) );
2147 }
2148
2149 // Add SVG data
2150 wxMemoryBuffer svgBuffer;
2151
2152 if( plotSelectionToSvg( m_frame, selection, selectionBox, svgBuffer ) )
2153 {
2154 wxCustomDataObject* svgObj = new wxCustomDataObject( wxDataFormat( "image/svg+xml" ) );
2155 svgObj->SetData( svgBuffer.GetDataLen(), svgBuffer.GetData() );
2156 data->Add( svgObj );
2157 }
2158 else
2159 {
2160 wxLogDebug( wxS( "Failed to generate SVG for clipboard" ) );
2161 }
2162 }
2163
2164 // Finally add text data
2165 data->Add( new wxTextDataObject( wxString::FromUTF8( prettyData ) ) );
2166
2167 result &= wxTheClipboard->SetData( data );
2168 result &= wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
2169 wxTheClipboard->Close();
2170 }
2171 }
2172
2173 if( selection.IsHover() )
2174 m_toolMgr->RunAction( ACTIONS::selectionClear );
2175
2176 if( aUseDuplicateClipboard )
2177 {
2178 m_duplicateClipboard = prettyData;
2179 return true;
2180 }
2181
2182 return result;
2183}
2184
2185
2186bool SCH_EDITOR_CONTROL::searchSupplementaryClipboard( const wxString& aSheetFilename, SCH_SCREEN** aScreen )
2187{
2188 if( m_supplementaryClipboard.count( aSheetFilename ) > 0 )
2189 {
2190 *aScreen = m_supplementaryClipboard[aSheetFilename];
2191 return true;
2192 }
2193
2194 return false;
2195}
2196
2197
2199{
2200 doCopy( true ); // Use the local clipboard
2201 Paste( aEvent );
2202
2203 return 0;
2204}
2205
2206
2208{
2209 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wxWindow::FindFocus() );
2210
2211 if( textEntry )
2212 {
2213 textEntry->Cut();
2214 return 0;
2215 }
2216
2217 if( doCopy() )
2218 m_toolMgr->RunAction( ACTIONS::doDelete );
2219
2220 return 0;
2221}
2222
2223
2225{
2226 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wxWindow::FindFocus() );
2227
2228 if( textEntry )
2229 {
2230 textEntry->Copy();
2231 return 0;
2232 }
2233
2234 doCopy();
2235
2236 return 0;
2237}
2238
2239
2241{
2242 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
2243 SCH_SELECTION& selection = selTool->RequestSelection();
2244
2245 if( selection.Empty() )
2246 return false;
2247
2248 wxString itemsAsText = GetSelectedItemsAsText( selection );
2249
2250 if( selection.IsHover() )
2251 m_toolMgr->RunAction( ACTIONS::selectionClear );
2252
2253 return SaveClipboard( itemsAsText.ToStdString() );
2254}
2255
2256
2258 const KIID_PATH& aClipPath, bool aForceKeepAnnotations )
2259{
2260 wxCHECK( m_frame && aSymbol, /* void */ );
2261
2262 SCH_SYMBOL_INSTANCE newInstance;
2263 bool instanceFound = false;
2264 KIID_PATH pasteLookupPath = aClipPath;
2265
2266 m_pastedSymbols.insert( aSymbol );
2267
2268 for( const SCH_SYMBOL_INSTANCE& tmp : aSymbol->GetInstances() )
2269 {
2270 if( ( tmp.m_Path.empty() && aClipPath.empty() ) || ( !aClipPath.empty() && tmp.m_Path.EndsWith( aClipPath ) ) )
2271 {
2272 newInstance = tmp;
2273 instanceFound = true;
2274
2275 wxLogTrace( traceSchPaste, wxS( "Pasting found symbol instance with reference %s, unit %d:\n"
2276 "\tClipboard path: %s\n"
2277 "\tSymbol UUID: %s." ),
2278 tmp.m_Reference,
2279 tmp.m_Unit,
2280 aClipPath.AsString(),
2281 aSymbol->m_Uuid.AsString() );
2282
2283 break;
2284 }
2285 }
2286
2287 // The pasted symbol look up paths include the symbol UUID.
2288 pasteLookupPath.push_back( aSymbol->m_Uuid );
2289
2290 if( !instanceFound )
2291 {
2292 wxLogTrace( traceSchPaste, wxS( "Clipboard symbol instance **not** found:\n\tClipboard path: %s\n"
2293 "\tSymbol UUID: %s." ),
2294 aClipPath.AsString(),
2295 aSymbol->m_Uuid.AsString() );
2296
2297 // Some legacy versions saved value fields escaped. While we still do in the symbol
2298 // editor, we don't anymore in the schematic, so be sure to unescape them.
2299 SCH_FIELD* valueField = aSymbol->GetField( FIELD_T::VALUE );
2300 valueField->SetText( UnescapeString( valueField->GetText() ) );
2301
2302 // Pasted from notepad or an older instance of eeschema. Use the values in the fields
2303 // instead.
2304 newInstance.m_Reference = aSymbol->GetField( FIELD_T::REFERENCE )->GetText();
2305 newInstance.m_Unit = aSymbol->GetUnit();
2306 }
2307
2308 newInstance.m_Path = aPastePath.Path();
2309 newInstance.m_ProjectName = m_frame->Prj().GetProjectName();
2310
2311 aSymbol->AddHierarchicalReference( newInstance );
2312
2313 if( !aForceKeepAnnotations )
2314 aSymbol->ClearAnnotation( &aPastePath, false );
2315
2316 // We might clear annotations but always leave the original unit number from the paste.
2317 aSymbol->SetUnit( newInstance.m_Unit );
2318}
2319
2320
2322 const KIID_PATH& aClipPath, bool aForceKeepAnnotations,
2323 SCH_SHEET_LIST* aPastedSheets, std::map<SCH_SHEET_PATH,
2324 SCH_REFERENCE_LIST>& aPastedSymbols )
2325{
2326 wxCHECK( aSheet && aPastedSheets, aPastePath );
2327
2328 SCH_SHEET_PATH sheetPath = aPastePath;
2329 sheetPath.push_back( aSheet );
2330
2331 aPastedSheets->push_back( sheetPath );
2332
2333 if( aSheet->GetScreen() == nullptr )
2334 return sheetPath; // We can only really set the page number but not load any items
2335
2336 bool isSharedPath = sheetPath.IsSharedPath();
2337
2338 for( SCH_ITEM* item : aSheet->GetScreen()->Items() )
2339 {
2340 if( item->IsConnectable() )
2341 item->SetConnectivityDirty();
2342
2343 if( item->Type() == SCH_SYMBOL_T )
2344 {
2345 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2346
2347 wxCHECK2( symbol, continue );
2348
2349 // Only do this once if the symbol is shared across multiple sheets.
2350 if( !m_pastedSymbols.count( symbol ) )
2351 {
2352 if( !isSharedPath )
2353 const_cast<KIID&>( symbol->m_Uuid ) = KIID();
2354
2355 for( SCH_PIN* pin : symbol->GetPins() )
2356 {
2357 // Only update the UUID if the symbol is not in a shared sheet.
2358 if( !isSharedPath )
2359 const_cast<KIID&>( pin->m_Uuid ) = KIID();
2360
2361 pin->SetConnectivityDirty();
2362 }
2363 }
2364
2365 updatePastedSymbol( symbol, sheetPath, aClipPath, aForceKeepAnnotations );
2366 }
2367 else if( item->Type() == SCH_SHEET_T )
2368 {
2369 SCH_SHEET* subsheet = static_cast<SCH_SHEET*>( item );
2370
2371 wxCHECK2( subsheet, continue );
2372
2373 // Make sure pins get a new UUID and set the dirty connectivity flag.
2374 if( !aPastedSheets->ContainsSheet( subsheet ) )
2375 {
2376 if( !isSharedPath )
2377 const_cast<KIID&>( subsheet->m_Uuid ) = KIID();
2378
2379 for( SCH_SHEET_PIN* pin : subsheet->GetPins() )
2380 {
2381 if( !isSharedPath )
2382 const_cast<KIID&>( pin->m_Uuid ) = KIID();
2383
2384 pin->SetConnectivityDirty();
2385 }
2386 }
2387
2388 KIID_PATH newClipPath = aClipPath;
2389 newClipPath.push_back( subsheet->m_Uuid );
2390
2391 updatePastedSheet( subsheet, sheetPath, newClipPath, aForceKeepAnnotations, aPastedSheets, aPastedSymbols );
2392 }
2393 }
2394
2395 sheetPath.GetSymbols( aPastedSymbols[aPastePath], SYMBOL_FILTER_ALL );
2396
2397 return sheetPath;
2398}
2399
2400
2402{
2403 wxCHECK( aScreen, /* void */ );
2404
2405 for( const SCH_ITEM* item : aScreen->Items() )
2406 {
2407 if( item->Type() == SCH_SYMBOL_T )
2408 {
2409 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( item );
2410
2411 wxCHECK2( symbol, continue );
2412
2413 for( const SCH_SYMBOL_INSTANCE& symbolInstance : symbol->GetInstances() )
2414 {
2415 KIID_PATH pathWithSymbol = symbolInstance.m_Path;
2416
2417 pathWithSymbol.push_back( symbol->m_Uuid );
2418
2419 m_clipboardSymbolInstances[pathWithSymbol] = symbolInstance;
2420 }
2421 }
2422 }
2423}
2424
2425
2427{
2428 wxCHECK( m_frame, /* void */ );
2429
2430 for( SCH_SYMBOL* symbol : m_pastedSymbols )
2431 {
2432 wxCHECK2( symbol, continue );
2433
2434 PrunePastedSymbolInstances( symbol, m_frame->Schematic() );
2435 }
2436}
2437
2438
2440 const SCH_SCREEN* aDestScreen,
2441 const wxString& aLibSymbolName )
2442{
2443 // The clipboard's cached library symbol is a matched pair with the pasted instance, so it
2444 // must win over the destination's same-named cache. Pasting from the destination cache would
2445 // silently remap the instance to a different definition and drop in-place edits such as
2446 // renumbered pins (issue 21401) or a changed power type (issue 22162). Fall back to the
2447 // destination cache only when the clipboard carries no copy.
2448 if( aClipboardScreen )
2449 {
2450 auto clipIt = aClipboardScreen->GetLibSymbols().find( aLibSymbolName );
2451
2452 if( clipIt != aClipboardScreen->GetLibSymbols().end() )
2453 return clipIt->second;
2454 }
2455
2456 if( aDestScreen )
2457 {
2458 auto destIt = aDestScreen->GetLibSymbols().find( aLibSymbolName );
2459
2460 if( destIt != aDestScreen->GetLibSymbols().end() )
2461 return destIt->second;
2462 }
2463
2464 return nullptr;
2465}
2466
2467
2469{
2470 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wxWindow::FindFocus() );
2471
2472 if( textEntry )
2473 {
2474 textEntry->Paste();
2475 return 0;
2476 }
2477
2478 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
2479 std::string content;
2480 VECTOR2I eventPos;
2481
2482 SCH_SHEET tempSheet;
2483
2484 // Priority for paste:
2485 // 1. application/kicad format (handled by GetClipboardUTF8 which checks this first)
2486 // 2. Text data that can be parsed as KiCad S-expressions
2487 // 3. Bitmap/image data (fallback only if no valid text content)
2488 if( aEvent.IsAction( &ACTIONS::duplicate ) )
2489 content = m_duplicateClipboard;
2490 else
2491 content = GetClipboardUTF8();
2492
2493 // Only fall back to image data if there's no text content
2494 if( content.empty() )
2495 {
2496 std::unique_ptr<wxBitmap> clipImg = GetImageFromClipboard();
2497
2498 if( clipImg )
2499 {
2500 auto bitmap = std::make_unique<SCH_BITMAP>();
2501
2502 if( bitmap->GetReferenceImage().SetImage( clipImg->ConvertToImage() ) )
2503 return m_toolMgr->RunAction( SCH_ACTIONS::placeImage, bitmap.release() );
2504 }
2505
2506 return 0;
2507 }
2508
2509 if( aEvent.IsAction( &ACTIONS::duplicate ) )
2510 eventPos = getViewControls()->GetCursorPosition( false );
2511
2512 STRING_LINE_READER reader( content, "Clipboard" );
2513 SCH_IO_KICAD_SEXPR plugin;
2514
2515 // Screen object on heap is owned by the sheet.
2516 SCH_SCREEN* tempScreen = new SCH_SCREEN( &m_frame->Schematic() );
2517 tempSheet.SetScreen( tempScreen );
2518
2519 try
2520 {
2521 plugin.LoadContent( reader, &tempSheet );
2522 }
2523 catch( IO_ERROR& )
2524 {
2525 // If it wasn't schematic content, paste as a text object
2526 {
2527 if( content.size() > static_cast<size_t>( ADVANCED_CFG::GetCfg().m_MaxPastedTextLength ) )
2528 {
2529 int result = IsOK( m_frame, _( "Pasting a long text text string may be very slow. "
2530 "Do you want to continue?" ) );
2531 if( !result )
2532 return 0;
2533 }
2534
2535 SCH_TEXT* text_item = new SCH_TEXT( VECTOR2I( 0, 0 ), content );
2536 tempScreen->Append( text_item );
2537 }
2538 }
2539
2540 SELECTION& currentSelection = selTool->GetSelection();
2541
2542 bool hasTableCells = false;
2543
2544 for( EDA_ITEM* item : currentSelection )
2545 {
2546 if( item->Type() == SCH_TABLECELL_T )
2547 {
2548 hasTableCells = true;
2549 break;
2550 }
2551 }
2552
2553 if( hasTableCells )
2554 {
2555 SCH_TABLE* clipboardTable = nullptr;
2556
2557 for( SCH_ITEM* item : tempScreen->Items() )
2558 {
2559 if( item->Type() == SCH_TABLE_T )
2560 {
2561 clipboardTable = static_cast<SCH_TABLE*>( item );
2562 break;
2563 }
2564 }
2565
2566 if( clipboardTable )
2567 {
2568 SCH_EDIT_TABLE_TOOL* tableEditTool = m_toolMgr->GetTool<SCH_EDIT_TABLE_TOOL>();
2569
2570 if( tableEditTool )
2571 {
2572 wxString errorMsg;
2573
2574 if( !tableEditTool->validatePasteIntoSelection( currentSelection, errorMsg ) )
2575 {
2576 DisplayError( m_frame, errorMsg );
2577 return 0;
2578 }
2579
2580 SCH_COMMIT commit( m_toolMgr );
2581
2582 if( tableEditTool->pasteCellsIntoSelection( currentSelection, clipboardTable, commit ) )
2583 {
2584 commit.Push( _( "Paste Cells" ) );
2585 return 0;
2586 }
2587 else
2588 {
2589 DisplayError( m_frame, _( "Failed to paste cells" ) );
2590 return 0;
2591 }
2592 }
2593 }
2594 }
2595
2596 m_pastedSymbols.clear();
2598
2599 // Save pasted symbol instances in case the user chooses to keep existing symbol annotation.
2600 setPastedSymbolInstances( tempScreen );
2601
2602 tempScreen->MigrateSimModels();
2603
2604 bool annotateAutomatic = m_frame->eeconfig()->m_AnnotatePanel.automatic;
2605 SCHEMATIC_SETTINGS& schematicSettings = m_frame->Schematic().Settings();
2606 int annotateStartNum = schematicSettings.m_AnnotateStartNum;
2607
2609 bool forceRemoveAnnotations = false;
2610
2611 if( aEvent.IsAction( &ACTIONS::pasteSpecial ) )
2612 {
2613 PASTE_MODE defaultPasteMode = pasteMode;
2614 DIALOG_PASTE_SPECIAL dlg( m_frame, &pasteMode );
2615
2616 if( dlg.ShowModal() == wxID_CANCEL )
2617 return 0;
2618
2619 // We have to distinguish if removing was explicit
2620 forceRemoveAnnotations = pasteMode == PASTE_MODE::REMOVE_ANNOTATIONS && pasteMode != defaultPasteMode;
2621 }
2622
2623 bool forceKeepAnnotations = pasteMode != PASTE_MODE::REMOVE_ANNOTATIONS;
2624
2625 // SCH_SEXP_PLUGIN added the items to the paste screen, but not to the view or anything
2626 // else. Pull them back out to start with.
2627 SCH_COMMIT commit( m_toolMgr );
2628 EDA_ITEMS loadedItems;
2629 std::vector<SCH_ITEM*> sortedLoadedItems;
2630 bool sheetsPasted = false;
2631 SCH_SHEET_LIST hierarchy = m_frame->Schematic().Hierarchy();
2632 SCH_SHEET_PATH& pasteRoot = m_frame->GetCurrentSheet();
2633 wxFileName destFn = pasteRoot.Last()->GetFileName();
2634
2635 if( destFn.IsRelative() )
2636 destFn.MakeAbsolute( m_frame->Prj().GetProjectPath() );
2637
2638 // List of paths in the hierarchy that refer to the destination sheet of the paste
2639 SCH_SHEET_LIST sheetPathsForScreen = hierarchy.FindAllSheetsForScreen( pasteRoot.LastScreen() );
2640 sheetPathsForScreen.SortByPageNumbers();
2641
2642 // Build a list of screens from the current design (to avoid loading sheets that already exist)
2643 std::map<wxString, SCH_SCREEN*> loadedScreens;
2644
2645 for( const SCH_SHEET_PATH& item : hierarchy )
2646 {
2647 if( item.LastScreen() )
2648 loadedScreens[item.Last()->GetFileName()] = item.LastScreen();
2649 }
2650
2651 // Get set of sheet names in the current schematic to prevent duplicate sheet names on paste.
2652 std::set<wxString> existingSheetNames = pasteRoot.LastScreen()->GetSheetNames();
2653
2654 // Build symbol list for reannotation of duplicates
2655 SCH_REFERENCE_LIST existingRefs;
2656 hierarchy.GetSymbols( existingRefs, SYMBOL_FILTER_ALL );
2657 existingRefs.SortByReferenceOnly();
2658
2659 std::set<wxString> existingRefsSet;
2660
2661 for( const SCH_REFERENCE& ref : existingRefs )
2662 existingRefsSet.insert( ref.GetRef() );
2663
2664 // Build UUID map for fetching last-resolved-properties
2665 std::map<KIID, EDA_ITEM*> itemMap;
2666 hierarchy.FillItemMap( itemMap );
2667
2668 // Keep track of pasted sheets and symbols for the different paths to the hierarchy.
2669 std::map<SCH_SHEET_PATH, SCH_REFERENCE_LIST> pastedSymbols;
2670 std::map<SCH_SHEET_PATH, SCH_SHEET_LIST> pastedSheets;
2671
2672 for( SCH_ITEM* item : tempScreen->Items() )
2673 {
2674 if( item->Type() == SCH_SHEET_T )
2675 sortedLoadedItems.push_back( item );
2676 else
2677 loadedItems.push_back( item );
2678 }
2679
2680 sort( sortedLoadedItems.begin(), sortedLoadedItems.end(),
2681 []( SCH_ITEM* firstItem, SCH_ITEM* secondItem )
2682 {
2683 SCH_SHEET* firstSheet = static_cast<SCH_SHEET*>( firstItem );
2684 SCH_SHEET* secondSheet = static_cast<SCH_SHEET*>( secondItem );
2685 return StrNumCmp( firstSheet->GetName(), secondSheet->GetName(), false ) < 0;
2686 } );
2687
2688
2689 for( SCH_ITEM* item : sortedLoadedItems )
2690 {
2691 loadedItems.push_back( item );
2692
2693 if( item->Type() == SCH_SHEET_T )
2694 {
2695 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
2696 wxFileName srcFn = sheet->GetFileName();
2697
2698 if( srcFn.IsRelative() )
2699 srcFn.MakeAbsolute( m_frame->Prj().GetProjectPath() );
2700
2701 SCH_SHEET_LIST sheetHierarchy( sheet );
2702
2703 if( hierarchy.TestForRecursion( sheetHierarchy, destFn.GetFullPath( wxPATH_UNIX ) ) )
2704 {
2705 auto msg = wxString::Format( _( "The pasted sheet '%s'\n"
2706 "was dropped because the destination already has "
2707 "the sheet or one of its subsheets as a parent." ),
2708 sheet->GetFileName() );
2709 DisplayError( m_frame, msg );
2710 loadedItems.pop_back();
2711 }
2712 }
2713 }
2714
2715 // Remove the references from our temporary screen to prevent freeing on the DTOR
2716 tempScreen->Clear( false );
2717
2718 for( EDA_ITEM* item : loadedItems )
2719 {
2720 KIID_PATH clipPath( wxT( "/" ) ); // clipboard is at root
2721
2722 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item );
2723
2724 wxCHECK2( schItem, continue );
2725
2726 if( schItem->IsConnectable() )
2727 schItem->SetConnectivityDirty();
2728
2729 // Clear lock state on paste to match PCB editor behavior
2730 schItem->SetLocked( false );
2731
2732 if( item->Type() == SCH_SYMBOL_T )
2733 {
2734 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2735
2736 SCH_SCREEN* currentScreen = m_frame->GetScreen();
2737
2738 wxCHECK2( currentScreen, continue );
2739
2740 const LIB_SYMBOL* source = ChoosePasteLibSymbol( tempScreen, currentScreen,
2741 symbol->GetSchSymbolLibraryName() );
2742
2743 if( source )
2744 symbol->SetLibSymbol( new LIB_SYMBOL( *source ) );
2745
2746 // If the symbol is already in the schematic we have to always keep the annotations. The exception
2747 // is if the user has chosen to remove them.
2748 for( const SCH_SYMBOL_INSTANCE& instance : symbol->GetInstances() )
2749 {
2750 if( !existingRefsSet.contains( instance.m_Reference ) )
2751 {
2752 forceKeepAnnotations = !forceRemoveAnnotations;
2753 break;
2754 }
2755 }
2756
2757 for( SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
2758 updatePastedSymbol( symbol, sheetPath, clipPath, forceKeepAnnotations );
2759
2760 // Most modes will need new KIIDs for the symbol and its pins. However, if we are pasting
2761 // unique annotations, we need to check if the symbol is not already in the hierarchy. If we
2762 // don't already have a copy of the symbol, we just keep the existing KIID data as it is likely
2763 // the same symbol being moved around the schematic.
2764 bool needsNewKiid = ( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS );
2765
2766 for( const SCH_SYMBOL_INSTANCE& instance : symbol->GetInstances() )
2767 {
2768 if( existingRefsSet.contains( instance.m_Reference ) )
2769 {
2770 needsNewKiid = true;
2771 break;
2772 }
2773 }
2774
2775 if( needsNewKiid )
2776 {
2777 // Assign a new KIID
2778 const_cast<KIID&>( item->m_Uuid ) = KIID();
2779
2780 // Make sure pins get a new UUID
2781 for( SCH_PIN* pin : symbol->GetPins() )
2782 {
2783 const_cast<KIID&>( pin->m_Uuid ) = KIID();
2784 pin->SetConnectivityDirty();
2785 }
2786
2787 for( SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
2788 {
2789 // Ignore symbols from a non-existant library.
2790 if( source )
2791 {
2792 SCH_REFERENCE schReference( symbol, sheetPath );
2793 schReference.SetSheetNumber( sheetPath.GetPageNumberAsInt() );
2794 pastedSymbols[sheetPath].AddItem( schReference );
2795 }
2796 }
2797 }
2798 }
2799 else if( item->Type() == SCH_SHEET_T )
2800 {
2801 SCH_SHEET* sheet = (SCH_SHEET*) item;
2802 SCH_FIELD* nameField = sheet->GetField( FIELD_T::SHEET_NAME );
2803 wxString baseName = nameField->GetText();
2804 wxString candidateName = baseName;
2805 wxString number;
2806
2807 while( !baseName.IsEmpty() && wxIsdigit( baseName.Last() ) )
2808 {
2809 number = baseName.Last() + number;
2810 baseName.RemoveLast();
2811 }
2812
2813 // Update hierarchy to include any other sheets we already added, avoiding
2814 // duplicate sheet names
2815 hierarchy = m_frame->Schematic().Hierarchy();
2816
2817 int uniquifier = std::max( 0, wxAtoi( number ) ) + 1;
2818
2819 while( existingSheetNames.count( candidateName ) )
2820 candidateName = wxString::Format( wxT( "%s%d" ), baseName, uniquifier++ );
2821
2822 nameField->SetText( candidateName );
2823 existingSheetNames.emplace( candidateName );
2824
2825 wxFileName fn = sheet->GetFileName();
2826 SCH_SCREEN* existingScreen = nullptr;
2827
2828 sheet->SetParent( pasteRoot.Last() );
2829 sheet->SetScreen( nullptr );
2830
2831 if( !fn.IsAbsolute() )
2832 {
2833 wxFileName currentSheetFileName = pasteRoot.LastScreen()->GetFileName();
2834 fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS, currentSheetFileName.GetPath() );
2835 }
2836
2837 // Try to find the screen for the pasted sheet by several means
2838 if( !m_frame->Schematic().Root().SearchHierarchy( fn.GetFullPath( wxPATH_UNIX ), &existingScreen ) )
2839 {
2840 if( loadedScreens.count( sheet->GetFileName() ) > 0 )
2841 existingScreen = loadedScreens.at( sheet->GetFileName() );
2842 else
2843 searchSupplementaryClipboard( sheet->GetFileName(), &existingScreen );
2844 }
2845
2846 if( existingScreen )
2847 {
2848 sheet->SetScreen( existingScreen );
2849 }
2850 else
2851 {
2852 if( !m_frame->LoadSheetFromFile( sheet, &pasteRoot, fn.GetFullPath() ) )
2853 m_frame->InitSheet( sheet, sheet->GetFileName() );
2854 }
2855
2856 // Save the symbol instances in case the user chooses to keep the existing
2857 // symbol annotation.
2859 sheetsPasted = true;
2860
2861 // Push it to the clipboard path while it still has its old KIID
2862 clipPath.push_back( sheet->m_Uuid );
2863
2864 // Assign a new KIID to the pasted sheet
2865 const_cast<KIID&>( sheet->m_Uuid ) = KIID();
2866
2867 // Make sure pins get a new UUID
2868 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
2869 {
2870 const_cast<KIID&>( pin->m_Uuid ) = KIID();
2871 pin->SetConnectivityDirty();
2872 }
2873
2874 // Once we have our new KIID we can update all pasted instances. This will either
2875 // reset the annotations or copy "kept" annotations from the supplementary clipboard.
2876 for( SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
2877 {
2878 SCH_SHEET_PATH subPath = updatePastedSheet( sheet, sheetPath, clipPath,
2879 ( forceKeepAnnotations && annotateAutomatic ),
2880 &pastedSheets[sheetPath], pastedSymbols );
2881 }
2882 }
2883 else
2884 {
2885 SCH_ITEM* srcItem = dynamic_cast<SCH_ITEM*>( itemMap[item->m_Uuid] );
2886 SCH_ITEM* destItem = dynamic_cast<SCH_ITEM*>( item );
2887
2888 // Everything gets a new KIID
2889 const_cast<KIID&>( item->m_Uuid ) = KIID();
2890
2891 if( srcItem && destItem )
2892 {
2893 destItem->SetConnectivityDirty( true );
2894 destItem->SetLastResolvedState( srcItem );
2895 }
2896
2897 // Pasted named groups need a unique name, the multichannel tool matches groups by name.
2898 if( item->Type() == SCH_GROUP_T )
2899 {
2900 SCH_GROUP* group = static_cast<SCH_GROUP*>( item );
2901
2902 if( !group->GetName().IsEmpty() )
2903 group->SetName( UniqueGroupName( m_frame->GetScreen(), group->GetName() ) );
2904 }
2905 }
2906
2907 // Lines need both ends selected for a move after paste so the whole line moves.
2908 if( item->Type() == SCH_LINE_T )
2909 item->SetFlags( STARTPOINT | ENDPOINT );
2910
2911 item->SetFlags( IS_NEW | IS_PASTED | IS_MOVING );
2912
2913 if( !m_frame->GetScreen()->CheckIfOnDrawList( (SCH_ITEM*) item ) ) // don't want a loop!
2914 m_frame->AddToScreen( item, m_frame->GetScreen() );
2915
2916 commit.Added( (SCH_ITEM*) item, m_frame->GetScreen() );
2917
2918 // Start out hidden so the pasted items aren't "ghosted" in their original location
2919 // before being moved to the current location.
2920 getView()->Hide( item, true );
2921 }
2922
2923 if( sheetsPasted )
2924 {
2925 // The full schematic hierarchy need to be update before assigning new annotation and page numbers.
2926 m_frame->Schematic().RefreshHierarchy();
2927
2928 // Update sheet instance page and virtual page numbers to ensure annotation works correctly.
2929 for( SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
2930 {
2931 for( SCH_SHEET_PATH& pastedSheet : pastedSheets[sheetPath] )
2932 {
2933 // Find next free string page number for the sheet instance.
2934 int page = 1;
2935 wxString pageNum = wxString::Format( "%d", page );
2936
2937 while( hierarchy.PageNumberExists( pageNum ) )
2938 pageNum = wxString::Format( "%d", ++page );
2939
2940 int virtualPageNumber = page;
2941
2942 // The virtual page and sheet instance page numbers do not necessarily track. Increment by one
2943 // to ensure the annotation sheet paths all have unique virtual page numbers.
2944 if( page == hierarchy.GetLastVirtualPageNumber() )
2945 virtualPageNumber = hierarchy.GetLastVirtualPageNumber() + 1;
2946
2947 pastedSheet.SetVirtualPageNumber( virtualPageNumber );
2948
2949 SCH_SHEET_INSTANCE sheetInstance;
2950
2951 sheetInstance.m_Path = pastedSheet.Path();
2952
2953 // Don't include the actual sheet in the instance path.
2954 sheetInstance.m_Path.pop_back();
2955 sheetInstance.m_PageNumber = pageNum;
2956 sheetInstance.m_ProjectName = m_frame->Prj().GetProjectName();
2957
2958 SCH_SHEET* sheet = pastedSheet.Last();
2959
2960 wxCHECK2( sheet, continue );
2961
2962 sheet->AddInstance( sheetInstance );
2963 hierarchy.push_back( pastedSheet );
2964
2965 // Remove all pasted sheet instance data that is not part of the current project.
2966 std::vector<KIID_PATH> instancesToRemove;
2967
2968 for( const SCH_SHEET_INSTANCE& instance : sheet->GetInstances() )
2969 {
2970 if( !hierarchy.HasPath( instance.m_Path ) )
2971 instancesToRemove.push_back( instance.m_Path );
2972 }
2973
2974 for( const KIID_PATH& instancePath : instancesToRemove )
2975 sheet->RemoveInstance( instancePath );
2976
2977 // The sheet paths for the annotation code where copied in updatePastedSheets() when the virtual
2978 // page number was still 1. Set the virtual page number in the copied sheet paths.
2979 for( auto&[path, refs] : pastedSymbols )
2980 {
2981 for( SCH_REFERENCE& ref : refs )
2982 {
2983 if( ref.GetSheetPath() == pastedSheet )
2984 {
2985 ref.GetSheetPath().SetVirtualPageNumber( virtualPageNumber );
2986 ref.SetSheetNumber( virtualPageNumber );
2987 }
2988 }
2989 }
2990 }
2991 }
2992
2993 m_frame->SetSheetNumberAndCount();
2994
2995 // Get a version with correct sheet numbers since we've pasted sheets,
2996 // we'll need this when annotating next
2997 hierarchy = m_frame->Schematic().Hierarchy();
2998 }
2999
3000 std::map<SCH_SHEET_PATH, SCH_REFERENCE_LIST> annotatedSymbols;
3001
3002 // Update the list of symbol instances that satisfy the annotation criteria.
3003 for( const SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
3004 {
3005 for( size_t i = 0; i < pastedSymbols[sheetPath].GetCount(); i++ )
3006 {
3007 if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS || pastedSymbols[sheetPath][i].AlwaysAnnotate() )
3008 annotatedSymbols[sheetPath].AddItem( pastedSymbols[sheetPath][i] );
3009 }
3010
3011 for( const SCH_SHEET_PATH& pastedSheetPath : pastedSheets[sheetPath] )
3012 {
3013 for( size_t i = 0; i < pastedSymbols[pastedSheetPath].GetCount(); i++ )
3014 {
3015 if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS || pastedSymbols[pastedSheetPath][i].AlwaysAnnotate() )
3016 annotatedSymbols[pastedSheetPath].AddItem( pastedSymbols[pastedSheetPath][i] );
3017 }
3018 }
3019 }
3020
3021 if( !annotatedSymbols.empty() )
3022 {
3023 ANNOTATE_ORDER_T annotateOrder = static_cast<ANNOTATE_ORDER_T>( schematicSettings.m_AnnotateSortOrder );
3024 ANNOTATE_ALGO_T annotateAlgo = static_cast<ANNOTATE_ALGO_T>( schematicSettings.m_AnnotateMethod );
3025
3026 for( SCH_SHEET_PATH& path : sheetPathsForScreen )
3027 {
3028 annotatedSymbols[path].SortByReferenceOnly();
3029 annotatedSymbols[path].SetRefDesTracker( schematicSettings.m_refDesTracker );
3030
3031 if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS )
3032 {
3033 annotatedSymbols[path].ReannotateDuplicates( existingRefs, annotateAlgo );
3034 }
3035 else
3036 {
3037 annotatedSymbols[path].ReannotateByOptions( annotateOrder, annotateAlgo, annotateStartNum,
3038 existingRefs, false, &hierarchy );
3039 }
3040
3041 annotatedSymbols[path].UpdateAnnotation();
3042
3043 // Update existing refs for next iteration
3044 for( size_t i = 0; i < annotatedSymbols[path].GetCount(); i++ )
3045 existingRefs.AddItem( annotatedSymbols[path][i] );
3046
3047 for( const SCH_SHEET_PATH& pastedSheetPath : pastedSheets[path] )
3048 {
3049 annotatedSymbols[pastedSheetPath].SortByReferenceOnly();
3050 annotatedSymbols[pastedSheetPath].SetRefDesTracker( schematicSettings.m_refDesTracker );
3051
3052 if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS )
3053 {
3054 annotatedSymbols[pastedSheetPath].ReannotateDuplicates( existingRefs, annotateAlgo );
3055 }
3056 else
3057 {
3058 annotatedSymbols[pastedSheetPath].ReannotateByOptions( annotateOrder, annotateAlgo,
3059 annotateStartNum, existingRefs,
3060 false, &hierarchy );
3061 }
3062
3063 annotatedSymbols[pastedSheetPath].UpdateAnnotation();
3064
3065 // Update existing refs for next iteration
3066 for( size_t i = 0; i < annotatedSymbols[pastedSheetPath].GetCount(); i++ )
3067 existingRefs.AddItem( annotatedSymbols[pastedSheetPath][i] );
3068 }
3069 }
3070 }
3071
3072 m_frame->GetCurrentSheet().UpdateAllScreenReferences();
3073
3074 // The copy operation creates instance paths that are not valid for the current project or
3075 // saved as part of another project. Prune them now so they do not accumulate in the saved
3076 // schematic file.
3078
3079 SCH_SHEET_LIST sheets = m_frame->Schematic().Hierarchy();
3080 SCH_SCREENS allScreens( m_frame->Schematic().Root() );
3081
3082 allScreens.PruneOrphanedSymbolInstances( m_frame->Prj().GetProjectName(), sheets );
3083 allScreens.PruneOrphanedSheetInstances( m_frame->Prj().GetProjectName(), sheets );
3084
3085 // Now clear the previous selection, select the pasted items, and fire up the "move" tool.
3086 m_toolMgr->RunAction( ACTIONS::selectionClear );
3087
3088 // If the item has a parent group, it will be part of the loadedItems, and will handle
3089 // the move action. Iterate backwards to avoid invalidating the iterator.
3090 for( int i = loadedItems.size() - 1; i >= 0; i-- )
3091 {
3092 EDA_ITEM* item = loadedItems[i];
3093
3094 if( item->GetParentGroup() )
3095 {
3096 loadedItems.erase( loadedItems.begin() + i );
3097 // These were hidden before because they would be added to the move preview,
3098 // but now they need to be shown as a preview so they appear to move when
3099 // the group moves.
3100 getView()->SetVisible( item );
3101 getView()->AddToPreview( item, false );
3102 }
3103 }
3104
3105 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &loadedItems );
3106
3107 SCH_SELECTION& selection = selTool->GetSelection();
3108
3109 if( !selection.Empty() )
3110 {
3111 if( aEvent.IsAction( &ACTIONS::duplicate ) )
3112 {
3113 int closest_dist = INT_MAX;
3114
3115 auto processPt =
3116 [&]( const VECTOR2I& pt )
3117 {
3118 int dist = ( eventPos - pt ).EuclideanNorm();
3119
3120 if( dist < closest_dist )
3121 {
3122 selection.SetReferencePoint( pt );
3123 closest_dist = dist;
3124 }
3125 };
3126
3127 std::vector<SCH_ITEM*> anchorCandidates = FlattenGroups( selection.Items() );
3128
3129 // Prefer connection points (which should remain on grid)
3130 for( EDA_ITEM* item : anchorCandidates )
3131 {
3132 SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item );
3133 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( item );
3134
3135 if( sch_item && sch_item->IsConnectable() )
3136 {
3137 for( const VECTOR2I& pt : sch_item->GetConnectionPoints() )
3138 processPt( pt );
3139 }
3140 else if( pin )
3141 {
3142 processPt( pin->GetPosition() );
3143 }
3144
3145 // Symbols need to have their center point added since often users are trying to
3146 // move parts from their center.
3147 if( dynamic_cast<SCH_SYMBOL*>( item ) )
3148 processPt( item->GetPosition() );
3149 }
3150
3151 // Only process other points if we didn't find any connection points
3152 if( closest_dist == INT_MAX )
3153 {
3154 for( EDA_ITEM* item : anchorCandidates )
3155 {
3156 switch( item->Type() )
3157 {
3158 // A group's position is its bounding box centre, which is off grid
3159 case SCH_GROUP_T: break;
3160
3161 case SCH_LINE_T:
3162 processPt( static_cast<SCH_LINE*>( item )->GetStartPoint() );
3163 processPt( static_cast<SCH_LINE*>( item )->GetEndPoint() );
3164 break;
3165
3166 case SCH_SHAPE_T:
3167 {
3168 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item );
3169
3170 switch( shape->GetShape() )
3171 {
3172 case SHAPE_T::RECTANGLE:
3173 for( const VECTOR2I& pt : shape->GetRectCorners() )
3174 processPt( pt );
3175
3176 break;
3177
3178 case SHAPE_T::CIRCLE:
3179 processPt( shape->GetCenter() );
3180 break;
3181
3182 case SHAPE_T::POLY:
3183 for( int ii = 0; ii < shape->GetPolyShape().TotalVertices(); ++ii )
3184 processPt( shape->GetPolyShape().CVertex( ii ) );
3185
3186 break;
3187
3188 default:
3189 processPt( shape->GetStart() );
3190 processPt( shape->GetEnd() );
3191 break;
3192 }
3193
3194 break;
3195 }
3196
3197 default:
3198 processPt( item->GetPosition() );
3199 break;
3200 }
3201 }
3202 }
3203
3204 selection.SetIsHover( m_duplicateIsHoverSelection );
3205 }
3206 // We want to the first non-group item in the selection to be the reference point.
3207 else if( selection.GetTopLeftItem()->Type() == SCH_GROUP_T )
3208 {
3209 SCH_GROUP* group = static_cast<SCH_GROUP*>( selection.GetTopLeftItem() );
3210
3211 bool found = false;
3212 SCH_ITEM* item = nullptr;
3213
3214 group->RunOnChildren(
3215 [&]( SCH_ITEM* schItem )
3216 {
3217 if( !found && schItem->Type() != SCH_GROUP_T )
3218 {
3219 item = schItem;
3220 found = true;
3221 }
3222 },
3224
3225 if( found )
3226 selection.SetReferencePoint( item->GetPosition() );
3227 else
3228 selection.SetReferencePoint( group->GetPosition() );
3229 }
3230 else
3231 {
3232 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetTopLeftItem() );
3233
3234 selection.SetReferencePoint( item->GetPosition() );
3235 }
3236
3237 if( m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit ) )
3238 {
3239 // Pushing the commit will update the connectivity.
3240 commit.Push( _( "Paste" ) );
3241
3242 if( sheetsPasted )
3243 {
3244 m_frame->UpdateHierarchyNavigator();
3245 // UpdateHierarchyNavigator() will call RefreshNetNavigator()
3246 }
3247 else
3248 {
3249 m_frame->RefreshNetNavigator();
3250 }
3251 }
3252 else
3253 {
3254 commit.Revert();
3255 }
3256
3257 getView()->ClearPreview();
3258 }
3259
3260 return 0;
3261}
3262
3263
3265{
3266 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
3267 SCH_SELECTION& selection = selTool->RequestSelection( { SCH_SYMBOL_T } );
3268 SCH_SYMBOL* symbol = nullptr;
3269 SYMBOL_EDIT_FRAME* symbolEditor;
3270
3271 if( selection.GetSize() >= 1 )
3272 symbol = (SCH_SYMBOL*) selection.Front();
3273
3274 if( selection.IsHover() )
3275 m_toolMgr->RunAction( ACTIONS::selectionClear );
3276
3277 if( !symbol )
3278 {
3279 // Giant hack: by default we assign Edit Table to the same hotkey, so give the table
3280 // tool a chance to handle it if we can't.
3281 if( SCH_EDIT_TABLE_TOOL* tableTool = m_toolMgr->GetTool<SCH_EDIT_TABLE_TOOL>() )
3282 tableTool->EditTable( aEvent );
3283
3284 return 0;
3285 }
3286
3287 if( symbol->GetEditFlags() != 0 )
3288 return 0;
3289
3290 if( symbol->IsMissingLibSymbol() )
3291 {
3292 m_frame->ShowInfoBarError( _( "Symbols with broken library symbol links cannot be edited." ) );
3293 return 0;
3294 }
3295
3297 symbolEditor = (SYMBOL_EDIT_FRAME*) m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR, false );
3298
3299 if( symbolEditor )
3300 {
3301 if( wxWindow* blocking_win = symbolEditor->Kiway().GetBlockingDialog() )
3302 blocking_win->Close( true );
3303
3304 if( aEvent.IsAction( &SCH_ACTIONS::editWithLibEdit ) )
3305 {
3306 symbolEditor->LoadSymbolFromSchematic( symbol );
3307 }
3309 {
3310 symbolEditor->LoadSymbol( symbol->GetLibId(), symbol->GetUnit(), symbol->GetBodyStyle() );
3311
3312 if( !symbolEditor->IsLibraryTreeShown() )
3313 symbolEditor->ToggleLibraryTree();
3314 }
3315 }
3316
3317 return 0;
3318}
3319
3320
3322{
3323 m_frame->OnAnnotate();
3324 return 0;
3325}
3326
3327
3329{
3331 dlg.m_FirstRefDes->SetValidator( wxTextValidator( wxFILTER_EMPTY ) );
3332
3333 dlg.SetInitialFocus( dlg.m_FirstRefDes );
3334
3335 if( dlg.ShowModal() == wxID_OK )
3336 {
3337 SCH_REFERENCE startRef;
3338 startRef.SetRef( dlg.m_FirstRefDes->GetValue() );
3339
3340 if( startRef.IsSplitNeeded() )
3341 startRef.Split();
3342 else
3343 return 0;
3344
3345 int startNum = atoi( startRef.GetRefNumber().utf8_string().c_str() );
3346
3347 SCH_COMMIT commit( m_frame );
3348 SCHEMATIC* schematic = m_frame->m_schematic;
3349 SCH_REFERENCE_LIST references;
3350
3351 if( dlg.m_AllSheets->GetValue() )
3352 schematic->Hierarchy().GetSymbols( references, SYMBOL_FILTER_ALL );
3353 else
3354 schematic->CurrentSheet().GetSymbols( references, SYMBOL_FILTER_ALL );
3355
3356 references.SplitReferences();
3357
3358 for( SCH_REFERENCE& ref : references )
3359 {
3360 if( ref.GetRef() == startRef.GetRef() )
3361 {
3362 int num = atoi( ref.GetRefNumber().utf8_string().c_str() );
3363
3364 if( num >= startNum )
3365 {
3366 const SCH_SHEET_PATH& sheet = ref.GetSheetPath();
3367 wxString fullRef = ref.GetRef();
3368
3369 num += dlg.m_Increment->GetValue();
3370 fullRef << num;
3371
3372 commit.Modify( ref.GetSymbol(), sheet.LastScreen(), RECURSE_MODE::NO_RECURSE );
3373 ref.GetSymbol()->SetRef( &sheet, From_UTF8( fullRef.c_str() ) );
3374 }
3375 }
3376 }
3377
3378 if( !commit.Empty() )
3379 commit.Push( _( "Increment Annotations" ) );
3380 }
3381
3382 return 0;
3383}
3384
3385
3387{
3388 m_frame->OnOpenCvpcb();
3389 return 0;
3390}
3391
3392
3394{
3395 m_frame->OnImportProject();
3396 return 0;
3397}
3398
3399
3401{
3402 DIALOG_SYMBOL_FIELDS_TABLE* dlg = m_frame->GetSymbolFieldsTableDialog();
3403
3404 if( !dlg )
3405 return 0;
3406
3407 // Needed at least on Windows. Raise() is not enough
3408 dlg->Show( true );
3409
3410 // Bring it to the top if already open. Dual monitor users need this.
3411 dlg->Raise();
3412
3413 dlg->ShowEditTab();
3414
3415 return 0;
3416}
3417
3418
3420{
3421 if( !m_frame->Schematic().GetCurrentVariant().IsEmpty() )
3422 {
3424 _( "Bulk Edit Symbol Library Links is not available when a design variant is "
3425 "active. Switch to the default variant first." ) );
3426 return 0;
3427 }
3428
3430 m_frame->HardRedraw();
3431
3432 return 0;
3433}
3434
3435
3437{
3438 m_frame->OnOpenPcbnew();
3439 return 0;
3440}
3441
3442
3444{
3445 m_frame->OnUpdatePCB();
3446 return 0;
3447}
3448
3449
3451{
3453 dlg.ShowModal();
3454 return 0;
3455}
3456
3457
3459{
3461
3462 // If a plugin is removed or added, rebuild and reopen the new dialog
3463 while( result == NET_PLUGIN_CHANGE )
3465
3466 return 0;
3467}
3468
3469
3471{
3472 DIALOG_SYMBOL_FIELDS_TABLE* dlg = m_frame->GetSymbolFieldsTableDialog();
3473
3474 if( !dlg )
3475 return 0;
3476
3477 // Needed at least on Windows. Raise() is not enough
3478 dlg->Show( true );
3479
3480 // Bring it to the top if already open. Dual monitor users need this.
3481 dlg->Raise();
3482
3483 dlg->ShowExportTab();
3484
3485 return 0;
3486}
3487
3488
3490{
3492 return 0;
3493}
3494
3495
3497{
3498 m_frame->RecalculateConnections( nullptr, LOCAL_CLEANUP );
3499
3500 // Create a selection with all items from the current sheet
3501 SCH_SELECTION sheetSelection;
3502 SCH_SCREEN* screen = m_frame->GetScreen();
3503
3504 for( SCH_ITEM* item : screen->Items() )
3505 {
3506 sheetSelection.Add( item );
3507 }
3508
3509 // Get the full page bounding box for rendering the complete sheet
3510 BOX2I pageBBox( VECTOR2I( 0, 0 ), m_frame->GetPageSizeIU() );
3511
3512 // Render the full sheet selection including the worksheet
3513 wxImage image = renderSelectionToImageForClipboard( m_frame, sheetSelection, pageBBox, true, true );
3514
3515 if( image.IsOk() )
3516 {
3517 wxLogNull doNotLog; // disable logging of failed clipboard actions
3518
3519 if( wxTheClipboard->Open() )
3520 {
3521 wxDataObjectComposite* data = new wxDataObjectComposite();
3522
3524
3525 wxTheClipboard->SetData( data );
3526 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
3527 wxTheClipboard->Close();
3528 }
3529 }
3530 else
3531 {
3532 wxLogMessage( _( "Cannot create the schematic image" ) );
3533 }
3534
3535 return 0;
3536}
3537
3538
3540{
3542 return 0;
3543}
3544
3545
3551
3552
3558
3559
3565
3566
3572
3573
3579
3580
3582{
3583 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3585
3587 m_frame->GetCanvas()->Refresh();
3588
3589 return 0;
3590}
3591
3592
3594{
3595 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3597
3598 m_frame->GetRenderSettings()->m_ShowHiddenFields = cfg->m_Appearance.show_hidden_fields;
3599
3601 m_frame->GetCanvas()->Refresh();
3602
3603 return 0;
3604}
3605
3606
3608{
3609 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3611
3613 m_frame->GetCanvas()->Refresh();
3614
3615 return 0;
3616}
3617
3618
3620{
3621 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3623
3625 m_frame->GetCanvas()->Refresh();
3626
3627 return 0;
3628}
3629
3630
3632{
3633 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3635
3637 m_frame->GetCanvas()->Refresh();
3638
3639 return 0;
3640}
3641
3642
3644{
3645 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3647
3648 m_frame->GetCanvas()->Refresh();
3649
3650 return 0;
3651}
3652
3653
3655{
3656 SCH_SHEET_PATH* sheetPath = &m_frame->GetCurrentSheet();
3657 wxString variant = m_frame->Schematic().GetCurrentVariant();
3658 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3660
3661 m_frame->GetCanvas()->GetView()->UpdateAllItemsConditionally(
3662 [&]( KIGFX::VIEW_ITEM* aItem ) -> int
3663 {
3664 int flags = 0;
3665
3666 auto invalidateTextVars =
3667 [&flags]( EDA_TEXT* text )
3668 {
3669 if( text->HasTextVars() )
3670 {
3671 text->ClearRenderCache();
3672 text->ClearBoundingBoxCache();
3674 }
3675 };
3676
3677 if( SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aItem ) )
3678 {
3679 item->RunOnChildren(
3680 [&invalidateTextVars]( SCH_ITEM* aChild )
3681 {
3682 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aChild ) )
3683 invalidateTextVars( text );
3684 },
3686
3687 if( item->GetExcludedFromSim( sheetPath, variant ) )
3689 }
3690
3691 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem ) )
3692 invalidateTextVars( text );
3693
3694 return flags;
3695 } );
3696
3697 m_frame->GetCanvas()->Refresh();
3698
3699 return 0;
3700}
3701
3702
3704{
3705 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3707
3709 m_frame->RefreshOperatingPointDisplay();
3710 m_frame->GetCanvas()->Refresh();
3711
3712 return 0;
3713}
3714
3715
3717{
3718 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3720
3722 m_frame->RefreshOperatingPointDisplay();
3723 m_frame->GetCanvas()->Refresh();
3724
3725 return 0;
3726}
3727
3728
3730{
3731 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3733
3734 m_frame->GetRenderSettings()->m_ShowPinAltIcons = cfg->m_Appearance.show_pin_alt_icons;
3735
3737 m_frame->GetCanvas()->Refresh();
3738
3739 return 0;
3740}
3741
3742
3744{
3745 m_frame->eeconfig()->m_Drawing.line_mode = aEvent.Parameter<LINE_MODE>();
3746 m_toolMgr->PostAction( ACTIONS::refreshPreview );
3747 // Notify toolbar to update selection
3749 return 0;
3750}
3751
3752
3754{
3755 m_frame->eeconfig()->m_Drawing.line_mode++;
3756 m_frame->eeconfig()->m_Drawing.line_mode %= LINE_MODE::LINE_MODE_COUNT;
3757 m_toolMgr->PostAction( ACTIONS::refreshPreview );
3758 // Notify toolbar to update selection
3760 return 0;
3761}
3762
3763
3765{
3766 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3768 return 0;
3769}
3770
3771
3773{
3774 // Update the left toolbar Line modes group icon to match current mode
3775 switch( static_cast<LINE_MODE>( m_frame->eeconfig()->m_Drawing.line_mode ) )
3776 {
3777 case LINE_MODE::LINE_MODE_FREE: m_frame->SelectToolbarAction( SCH_ACTIONS::lineModeFree ); break;
3778 case LINE_MODE::LINE_MODE_90: m_frame->SelectToolbarAction( SCH_ACTIONS::lineMode90 ); break;
3779 default:
3780 case LINE_MODE::LINE_MODE_45: m_frame->SelectToolbarAction( SCH_ACTIONS::lineMode45 ); break;
3781 }
3782
3783 return 0;
3784}
3785
3786
3788{
3789 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
3790 return 0;
3791
3792 GRID_SETTINGS& gridSettings = m_toolMgr->GetSettings()->m_Window.grid;
3793 int currentIdx = m_toolMgr->GetSettings()->m_Window.grid.last_size_idx;
3794
3795 wxArrayString gridsLabels;
3796
3797 for( const GRID& grid : gridSettings.grids )
3798 gridsLabels.Add( grid.UserUnitsMessageText( m_frame ) );
3799
3800 if( !m_frame->GetHotkeyPopup() )
3801 m_frame->CreateHotkeyPopup();
3802
3803 HOTKEY_CYCLE_POPUP* popup = m_frame->GetHotkeyPopup();
3804
3805 if( popup )
3806 popup->Popup( _( "Grid" ), gridsLabels, currentIdx );
3807
3808 return 0;
3809}
3810
3811
3813{
3814 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3815
3816 if( !editFrame )
3817 return 1;
3818
3819 // Need to have a group selected and it needs to have a linked design block
3820 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
3821 SCH_SELECTION selection = selTool->GetSelection();
3822
3823 if( selection.Size() != 1 || selection[0]->Type() != SCH_GROUP_T )
3824 return 1;
3825
3826 SCH_GROUP* group = static_cast<SCH_GROUP*>( selection[0] );
3827
3828 if( !group->HasDesignBlockLink() )
3829 return 1;
3830
3831 // Get the associated design block
3832 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
3833 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
3834 true, true ) );
3835
3836 if( !designBlock )
3837 return 1;
3838
3839 if( designBlock->GetSchematicFile().IsEmpty() )
3840 {
3841 wxString msg;
3842 msg.Printf( _( "Design block %s does not have a schematic file." ),
3843 group->GetDesignBlockLibId().GetUniStringLibId() );
3844 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
3845 return 1;
3846 }
3847
3848 editFrame->GetDesignBlockPane()->SelectLibId( group->GetDesignBlockLibId() );
3849
3850 return m_toolMgr->RunAction( SCH_ACTIONS::placeDesignBlock, designBlock.release() );
3851}
3852
3853
3855{
3856 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3857
3858 if( !editFrame )
3859 return 1;
3860
3861 // Need to have a group selected and it needs to have a linked design block
3862 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
3863 SCH_SELECTION selection = selTool->GetSelection();
3864
3865 if( selection.Size() != 1 || selection[0]->Type() != SCH_GROUP_T )
3866 return 1;
3867
3868 SCH_GROUP* group = static_cast<SCH_GROUP*>( selection[0] );
3869
3870 if( !group->HasDesignBlockLink() )
3871 return 1;
3872
3873 // Get the associated design block
3874 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
3875 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
3876 true, true ) );
3877
3878 if( !designBlock )
3879 return 1;
3880
3881 editFrame->GetDesignBlockPane()->SelectLibId( group->GetDesignBlockLibId() );
3882
3883 return m_toolMgr->RunAction( SCH_ACTIONS::updateDesignBlockFromSelection ) ? 1 : 0;
3884}
3885
3886
3888{
3889 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3890
3891 if( !editFrame )
3892 return 1;
3893
3894 editFrame->AddVariant();
3895
3896 return 0;
3897}
3898
3899
3901{
3902 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3903
3904 if( !editFrame )
3905 return 1;
3906
3907 editFrame->RemoveVariant();
3908 return 0;
3909}
3910
3911
3913{
3914 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3915
3916 if( !editFrame )
3917 return 1;
3918
3919 editFrame->EditVariantDescription();
3920 return 0;
3921}
3922
3923
3925{
3926 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3927
3928 if( !editFrame )
3929 return 1;
3930
3931 editFrame->RenameVariant();
3932 return 0;
3933}
3934
3935
3937{
3938 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3939
3940 if( !editFrame )
3941 return 1;
3942
3943 editFrame->CopyVariant();
3944 return 0;
3945}
3946
3947
3949{
3950 Go( &SCH_EDITOR_CONTROL::New, ACTIONS::doNew.MakeEvent() );
3951 Go( &SCH_EDITOR_CONTROL::Open, ACTIONS::open.MakeEvent() );
3952 Go( &SCH_EDITOR_CONTROL::Save, ACTIONS::save.MakeEvent() );
3959 Go( &SCH_EDITOR_CONTROL::Plot, ACTIONS::plot.MakeEvent() );
3960
3963
3969
3972
3984
3987
3988 Go( &SCH_EDITOR_CONTROL::Undo, ACTIONS::undo.MakeEvent() );
3989 Go( &SCH_EDITOR_CONTROL::Redo, ACTIONS::redo.MakeEvent() );
3990 Go( &SCH_EDITOR_CONTROL::Cut, ACTIONS::cut.MakeEvent() );
3991 Go( &SCH_EDITOR_CONTROL::Copy, ACTIONS::copy.MakeEvent() );
3996
3998
4015
4023
4040
4042
4045
4051}
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:123
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
BOX2< VECTOR2D > BOX2D
Definition box2.h:928
static TOOL_ACTION updatePcbFromSchematic
Definition actions.h:260
static TOOL_ACTION paste
Definition actions.h:76
static TOOL_ACTION revert
Definition actions.h:58
static TOOL_ACTION saveAs
Definition actions.h:55
static TOOL_ACTION copy
Definition actions.h:74
static TOOL_ACTION pickerTool
Definition actions.h:249
static TOOL_ACTION showSymbolEditor
Definition actions.h:256
static TOOL_ACTION pasteSpecial
Definition actions.h:77
static TOOL_ACTION plot
Definition actions.h:61
static TOOL_ACTION open
Definition actions.h:53
static TOOL_ACTION pageSettings
Definition actions.h:59
static TOOL_ACTION showSearch
Definition actions.h:112
static TOOL_ACTION undo
Definition actions.h:71
static TOOL_ACTION selectionActivate
Activation of the selection tool.
Definition actions.h:210
static TOOL_ACTION duplicate
Definition actions.h:80
static TOOL_ACTION doDelete
Definition actions.h:81
static TOOL_ACTION save
Definition actions.h:54
static TOOL_ACTION redo
Definition actions.h:72
static TOOL_ACTION updateSchematicFromPcb
Definition actions.h:261
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
static TOOL_ACTION print
Definition actions.h:60
static TOOL_ACTION showProperties
Definition actions.h:262
static TOOL_ACTION doNew
Definition actions.h:50
static TOOL_ACTION cut
Definition actions.h:73
static TOOL_ACTION copyAsText
Definition actions.h:75
static TOOL_ACTION refreshPreview
Definition actions.h:155
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:228
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
int GetPageCount() const
Definition base_screen.h:68
int GetVirtualPageNumber() const
Definition base_screen.h:71
static wxString m_DrawingSheetFileName
the name of the drawing sheet file, or empty to use the default drawing sheet
Definition base_screen.h:81
const wxString & GetPageNumber() const
void SetContentModified(bool aModified=true)
Definition base_screen.h:55
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr Vec Centre() const
Definition box2.h:94
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:653
constexpr const Vec GetCenter() const
Definition box2.h:227
constexpr size_type GetHeight() const
Definition box2.h:212
constexpr const Vec & GetOrigin() const
Definition box2.h:207
constexpr const SizeVec & GetSize() const
Definition box2.h:203
int GetCount() const
Return the number of objects in the list.
Definition collector.h:79
int m_Threshold
Definition collector.h:234
static const COLOR4D CLEAR
Definition color4d.h:404
COMMIT & Added(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition commit.h:80
bool Empty() const
Definition commit.h:142
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:102
Calculate the connectivity of a schematic and generates netlists.
SCH_NETCHAIN * GetNetChainByName(const wxString &aName)
CONNECTION_SUBGRAPH * FindSubgraphByName(const wxString &aNetName, const SCH_SHEET_PATH &aPath)
Return the subgraph for a given net name on a given sheet.
SCH_NETCHAIN * GetNetChainForNet(const wxString &aNet)
const std::vector< CONNECTION_SUBGRAPH * > & GetAllSubgraphs(const wxString &aNetName) const
SCH_NETCHAIN * CreateNetChainFromPotential(SCH_NETCHAIN *aPotential, const wxString &aName)
Promote a potential net chain to an actual user net chain with the provided name.
void Recalculate(const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr)
Update the connection graph for the given list of sheets.
const std::vector< std::unique_ptr< SCH_NETCHAIN > > & GetPotentialNetChains() const
Potential net chains are inferred groupings produced by RebuildNetChains() but not yet user-committed...
bool NetChainsBuilt() const
Returns true once RebuildNetChains() has completed at least once on this graph.
SCH_NETCHAIN * FindPotentialNetChainBetweenPins(SCH_PIN *aPinA, SCH_PIN *aPinB)
Locate a potential net chain that contains both pins (by subgraph net membership).
void ReplaceNetChainTerminalPin(const wxString &aNetChain, const KIID &aPrev, const KIID &aNew)
std::vector< wxString > GetEquivalentBusNames(const wxString &aBusName) const
Map a bus group name between its alias and expanded forms ({MIXED_BUS} <-> {FOO BAR HAM EGGS}...
A subgraph is a set of items that are electrically connected on a single sheet.
static PRIORITY GetDriverPriority(SCH_ITEM *aDriver)
Return the priority (higher is more important) of a candidate driver.
void SelectLibId(const LIB_ID &aLibId)
DESIGN_BLOCK * GetDesignBlock(const LIB_ID &aLibId, bool aUseCacheLib, bool aShowErrorMsg, wxString *aErrorMsg=nullptr)
Load design block from design block library table.
Class DIALOG_INCREMENT_ANNOTATIONS_BASE.
void SetWksFileName(const wxString &aFilename)
bool Show(bool show) override
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition dialog_shim.h:94
int ShowModal() override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
virtual VECTOR2I GetPosition() const
Definition eda_item.h:338
EDA_ITEM_FLAGS GetEditFlags() const
Definition eda_item.h:160
const KIID m_Uuid
Definition eda_item.h:587
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:116
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:204
void ClearBrightened()
Definition eda_item.h:150
void SetBrightened()
Definition eda_item.h:147
virtual EDA_ITEM * Clone() const
Create a duplicate of this item with linked list members set to NULL.
Definition eda_item.cpp:265
bool IsBrightened() const
Definition eda_item.h:136
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:140
SHAPE_POLY_SET & GetPolyShape()
SHAPE_T GetShape() const
Definition eda_shape.h:175
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:325
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:275
std::vector< VECTOR2I > GetRectCorners() const
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:94
virtual bool IsVisible() const
Definition eda_text.h:226
bool validatePasteIntoSelection(const SELECTION &aSel, wxString &aErrorMsg)
Validate if paste-into-cells is possible for the given selection.
bool pasteCellsIntoSelection(const SELECTION &aSel, T_TABLE *aSourceTable, T_COMMIT &aCommit)
Paste text content from source table into selected cells.
PANEL_ANNOTATE m_AnnotatePanel
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:242
static const TOOL_EVENT ClearedEvent
Definition actions.h:345
static const TOOL_EVENT GridChangedByKeyEvent
Definition actions.h:363
static const TOOL_EVENT SelectedEvent
Definition actions.h:343
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:350
static const TOOL_EVENT PointSelectedEvent
Definition actions.h:342
static const TOOL_EVENT UnselectedEvent
Definition actions.h:344
Similar to EDA_VIEW_SWITCHER, this dialog is a popup that shows feedback when using a hotkey to cycle...
void Popup(const wxString &aTitle, const wxArrayString &aItems, int aSelection)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
static std::unique_ptr< CAIRO_PRINT_GAL > Create(GAL_DISPLAY_OPTIONS &aOptions, wxImage *aImage, double aDPI)
GAL_ANTIALIASING_MODE antialiasing_mode
The grid style to draw the grid in.
virtual bool HasNativeLandscapeRotation() const =0
void SetLayerColor(int aLayer, const COLOR4D &aColor)
Change the color used to draw a layer.
void SetDefaultFont(const wxString &aFont)
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
void SetIsPrinting(bool isPrinting)
An interface for classes handling user events controlling the view behavior such as zooming,...
VECTOR2D GetCursorPosition() const
Return the current cursor position in world coordinates.
An abstract base class for deriving all objects that can be added to a VIEW.
Definition view_item.h:82
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition view.cpp:1852
void SetLayerVisible(int aLayer, bool aVisible=true)
Control the visibility of a particular layer.
Definition view.h:405
void ClearPreview()
Definition view.cpp:1875
static constexpr int VIEW_MAX_LAYERS
Maximum number of layers that may be shown.
Definition view.h:773
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition view.cpp:1703
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition view.cpp:1797
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition view.cpp:1897
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition view.cpp:1773
bool EndsWith(const KIID_PATH &aPath) const
Test if aPath from the last path towards the first path.
Definition kiid.cpp:402
wxString AsString() const
Definition kiid.cpp:423
Definition kiid.h:46
wxString AsString() const
Definition kiid.cpp:264
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
wxWindow * GetBlockingDialog()
Gets the window pointer to the blocking dialog (to send it signals)
Definition kiway.cpp:680
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false)
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
const wxString & Type() const
const wxString & Nickname() const
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:113
Define a library symbol object.
Definition lib_symbol.h:114
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:183
bool IsPower() const override
wxString GetName() const override
Definition lib_symbol.h:176
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
static void ConvertToSpiceMarkup(wxString *aNetName)
Remove formatting wrappers and replace illegal spice net name characters with underscores.
Tree view item data for the net navigator.
static bool ParseBusGroup(const wxString &aGroup, wxString *name, std::vector< wxString > *aMemberList, size_t *aPrefixEnd=nullptr)
Parse a bus group label into the name and a list of components.
static bool ParseBusVector(const wxString &aBus, wxString *aName, std::vector< wxString > *aMemberList)
Parse a bus vector (e.g.
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:75
void SetHeightMils(double aHeightInMils)
void SetWidthMils(double aWidthInMils)
A holder to handle information on schematic or board items.
void PushItem(const ITEM_PICKER &aItem)
Push aItem to the top of the list.
void SetDescription(const wxString &aDescription)
void ReversePickersListOrder()
Reverse the order of pickers stored in this list.
void SetMotionHandler(MOTION_HANDLER aHandler)
Set a handler for mouse motion.
Definition picker_tool.h:92
void SetClickHandler(CLICK_HANDLER aHandler)
Set a handler for mouse click event.
Definition picker_tool.h:81
void SetSnapping(bool aSnap)
Definition picker_tool.h:65
void SetCursor(KICURSOR aCursor)
Definition picker_tool.h:63
void SetFinalizeHandler(FINALIZE_HANDLER aHandler)
Set a handler for the finalize event.
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
static bool RescueProject(wxWindow *aParent, RESCUER &aRescuer, bool aRunningOnDemand)
size_t GetCandidateCount()
Return the number of rescue candidates found.
These are loaded from Eeschema settings but then overwritten by the project settings.
double GetHopOverScale()
Accessor that computes the current hop-over size.
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:147
wxString GetVariantDescription(const wxString &aVariantName) const
Return the description for a variant.
wxString GetFileName() const
Helper to retrieve the filename from the root sheet screen.
SCHEMATIC_SETTINGS & Settings() const
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
PROJECT & Project() const
Return a reference to the project this schematic is part of.
Definition schematic.h:169
wxString GetCurrentVariant() const
Return the current variant being edited.
CONNECTION_GRAPH * ConnectionGraph() const
Definition schematic.h:316
const std::map< wxString, wxString > * GetProperties()
Definition schematic.h:172
SCH_SHEET & Root() const
Definition schematic.h:198
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:302
static TOOL_ACTION showPcbNew
static TOOL_ACTION createNetChain
static TOOL_ACTION assignFootprints
static TOOL_ACTION copyVariant
static TOOL_ACTION lineModeNext
static TOOL_ACTION toggleOPCurrents
static TOOL_ACTION saveToLinkedDesignBlock
Definition sch_actions.h:76
static TOOL_ACTION clearHighlight
static TOOL_ACTION removeVariant
static TOOL_ACTION editSymbolFields
static TOOL_ACTION importFPAssignments
static TOOL_ACTION toggleAnnotateAuto
static TOOL_ACTION editLibSymbolWithLibEdit
static TOOL_ACTION toggleERCWarnings
static TOOL_ACTION editVariantDescription
static TOOL_ACTION schematicSetup
static TOOL_ACTION toggleDirectiveLabels
static TOOL_ACTION highlightNetTool
static TOOL_ACTION removeFromNetChain
static TOOL_ACTION findNetInInspector
static TOOL_ACTION toggleHiddenFields
static TOOL_ACTION saveCurrSheetCopyAs
Definition sch_actions.h:48
static TOOL_ACTION showRemoteSymbolPanel
static TOOL_ACTION remapSymbols
static TOOL_ACTION lineMode45
static TOOL_ACTION editSymbolLibraryLinks
static TOOL_ACTION simTune
static TOOL_ACTION generateBOM
static TOOL_ACTION showHierarchy
static TOOL_ACTION highlightNetChain
static TOOL_ACTION showNetNavigator
static TOOL_ACTION markSimExclusions
static TOOL_ACTION placeImage
static TOOL_ACTION editWithLibEdit
static TOOL_ACTION toggleERCErrors
static TOOL_ACTION incrementAnnotations
static TOOL_ACTION rescueSymbols
static TOOL_ACTION angleSnapModeChanged
static TOOL_ACTION placeLinkedDesignBlock
Definition sch_actions.h:75
static TOOL_ACTION generateBOMLegacy
static TOOL_ACTION placeDesignBlock
Definition sch_actions.h:74
static TOOL_ACTION toggleOPVoltages
static TOOL_ACTION simProbe
static TOOL_ACTION lineMode90
static TOOL_ACTION lineModeFree
static TOOL_ACTION changeSheet
static TOOL_ACTION highlightNet
static TOOL_ACTION assignNetclass
static TOOL_ACTION annotate
static TOOL_ACTION showDesignBlockPanel
static TOOL_ACTION updateDesignBlockFromSelection
static TOOL_ACTION replaceTerminalPin
static TOOL_ACTION togglePinAltIcons
static TOOL_ACTION toggleERCExclusions
static TOOL_ACTION updateNetHighlighting
static TOOL_ACTION renameVariant
static TOOL_ACTION createNetChainBetweenPins
static TOOL_ACTION exportNetlist
static TOOL_ACTION drawSheetOnClipboard
static TOOL_ACTION exportSymbolsToLibrary
static TOOL_ACTION toggleHiddenPins
static TOOL_ACTION selectOnPCB
static TOOL_ACTION addVariant
static TOOL_ACTION move
static TOOL_ACTION importNonKicadSchematic
static TOOL_ACTION nameNetChain
SCH_RENDER_SETTINGS * GetRenderSettings()
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
EESCHEMA_SETTINGS * eeconfig() const
COLOR_SETTINGS * GetColorSettings(bool aForceRefresh=false) const override
Returns a pointer to the active color theme settings.
Base class for a bus or wire entry.
void Collect(SCH_SCREEN *aScreen, const std::vector< KICAD_T > &aScanTypes, const VECTOR2I &aPos, int aUnit=0, int aBodyStyle=0)
Scan a EDA_ITEM using this class's Inspector method which does the collection.
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).
wxString Name(bool aIgnoreSheet=false) const
Handle actions specific to the schematic editor.
int PageSetup(const TOOL_EVENT &aEvent)
bool RescueLegacyProject(bool aRunningOnDemand)
int ToggleDirectiveLabels(const TOOL_EVENT &aEvent)
int SaveAs(const TOOL_EVENT &aEvent)
int MarkSimExclusions(const TOOL_EVENT &aEvent)
int Annotate(const TOOL_EVENT &aEvent)
int ShowSchematicSetup(const TOOL_EVENT &aEvent)
int HighlightNet(const TOOL_EVENT &aEvent)
Highlight net chain under the cursor.
int ClearHighlight(const TOOL_EVENT &aEvent)
Update net highlighting after an edit.
int FindNetInInspector(const TOOL_EVENT &aEvent)
int EditSymbolFields(const TOOL_EVENT &aEvent)
int GenerateBOMLegacy(const TOOL_EVENT &aEvent)
int RemoveFromNetChain(const TOOL_EVENT &aEvent)
Remove any net highlighting.
int HighlightNetCursor(const TOOL_EVENT &aEvent)
Replace one of a net chain's terminal pins.
int CopyAsText(const TOOL_EVENT &aEvent)
int AddVariant(const TOOL_EVENT &aEvent)
int ImportFPAssignments(const TOOL_EVENT &aEvent)
int ChangeLineMode(const TOOL_EVENT &aEvent)
void doCrossProbeSchToPcb(const TOOL_EVENT &aEvent, bool aForce)
int ExportSymbolsToLibrary(const TOOL_EVENT &aEvent)
int SaveCurrSheetCopyAs(const TOOL_EVENT &aEvent)
Saves the currently-open schematic sheet to an other name.
bool rescueProject(RESCUER &aRescuer, bool aRunningOnDemand)
int CrossProbeToPcb(const TOOL_EVENT &aEvent)
Equivalent to the above, but initiated by the user.
int CopyVariant(const TOOL_EVENT &aEvent)
int PlaceLinkedDesignBlock(const TOOL_EVENT &aEvent)
int ToggleRemoteSymbolPanel(const TOOL_EVENT &aEvent)
int RemapSymbols(const TOOL_EVENT &aEvent)
int DrawSheetOnClipboard(const TOOL_EVENT &aEvent)
SCH_SHEET_PATH updatePastedSheet(SCH_SHEET *aSheet, const SCH_SHEET_PATH &aPastePath, const KIID_PATH &aClipPath, bool aForceKeepAnnotations, SCH_SHEET_LIST *aPastedSheets, std::map< SCH_SHEET_PATH, SCH_REFERENCE_LIST > &aPastedSymbols)
int TogglePinAltIcons(const TOOL_EVENT &aEvent)
int RescueSymbols(const TOOL_EVENT &aEvent)
Perform rescue operations to recover old projects from before certain changes were made.
int AssignNetclass(const TOOL_EVENT &aEvent)
std::string m_duplicateClipboard
int ExportNetlist(const TOOL_EVENT &aEvent)
int Open(const TOOL_EVENT &aEvent)
int Paste(const TOOL_EVENT &aEvent)
int ToggleOPVoltages(const TOOL_EVENT &aEvent)
int Copy(const TOOL_EVENT &aEvent)
int SaveToLinkedDesignBlock(const TOOL_EVENT &aEvent)
int ToggleERCWarnings(const TOOL_EVENT &aEvent)
int NextLineMode(const TOOL_EVENT &aEvent)
int Redo(const TOOL_EVENT &aEvent)
Clipboard support.
int UpdatePCB(const TOOL_EVENT &aEvent)
int RemoveVariant(const TOOL_EVENT &aEvent)
int UpdateFromPCB(const TOOL_EVENT &aEvent)
int ToggleAnnotateAuto(const TOOL_EVENT &aEvent)
int EditVariantDescription(const TOOL_EVENT &aEvent)
int ToggleHiddenPins(const TOOL_EVENT &aEvent)
int Duplicate(const TOOL_EVENT &aEvent)
int IncrementAnnotations(const TOOL_EVENT &aEvent)
bool searchSupplementaryClipboard(const wxString &aSheetFilename, SCH_SCREEN **aScreen)
int GridFeedback(const TOOL_EVENT &aEvent)
int ShowSearch(const TOOL_EVENT &aEvent)
int EditWithSymbolEditor(const TOOL_EVENT &aEvent)
int ReplaceTerminalPin(const TOOL_EVENT &aEvent)
int SimTune(const TOOL_EVENT &aEvent)
Highlight net under the cursor.
int EditSymbolLibraryLinks(const TOOL_EVENT &aEvent)
int New(const TOOL_EVENT &aEvent)
int ImportNonKicadSchematic(const TOOL_EVENT &aEvent)
int ShowCreateNetChain(const TOOL_EVENT &aEvent)
std::map< wxString, SCH_SCREEN * > m_supplementaryClipboard
int ExplicitCrossProbeToPcb(const TOOL_EVENT &aEvent)
int ToggleOPCurrents(const TOOL_EVENT &aEvent)
int ShowPcbNew(const TOOL_EVENT &aEvent)
int UpdateNetHighlighting(const TOOL_EVENT &aEvent)
Launch a tool to highlight nets.
int ToggleERCErrors(const TOOL_EVENT &aEvent)
int ShowHierarchy(const TOOL_EVENT &aEvent)
int OnAngleSnapModeChanged(const TOOL_EVENT &aEvent)
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
static const LIB_SYMBOL * ChoosePasteLibSymbol(const SCH_SCREEN *aClipboardScreen, const SCH_SCREEN *aDestScreen, const wxString &aLibSymbolName)
Choose which cached library symbol a pasted instance should adopt.
int ShowNetNavigator(const TOOL_EVENT &aEvent)
int NameNetChain(const TOOL_EVENT &aEvent)
int SimProbe(const TOOL_EVENT &aEvent)
void updatePastedSymbol(SCH_SYMBOL *aSymbol, const SCH_SHEET_PATH &aPastePath, const KIID_PATH &aClipPath, bool aForceKeepAnnotations)
int ShowCvpcb(const TOOL_EVENT &aEvent)
int HighlightNetChain(const TOOL_EVENT &aEvent)
int ToggleLibraryTree(const TOOL_EVENT &aEvent)
int RenameVariant(const TOOL_EVENT &aEvent)
std::set< SCH_SYMBOL * > m_pastedSymbols
void prunePastedSymbolInstances()
Reconcile every pasted symbol's instances against the current project.
int Cut(const TOOL_EVENT &aEvent)
int ToggleProperties(const TOOL_EVENT &aEvent)
std::map< KIID_PATH, SCH_SYMBOL_INSTANCE > m_clipboardSymbolInstances
int Save(const TOOL_EVENT &aEvent)
bool RescueSymbolLibTableProject(bool aRunningOnDemand)
Notifies pcbnew about the selected item.
bool doCopy(bool aUseDuplicateClipboard=false)
< copy selection to clipboard or to m_duplicateClipboard
int Undo(const TOOL_EVENT &aEvent)
int ToggleERCExclusions(const TOOL_EVENT &aEvent)
int Plot(const TOOL_EVENT &aEvent)
int CreateNetChainBetweenPins(const TOOL_EVENT &aEvent)
int Print(const TOOL_EVENT &aEvent)
int Revert(const TOOL_EVENT &aEvent)
int GenerateBOM(const TOOL_EVENT &aEvent)
void setPastedSymbolInstances(const SCH_SCREEN *aScreen)
int ToggleHiddenFields(const TOOL_EVENT &aEvent)
Schematic editor (Eeschema) main window.
void ToggleProperties() override
SCH_DESIGN_BLOCK_PANE * GetDesignBlockPane() const
void ToggleLibraryTree() override
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void SendCrossProbeClearHighlight()
Tell Pcbnew to clear the existing highlighted net, if one exists.
SCH_SHEET_PATH & GetCurrentSheet() const
void RecalculateConnections(SCH_COMMIT *aCommit, SCH_CLEANUP_FLAGS aCleanupFlags, PROGRESS_REPORTER *aProgressReporter=nullptr)
Generate the connection data for the entire schematic hierarchy.
const SCH_ITEM * GetSelectedNetNavigatorItem() const
SCHEMATIC & Schematic() const
void ToggleSearch()
Toggle the show/hide state of Search pane.
wxString GetFullScreenDesc() const override
const wxString & GetHighlightedNetChain() const
void ToggleSchematicHierarchy()
Toggle the show/hide state of the left side schematic navigation panel.
void SendCrossProbeNetName(const wxString &aNetName)
Send a net name to Pcbnew for highlighting.
void SetHighlightedConnection(const wxString &aConnection, const NET_NAVIGATOR_ITEM_DATA *aSelection=nullptr, bool aForceNetNavigatorRefresh=false)
void SetHighlightedNetChain(const wxString &aNetChain)
const wxString & GetHighlightedConnection() const
void UpdateNetHighlightStatus()
wxString GetScreenDesc() const override
Return a human-readable description of the current screen.
void SelectNetNavigatorItem(const NET_NAVIGATOR_ITEM_DATA *aSelection=nullptr)
void SetCrossProbeConnection(const SCH_CONNECTION *aConnection)
Send a connection (net or bus) to Pcbnew for highlighting.
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:138
void SetText(const wxString &aText) override
A set of SCH_ITEMs (i.e., without duplicates).
Definition sch_group.h:48
A SCH_IO derivation for loading schematic files using the new s-expression file format.
void LoadContent(LINE_READER &aReader, SCH_SHEET *aSheet, int aVersion=SEXPR_SCHEMATIC_FILE_VERSION)
void Format(SCH_SHEET *aSheet)
static SCH_FILE_T EnumFromStr(const wxString &aFileType)
Return the #SCH_FILE_T from the corresponding plugin type name: "kicad", "legacy",...
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:162
virtual bool IsConnectable() const
Definition sch_item.h:526
void SetLocked(bool aLocked) override
Definition sch_item.h:253
const SYMBOL * GetParentSymbol() const
Definition sch_item.cpp:274
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:268
virtual void SetLastResolvedState(const SCH_ITEM *aItem)
Definition sch_item.h:618
int GetBodyStyle() const
Definition sch_item.h:244
int GetUnit() const
Definition sch_item.h:234
void SetConnectivityDirty(bool aDirty=true)
Definition sch_item.h:589
virtual void SetUnit(int aUnit)
Definition sch_item.h:233
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition sch_item.cpp:487
virtual std::vector< VECTOR2I > GetConnectionPoints() const
Add all the connection points for this item to aPoints.
Definition sch_item.h:541
bool IsType(const std::vector< KICAD_T > &aScanTypes) const override
Check whether the item is one of the listed types.
Definition sch_item.h:177
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:39
A net chain is a collection of nets that are connected together through passive components.
const wxString & GetName() const
SCH_PIN * GetLibPin() const
Definition sch_pin.h:107
const wxString & GetNumber() const
Definition sch_pin.h:142
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition sch_pin.h:276
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 SplitReferences()
Attempt to split all reference designators into a name (U) and number (1).
void AddItem(const SCH_REFERENCE &aItem)
A helper to define a symbol's reference designator in a schematic.
void SetRef(const wxString &aReference)
void Split()
Attempt to split the reference designator into a name (U) and number (1).
bool IsSplitNeeded()
Determine if this reference needs to be split or if it likely already has been.
wxString GetRef() const
void SetSheetNumber(int aSheetNumber)
wxString GetRefNumber() const
void SetBackgroundColor(const COLOR4D &aColor) override
Set the background color.
const KIGFX::COLOR4D & GetBackgroundColor() const override
Return current background color settings.
void LoadColors(const COLOR_SETTINGS *aSettings) override
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:758
SCH_SCREEN * GetNext()
void UpdateSymbolLinks(REPORTER *aReporter=nullptr)
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in the full schematic.
SCH_SCREEN * GetFirst()
void PruneOrphanedSheetInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
void PruneOrphanedSymbolInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
bool HasNoFullyDefinedLibIds()
Test all of the schematic symbols to see if all LIB_ID objects library nickname is not set.
const PAGE_INFO & GetPageSettings() const
Definition sch_screen.h:140
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void Clear(bool aFree=true)
Delete all draw items and clears the project settings.
std::set< wxString > GetSheetNames() const
const std::map< wxString, LIB_SYMBOL * > & GetLibSymbols() const
Fetch a list of unique LIB_SYMBOL object pointers required to properly render each SCH_SYMBOL in this...
Definition sch_screen.h:503
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:118
const wxString & GetFileName() const
Definition sch_screen.h:153
void UpdateSymbolLinks(REPORTER *aReporter=nullptr, LEGACY_SYMBOL_LIBS *aLegacyLibs=nullptr, SYMBOL_LIBRARY_ADAPTER *aLibraries=nullptr)
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in this schematic from the project #SYM...
SCHEMATIC * Schematic() const
TITLE_BLOCK & GetTitleBlock()
Definition sch_screen.h:164
void Plot(PLOTTER *aPlotter, const SCH_PLOT_OPTS &aPlotOpts) const
Plot all the schematic objects to aPlotter.
void MigrateSimModels()
Migrate any symbols having V6 simulation models to their V7 equivalents.
EDA_ITEM * GetNode(const VECTOR2I &aPosition)
Finds a connected item at a point (usually the cursor position).
bool SelectPoint(const VECTOR2I &aWhere, const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, EDA_ITEM **aItem=nullptr, bool *aSelectionCancelledFlag=nullptr, bool aCheckLocked=false, bool aAdd=false, bool aSubtract=false, bool aExclusiveOr=false)
Perform a click-type selection at a point (usually the cursor position).
int ClearSelection(const TOOL_EVENT &aEvent)
Select all visible items in sheet.
void GuessSelectionCandidates(SCH_COLLECTOR &collector, const VECTOR2I &aPos)
Apply heuristics to try and determine a single object when multiple are found under the cursor.
SCH_SELECTION & GetSelection()
SCH_SELECTION & RequestSelection(const std::vector< KICAD_T > &aScanTypes={ SCH_LOCATE_ANY_T }, bool aPromoteCellSelections=false, bool aPromoteGroups=false)
Return either an existing selection (filtered), or the selection at the current cursor position if th...
BOX2I GetBoundingBox() const override
VECTOR2I GetCenter() const
Definition sch_shape.h:94
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void FillItemMap(std::map< KIID, EDA_ITEM * > &aMap)
Fill an item cache for temporary use when many items need to be fetched.
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.
int GetLastVirtualPageNumber() const
bool PageNumberExists(const wxString &aPageNumber) const
bool ContainsSheet(const SCH_SHEET *aSheet) const
bool HasPath(const KIID_PATH &aPath) 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.
bool TestForRecursion(const SCH_SHEET_LIST &aSrcSheetHierarchy, const wxString &aDestFileName)
Test every SCH_SHEET_PATH in this SCH_SHEET_LIST to verify if adding the sheets stored in aSrcSheetHi...
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
bool IsSharedPath() const
Determine if this sheet path is shared in a complex hierarchy.
void GetSymbols(SCH_REFERENCE_LIST &aReferences, SYMBOL_FILTER aSymbolFilter, bool aForceIncludeOrphanSymbols=false) const
Adds SCH_REFERENCE object to aReferences for each symbol in the sheet.
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
SCH_SCREEN * LastScreen()
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
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:384
void RemoveInstance(const KIID_PATH &aInstancePath)
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
void AddInstance(const SCH_SHEET_INSTANCE &aInstance)
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:145
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition sch_sheet.h:241
const std::vector< SCH_SHEET_INSTANCE > & GetInstances() const
Definition sch_sheet.h:519
Schematic symbol object.
Definition sch_symbol.h:75
PASSTHROUGH_MODE GetPassthroughMode() const
Definition sch_symbol.h:893
EMBEDDED_FILES * GetEmbeddedFiles() override
SCH_SYMBOLs don't currently support embedded files, but their LIB_SYMBOL counterparts do.
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:134
wxString GetSchSymbolLibraryName() const
std::vector< const SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
void ClearAnnotation(const SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear exiting symbol annotation.
void AddHierarchicalReference(const KIID_PATH &aPath, const wxString &aRef, int aUnit)
Add a full hierarchical reference to this symbol.
bool IsMissingLibSymbol() const
Check to see if the library symbol is set to the dummy library symbol.
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:164
void SetPassthroughMode(PASSTHROUGH_MODE aMode)
Definition sch_symbol.h:894
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:183
void SetLibSymbol(LIB_SYMBOL *aLibSymbol)
Set this schematic symbol library symbol reference to aLibSymbol.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
bool IsPower() const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
void BrightenItem(EDA_ITEM *aItem)
void UnbrightenItem(EDA_ITEM *aItem)
virtual void Add(EDA_ITEM *aItem)
A null aItem is ignored; the selection never holds null members.
Definition selection.cpp:38
const std::deque< EDA_ITEM * > GetItems() const
Definition selection.h:125
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition selection.h:104
EDA_ITEM * Front() const
Definition selection.h:176
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the index-th vertex in a given hole outline within a given outline.
The SIMULATOR_FRAME holds the main user-interface for running simulations.
void AddCurrentTrace(const wxString &aDeviceName)
Add a current trace for a given device to the current plot.
void AddVoltageTrace(const wxString &aNetName)
Add a voltage trace for a given net to the current plot.
SIM_MODEL & CreateModel(SIM_MODEL::TYPE aType, const std::vector< SCH_PIN * > &aPins, REPORTER &aReporter)
void SetFilesStack(std::vector< EMBEDDED_FILES * > aFilesStack)
Definition sim_lib_mgr.h:44
Implement an OUTPUTFORMATTER to a memory buffer.
Definition richio.h:430
const std::string & GetString()
Definition richio.h:453
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition richio.h:225
The symbol library editor main window.
bool IsLibraryTreeShown() const override
void LoadSymbol(const wxString &aLibrary, const wxString &aSymbol, int Unit)
void LoadSymbolFromSchematic(SCH_SYMBOL *aSymbol)
Load a symbol from the schematic to edit in place.
void ToggleLibraryTree() override
An interface to the global shared library manager that is schematic-specific and linked to one projec...
Class to handle modifications to the symbol libraries.
Symbol library viewer main window.
virtual const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const =0
SCH_EDIT_FRAME * getEditFrame() const
Definition tool_base.h:182
KIGFX::VIEW_CONTROLS * getViewControls() const
Definition tool_base.cpp:40
KIGFX::VIEW * getView() const
Definition tool_base.cpp:34
Generic, UI-independent tool event.
Definition tool_event.h:167
bool DisableGridSnapping() const
Definition tool_event.h:367
bool IsAction(const TOOL_ACTION *aAction) const
Test if the event contains an action issued upon activation of the given TOOL_ACTION.
T Parameter() const
Return a parameter assigned to the event.
Definition tool_event.h:469
void Go(int(SCH_EDIT_FRAME::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Master controller class:
TOOLS_HOLDER * GetToolHolder() const
A wrapper for reporting to a wxString object.
Definition reporter.h:242
std::unique_ptr< wxBitmap > GetImageFromClipboard()
Get image data from the clipboard, if there is any.
bool EncodeImageToPng(const wxImage &aImage, wxMemoryBuffer &aOutput)
Encode an image to PNG format with fast compression settings optimized for clipboard use.
bool AddTransparentImageToClipboardData(wxDataObjectComposite *aData, wxImage aImage)
Adds an image to clipboard data in a platform-specific way such that transparency is supported.
bool SaveClipboard(const std::string &aTextUTF8)
Store information to the system clipboard.
Definition clipboard.cpp:32
std::string GetClipboardUTF8()
Return the information currently stored in the system clipboard.
bool AddPngToClipboardData(wxDataObjectComposite *aData, const wxMemoryBuffer &aPngData, const wxImage *aFallbackImage)
Adds pre-encoded PNG data to clipboard in a platform-specific way.
wxString EnsureFileExtension(const wxString &aFilename, const wxString &aExtension)
It's annoying to throw up nag dialogs when the extension isn't right.
Definition common.cpp:848
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:274
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:245
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:192
This file is part of the common library.
@ VOLTAGE_PROBE
Definition cursors.h:56
@ CURRENT_PROBE
Definition cursors.h:58
@ BULLSEYE
Definition cursors.h:54
int InvokeDialogCreateBOM(SCH_EDIT_FRAME *aCaller)
Create and show DIALOG_BOM and return whatever DIALOG_BOM::ShowModal() returns.
bool InvokeDialogEditSymbolsLibId(SCH_EDIT_FRAME *aCaller)
Run a dialog to modify the LIB_ID of symbols for instance when a symbol has moved from a symbol libra...
int InvokeDialogNetList(SCH_EDIT_FRAME *aCaller)
bool equivalent(SIM_MODEL::DEVICE_T a, SIM_MODEL::DEVICE_T b)
#define _(s)
@ RECURSE
Definition eda_item.h:51
@ NO_RECURSE
Definition eda_item.h:52
#define IS_PASTED
Modifier on IS_NEW which indicates it came from clipboard.
#define IS_NEW
New item, just created.
#define ENDPOINT
ends. (Used to support dragging.)
#define IS_MOVING
Item being moved.
#define STARTPOINT
When a line is selected, these flags indicate which.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
@ LINE_MODE_90
@ LINE_MODE_45
@ LINE_MODE_FREE
@ LINE_MODE_COUNT
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:31
@ FRAME_SCH_VIEWER
Definition frame_type.h:32
@ FRAME_SIMULATOR
Definition frame_type.h:34
static const std::string KiCadSchematicFileExtension
static wxString KiCadSchematicFileWildcard()
static const wxChar traceSchPaste[]
Flag to enable schematic paste debugging output.
#define NET_PLUGIN_CHANGE
Create and shows DIALOG_EXPORT_NETLIST and returns whatever DIALOG_EXPORT_NETLIST::ShowModal() return...
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
bool LoadFileToMemory(const wxString &aFileName, wxMemoryBuffer &aBuffer)
Load the contents of a file into a memory buffer.
#define KICTL_REVERT
reverting to a previously-saved (KiCad) file.
@ LAYER_DRAWINGSHEET
Sheet frame and title block.
Definition layer_ids.h:274
@ LAYER_ERC_WARN
Definition layer_ids.h:501
@ LAYER_ERC_ERR
Definition layer_ids.h:502
@ LAYER_SCHEMATIC_DRAWINGSHEET
Definition layer_ids.h:518
@ LAYER_OP_CURRENTS
Definition layer_ids.h:524
@ LAYER_SCHEMATIC_PAGE_LIMITS
Definition layer_ids.h:519
@ LAYER_OP_VOLTAGES
Definition layer_ids.h:523
void Prettify(std::string &aSource, FORMAT_MODE aMode)
Pretty-prints s-expression text according to KiCad format rules.
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:54
@ GEOMETRY
Position or shape has changed.
Definition view_item.h:51
@ TARGET_NONCACHED
Auxiliary rendering target (noncached)
Definition definitions.h:34
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:521
void encode(const std::vector< uint8_t > &aInput, std::vector< uint8_t > &aOutput)
Definition base64.cpp:76
#define MAX_PAGE_SIZE_EESCHEMA_MILS
Definition page_info.h:32
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
Plotting engines similar to ps (PostScript, Gerber, svg)
static bool highlightNet(TOOL_MANAGER *aToolMgr, const VECTOR2D &aPosition)
#define HITTEST_THRESHOLD_PIXELS
static VECTOR2D CLEAR
Class to handle a set of SCH_ITEMs.
std::vector< EDA_ITEM * > EDA_ITEMS
ANNOTATE_ORDER_T
Schematic annotation order options.
ANNOTATE_ALGO_T
Schematic annotation type options.
@ SYMBOL_FILTER_NON_POWER
@ SYMBOL_FILTER_ALL
wxString UniqueGroupName(SCH_SCREEN *aScreen, const wxString &aBaseName)
Return aBaseName, or aBaseName + smallest free integer if a group with that name already exists on aS...
wxString GetSelectedItemsAsText(const SELECTION &aSel)
void PrunePastedSymbolInstances(SCH_SYMBOL *aSymbol, const SCHEMATIC &aSchematic)
Discard the instance data a paste dragged in from somewhere else, keyed by path rather than project n...
std::vector< SCH_ITEM * > FlattenGroups(const EDA_ITEMS &aItems)
Return the given items with the members of any group added, recursively.
constexpr double SCH_WORLD_UNIT(1e-7/0.0254)
@ LOCAL_CLEANUP
Definition schematic.h:92
@ NO_CLEANUP
Definition schematic.h:91
@ GLOBAL_CLEANUP
Definition schematic.h:93
const int scale
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
wxString From_UTF8(const char *cstring)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Optional context derived from the user selection that opened the dialog.
wxString toRef
Second selected symbol reference, if any.
wxString fromRef
Selected symbol reference (or first of two)
wxString netName
Net name from a selected pin or wire/bus.
std::vector< GRID > grids
Common grid settings, available to every frame.
A simple container for sheet instance information.
A simple container for schematic symbol instance information.
static constexpr auto NOT_CONNECTED
Definition sim_model.h:70
std::string refName
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
std::string path
IbisParser parser & reporter
KIBIS_MODEL * model
KIBIS_PIN * pin
KIBIS_PIN * pinA
const SHAPE_LINE_CHAIN chain
wxString result
Test unit parsing edge cases and error handling.
@ AS_GLOBAL
Global action (toolbar/main menu event, global shortcut)
Definition tool_action.h:45
@ TA_UNDO_REDO_PRE
This event is sent before undo/redo command is performed.
Definition tool_event.h:102
@ TC_MESSAGE
Definition tool_event.h:54
@ SCH_GROUP_T
Definition typeinfo.h:169
@ SCH_TABLE_T
Definition typeinfo.h:161
@ SCH_LINE_T
Definition typeinfo.h:159
@ SCH_SYMBOL_T
Definition typeinfo.h:168
@ SCH_TABLECELL_T
Definition typeinfo.h:162
@ SCH_FIELD_T
Definition typeinfo.h:146
@ SCH_SHEET_T
Definition typeinfo.h:171
@ SCH_MARKER_T
Definition typeinfo.h:154
@ SCH_SHAPE_T
Definition typeinfo.h:145
@ SCH_PIN_T
Definition typeinfo.h:149
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition wx_filename.h:35
#define ZOOM_MIN_LIMIT_EESCHEMA
#define ZOOM_MAX_LIMIT_EESCHEMA