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{
2474 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wxWindow::FindFocus() );
2475
2476 if( textEntry )
2477 {
2478 textEntry->Paste();
2479 return 0;
2480 }
2481
2482 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
2483 std::string content;
2484 VECTOR2I eventPos;
2485
2486 SCH_SHEET tempSheet;
2487
2488 // Priority for paste:
2489 // 1. application/kicad format (handled by GetClipboardUTF8 which checks this first)
2490 // 2. Text data that can be parsed as KiCad S-expressions
2491 // 3. Bitmap/image data (fallback only if no valid text content)
2492 if( aEvent.IsAction( &ACTIONS::duplicate ) )
2493 content = m_duplicateClipboard;
2494 else
2495 content = GetClipboardUTF8();
2496
2497 // Only fall back to image data if there's no text content
2498 if( content.empty() )
2499 {
2500 std::unique_ptr<wxBitmap> clipImg = GetImageFromClipboard();
2501
2502 if( clipImg )
2503 {
2504 auto bitmap = std::make_unique<SCH_BITMAP>();
2505
2506 if( bitmap->GetReferenceImage().SetImage( clipImg->ConvertToImage() ) )
2507 return m_toolMgr->RunAction( SCH_ACTIONS::placeImage, bitmap.release() );
2508 }
2509
2510 return 0;
2511 }
2512
2513 if( aEvent.IsAction( &ACTIONS::duplicate ) )
2514 eventPos = getViewControls()->GetCursorPosition( false );
2515
2516 STRING_LINE_READER reader( content, "Clipboard" );
2517 SCH_IO_KICAD_SEXPR plugin;
2518
2519 // Screen object on heap is owned by the sheet.
2520 SCH_SCREEN* tempScreen = new SCH_SCREEN( &m_frame->Schematic() );
2521 tempSheet.SetScreen( tempScreen );
2522
2523 try
2524 {
2525 plugin.LoadContent( reader, &tempSheet );
2526 }
2527 catch( IO_ERROR& )
2528 {
2529 // If it wasn't schematic content, paste as a text object
2530 {
2531 if( content.size() > static_cast<size_t>( ADVANCED_CFG::GetCfg().m_MaxPastedTextLength ) )
2532 {
2533 int result = IsOK( m_frame, _( "Pasting a long text text string may be very slow. "
2534 "Do you want to continue?" ) );
2535 if( !result )
2536 return 0;
2537 }
2538
2539 SCH_TEXT* text_item = new SCH_TEXT( VECTOR2I( 0, 0 ), content );
2540 tempScreen->Append( text_item );
2541 }
2542 }
2543
2544 SELECTION& currentSelection = selTool->GetSelection();
2545
2546 bool hasTableCells = false;
2547
2548 for( EDA_ITEM* item : currentSelection )
2549 {
2550 if( item->Type() == SCH_TABLECELL_T )
2551 {
2552 hasTableCells = true;
2553 break;
2554 }
2555 }
2556
2557 if( hasTableCells )
2558 {
2559 SCH_TABLE* clipboardTable = nullptr;
2560
2561 for( SCH_ITEM* item : tempScreen->Items() )
2562 {
2563 if( item->Type() == SCH_TABLE_T )
2564 {
2565 clipboardTable = static_cast<SCH_TABLE*>( item );
2566 break;
2567 }
2568 }
2569
2570 if( clipboardTable )
2571 {
2572 SCH_EDIT_TABLE_TOOL* tableEditTool = m_toolMgr->GetTool<SCH_EDIT_TABLE_TOOL>();
2573
2574 if( tableEditTool )
2575 {
2576 wxString errorMsg;
2577
2578 if( !tableEditTool->validatePasteIntoSelection( currentSelection, errorMsg ) )
2579 {
2580 DisplayError( m_frame, errorMsg );
2581 return 0;
2582 }
2583
2584 SCH_COMMIT commit( m_toolMgr );
2585
2586 if( tableEditTool->pasteCellsIntoSelection( currentSelection, clipboardTable, commit ) )
2587 {
2588 commit.Push( _( "Paste Cells" ) );
2589 return 0;
2590 }
2591 else
2592 {
2593 DisplayError( m_frame, _( "Failed to paste cells" ) );
2594 return 0;
2595 }
2596 }
2597 }
2598 }
2599
2600 m_pastedSymbols.clear();
2602
2603 // Save pasted symbol instances in case the user chooses to keep existing symbol annotation.
2604 setPastedSymbolInstances( tempScreen );
2605
2606 tempScreen->MigrateSimModels();
2607
2608 bool annotateAutomatic = m_frame->eeconfig()->m_AnnotatePanel.automatic;
2609 SCHEMATIC_SETTINGS& schematicSettings = m_frame->Schematic().Settings();
2610 int annotateStartNum = schematicSettings.m_AnnotateStartNum;
2611
2613 bool forceRemoveAnnotations = false;
2614
2615 if( aEvent.IsAction( &ACTIONS::pasteSpecial ) )
2616 {
2617 PASTE_MODE defaultPasteMode = pasteMode;
2618 DIALOG_PASTE_SPECIAL dlg( m_frame, &pasteMode );
2619
2620 if( dlg.ShowModal() == wxID_CANCEL )
2621 return 0;
2622
2623 // We have to distinguish if removing was explicit
2624 forceRemoveAnnotations = pasteMode == PASTE_MODE::REMOVE_ANNOTATIONS && pasteMode != defaultPasteMode;
2625 }
2626
2627 bool forceKeepAnnotations = pasteMode != PASTE_MODE::REMOVE_ANNOTATIONS;
2628
2629 // SCH_SEXP_PLUGIN added the items to the paste screen, but not to the view or anything
2630 // else. Pull them back out to start with.
2631 SCH_COMMIT commit( m_toolMgr );
2632 EDA_ITEMS loadedItems;
2633 std::vector<SCH_ITEM*> sortedLoadedItems;
2634 bool sheetsPasted = false;
2635 SCH_SHEET_LIST hierarchy = m_frame->Schematic().Hierarchy();
2636 SCH_SHEET_PATH& pasteRoot = m_frame->GetCurrentSheet();
2637 wxFileName destFn = pasteRoot.Last()->GetFileName();
2638
2639 if( destFn.IsRelative() )
2640 destFn.MakeAbsolute( m_frame->Prj().GetProjectPath() );
2641
2642 // List of paths in the hierarchy that refer to the destination sheet of the paste
2643 SCH_SHEET_LIST sheetPathsForScreen = hierarchy.FindAllSheetsForScreen( pasteRoot.LastScreen() );
2644 sheetPathsForScreen.SortByPageNumbers();
2645
2646 // Build a list of screens from the current design (to avoid loading sheets that already exist)
2647 std::map<wxString, SCH_SCREEN*> loadedScreens;
2648
2649 for( const SCH_SHEET_PATH& item : hierarchy )
2650 {
2651 if( item.LastScreen() )
2652 loadedScreens[item.Last()->GetFileName()] = item.LastScreen();
2653 }
2654
2655 // Get set of sheet names in the current schematic to prevent duplicate sheet names on paste.
2656 std::set<wxString> existingSheetNames = pasteRoot.LastScreen()->GetSheetNames();
2657
2658 // Build symbol list for reannotation of duplicates
2659 SCH_REFERENCE_LIST existingRefs;
2660 hierarchy.GetSymbols( existingRefs, SYMBOL_FILTER_ALL );
2661 existingRefs.SortByReferenceOnly();
2662
2663 std::set<wxString> existingRefsSet;
2664
2665 for( const SCH_REFERENCE& ref : existingRefs )
2666 existingRefsSet.insert( ref.GetRef() );
2667
2668 // Build UUID map for fetching last-resolved-properties
2669 std::map<KIID, EDA_ITEM*> itemMap;
2670 hierarchy.FillItemMap( itemMap );
2671
2672 // Keep track of pasted sheets and symbols for the different paths to the hierarchy.
2673 std::map<SCH_SHEET_PATH, SCH_REFERENCE_LIST> pastedSymbols;
2674 std::map<SCH_SHEET_PATH, SCH_SHEET_LIST> pastedSheets;
2675
2676 for( SCH_ITEM* item : tempScreen->Items() )
2677 {
2678 if( item->Type() == SCH_SHEET_T )
2679 sortedLoadedItems.push_back( item );
2680 else
2681 loadedItems.push_back( item );
2682 }
2683
2684 sort( sortedLoadedItems.begin(), sortedLoadedItems.end(),
2685 []( SCH_ITEM* firstItem, SCH_ITEM* secondItem )
2686 {
2687 SCH_SHEET* firstSheet = static_cast<SCH_SHEET*>( firstItem );
2688 SCH_SHEET* secondSheet = static_cast<SCH_SHEET*>( secondItem );
2689 return StrNumCmp( firstSheet->GetName(), secondSheet->GetName(), false ) < 0;
2690 } );
2691
2692
2693 for( SCH_ITEM* item : sortedLoadedItems )
2694 {
2695 loadedItems.push_back( item );
2696
2697 if( item->Type() == SCH_SHEET_T )
2698 {
2699 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
2700 wxFileName srcFn = sheet->GetFileName();
2701
2702 if( srcFn.IsRelative() )
2703 srcFn.MakeAbsolute( m_frame->Prj().GetProjectPath() );
2704
2705 SCH_SHEET_LIST sheetHierarchy( sheet );
2706
2707 if( hierarchy.TestForRecursion( sheetHierarchy, destFn.GetFullPath( wxPATH_UNIX ) ) )
2708 {
2709 auto msg = wxString::Format( _( "The pasted sheet '%s'\n"
2710 "was dropped because the destination already has "
2711 "the sheet or one of its subsheets as a parent." ),
2712 sheet->GetFileName() );
2713 DisplayError( m_frame, msg );
2714 loadedItems.pop_back();
2715 }
2716 }
2717 }
2718
2719 // Remove the references from our temporary screen to prevent freeing on the DTOR
2720 tempScreen->Clear( false );
2721
2722 for( EDA_ITEM* item : loadedItems )
2723 {
2724 KIID_PATH clipPath( wxT( "/" ) ); // clipboard is at root
2725
2726 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item );
2727
2728 wxCHECK2( schItem, continue );
2729
2730 if( schItem->IsConnectable() )
2731 schItem->SetConnectivityDirty();
2732
2733 // Clear lock state on paste to match PCB editor behavior
2734 schItem->SetLocked( false );
2735
2736 if( item->Type() == SCH_SYMBOL_T )
2737 {
2738 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2739
2740 // The library symbol gets set from the cached library symbols in the current
2741 // schematic not the symbol libraries. The cached library symbol may have
2742 // changed from the original library symbol which would cause the copy to
2743 // be incorrect.
2744 SCH_SCREEN* currentScreen = m_frame->GetScreen();
2745
2746 wxCHECK2( currentScreen, continue );
2747
2748 // First get the library symbol from the clipboard (if available)
2749 auto clipIt = tempScreen->GetLibSymbols().find( symbol->GetSchSymbolLibraryName() );
2750 LIB_SYMBOL* clipLibSymbol = ( clipIt != tempScreen->GetLibSymbols().end() )
2751 ? clipIt->second
2752 : nullptr;
2753
2754 // Then check the current screen
2755 auto it = currentScreen->GetLibSymbols().find( symbol->GetSchSymbolLibraryName() );
2756 auto end = currentScreen->GetLibSymbols().end();
2757
2758 LIB_SYMBOL* libSymbol = nullptr;
2759
2760 if( it != end && clipLibSymbol )
2761 {
2762 // Both exist - check if power types match. If they differ (e.g., one is
2763 // local power and the other is global power), use the clipboard version
2764 // to preserve the copied symbol's power type.
2765 if( clipLibSymbol->IsLocalPower() != it->second->IsLocalPower()
2766 || clipLibSymbol->IsGlobalPower() != it->second->IsGlobalPower() )
2767 {
2768 libSymbol = new LIB_SYMBOL( *clipLibSymbol );
2769 }
2770 else
2771 {
2772 libSymbol = new LIB_SYMBOL( *it->second );
2773 }
2774 }
2775 else if( it != end )
2776 {
2777 libSymbol = new LIB_SYMBOL( *it->second );
2778 }
2779 else if( clipLibSymbol )
2780 {
2781 libSymbol = new LIB_SYMBOL( *clipLibSymbol );
2782 }
2783
2784 if( libSymbol )
2785 symbol->SetLibSymbol( libSymbol );
2786
2787 // If the symbol is already in the schematic we have to always keep the annotations. The exception
2788 // is if the user has chosen to remove them.
2789 for( const SCH_SYMBOL_INSTANCE& instance : symbol->GetInstances() )
2790 {
2791 if( !existingRefsSet.contains( instance.m_Reference ) )
2792 {
2793 forceKeepAnnotations = !forceRemoveAnnotations;
2794 break;
2795 }
2796 }
2797
2798 for( SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
2799 updatePastedSymbol( symbol, sheetPath, clipPath, forceKeepAnnotations );
2800
2801 // Most modes will need new KIIDs for the symbol and its pins. However, if we are pasting
2802 // unique annotations, we need to check if the symbol is not already in the hierarchy. If we
2803 // don't already have a copy of the symbol, we just keep the existing KIID data as it is likely
2804 // the same symbol being moved around the schematic.
2805 bool needsNewKiid = ( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS );
2806
2807 for( const SCH_SYMBOL_INSTANCE& instance : symbol->GetInstances() )
2808 {
2809 if( existingRefsSet.contains( instance.m_Reference ) )
2810 {
2811 needsNewKiid = true;
2812 break;
2813 }
2814 }
2815
2816 if( needsNewKiid )
2817 {
2818 // Assign a new KIID
2819 const_cast<KIID&>( item->m_Uuid ) = KIID();
2820
2821 // Make sure pins get a new UUID
2822 for( SCH_PIN* pin : symbol->GetPins() )
2823 {
2824 const_cast<KIID&>( pin->m_Uuid ) = KIID();
2825 pin->SetConnectivityDirty();
2826 }
2827
2828 for( SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
2829 {
2830 // Ignore symbols from a non-existant library.
2831 if( libSymbol )
2832 {
2833 SCH_REFERENCE schReference( symbol, sheetPath );
2834 schReference.SetSheetNumber( sheetPath.GetPageNumberAsInt() );
2835 pastedSymbols[sheetPath].AddItem( schReference );
2836 }
2837 }
2838 }
2839 }
2840 else if( item->Type() == SCH_SHEET_T )
2841 {
2842 SCH_SHEET* sheet = (SCH_SHEET*) item;
2843 SCH_FIELD* nameField = sheet->GetField( FIELD_T::SHEET_NAME );
2844 wxString baseName = nameField->GetText();
2845 wxString candidateName = baseName;
2846 wxString number;
2847
2848 while( !baseName.IsEmpty() && wxIsdigit( baseName.Last() ) )
2849 {
2850 number = baseName.Last() + number;
2851 baseName.RemoveLast();
2852 }
2853
2854 // Update hierarchy to include any other sheets we already added, avoiding
2855 // duplicate sheet names
2856 hierarchy = m_frame->Schematic().Hierarchy();
2857
2858 int uniquifier = std::max( 0, wxAtoi( number ) ) + 1;
2859
2860 while( existingSheetNames.count( candidateName ) )
2861 candidateName = wxString::Format( wxT( "%s%d" ), baseName, uniquifier++ );
2862
2863 nameField->SetText( candidateName );
2864 existingSheetNames.emplace( candidateName );
2865
2866 wxFileName fn = sheet->GetFileName();
2867 SCH_SCREEN* existingScreen = nullptr;
2868
2869 sheet->SetParent( pasteRoot.Last() );
2870 sheet->SetScreen( nullptr );
2871
2872 if( !fn.IsAbsolute() )
2873 {
2874 wxFileName currentSheetFileName = pasteRoot.LastScreen()->GetFileName();
2875 fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS, currentSheetFileName.GetPath() );
2876 }
2877
2878 // Try to find the screen for the pasted sheet by several means
2879 if( !m_frame->Schematic().Root().SearchHierarchy( fn.GetFullPath( wxPATH_UNIX ), &existingScreen ) )
2880 {
2881 if( loadedScreens.count( sheet->GetFileName() ) > 0 )
2882 existingScreen = loadedScreens.at( sheet->GetFileName() );
2883 else
2884 searchSupplementaryClipboard( sheet->GetFileName(), &existingScreen );
2885 }
2886
2887 if( existingScreen )
2888 {
2889 sheet->SetScreen( existingScreen );
2890 }
2891 else
2892 {
2893 if( !m_frame->LoadSheetFromFile( sheet, &pasteRoot, fn.GetFullPath() ) )
2894 m_frame->InitSheet( sheet, sheet->GetFileName() );
2895 }
2896
2897 // Save the symbol instances in case the user chooses to keep the existing
2898 // symbol annotation.
2900 sheetsPasted = true;
2901
2902 // Push it to the clipboard path while it still has its old KIID
2903 clipPath.push_back( sheet->m_Uuid );
2904
2905 // Assign a new KIID to the pasted sheet
2906 const_cast<KIID&>( sheet->m_Uuid ) = KIID();
2907
2908 // Make sure pins get a new UUID
2909 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
2910 {
2911 const_cast<KIID&>( pin->m_Uuid ) = KIID();
2912 pin->SetConnectivityDirty();
2913 }
2914
2915 // Once we have our new KIID we can update all pasted instances. This will either
2916 // reset the annotations or copy "kept" annotations from the supplementary clipboard.
2917 for( SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
2918 {
2919 SCH_SHEET_PATH subPath = updatePastedSheet( sheet, sheetPath, clipPath,
2920 ( forceKeepAnnotations && annotateAutomatic ),
2921 &pastedSheets[sheetPath], pastedSymbols );
2922 }
2923 }
2924 else
2925 {
2926 SCH_ITEM* srcItem = dynamic_cast<SCH_ITEM*>( itemMap[item->m_Uuid] );
2927 SCH_ITEM* destItem = dynamic_cast<SCH_ITEM*>( item );
2928
2929 // Everything gets a new KIID
2930 const_cast<KIID&>( item->m_Uuid ) = KIID();
2931
2932 if( srcItem && destItem )
2933 {
2934 destItem->SetConnectivityDirty( true );
2935 destItem->SetLastResolvedState( srcItem );
2936 }
2937 }
2938
2939 // Lines need both ends selected for a move after paste so the whole line moves.
2940 if( item->Type() == SCH_LINE_T )
2941 item->SetFlags( STARTPOINT | ENDPOINT );
2942
2943 item->SetFlags( IS_NEW | IS_PASTED | IS_MOVING );
2944
2945 if( !m_frame->GetScreen()->CheckIfOnDrawList( (SCH_ITEM*) item ) ) // don't want a loop!
2946 m_frame->AddToScreen( item, m_frame->GetScreen() );
2947
2948 commit.Added( (SCH_ITEM*) item, m_frame->GetScreen() );
2949
2950 // Start out hidden so the pasted items aren't "ghosted" in their original location
2951 // before being moved to the current location.
2952 getView()->Hide( item, true );
2953 }
2954
2955 if( sheetsPasted )
2956 {
2957 // The full schematic hierarchy need to be update before assigning new annotation and page numbers.
2958 m_frame->Schematic().RefreshHierarchy();
2959
2960 // Update sheet instance page and virtual page numbers to ensure annotation works correctly.
2961 for( SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
2962 {
2963 for( SCH_SHEET_PATH& pastedSheet : pastedSheets[sheetPath] )
2964 {
2965 // Find next free string page number for the sheet instance.
2966 int page = 1;
2967 wxString pageNum = wxString::Format( "%d", page );
2968
2969 while( hierarchy.PageNumberExists( pageNum ) )
2970 pageNum = wxString::Format( "%d", ++page );
2971
2972 int virtualPageNumber = page;
2973
2974 // The virtual page and sheet instance page numbers do not necessarily track. Increment by one
2975 // to ensure the annotation sheet paths all have unique virtual page numbers.
2976 if( page == hierarchy.GetLastVirtualPageNumber() )
2977 virtualPageNumber = hierarchy.GetLastVirtualPageNumber() + 1;
2978
2979 pastedSheet.SetVirtualPageNumber( virtualPageNumber );
2980
2981 SCH_SHEET_INSTANCE sheetInstance;
2982
2983 sheetInstance.m_Path = pastedSheet.Path();
2984
2985 // Don't include the actual sheet in the instance path.
2986 sheetInstance.m_Path.pop_back();
2987 sheetInstance.m_PageNumber = pageNum;
2988 sheetInstance.m_ProjectName = m_frame->Prj().GetProjectName();
2989
2990 SCH_SHEET* sheet = pastedSheet.Last();
2991
2992 wxCHECK2( sheet, continue );
2993
2994 sheet->AddInstance( sheetInstance );
2995 hierarchy.push_back( pastedSheet );
2996
2997 // Remove all pasted sheet instance data that is not part of the current project.
2998 std::vector<KIID_PATH> instancesToRemove;
2999
3000 for( const SCH_SHEET_INSTANCE& instance : sheet->GetInstances() )
3001 {
3002 if( !hierarchy.HasPath( instance.m_Path ) )
3003 instancesToRemove.push_back( instance.m_Path );
3004 }
3005
3006 for( const KIID_PATH& instancePath : instancesToRemove )
3007 sheet->RemoveInstance( instancePath );
3008
3009 // The sheet paths for the annotation code where copied in updatePastedSheets() when the virtual
3010 // page number was still 1. Set the virtual page number in the copied sheet paths.
3011 for( auto&[path, refs] : pastedSymbols )
3012 {
3013 for( SCH_REFERENCE& ref : refs )
3014 {
3015 if( ref.GetSheetPath() == pastedSheet )
3016 {
3017 ref.GetSheetPath().SetVirtualPageNumber( virtualPageNumber );
3018 ref.SetSheetNumber( virtualPageNumber );
3019 }
3020 }
3021 }
3022 }
3023 }
3024
3025 m_frame->SetSheetNumberAndCount();
3026
3027 // Get a version with correct sheet numbers since we've pasted sheets,
3028 // we'll need this when annotating next
3029 hierarchy = m_frame->Schematic().Hierarchy();
3030 }
3031
3032 std::map<SCH_SHEET_PATH, SCH_REFERENCE_LIST> annotatedSymbols;
3033
3034 // Update the list of symbol instances that satisfy the annotation criteria.
3035 for( const SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
3036 {
3037 for( size_t i = 0; i < pastedSymbols[sheetPath].GetCount(); i++ )
3038 {
3039 if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS || pastedSymbols[sheetPath][i].AlwaysAnnotate() )
3040 annotatedSymbols[sheetPath].AddItem( pastedSymbols[sheetPath][i] );
3041 }
3042
3043 for( const SCH_SHEET_PATH& pastedSheetPath : pastedSheets[sheetPath] )
3044 {
3045 for( size_t i = 0; i < pastedSymbols[pastedSheetPath].GetCount(); i++ )
3046 {
3047 if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS || pastedSymbols[pastedSheetPath][i].AlwaysAnnotate() )
3048 annotatedSymbols[pastedSheetPath].AddItem( pastedSymbols[pastedSheetPath][i] );
3049 }
3050 }
3051 }
3052
3053 if( !annotatedSymbols.empty() )
3054 {
3055 ANNOTATE_ORDER_T annotateOrder = static_cast<ANNOTATE_ORDER_T>( schematicSettings.m_AnnotateSortOrder );
3056 ANNOTATE_ALGO_T annotateAlgo = static_cast<ANNOTATE_ALGO_T>( schematicSettings.m_AnnotateMethod );
3057
3058 for( SCH_SHEET_PATH& path : sheetPathsForScreen )
3059 {
3060 annotatedSymbols[path].SortByReferenceOnly();
3061 annotatedSymbols[path].SetRefDesTracker( schematicSettings.m_refDesTracker );
3062
3063 if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS )
3064 {
3065 annotatedSymbols[path].ReannotateDuplicates( existingRefs, annotateAlgo );
3066 }
3067 else
3068 {
3069 annotatedSymbols[path].ReannotateByOptions( annotateOrder, annotateAlgo, annotateStartNum,
3070 existingRefs, false, &hierarchy );
3071 }
3072
3073 annotatedSymbols[path].UpdateAnnotation();
3074
3075 // Update existing refs for next iteration
3076 for( size_t i = 0; i < annotatedSymbols[path].GetCount(); i++ )
3077 existingRefs.AddItem( annotatedSymbols[path][i] );
3078
3079 for( const SCH_SHEET_PATH& pastedSheetPath : pastedSheets[path] )
3080 {
3081 annotatedSymbols[pastedSheetPath].SortByReferenceOnly();
3082 annotatedSymbols[pastedSheetPath].SetRefDesTracker( schematicSettings.m_refDesTracker );
3083
3084 if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS )
3085 {
3086 annotatedSymbols[pastedSheetPath].ReannotateDuplicates( existingRefs, annotateAlgo );
3087 }
3088 else
3089 {
3090 annotatedSymbols[pastedSheetPath].ReannotateByOptions( annotateOrder, annotateAlgo,
3091 annotateStartNum, existingRefs,
3092 false, &hierarchy );
3093 }
3094
3095 annotatedSymbols[pastedSheetPath].UpdateAnnotation();
3096
3097 // Update existing refs for next iteration
3098 for( size_t i = 0; i < annotatedSymbols[pastedSheetPath].GetCount(); i++ )
3099 existingRefs.AddItem( annotatedSymbols[pastedSheetPath][i] );
3100 }
3101 }
3102 }
3103
3104 m_frame->GetCurrentSheet().UpdateAllScreenReferences();
3105
3106 // The copy operation creates instance paths that are not valid for the current project or
3107 // saved as part of another project. Prune them now so they do not accumulate in the saved
3108 // schematic file.
3110
3111 SCH_SHEET_LIST sheets = m_frame->Schematic().Hierarchy();
3112 SCH_SCREENS allScreens( m_frame->Schematic().Root() );
3113
3114 allScreens.PruneOrphanedSymbolInstances( m_frame->Prj().GetProjectName(), sheets );
3115 allScreens.PruneOrphanedSheetInstances( m_frame->Prj().GetProjectName(), sheets );
3116
3117 // Now clear the previous selection, select the pasted items, and fire up the "move" tool.
3118 m_toolMgr->RunAction( ACTIONS::selectionClear );
3119
3120 // If the item has a parent group, it will be part of the loadedItems, and will handle
3121 // the move action. Iterate backwards to avoid invalidating the iterator.
3122 for( int i = loadedItems.size() - 1; i >= 0; i-- )
3123 {
3124 EDA_ITEM* item = loadedItems[i];
3125
3126 if( item->GetParentGroup() )
3127 {
3128 loadedItems.erase( loadedItems.begin() + i );
3129 // These were hidden before because they would be added to the move preview,
3130 // but now they need to be shown as a preview so they appear to move when
3131 // the group moves.
3132 getView()->SetVisible( item );
3133 getView()->AddToPreview( item, false );
3134 }
3135 }
3136
3137 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &loadedItems );
3138
3139 SCH_SELECTION& selection = selTool->GetSelection();
3140
3141 if( !selection.Empty() )
3142 {
3143 if( aEvent.IsAction( &ACTIONS::duplicate ) )
3144 {
3145 int closest_dist = INT_MAX;
3146
3147 auto processPt =
3148 [&]( const VECTOR2I& pt )
3149 {
3150 int dist = ( eventPos - pt ).EuclideanNorm();
3151
3152 if( dist < closest_dist )
3153 {
3154 selection.SetReferencePoint( pt );
3155 closest_dist = dist;
3156 }
3157 };
3158
3159 // Prefer connection points (which should remain on grid)
3160 for( EDA_ITEM* item : selection.Items() )
3161 {
3162 SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item );
3163 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( item );
3164
3165 if( sch_item && sch_item->IsConnectable() )
3166 {
3167 for( const VECTOR2I& pt : sch_item->GetConnectionPoints() )
3168 processPt( pt );
3169 }
3170 else if( pin )
3171 {
3172 processPt( pin->GetPosition() );
3173 }
3174
3175 // Symbols need to have their center point added since often users are trying to
3176 // move parts from their center.
3177 if( dynamic_cast<SCH_SYMBOL*>( item ) )
3178 processPt( item->GetPosition() );
3179 }
3180
3181 // Only process other points if we didn't find any connection points
3182 if( closest_dist == INT_MAX )
3183 {
3184 for( EDA_ITEM* item : selection.Items() )
3185 {
3186 switch( item->Type() )
3187 {
3188 case SCH_LINE_T:
3189 processPt( static_cast<SCH_LINE*>( item )->GetStartPoint() );
3190 processPt( static_cast<SCH_LINE*>( item )->GetEndPoint() );
3191 break;
3192
3193 case SCH_SHAPE_T:
3194 {
3195 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item );
3196
3197 switch( shape->GetShape() )
3198 {
3199 case SHAPE_T::RECTANGLE:
3200 for( const VECTOR2I& pt : shape->GetRectCorners() )
3201 processPt( pt );
3202
3203 break;
3204
3205 case SHAPE_T::CIRCLE:
3206 processPt( shape->GetCenter() );
3207 break;
3208
3209 case SHAPE_T::POLY:
3210 for( int ii = 0; ii < shape->GetPolyShape().TotalVertices(); ++ii )
3211 processPt( shape->GetPolyShape().CVertex( ii ) );
3212
3213 break;
3214
3215 default:
3216 processPt( shape->GetStart() );
3217 processPt( shape->GetEnd() );
3218 break;
3219 }
3220
3221 break;
3222 }
3223
3224 default:
3225 processPt( item->GetPosition() );
3226 break;
3227 }
3228 }
3229 }
3230
3231 selection.SetIsHover( m_duplicateIsHoverSelection );
3232 }
3233 // We want to the first non-group item in the selection to be the reference point.
3234 else if( selection.GetTopLeftItem()->Type() == SCH_GROUP_T )
3235 {
3236 SCH_GROUP* group = static_cast<SCH_GROUP*>( selection.GetTopLeftItem() );
3237
3238 bool found = false;
3239 SCH_ITEM* item = nullptr;
3240
3241 group->RunOnChildren(
3242 [&]( SCH_ITEM* schItem )
3243 {
3244 if( !found && schItem->Type() != SCH_GROUP_T )
3245 {
3246 item = schItem;
3247 found = true;
3248 }
3249 },
3251
3252 if( found )
3253 selection.SetReferencePoint( item->GetPosition() );
3254 else
3255 selection.SetReferencePoint( group->GetPosition() );
3256 }
3257 else
3258 {
3259 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetTopLeftItem() );
3260
3261 selection.SetReferencePoint( item->GetPosition() );
3262 }
3263
3264 if( m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit ) )
3265 {
3266 // Pushing the commit will update the connectivity.
3267 commit.Push( _( "Paste" ) );
3268
3269 if( sheetsPasted )
3270 {
3271 m_frame->UpdateHierarchyNavigator();
3272 // UpdateHierarchyNavigator() will call RefreshNetNavigator()
3273 }
3274 else
3275 {
3276 m_frame->RefreshNetNavigator();
3277 }
3278 }
3279 else
3280 {
3281 commit.Revert();
3282 }
3283
3284 getView()->ClearPreview();
3285 }
3286
3287 return 0;
3288}
3289
3290
3292{
3293 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
3294 SCH_SELECTION& selection = selTool->RequestSelection( { SCH_SYMBOL_T } );
3295 SCH_SYMBOL* symbol = nullptr;
3296 SYMBOL_EDIT_FRAME* symbolEditor;
3297
3298 if( selection.GetSize() >= 1 )
3299 symbol = (SCH_SYMBOL*) selection.Front();
3300
3301 if( selection.IsHover() )
3302 m_toolMgr->RunAction( ACTIONS::selectionClear );
3303
3304 if( !symbol )
3305 {
3306 // Giant hack: by default we assign Edit Table to the same hotkey, so give the table
3307 // tool a chance to handle it if we can't.
3308 if( SCH_EDIT_TABLE_TOOL* tableTool = m_toolMgr->GetTool<SCH_EDIT_TABLE_TOOL>() )
3309 tableTool->EditTable( aEvent );
3310
3311 return 0;
3312 }
3313
3314 if( symbol->GetEditFlags() != 0 )
3315 return 0;
3316
3317 if( symbol->IsMissingLibSymbol() )
3318 {
3319 m_frame->ShowInfoBarError( _( "Symbols with broken library symbol links cannot be edited." ) );
3320 return 0;
3321 }
3322
3324 symbolEditor = (SYMBOL_EDIT_FRAME*) m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR, false );
3325
3326 if( symbolEditor )
3327 {
3328 if( wxWindow* blocking_win = symbolEditor->Kiway().GetBlockingDialog() )
3329 blocking_win->Close( true );
3330
3331 if( aEvent.IsAction( &SCH_ACTIONS::editWithLibEdit ) )
3332 {
3333 symbolEditor->LoadSymbolFromSchematic( symbol );
3334 }
3336 {
3337 symbolEditor->LoadSymbol( symbol->GetLibId(), symbol->GetUnit(), symbol->GetBodyStyle() );
3338
3339 if( !symbolEditor->IsLibraryTreeShown() )
3340 symbolEditor->ToggleLibraryTree();
3341 }
3342 }
3343
3344 return 0;
3345}
3346
3347
3349{
3350 m_frame->OnAnnotate();
3351 return 0;
3352}
3353
3354
3356{
3358 dlg.m_FirstRefDes->SetValidator( wxTextValidator( wxFILTER_EMPTY ) );
3359
3360 dlg.SetInitialFocus( dlg.m_FirstRefDes );
3361
3362 if( dlg.ShowModal() == wxID_OK )
3363 {
3364 SCH_REFERENCE startRef;
3365 startRef.SetRef( dlg.m_FirstRefDes->GetValue() );
3366
3367 if( startRef.IsSplitNeeded() )
3368 startRef.Split();
3369 else
3370 return 0;
3371
3372 int startNum = atoi( startRef.GetRefNumber().utf8_string().c_str() );
3373
3374 SCH_COMMIT commit( m_frame );
3375 SCHEMATIC* schematic = m_frame->m_schematic;
3376 SCH_REFERENCE_LIST references;
3377
3378 if( dlg.m_AllSheets->GetValue() )
3379 schematic->Hierarchy().GetSymbols( references, SYMBOL_FILTER_ALL );
3380 else
3381 schematic->CurrentSheet().GetSymbols( references, SYMBOL_FILTER_ALL );
3382
3383 references.SplitReferences();
3384
3385 for( SCH_REFERENCE& ref : references )
3386 {
3387 if( ref.GetRef() == startRef.GetRef() )
3388 {
3389 int num = atoi( ref.GetRefNumber().utf8_string().c_str() );
3390
3391 if( num >= startNum )
3392 {
3393 const SCH_SHEET_PATH& sheet = ref.GetSheetPath();
3394 wxString fullRef = ref.GetRef();
3395
3396 num += dlg.m_Increment->GetValue();
3397 fullRef << num;
3398
3399 commit.Modify( ref.GetSymbol(), sheet.LastScreen(), RECURSE_MODE::NO_RECURSE );
3400 ref.GetSymbol()->SetRef( &sheet, From_UTF8( fullRef.c_str() ) );
3401 }
3402 }
3403 }
3404
3405 if( !commit.Empty() )
3406 commit.Push( _( "Increment Annotations" ) );
3407 }
3408
3409 return 0;
3410}
3411
3412
3414{
3415 m_frame->OnOpenCvpcb();
3416 return 0;
3417}
3418
3419
3421{
3422 m_frame->OnImportProject();
3423 return 0;
3424}
3425
3426
3428{
3429 DIALOG_SYMBOL_FIELDS_TABLE* dlg = m_frame->GetSymbolFieldsTableDialog();
3430
3431 if( !dlg )
3432 return 0;
3433
3434 // Needed at least on Windows. Raise() is not enough
3435 dlg->Show( true );
3436
3437 // Bring it to the top if already open. Dual monitor users need this.
3438 dlg->Raise();
3439
3440 dlg->ShowEditTab();
3441
3442 return 0;
3443}
3444
3445
3447{
3449 m_frame->HardRedraw();
3450
3451 return 0;
3452}
3453
3454
3456{
3457 m_frame->OnOpenPcbnew();
3458 return 0;
3459}
3460
3461
3463{
3464 m_frame->OnUpdatePCB();
3465 return 0;
3466}
3467
3468
3470{
3472 dlg.ShowModal();
3473 return 0;
3474}
3475
3476
3478{
3480
3481 // If a plugin is removed or added, rebuild and reopen the new dialog
3482 while( result == NET_PLUGIN_CHANGE )
3484
3485 return 0;
3486}
3487
3488
3490{
3491 DIALOG_SYMBOL_FIELDS_TABLE* dlg = m_frame->GetSymbolFieldsTableDialog();
3492
3493 if( !dlg )
3494 return 0;
3495
3496 // Needed at least on Windows. Raise() is not enough
3497 dlg->Show( true );
3498
3499 // Bring it to the top if already open. Dual monitor users need this.
3500 dlg->Raise();
3501
3502 dlg->ShowExportTab();
3503
3504 return 0;
3505}
3506
3507
3509{
3511 return 0;
3512}
3513
3514
3516{
3517 m_frame->RecalculateConnections( nullptr, LOCAL_CLEANUP );
3518
3519 // Create a selection with all items from the current sheet
3520 SCH_SELECTION sheetSelection;
3521 SCH_SCREEN* screen = m_frame->GetScreen();
3522
3523 for( SCH_ITEM* item : screen->Items() )
3524 {
3525 sheetSelection.Add( item );
3526 }
3527
3528 // Get the full page bounding box for rendering the complete sheet
3529 BOX2I pageBBox( VECTOR2I( 0, 0 ), m_frame->GetPageSizeIU() );
3530
3531 // Render the full sheet selection including the worksheet
3532 wxImage image = renderSelectionToImageForClipboard( m_frame, sheetSelection, pageBBox, true, true );
3533
3534 if( image.IsOk() )
3535 {
3536 wxLogNull doNotLog; // disable logging of failed clipboard actions
3537
3538 if( wxTheClipboard->Open() )
3539 {
3540 wxDataObjectComposite* data = new wxDataObjectComposite();
3541
3543
3544 wxTheClipboard->SetData( data );
3545 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
3546 wxTheClipboard->Close();
3547 }
3548 }
3549 else
3550 {
3551 wxLogMessage( _( "Cannot create the schematic image" ) );
3552 }
3553
3554 return 0;
3555}
3556
3557
3559{
3561 return 0;
3562}
3563
3564
3570
3571
3577
3578
3584
3585
3591
3592
3598
3599
3601{
3602 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3604
3606 m_frame->GetCanvas()->Refresh();
3607
3608 return 0;
3609}
3610
3611
3613{
3614 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3616
3617 m_frame->GetRenderSettings()->m_ShowHiddenFields = cfg->m_Appearance.show_hidden_fields;
3618
3620 m_frame->GetCanvas()->Refresh();
3621
3622 return 0;
3623}
3624
3625
3627{
3628 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3630
3632 m_frame->GetCanvas()->Refresh();
3633
3634 return 0;
3635}
3636
3637
3639{
3640 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3642
3644 m_frame->GetCanvas()->Refresh();
3645
3646 return 0;
3647}
3648
3649
3651{
3652 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3654
3656 m_frame->GetCanvas()->Refresh();
3657
3658 return 0;
3659}
3660
3661
3663{
3664 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3666
3667 m_frame->GetCanvas()->Refresh();
3668
3669 return 0;
3670}
3671
3672
3674{
3675 SCH_SHEET_PATH* sheetPath = &m_frame->GetCurrentSheet();
3676 wxString variant = m_frame->Schematic().GetCurrentVariant();
3677 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3679
3680 m_frame->GetCanvas()->GetView()->UpdateAllItemsConditionally(
3681 [&]( KIGFX::VIEW_ITEM* aItem ) -> int
3682 {
3683 int flags = 0;
3684
3685 auto invalidateTextVars =
3686 [&flags]( EDA_TEXT* text )
3687 {
3688 if( text->HasTextVars() )
3689 {
3690 text->ClearRenderCache();
3691 text->ClearBoundingBoxCache();
3693 }
3694 };
3695
3696 if( SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aItem ) )
3697 {
3698 item->RunOnChildren(
3699 [&invalidateTextVars]( SCH_ITEM* aChild )
3700 {
3701 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aChild ) )
3702 invalidateTextVars( text );
3703 },
3705
3706 if( item->GetExcludedFromSim( sheetPath, variant ) )
3708 }
3709
3710 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem ) )
3711 invalidateTextVars( text );
3712
3713 return flags;
3714 } );
3715
3716 m_frame->GetCanvas()->Refresh();
3717
3718 return 0;
3719}
3720
3721
3723{
3724 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3726
3728 m_frame->RefreshOperatingPointDisplay();
3729 m_frame->GetCanvas()->Refresh();
3730
3731 return 0;
3732}
3733
3734
3736{
3737 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3739
3741 m_frame->RefreshOperatingPointDisplay();
3742 m_frame->GetCanvas()->Refresh();
3743
3744 return 0;
3745}
3746
3747
3749{
3750 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3752
3753 m_frame->GetRenderSettings()->m_ShowPinAltIcons = cfg->m_Appearance.show_pin_alt_icons;
3754
3756 m_frame->GetCanvas()->Refresh();
3757
3758 return 0;
3759}
3760
3761
3763{
3764 m_frame->eeconfig()->m_Drawing.line_mode = aEvent.Parameter<LINE_MODE>();
3765 m_toolMgr->PostAction( ACTIONS::refreshPreview );
3766 // Notify toolbar to update selection
3768 return 0;
3769}
3770
3771
3773{
3774 m_frame->eeconfig()->m_Drawing.line_mode++;
3775 m_frame->eeconfig()->m_Drawing.line_mode %= LINE_MODE::LINE_MODE_COUNT;
3776 m_toolMgr->PostAction( ACTIONS::refreshPreview );
3777 // Notify toolbar to update selection
3779 return 0;
3780}
3781
3782
3784{
3785 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3787 return 0;
3788}
3789
3790
3792{
3793 // Update the left toolbar Line modes group icon to match current mode
3794 switch( static_cast<LINE_MODE>( m_frame->eeconfig()->m_Drawing.line_mode ) )
3795 {
3796 case LINE_MODE::LINE_MODE_FREE: m_frame->SelectToolbarAction( SCH_ACTIONS::lineModeFree ); break;
3797 case LINE_MODE::LINE_MODE_90: m_frame->SelectToolbarAction( SCH_ACTIONS::lineMode90 ); break;
3798 default:
3799 case LINE_MODE::LINE_MODE_45: m_frame->SelectToolbarAction( SCH_ACTIONS::lineMode45 ); break;
3800 }
3801
3802 return 0;
3803}
3804
3805
3807{
3808 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
3809 return 0;
3810
3811 GRID_SETTINGS& gridSettings = m_toolMgr->GetSettings()->m_Window.grid;
3812 int currentIdx = m_toolMgr->GetSettings()->m_Window.grid.last_size_idx;
3813
3814 wxArrayString gridsLabels;
3815
3816 for( const GRID& grid : gridSettings.grids )
3817 gridsLabels.Add( grid.UserUnitsMessageText( m_frame ) );
3818
3819 if( !m_frame->GetHotkeyPopup() )
3820 m_frame->CreateHotkeyPopup();
3821
3822 HOTKEY_CYCLE_POPUP* popup = m_frame->GetHotkeyPopup();
3823
3824 if( popup )
3825 popup->Popup( _( "Grid" ), gridsLabels, currentIdx );
3826
3827 return 0;
3828}
3829
3830
3832{
3833 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3834
3835 if( !editFrame )
3836 return 1;
3837
3838 // Need to have a group selected and it needs to have a linked design block
3839 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
3840 SCH_SELECTION selection = selTool->GetSelection();
3841
3842 if( selection.Size() != 1 || selection[0]->Type() != SCH_GROUP_T )
3843 return 1;
3844
3845 SCH_GROUP* group = static_cast<SCH_GROUP*>( selection[0] );
3846
3847 if( !group->HasDesignBlockLink() )
3848 return 1;
3849
3850 // Get the associated design block
3851 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
3852 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
3853 true, true ) );
3854
3855 if( !designBlock )
3856 {
3857 wxString msg;
3858 msg.Printf( _( "Could not find design block %s." ), group->GetDesignBlockLibId().GetUniStringLibId() );
3859 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
3860 return 1;
3861 }
3862
3863 if( designBlock->GetSchematicFile().IsEmpty() )
3864 {
3865 wxString msg;
3866 msg.Printf( _( "Design block %s does not have a schematic file." ),
3867 group->GetDesignBlockLibId().GetUniStringLibId() );
3868 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
3869 return 1;
3870 }
3871
3872 editFrame->GetDesignBlockPane()->SelectLibId( group->GetDesignBlockLibId() );
3873
3874 return m_toolMgr->RunAction( SCH_ACTIONS::placeDesignBlock, designBlock.release() );
3875}
3876
3877
3879{
3880 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3881
3882 if( !editFrame )
3883 return 1;
3884
3885 // Need to have a group selected and it needs to have a linked design block
3886 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
3887 SCH_SELECTION selection = selTool->GetSelection();
3888
3889 if( selection.Size() != 1 || selection[0]->Type() != SCH_GROUP_T )
3890 return 1;
3891
3892 SCH_GROUP* group = static_cast<SCH_GROUP*>( selection[0] );
3893
3894 if( !group->HasDesignBlockLink() )
3895 return 1;
3896
3897 // Get the associated design block
3898 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
3899 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
3900 true, true ) );
3901
3902 if( !designBlock )
3903 {
3904 wxString msg;
3905 msg.Printf( _( "Could not find design block %s." ), group->GetDesignBlockLibId().GetUniStringLibId() );
3906 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
3907 return 1;
3908 }
3909
3910 editFrame->GetDesignBlockPane()->SelectLibId( group->GetDesignBlockLibId() );
3911
3912 return m_toolMgr->RunAction( SCH_ACTIONS::updateDesignBlockFromSelection ) ? 1 : 0;
3913}
3914
3915
3917{
3918 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3919
3920 if( !editFrame )
3921 return 1;
3922
3923 editFrame->AddVariant();
3924
3925 return 0;
3926}
3927
3928
3930{
3931 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3932
3933 if( !editFrame )
3934 return 1;
3935
3936 editFrame->RemoveVariant();
3937 return 0;
3938}
3939
3940
3942{
3943 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3944
3945 if( !editFrame )
3946 return 1;
3947
3948 editFrame->EditVariantDescription();
3949 return 0;
3950}
3951
3952
3954{
3955 Go( &SCH_EDITOR_CONTROL::New, ACTIONS::doNew.MakeEvent() );
3956 Go( &SCH_EDITOR_CONTROL::Open, ACTIONS::open.MakeEvent() );
3957 Go( &SCH_EDITOR_CONTROL::Save, ACTIONS::save.MakeEvent() );
3964 Go( &SCH_EDITOR_CONTROL::Plot, ACTIONS::plot.MakeEvent() );
3965
3968
3974
3977
3989
3992
3993 Go( &SCH_EDITOR_CONTROL::Undo, ACTIONS::undo.MakeEvent() );
3994 Go( &SCH_EDITOR_CONTROL::Redo, ACTIONS::redo.MakeEvent() );
3995 Go( &SCH_EDITOR_CONTROL::Cut, ACTIONS::cut.MakeEvent() );
3996 Go( &SCH_EDITOR_CONTROL::Copy, ACTIONS::copy.MakeEvent() );
4001
4003
4020
4028
4045
4047
4050
4054}
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:232
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:79
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:343
static const TOOL_EVENT GridChangedByKeyEvent
Definition actions.h:361
static const TOOL_EVENT SelectedEvent
Definition actions.h:341
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:348
static const TOOL_EVENT PointSelectedEvent
Definition actions.h:340
static const TOOL_EVENT UnselectedEvent
Definition actions.h:342
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:372
wxString AsString() const
Definition kiid.cpp:393
Definition kiid.h:44
wxString AsString() const
Definition kiid.cpp:242
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:686
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:80
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:149
bool IsPower() const override
wxString GetName() const override
Definition lib_symbol.h:142
bool IsLocalPower() const override
bool IsGlobalPower() const override
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 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 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 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.
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)
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:258
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:873
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:874
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)
Definition selection.cpp:38
const std::deque< EDA_ITEM * > GetItems() const
Definition selection.h:122
virtual unsigned int GetSize() const override
Return the number of stored items.
Definition selection.h:101
EDA_ITEM * Front() const
Definition selection.h:173
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:189
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 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:477
@ LAYER_ERC_ERR
Definition layer_ids.h:478
@ LAYER_SCHEMATIC_DRAWINGSHEET
Definition layer_ids.h:494
@ LAYER_OP_CURRENTS
Definition layer_ids.h:500
@ LAYER_SCHEMATIC_PAGE_LIMITS
Definition layer_ids.h:495
@ LAYER_OP_VOLTAGES
Definition layer_ids.h:499
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:448
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 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
VECTOR2I end
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