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