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 if( CONNECTION_SUBGRAPH* sg = connectionGraph->FindSubgraphByName( selectedName, sheetPath ) )
1603 {
1605 {
1606 for( const SCH_ITEM* item : sg->GetItems() )
1607 {
1608 wxCHECK2( item, continue );
1609
1610 if( SCH_CONNECTION* connection = item->Connection() )
1611 {
1612 for( const std::shared_ptr<SCH_CONNECTION>& member : connection->AllMembers() )
1613 {
1614 if( member )
1615 connNames.emplace( member->Name() );
1616 }
1617 }
1618 }
1619 }
1620 }
1621
1622 // Place all bus names that are connected to the selected net in the set, regardless of
1623 // their sheet. This ensures that nets that are connected to a bus on a different sheet
1624 // get their buses highlighted as well.
1625 for( CONNECTION_SUBGRAPH* sg : connectionGraph->GetAllSubgraphs( selectedName ) )
1626 {
1627 for( const auto& [_, bus_sgs] : sg->GetBusParents() )
1628 {
1629 for( CONNECTION_SUBGRAPH* bus_sg : bus_sgs )
1630 connNames.emplace( bus_sg->GetNetName() );
1631 }
1632 }
1633 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "UpdateNetHighlighting: connNames after connection='%zu'", connNames.size() );
1634 }
1635
1636 if( !m_frame->GetHighlightedNetChain().IsEmpty() )
1637 {
1638 if( SCH_NETCHAIN* sig = connectionGraph->GetNetChainByName( m_frame->GetHighlightedNetChain() ) )
1639 {
1640 for( const wxString& n : sig->GetNets() )
1641 connNames.emplace( n );
1642 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "UpdateNetHighlighting: added %zu nets from chain '%s'",
1643 sig->GetNets().size(), m_frame->GetHighlightedNetChain() );
1644 }
1645 }
1646
1647 for( SCH_ITEM* item : screen->Items() )
1648 {
1649 if( !item || !item->IsConnectable() )
1650 continue;
1651
1652 SCH_ITEM* redrawItem = nullptr;
1653
1654 if( item->Type() == SCH_SYMBOL_T )
1655 {
1656 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
1657
1658 for( SCH_PIN* pin : symbol->GetPins() )
1659 {
1660 SCH_CONNECTION* pin_conn = pin->Connection();
1661
1662 if( pin_conn )
1663 {
1664 if( !pin->IsBrightened() && connNames.count( pin_conn->Name() ) )
1665 {
1666 pin->SetBrightened();
1667 redrawItem = symbol;
1668 }
1669 else if( pin->IsBrightened() && !connNames.count( pin_conn->Name() ) )
1670 {
1671 pin->ClearBrightened();
1672 redrawItem = symbol;
1673 }
1674 }
1675 else if( pin->IsBrightened() )
1676 {
1677 pin->ClearBrightened();
1678 redrawItem = symbol;
1679 }
1680 }
1681
1682 if( symbol->IsPower() && symbol->GetPins().size() )
1683 {
1684 SCH_CONNECTION* pinConn = symbol->GetPins()[0]->Connection();
1685
1687 {
1688 SCH_FIELD* field = symbol->GetField( id );
1689
1690 if( !field->IsVisible() )
1691 continue;
1692
1693 if( pinConn )
1694 {
1695 if( !field->IsBrightened() && connNames.count( pinConn->Name() ) )
1696 {
1697 field->SetBrightened();
1698 redrawItem = symbol;
1699 }
1700 else if( field->IsBrightened() && !connNames.count( pinConn->Name() ) )
1701 {
1702 field->ClearBrightened();
1703 redrawItem = symbol;
1704 }
1705 }
1706 else if( field->IsBrightened() )
1707 {
1708 field->ClearBrightened();
1709 redrawItem = symbol;
1710 }
1711 }
1712 }
1713 }
1714 else if( item->Type() == SCH_SHEET_T )
1715 {
1716 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1717
1718 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
1719 {
1720 wxCHECK2( pin, continue );
1721
1722 SCH_CONNECTION* pin_conn = pin->Connection();
1723
1724 if( pin_conn )
1725 {
1726 if( !pin->IsBrightened() && connNames.count( pin_conn->Name() ) )
1727 {
1728 pin->SetBrightened();
1729 redrawItem = sheet;
1730 }
1731 else if( pin->IsBrightened() && !connNames.count( pin_conn->Name() ) )
1732 {
1733 pin->ClearBrightened();
1734 redrawItem = sheet;
1735 }
1736 }
1737 else if( pin->IsBrightened() )
1738 {
1739 pin->ClearBrightened();
1740 redrawItem = sheet;
1741 }
1742 }
1743 }
1744 else
1745 {
1746 SCH_CONNECTION* itemConn = item->Connection();
1747
1748 if( itemConn )
1749 {
1750 if( !item->IsBrightened() && connNames.count( itemConn->Name() ) )
1751 {
1752 item->SetBrightened();
1753 redrawItem = item;
1754 }
1755 else if( item->IsBrightened() && !connNames.count( itemConn->Name() ) )
1756 {
1757 item->ClearBrightened();
1758 redrawItem = item;
1759 }
1760 }
1761 else if( item->IsBrightened() )
1762 {
1763 item->ClearBrightened();
1764 redrawItem = item;
1765 }
1766 }
1767
1768 if( redrawItem )
1769 itemsToRedraw.push_back( redrawItem );
1770 }
1771
1772 if( itemsToRedraw.size() )
1773 {
1774 wxLogTrace( "KICAD_SCH_HIGHLIGHT", "UpdateNetHighlighting: itemsToRedraw=%zu", itemsToRedraw.size() );
1775 // Be sure highlight change will be redrawn
1776 KIGFX::VIEW* view = getView();
1777
1778 for( EDA_ITEM* redrawItem : itemsToRedraw )
1780
1781 m_frame->GetCanvas()->Refresh();
1782 }
1783
1784 return 0;
1785}
1786
1787
1789{
1790 PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
1791
1792 // Deactivate other tools; particularly important if another PICKER is currently running
1793 Activate();
1794
1795 picker->SetCursor( KICURSOR::BULLSEYE );
1796 picker->SetSnapping( false );
1797 picker->ClearHandlers();
1798
1799 picker->SetClickHandler(
1800 [this]( const VECTOR2D& aPos )
1801 {
1802 return highlightNet( m_toolMgr, aPos );
1803 } );
1804
1805 m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
1806
1807 return 0;
1808}
1809
1810
1812{
1813 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_toolMgr->GetToolHolder() );
1814 auto ids = aEvent.Parameter<std::pair<wxString, wxString>>();
1815 wxString oldStr = ids.first;
1816 wxString newStr = ids.second;
1817 KIID oldPin( oldStr );
1818 KIID newPin( newStr );
1819 wxString sig = editFrame->GetHighlightedNetChain();
1820
1821 if( !sig.IsEmpty() )
1822 editFrame->Schematic().ConnectionGraph()->ReplaceNetChainTerminalPin( sig, oldPin, newPin );
1823
1824 return 0;
1825}
1826
1827
1829{
1830 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1831 SCH_ITEM* item = static_cast<SCH_ITEM*>( selTool->GetSelection().Front() );
1832 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( item );
1833
1834 if( !pin || !pin->Connection() )
1835 return 0;
1836
1837 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_toolMgr->GetToolHolder() );
1838 CONNECTION_GRAPH* graph = editFrame->Schematic().ConnectionGraph();
1839
1840 if( SCH_NETCHAIN* sig = graph->GetNetChainForNet( pin->Connection()->Name() ) )
1841 {
1842 wxString newName = wxGetTextFromUser( _( "Net chain name:" ), _( "Name Net Chain" ), sig->GetName() );
1843
1844 if( !newName.IsEmpty() && newName != sig->GetName() )
1845 {
1846 sig->SetName( newName );
1847
1848 editFrame->SetHighlightedNetChain( newName );
1851 editFrame->UpdateNetHighlightStatus();
1852 }
1853 }
1854
1855 return 0;
1856}
1857
1859{
1860 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
1861 auto& selection = selTool->GetSelection();
1862
1863 if( selection.GetSize() != 2 )
1864 return 0;
1865
1866 SCH_PIN* pinA = dynamic_cast<SCH_PIN*>( static_cast<SCH_ITEM*>( selection[0] ) );
1867 SCH_PIN* pinB = dynamic_cast<SCH_PIN*>( static_cast<SCH_ITEM*>( selection[1] ) );
1868
1869 if( !pinA || !pinB )
1870 return 0;
1871
1872 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_toolMgr->GetToolHolder() );
1873 CONNECTION_GRAPH* graph = editFrame->Schematic().ConnectionGraph();
1874
1875 SCH_NETCHAIN* potential = graph->FindPotentialNetChainBetweenPins( pinA, pinB );
1876 if( !potential )
1877 {
1878 DisplayError( editFrame, _( "No potential net chain connects the selected pins." ) );
1879 return 0;
1880 }
1881
1882 // Build default suggestion name
1883 wxString suggestion = wxString::Format( wxS( "%s_%s" ), pinA->GetParentSymbol()->GetRef( &editFrame->GetCurrentSheet() ), pinB->GetParentSymbol()->GetRef( &editFrame->GetCurrentSheet() ) );
1884
1885 // Compose display text for dialog
1886 wxString msg = wxString::Format( _( "Create Net Chain between %s:%s and %s:%s" ),
1887 pinA->GetParentSymbol()->GetRef( &editFrame->GetCurrentSheet() ), pinA->GetNumber(),
1888 pinB->GetParentSymbol()->GetRef( &editFrame->GetCurrentSheet() ), pinB->GetNumber() );
1889
1890 // Temporary highlight preview: highlight all nets in potential (reuse SetHighlightedNetChain with temp name)
1891 // We use the potential's current name as a temporary highlight identifier
1892 wxString prevHighlightedChain = editFrame->GetHighlightedNetChain();
1893 wxString prevHighlightedConn = editFrame->GetHighlightedConnection();
1894
1895 editFrame->SetHighlightedConnection( wxEmptyString );
1896 editFrame->SetHighlightedNetChain( potential->GetName() );
1899 editFrame->UpdateNetHighlightStatus();
1900
1901 // Zoom to bounding box of the two pins (union) expanded slightly
1902 BOX2I bbox = pinA->GetBoundingBox();
1903 bbox.Merge( pinB->GetBoundingBox() );
1904 // Expand by 25% for context
1905 int dx = bbox.GetWidth() / 4; if( dx < 100 ) dx = 100;
1906 int dy = bbox.GetHeight() / 4; if( dy < 100 ) dy = 100;
1907 bbox.Inflate( dx, dy );
1908 if( auto canvas = editFrame->GetCanvas() )
1909 {
1910 canvas->GetView()->SetCenter( bbox.GetCenter() );
1911 // Compute scale so bbox roughly fits viewport height
1912 auto view = canvas->GetView();
1913 if( view )
1914 {
1915 BOX2D viewBox = view->GetBoundary();
1916 double scaleX = (double) viewBox.GetWidth() / (double) bbox.GetWidth();
1917 double scaleY = (double) viewBox.GetHeight() / (double) bbox.GetHeight();
1918 double scale = std::min( scaleX, scaleY );
1919 if( scale > 0 )
1920 view->SetScale( scale );
1921 }
1922 }
1923
1924 wxString name = wxGetTextFromUser( msg, _( "Create Net Chain" ), suggestion, editFrame );
1925 if( name.IsEmpty() )
1926 {
1927 // Restore previous highlight state
1928 editFrame->SetHighlightedNetChain( prevHighlightedChain );
1929 editFrame->SetHighlightedConnection( prevHighlightedConn );
1931 editFrame->UpdateNetHighlightStatus();
1932 return 0; // cancelled
1933 }
1934
1935 if( graph->CreateNetChainFromPotential( potential, name ) )
1936 {
1937 // Replace temporary highlight with new chain name
1938 editFrame->SetHighlightedNetChain( name );
1939 editFrame->SetHighlightedConnection( wxEmptyString );
1941 editFrame->UpdateNetHighlightStatus();
1942 editFrame->Refresh();
1943 }
1944
1945 return 0;
1946}
1947
1948
1950{
1951 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_toolMgr->GetToolHolder() );
1952
1953 CONNECTION_GRAPH* graph = editFrame->Schematic().ConnectionGraph();
1954
1955 if( graph && graph->GetPotentialNetChains().empty() )
1956 {
1957 SCH_SHEET_LIST sheets = editFrame->Schematic().Hierarchy();
1958 graph->Recalculate( sheets, true );
1959 }
1960
1962
1963 if( SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>() )
1964 {
1965 const SCH_SELECTION& sel = selTool->GetSelection();
1966
1967 std::vector<SCH_SYMBOL*> symbols;
1968
1969 for( EDA_ITEM* item : sel )
1970 {
1971 if( SCH_SYMBOL* sym = dynamic_cast<SCH_SYMBOL*>( static_cast<SCH_ITEM*>( item ) ) )
1972 symbols.push_back( sym );
1973 }
1974
1975 if( symbols.size() >= 1 )
1976 hint.fromRef = symbols[0]->GetRef( &editFrame->GetCurrentSheet() );
1977
1978 if( symbols.size() >= 2 )
1979 hint.toRef = symbols[1]->GetRef( &editFrame->GetCurrentSheet() );
1980
1981 // Single pin or single wire/bus → use its connection's net name as the focus hint.
1982 if( symbols.empty() && sel.GetSize() == 1 )
1983 {
1984 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( sel.Front() );
1985
1986 if( SCH_PIN* pin = dynamic_cast<SCH_PIN*>( schItem ) )
1987 {
1988 if( pin->Connection() )
1989 hint.netName = pin->Connection()->Name();
1990 }
1991 else if( schItem
1992 && schItem->Type() == SCH_LINE_T
1993 && schItem->IsType( { SCH_ITEM_LOCATE_WIRE_T, SCH_ITEM_LOCATE_BUS_T } )
1994 && schItem->Connection() )
1995 {
1996 hint.netName = schItem->Connection()->Name();
1997 }
1998 }
1999 }
2000
2001 DIALOG_CREATE_NET_CHAIN dlg( editFrame, hint );
2002 dlg.ShowModal();
2003
2004 return 0;
2005}
2006
2007
2009{
2010 wxCHECK( m_frame, 0 );
2011
2012 if( m_frame->GetUndoCommandCount() <= 0 )
2013 return 0;
2014
2015 // Inform tools that undo command was issued
2016 m_toolMgr->ProcessEvent( { TC_MESSAGE, TA_UNDO_REDO_PRE, AS_GLOBAL } );
2017
2018 // Get the old list
2019 PICKED_ITEMS_LIST* undo_list = m_frame->PopCommandFromUndoList();
2020
2021 wxCHECK( undo_list, 0 );
2022
2023 m_frame->PutDataInPreviousState( undo_list );
2024
2025 // Now push the old command to the RedoList
2026 undo_list->ReversePickersListOrder();
2027 m_frame->PushCommandToRedoList( undo_list );
2028
2029 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->RebuildSelection();
2030
2031 m_frame->GetCanvas()->Refresh();
2032 m_frame->OnModify();
2033
2034 return 0;
2035}
2036
2037
2039{
2040 wxCHECK( m_frame, 0 );
2041
2042 if( m_frame->GetRedoCommandCount() == 0 )
2043 return 0;
2044
2045 // Inform tools that undo command was issued
2046 m_toolMgr->ProcessEvent( { TC_MESSAGE, TA_UNDO_REDO_PRE, AS_GLOBAL } );
2047
2048 /* Get the old list */
2049 PICKED_ITEMS_LIST* list = m_frame->PopCommandFromRedoList();
2050
2051 wxCHECK( list, 0 );
2052
2053 /* Redo the command: */
2054 m_frame->PutDataInPreviousState( list );
2055
2056 /* Put the old list in UndoList */
2057 list->ReversePickersListOrder();
2058 m_frame->PushCommandToUndoList( list );
2059
2060 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->RebuildSelection();
2061
2062 m_frame->GetCanvas()->Refresh();
2063 m_frame->OnModify();
2064
2065 return 0;
2066}
2067
2068
2069bool SCH_EDITOR_CONTROL::doCopy( bool aUseDuplicateClipboard )
2070{
2071 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
2072 SCH_SELECTION& selection = selTool->RequestSelection();
2073 SCHEMATIC& schematic = m_frame->Schematic();
2074
2075 if( selection.Empty() )
2076 return false;
2077
2078 if( aUseDuplicateClipboard )
2079 m_duplicateIsHoverSelection = selection.IsHover();
2080
2081 selection.SetScreen( m_frame->GetScreen() );
2083
2084 for( EDA_ITEM* item : selection.GetItems() )
2085 {
2086 if( item->Type() == SCH_SHEET_T )
2087 {
2088 SCH_SHEET* sheet = (SCH_SHEET*) item;
2089 m_supplementaryClipboard[sheet->GetFileName()] = sheet->GetScreen();
2090 }
2091 else if( item->Type() == SCH_FIELD_T && selection.IsHover() )
2092 {
2093 // Most of the time the user is trying to duplicate the parent symbol
2094 // and the field text is in it
2095 selection.Add( item->GetParent() );
2096 }
2097 else if( item->Type() == SCH_MARKER_T )
2098 {
2099 // Don't let the markers be copied
2100 selection.Remove( item );
2101 }
2102 else if( item->Type() == SCH_GROUP_T )
2103 {
2104 // Groups need to have all their items selected
2105 static_cast<SCH_ITEM*>( item )->RunOnChildren(
2106 [&]( EDA_ITEM* aChild )
2107 {
2108 selection.Add( aChild );
2109 },
2111 }
2112 }
2113
2114 bool result = true;
2115 STRING_FORMATTER formatter;
2116 SCH_IO_KICAD_SEXPR plugin;
2117 SCH_SHEET_PATH selPath = m_frame->GetCurrentSheet();
2118
2119 plugin.Format( &selection, &selPath, schematic, &formatter, true );
2120
2121 std::string prettyData = formatter.GetString();
2122 KICAD_FORMAT::Prettify( prettyData, KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES );
2123
2124 if( !aUseDuplicateClipboard )
2125 {
2126 wxLogNull doNotLog; // disable logging of failed clipboard actions
2127
2128 result &= wxTheClipboard->Open();
2129
2130 if( result )
2131 {
2132 wxDataObjectComposite* data = new wxDataObjectComposite();
2133
2134 // Add KiCad data
2135 wxCustomDataObject* kicadObj = new wxCustomDataObject( wxDataFormat( "application/kicad" ) );
2136 kicadObj->SetData( prettyData.size(), prettyData.data() );
2137 data->Add( kicadObj );
2138
2139 BOX2I selectionBox = expandedSelectionBox( selection );
2140
2141 if( selectionBox.GetWidth() > 0 && selectionBox.GetHeight() > 0 )
2142 {
2143 // Add bitmap data (encoded once, used for both PNG clipboard and HTML)
2144 wxImage image = renderSelectionToImageForClipboard( m_frame, selection, selectionBox, true, false );
2145 wxMemoryBuffer pngBuffer;
2146
2147 if( image.IsOk() && EncodeImageToPng( image, pngBuffer ) )
2148 {
2149 AddPngToClipboardData( data, pngBuffer, &image );
2150
2151 // Add HTML with embedded base64 PNG for pasting into documents
2152 wxMemoryBuffer htmlBuffer;
2153
2154 if( generateHtmlFromPngData( pngBuffer, htmlBuffer ) )
2155 {
2156 wxCustomDataObject* htmlObj = new wxCustomDataObject( wxDF_HTML );
2157 htmlObj->SetData( htmlBuffer.GetDataLen(), htmlBuffer.GetData() );
2158 data->Add( htmlObj );
2159 }
2160 }
2161 else
2162 {
2163 wxLogDebug( wxS( "Failed to generate bitmap for clipboard" ) );
2164 }
2165
2166 // Add SVG data
2167 wxMemoryBuffer svgBuffer;
2168
2169 if( plotSelectionToSvg( m_frame, selection, selectionBox, svgBuffer ) )
2170 {
2171 wxCustomDataObject* svgObj = new wxCustomDataObject( wxDataFormat( "image/svg+xml" ) );
2172 svgObj->SetData( svgBuffer.GetDataLen(), svgBuffer.GetData() );
2173 data->Add( svgObj );
2174 }
2175 else
2176 {
2177 wxLogDebug( wxS( "Failed to generate SVG for clipboard" ) );
2178 }
2179 }
2180
2181 // Finally add text data
2182 data->Add( new wxTextDataObject( wxString::FromUTF8( prettyData ) ) );
2183
2184 result &= wxTheClipboard->SetData( data );
2185 result &= wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
2186 wxTheClipboard->Close();
2187 }
2188 }
2189
2190 if( selection.IsHover() )
2191 m_toolMgr->RunAction( ACTIONS::selectionClear );
2192
2193 if( aUseDuplicateClipboard )
2194 {
2195 m_duplicateClipboard = prettyData;
2196 return true;
2197 }
2198
2199 return result;
2200}
2201
2202
2203bool SCH_EDITOR_CONTROL::searchSupplementaryClipboard( const wxString& aSheetFilename, SCH_SCREEN** aScreen )
2204{
2205 if( m_supplementaryClipboard.count( aSheetFilename ) > 0 )
2206 {
2207 *aScreen = m_supplementaryClipboard[aSheetFilename];
2208 return true;
2209 }
2210
2211 return false;
2212}
2213
2214
2216{
2217 doCopy( true ); // Use the local clipboard
2218 Paste( aEvent );
2219
2220 return 0;
2221}
2222
2223
2225{
2226 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wxWindow::FindFocus() );
2227
2228 if( textEntry )
2229 {
2230 textEntry->Cut();
2231 return 0;
2232 }
2233
2234 if( doCopy() )
2235 m_toolMgr->RunAction( ACTIONS::doDelete );
2236
2237 return 0;
2238}
2239
2240
2242{
2243 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wxWindow::FindFocus() );
2244
2245 if( textEntry )
2246 {
2247 textEntry->Copy();
2248 return 0;
2249 }
2250
2251 doCopy();
2252
2253 return 0;
2254}
2255
2256
2258{
2259 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
2260 SCH_SELECTION& selection = selTool->RequestSelection();
2261
2262 if( selection.Empty() )
2263 return false;
2264
2265 wxString itemsAsText = GetSelectedItemsAsText( selection );
2266
2267 if( selection.IsHover() )
2268 m_toolMgr->RunAction( ACTIONS::selectionClear );
2269
2270 return SaveClipboard( itemsAsText.ToStdString() );
2271}
2272
2273
2275 const KIID_PATH& aClipPath, bool aForceKeepAnnotations )
2276{
2277 wxCHECK( m_frame && aSymbol, /* void */ );
2278
2279 SCH_SYMBOL_INSTANCE newInstance;
2280 bool instanceFound = false;
2281 KIID_PATH pasteLookupPath = aClipPath;
2282
2283 m_pastedSymbols.insert( aSymbol );
2284
2285 for( const SCH_SYMBOL_INSTANCE& tmp : aSymbol->GetInstances() )
2286 {
2287 if( ( tmp.m_Path.empty() && aClipPath.empty() ) || ( !aClipPath.empty() && tmp.m_Path.EndsWith( aClipPath ) ) )
2288 {
2289 newInstance = tmp;
2290 instanceFound = true;
2291
2292 wxLogTrace( traceSchPaste, wxS( "Pasting found symbol instance with reference %s, unit %d:\n"
2293 "\tClipboard path: %s\n"
2294 "\tSymbol UUID: %s." ),
2295 tmp.m_Reference,
2296 tmp.m_Unit,
2297 aClipPath.AsString(),
2298 aSymbol->m_Uuid.AsString() );
2299
2300 break;
2301 }
2302 }
2303
2304 // The pasted symbol look up paths include the symbol UUID.
2305 pasteLookupPath.push_back( aSymbol->m_Uuid );
2306
2307 if( !instanceFound )
2308 {
2309 wxLogTrace( traceSchPaste, wxS( "Clipboard symbol instance **not** found:\n\tClipboard path: %s\n"
2310 "\tSymbol UUID: %s." ),
2311 aClipPath.AsString(),
2312 aSymbol->m_Uuid.AsString() );
2313
2314 // Some legacy versions saved value fields escaped. While we still do in the symbol
2315 // editor, we don't anymore in the schematic, so be sure to unescape them.
2316 SCH_FIELD* valueField = aSymbol->GetField( FIELD_T::VALUE );
2317 valueField->SetText( UnescapeString( valueField->GetText() ) );
2318
2319 // Pasted from notepad or an older instance of eeschema. Use the values in the fields
2320 // instead.
2321 newInstance.m_Reference = aSymbol->GetField( FIELD_T::REFERENCE )->GetText();
2322 newInstance.m_Unit = aSymbol->GetUnit();
2323 }
2324
2325 newInstance.m_Path = aPastePath.Path();
2326 newInstance.m_ProjectName = m_frame->Prj().GetProjectName();
2327
2328 aSymbol->AddHierarchicalReference( newInstance );
2329
2330 if( !aForceKeepAnnotations )
2331 aSymbol->ClearAnnotation( &aPastePath, false );
2332
2333 // We might clear annotations but always leave the original unit number from the paste.
2334 aSymbol->SetUnit( newInstance.m_Unit );
2335}
2336
2337
2339 const KIID_PATH& aClipPath, bool aForceKeepAnnotations,
2340 SCH_SHEET_LIST* aPastedSheets, std::map<SCH_SHEET_PATH,
2341 SCH_REFERENCE_LIST>& aPastedSymbols )
2342{
2343 wxCHECK( aSheet && aPastedSheets, aPastePath );
2344
2345 SCH_SHEET_PATH sheetPath = aPastePath;
2346 sheetPath.push_back( aSheet );
2347
2348 aPastedSheets->push_back( sheetPath );
2349
2350 if( aSheet->GetScreen() == nullptr )
2351 return sheetPath; // We can only really set the page number but not load any items
2352
2353 for( SCH_ITEM* item : aSheet->GetScreen()->Items() )
2354 {
2355 if( item->IsConnectable() )
2356 item->SetConnectivityDirty();
2357
2358 if( item->Type() == SCH_SYMBOL_T )
2359 {
2360 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2361
2362 wxCHECK2( symbol, continue );
2363
2364 // Only do this once if the symbol is shared across multiple sheets.
2365 if( !m_pastedSymbols.count( symbol ) )
2366 {
2367 for( SCH_PIN* pin : symbol->GetPins() )
2368 {
2369 const_cast<KIID&>( pin->m_Uuid ) = KIID();
2370 pin->SetConnectivityDirty();
2371 }
2372 }
2373
2374 updatePastedSymbol( symbol, sheetPath, aClipPath, aForceKeepAnnotations );
2375 }
2376 else if( item->Type() == SCH_SHEET_T )
2377 {
2378 SCH_SHEET* subsheet = static_cast<SCH_SHEET*>( item );
2379
2380 wxCHECK2( subsheet, continue );
2381
2382 // Make sure pins get a new UUID and set the dirty connectivity flag.
2383 if( !aPastedSheets->ContainsSheet( subsheet ) )
2384 {
2385 for( SCH_SHEET_PIN* pin : subsheet->GetPins() )
2386 {
2387 const_cast<KIID&>( pin->m_Uuid ) = KIID();
2388 pin->SetConnectivityDirty();
2389 }
2390 }
2391
2392 KIID_PATH newClipPath = aClipPath;
2393 newClipPath.push_back( subsheet->m_Uuid );
2394
2395 updatePastedSheet( subsheet, sheetPath, newClipPath, aForceKeepAnnotations, aPastedSheets, aPastedSymbols );
2396 }
2397 }
2398
2399 sheetPath.GetSymbols( aPastedSymbols[aPastePath], SYMBOL_FILTER_ALL );
2400
2401 return sheetPath;
2402}
2403
2404
2406{
2407 wxCHECK( aScreen, /* void */ );
2408
2409 for( const SCH_ITEM* item : aScreen->Items() )
2410 {
2411 if( item->Type() == SCH_SYMBOL_T )
2412 {
2413 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( item );
2414
2415 wxCHECK2( symbol, continue );
2416
2417 for( const SCH_SYMBOL_INSTANCE& symbolInstance : symbol->GetInstances() )
2418 {
2419 KIID_PATH pathWithSymbol = symbolInstance.m_Path;
2420
2421 pathWithSymbol.push_back( symbol->m_Uuid );
2422
2423 m_clipboardSymbolInstances[pathWithSymbol] = symbolInstance;
2424 }
2425 }
2426 }
2427}
2428
2429
2431{
2432 wxCHECK( m_frame, /* void */ );
2433
2434 for( SCH_SYMBOL* symbol : m_pastedSymbols )
2435 {
2436 wxCHECK2( symbol, continue );
2437
2438 std::vector<KIID_PATH> instancePathsToRemove;
2439
2440 for( const SCH_SYMBOL_INSTANCE& instance : symbol->GetInstances() )
2441 {
2442 if( instance.m_ProjectName != m_frame->Prj().GetProjectName() || instance.m_Path.empty() )
2443 instancePathsToRemove.emplace_back( instance.m_Path );
2444 }
2445
2446 for( const KIID_PATH& path : instancePathsToRemove )
2447 symbol->RemoveInstance( path );
2448 }
2449}
2450
2451
2453{
2454 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( wxWindow::FindFocus() );
2455
2456 if( textEntry )
2457 {
2458 textEntry->Paste();
2459 return 0;
2460 }
2461
2462 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
2463 std::string content;
2464 VECTOR2I eventPos;
2465
2466 SCH_SHEET tempSheet;
2467
2468 // Priority for paste:
2469 // 1. application/kicad format (handled by GetClipboardUTF8 which checks this first)
2470 // 2. Text data that can be parsed as KiCad S-expressions
2471 // 3. Bitmap/image data (fallback only if no valid text content)
2472 if( aEvent.IsAction( &ACTIONS::duplicate ) )
2473 content = m_duplicateClipboard;
2474 else
2475 content = GetClipboardUTF8();
2476
2477 // Only fall back to image data if there's no text content
2478 if( content.empty() )
2479 {
2480 std::unique_ptr<wxBitmap> clipImg = GetImageFromClipboard();
2481
2482 if( clipImg )
2483 {
2484 auto bitmap = std::make_unique<SCH_BITMAP>();
2485
2486 if( bitmap->GetReferenceImage().SetImage( clipImg->ConvertToImage() ) )
2487 return m_toolMgr->RunAction( SCH_ACTIONS::placeImage, bitmap.release() );
2488 }
2489
2490 return 0;
2491 }
2492
2493 if( aEvent.IsAction( &ACTIONS::duplicate ) )
2494 eventPos = getViewControls()->GetCursorPosition( false );
2495
2496 STRING_LINE_READER reader( content, "Clipboard" );
2497 SCH_IO_KICAD_SEXPR plugin;
2498
2499 // Screen object on heap is owned by the sheet.
2500 SCH_SCREEN* tempScreen = new SCH_SCREEN( &m_frame->Schematic() );
2501 tempSheet.SetScreen( tempScreen );
2502
2503 try
2504 {
2505 plugin.LoadContent( reader, &tempSheet );
2506 }
2507 catch( IO_ERROR& )
2508 {
2509 // If it wasn't schematic content, paste as a text object
2510 {
2511 if( content.size() > static_cast<size_t>( ADVANCED_CFG::GetCfg().m_MaxPastedTextLength ) )
2512 {
2513 int result = IsOK( m_frame, _( "Pasting a long text text string may be very slow. "
2514 "Do you want to continue?" ) );
2515 if( !result )
2516 return 0;
2517 }
2518
2519 SCH_TEXT* text_item = new SCH_TEXT( VECTOR2I( 0, 0 ), content );
2520 tempScreen->Append( text_item );
2521 }
2522 }
2523
2524 SELECTION& currentSelection = selTool->GetSelection();
2525
2526 bool hasTableCells = false;
2527
2528 for( EDA_ITEM* item : currentSelection )
2529 {
2530 if( item->Type() == SCH_TABLECELL_T )
2531 {
2532 hasTableCells = true;
2533 break;
2534 }
2535 }
2536
2537 if( hasTableCells )
2538 {
2539 SCH_TABLE* clipboardTable = nullptr;
2540
2541 for( SCH_ITEM* item : tempScreen->Items() )
2542 {
2543 if( item->Type() == SCH_TABLE_T )
2544 {
2545 clipboardTable = static_cast<SCH_TABLE*>( item );
2546 break;
2547 }
2548 }
2549
2550 if( clipboardTable )
2551 {
2552 SCH_EDIT_TABLE_TOOL* tableEditTool = m_toolMgr->GetTool<SCH_EDIT_TABLE_TOOL>();
2553
2554 if( tableEditTool )
2555 {
2556 wxString errorMsg;
2557
2558 if( !tableEditTool->validatePasteIntoSelection( currentSelection, errorMsg ) )
2559 {
2560 DisplayError( m_frame, errorMsg );
2561 return 0;
2562 }
2563
2564 SCH_COMMIT commit( m_toolMgr );
2565
2566 if( tableEditTool->pasteCellsIntoSelection( currentSelection, clipboardTable, commit ) )
2567 {
2568 commit.Push( _( "Paste Cells" ) );
2569 return 0;
2570 }
2571 else
2572 {
2573 DisplayError( m_frame, _( "Failed to paste cells" ) );
2574 return 0;
2575 }
2576 }
2577 }
2578 }
2579
2580 m_pastedSymbols.clear();
2582
2583 // Save pasted symbol instances in case the user chooses to keep existing symbol annotation.
2584 setPastedSymbolInstances( tempScreen );
2585
2586 tempScreen->MigrateSimModels();
2587
2588 bool annotateAutomatic = m_frame->eeconfig()->m_AnnotatePanel.automatic;
2589 SCHEMATIC_SETTINGS& schematicSettings = m_frame->Schematic().Settings();
2590 int annotateStartNum = schematicSettings.m_AnnotateStartNum;
2591
2593 bool forceRemoveAnnotations = false;
2594
2595 if( aEvent.IsAction( &ACTIONS::pasteSpecial ) )
2596 {
2597 PASTE_MODE defaultPasteMode = pasteMode;
2598 DIALOG_PASTE_SPECIAL dlg( m_frame, &pasteMode );
2599
2600 if( dlg.ShowModal() == wxID_CANCEL )
2601 return 0;
2602
2603 // We have to distinguish if removing was explicit
2604 forceRemoveAnnotations = pasteMode == PASTE_MODE::REMOVE_ANNOTATIONS && pasteMode != defaultPasteMode;
2605 }
2606
2607 bool forceKeepAnnotations = pasteMode != PASTE_MODE::REMOVE_ANNOTATIONS;
2608
2609 // SCH_SEXP_PLUGIN added the items to the paste screen, but not to the view or anything
2610 // else. Pull them back out to start with.
2611 SCH_COMMIT commit( m_toolMgr );
2612 EDA_ITEMS loadedItems;
2613 std::vector<SCH_ITEM*> sortedLoadedItems;
2614 bool sheetsPasted = false;
2615 SCH_SHEET_LIST hierarchy = m_frame->Schematic().Hierarchy();
2616 SCH_SHEET_PATH& pasteRoot = m_frame->GetCurrentSheet();
2617 wxFileName destFn = pasteRoot.Last()->GetFileName();
2618
2619 if( destFn.IsRelative() )
2620 destFn.MakeAbsolute( m_frame->Prj().GetProjectPath() );
2621
2622 // List of paths in the hierarchy that refer to the destination sheet of the paste
2623 SCH_SHEET_LIST sheetPathsForScreen = hierarchy.FindAllSheetsForScreen( pasteRoot.LastScreen() );
2624 sheetPathsForScreen.SortByPageNumbers();
2625
2626 // Build a list of screens from the current design (to avoid loading sheets that already exist)
2627 std::map<wxString, SCH_SCREEN*> loadedScreens;
2628
2629 for( const SCH_SHEET_PATH& item : hierarchy )
2630 {
2631 if( item.LastScreen() )
2632 loadedScreens[item.Last()->GetFileName()] = item.LastScreen();
2633 }
2634
2635 // Get set of sheet names in the current schematic to prevent duplicate sheet names on paste.
2636 std::set<wxString> existingSheetNames = pasteRoot.LastScreen()->GetSheetNames();
2637
2638 // Build symbol list for reannotation of duplicates
2639 SCH_REFERENCE_LIST existingRefs;
2640 hierarchy.GetSymbols( existingRefs, SYMBOL_FILTER_ALL );
2641 existingRefs.SortByReferenceOnly();
2642
2643 std::set<wxString> existingRefsSet;
2644
2645 for( const SCH_REFERENCE& ref : existingRefs )
2646 existingRefsSet.insert( ref.GetRef() );
2647
2648 // Build UUID map for fetching last-resolved-properties
2649 std::map<KIID, EDA_ITEM*> itemMap;
2650 hierarchy.FillItemMap( itemMap );
2651
2652 // Keep track of pasted sheets and symbols for the different paths to the hierarchy.
2653 std::map<SCH_SHEET_PATH, SCH_REFERENCE_LIST> pastedSymbols;
2654 std::map<SCH_SHEET_PATH, SCH_SHEET_LIST> pastedSheets;
2655
2656 for( SCH_ITEM* item : tempScreen->Items() )
2657 {
2658 if( item->Type() == SCH_SHEET_T )
2659 sortedLoadedItems.push_back( item );
2660 else
2661 loadedItems.push_back( item );
2662 }
2663
2664 sort( sortedLoadedItems.begin(), sortedLoadedItems.end(),
2665 []( SCH_ITEM* firstItem, SCH_ITEM* secondItem )
2666 {
2667 SCH_SHEET* firstSheet = static_cast<SCH_SHEET*>( firstItem );
2668 SCH_SHEET* secondSheet = static_cast<SCH_SHEET*>( secondItem );
2669 return StrNumCmp( firstSheet->GetName(), secondSheet->GetName(), false ) < 0;
2670 } );
2671
2672
2673 for( SCH_ITEM* item : sortedLoadedItems )
2674 {
2675 loadedItems.push_back( item );
2676
2677 if( item->Type() == SCH_SHEET_T )
2678 {
2679 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
2680 wxFileName srcFn = sheet->GetFileName();
2681
2682 if( srcFn.IsRelative() )
2683 srcFn.MakeAbsolute( m_frame->Prj().GetProjectPath() );
2684
2685 SCH_SHEET_LIST sheetHierarchy( sheet );
2686
2687 if( hierarchy.TestForRecursion( sheetHierarchy, destFn.GetFullPath( wxPATH_UNIX ) ) )
2688 {
2689 auto msg = wxString::Format( _( "The pasted sheet '%s'\n"
2690 "was dropped because the destination already has "
2691 "the sheet or one of its subsheets as a parent." ),
2692 sheet->GetFileName() );
2693 DisplayError( m_frame, msg );
2694 loadedItems.pop_back();
2695 }
2696 }
2697 }
2698
2699 // Remove the references from our temporary screen to prevent freeing on the DTOR
2700 tempScreen->Clear( false );
2701
2702 for( EDA_ITEM* item : loadedItems )
2703 {
2704 KIID_PATH clipPath( wxT( "/" ) ); // clipboard is at root
2705
2706 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item );
2707
2708 wxCHECK2( schItem, continue );
2709
2710 if( schItem->IsConnectable() )
2711 schItem->SetConnectivityDirty();
2712
2713 // Clear lock state on paste to match PCB editor behavior
2714 schItem->SetLocked( false );
2715
2716 if( item->Type() == SCH_SYMBOL_T )
2717 {
2718 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2719
2720 // The library symbol gets set from the cached library symbols in the current
2721 // schematic not the symbol libraries. The cached library symbol may have
2722 // changed from the original library symbol which would cause the copy to
2723 // be incorrect.
2724 SCH_SCREEN* currentScreen = m_frame->GetScreen();
2725
2726 wxCHECK2( currentScreen, continue );
2727
2728 // First get the library symbol from the clipboard (if available)
2729 auto clipIt = tempScreen->GetLibSymbols().find( symbol->GetSchSymbolLibraryName() );
2730 LIB_SYMBOL* clipLibSymbol = ( clipIt != tempScreen->GetLibSymbols().end() )
2731 ? clipIt->second
2732 : nullptr;
2733
2734 // Then check the current screen
2735 auto it = currentScreen->GetLibSymbols().find( symbol->GetSchSymbolLibraryName() );
2736 auto end = currentScreen->GetLibSymbols().end();
2737
2738 LIB_SYMBOL* libSymbol = nullptr;
2739
2740 if( it != end && clipLibSymbol )
2741 {
2742 // Both exist - check if power types match. If they differ (e.g., one is
2743 // local power and the other is global power), use the clipboard version
2744 // to preserve the copied symbol's power type.
2745 if( clipLibSymbol->IsLocalPower() != it->second->IsLocalPower()
2746 || clipLibSymbol->IsGlobalPower() != it->second->IsGlobalPower() )
2747 {
2748 libSymbol = new LIB_SYMBOL( *clipLibSymbol );
2749 }
2750 else
2751 {
2752 libSymbol = new LIB_SYMBOL( *it->second );
2753 }
2754 }
2755 else if( it != end )
2756 {
2757 libSymbol = new LIB_SYMBOL( *it->second );
2758 }
2759 else if( clipLibSymbol )
2760 {
2761 libSymbol = new LIB_SYMBOL( *clipLibSymbol );
2762 }
2763
2764 if( libSymbol )
2765 symbol->SetLibSymbol( libSymbol );
2766
2767 // If the symbol is already in the schematic we have to always keep the annotations. The exception
2768 // is if the user has chosen to remove them.
2769 for( const SCH_SYMBOL_INSTANCE& instance : symbol->GetInstances() )
2770 {
2771 if( !existingRefsSet.contains( instance.m_Reference ) )
2772 {
2773 forceKeepAnnotations = !forceRemoveAnnotations;
2774 break;
2775 }
2776 }
2777
2778 for( SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
2779 updatePastedSymbol( symbol, sheetPath, clipPath, forceKeepAnnotations );
2780
2781 // Most modes will need new KIIDs for the symbol and its pins. However, if we are pasting
2782 // unique annotations, we need to check if the symbol is not already in the hierarchy. If we
2783 // don't already have a copy of the symbol, we just keep the existing KIID data as it is likely
2784 // the same symbol being moved around the schematic.
2785 bool needsNewKiid = ( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS );
2786
2787 for( const SCH_SYMBOL_INSTANCE& instance : symbol->GetInstances() )
2788 {
2789 if( existingRefsSet.contains( instance.m_Reference ) )
2790 {
2791 needsNewKiid = true;
2792 break;
2793 }
2794 }
2795
2796 if( needsNewKiid )
2797 {
2798 // Assign a new KIID
2799 const_cast<KIID&>( item->m_Uuid ) = KIID();
2800
2801 // Make sure pins get a new UUID
2802 for( SCH_PIN* pin : symbol->GetPins() )
2803 {
2804 const_cast<KIID&>( pin->m_Uuid ) = KIID();
2805 pin->SetConnectivityDirty();
2806 }
2807
2808 for( SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
2809 {
2810 // Ignore symbols from a non-existant library.
2811 if( libSymbol )
2812 {
2813 SCH_REFERENCE schReference( symbol, sheetPath );
2814 schReference.SetSheetNumber( sheetPath.GetPageNumberAsInt() );
2815 pastedSymbols[sheetPath].AddItem( schReference );
2816 }
2817 }
2818 }
2819 }
2820 else if( item->Type() == SCH_SHEET_T )
2821 {
2822 SCH_SHEET* sheet = (SCH_SHEET*) item;
2823 SCH_FIELD* nameField = sheet->GetField( FIELD_T::SHEET_NAME );
2824 wxString baseName = nameField->GetText();
2825 wxString candidateName = baseName;
2826 wxString number;
2827
2828 while( !baseName.IsEmpty() && wxIsdigit( baseName.Last() ) )
2829 {
2830 number = baseName.Last() + number;
2831 baseName.RemoveLast();
2832 }
2833
2834 // Update hierarchy to include any other sheets we already added, avoiding
2835 // duplicate sheet names
2836 hierarchy = m_frame->Schematic().Hierarchy();
2837
2838 int uniquifier = std::max( 0, wxAtoi( number ) ) + 1;
2839
2840 while( existingSheetNames.count( candidateName ) )
2841 candidateName = wxString::Format( wxT( "%s%d" ), baseName, uniquifier++ );
2842
2843 nameField->SetText( candidateName );
2844 existingSheetNames.emplace( candidateName );
2845
2846 wxFileName fn = sheet->GetFileName();
2847 SCH_SCREEN* existingScreen = nullptr;
2848
2849 sheet->SetParent( pasteRoot.Last() );
2850 sheet->SetScreen( nullptr );
2851
2852 if( !fn.IsAbsolute() )
2853 {
2854 wxFileName currentSheetFileName = pasteRoot.LastScreen()->GetFileName();
2855 fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS, currentSheetFileName.GetPath() );
2856 }
2857
2858 // Try to find the screen for the pasted sheet by several means
2859 if( !m_frame->Schematic().Root().SearchHierarchy( fn.GetFullPath( wxPATH_UNIX ), &existingScreen ) )
2860 {
2861 if( loadedScreens.count( sheet->GetFileName() ) > 0 )
2862 existingScreen = loadedScreens.at( sheet->GetFileName() );
2863 else
2864 searchSupplementaryClipboard( sheet->GetFileName(), &existingScreen );
2865 }
2866
2867 if( existingScreen )
2868 {
2869 sheet->SetScreen( existingScreen );
2870 }
2871 else
2872 {
2873 if( !m_frame->LoadSheetFromFile( sheet, &pasteRoot, fn.GetFullPath() ) )
2874 m_frame->InitSheet( sheet, sheet->GetFileName() );
2875 }
2876
2877 // Save the symbol instances in case the user chooses to keep the existing
2878 // symbol annotation.
2880 sheetsPasted = true;
2881
2882 // Push it to the clipboard path while it still has its old KIID
2883 clipPath.push_back( sheet->m_Uuid );
2884
2885 // Assign a new KIID to the pasted sheet
2886 const_cast<KIID&>( sheet->m_Uuid ) = KIID();
2887
2888 // Make sure pins get a new UUID
2889 for( SCH_SHEET_PIN* pin : sheet->GetPins() )
2890 {
2891 const_cast<KIID&>( pin->m_Uuid ) = KIID();
2892 pin->SetConnectivityDirty();
2893 }
2894
2895 // Once we have our new KIID we can update all pasted instances. This will either
2896 // reset the annotations or copy "kept" annotations from the supplementary clipboard.
2897 for( SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
2898 {
2899 SCH_SHEET_PATH subPath = updatePastedSheet( sheet, sheetPath, clipPath,
2900 ( forceKeepAnnotations && annotateAutomatic ),
2901 &pastedSheets[sheetPath], pastedSymbols );
2902 }
2903 }
2904 else
2905 {
2906 SCH_ITEM* srcItem = dynamic_cast<SCH_ITEM*>( itemMap[item->m_Uuid] );
2907 SCH_ITEM* destItem = dynamic_cast<SCH_ITEM*>( item );
2908
2909 // Everything gets a new KIID
2910 const_cast<KIID&>( item->m_Uuid ) = KIID();
2911
2912 if( srcItem && destItem )
2913 {
2914 destItem->SetConnectivityDirty( true );
2915 destItem->SetLastResolvedState( srcItem );
2916 }
2917 }
2918
2919 // Lines need both ends selected for a move after paste so the whole line moves.
2920 if( item->Type() == SCH_LINE_T )
2921 item->SetFlags( STARTPOINT | ENDPOINT );
2922
2923 item->SetFlags( IS_NEW | IS_PASTED | IS_MOVING );
2924
2925 if( !m_frame->GetScreen()->CheckIfOnDrawList( (SCH_ITEM*) item ) ) // don't want a loop!
2926 m_frame->AddToScreen( item, m_frame->GetScreen() );
2927
2928 commit.Added( (SCH_ITEM*) item, m_frame->GetScreen() );
2929
2930 // Start out hidden so the pasted items aren't "ghosted" in their original location
2931 // before being moved to the current location.
2932 getView()->Hide( item, true );
2933 }
2934
2935 if( sheetsPasted )
2936 {
2937 // The full schematic hierarchy need to be update before assigning new annotation and page numbers.
2938 m_frame->Schematic().RefreshHierarchy();
2939
2940 // Update sheet instance page and virtual page numbers to ensure annotation works correctly.
2941 for( SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
2942 {
2943 for( SCH_SHEET_PATH& pastedSheet : pastedSheets[sheetPath] )
2944 {
2945 // Find next free string page number for the sheet instance.
2946 int page = 1;
2947 wxString pageNum = wxString::Format( "%d", page );
2948
2949 while( hierarchy.PageNumberExists( pageNum ) )
2950 pageNum = wxString::Format( "%d", ++page );
2951
2952 int virtualPageNumber = page;
2953
2954 // The virtual page and sheet instance page numbers do not necessarily track. Increment by one
2955 // to ensure the annotation sheet paths all have unique virtual page numbers.
2956 if( page == hierarchy.GetLastVirtualPageNumber() )
2957 virtualPageNumber = hierarchy.GetLastVirtualPageNumber() + 1;
2958
2959 pastedSheet.SetVirtualPageNumber( virtualPageNumber );
2960
2961 SCH_SHEET_INSTANCE sheetInstance;
2962
2963 sheetInstance.m_Path = pastedSheet.Path();
2964
2965 // Don't include the actual sheet in the instance path.
2966 sheetInstance.m_Path.pop_back();
2967 sheetInstance.m_PageNumber = pageNum;
2968 sheetInstance.m_ProjectName = m_frame->Prj().GetProjectName();
2969
2970 SCH_SHEET* sheet = pastedSheet.Last();
2971
2972 wxCHECK2( sheet, continue );
2973
2974 sheet->AddInstance( sheetInstance );
2975 hierarchy.push_back( pastedSheet );
2976
2977 // Remove all pasted sheet instance data that is not part of the current project.
2978 std::vector<KIID_PATH> instancesToRemove;
2979
2980 for( const SCH_SHEET_INSTANCE& instance : sheet->GetInstances() )
2981 {
2982 if( !hierarchy.HasPath( instance.m_Path ) )
2983 instancesToRemove.push_back( instance.m_Path );
2984 }
2985
2986 for( const KIID_PATH& instancePath : instancesToRemove )
2987 sheet->RemoveInstance( instancePath );
2988
2989 // The sheet paths for the annotation code where copied in updatePastedSheets() when the virtual
2990 // page number was still 1. Set the virtual page number in the copied sheet paths.
2991 for( auto&[path, refs] : pastedSymbols )
2992 {
2993 for( SCH_REFERENCE& ref : refs )
2994 {
2995 if( ref.GetSheetPath() == pastedSheet )
2996 {
2997 ref.GetSheetPath().SetVirtualPageNumber( virtualPageNumber );
2998 ref.SetSheetNumber( virtualPageNumber );
2999 }
3000 }
3001 }
3002 }
3003 }
3004
3005 m_frame->SetSheetNumberAndCount();
3006
3007 // Get a version with correct sheet numbers since we've pasted sheets,
3008 // we'll need this when annotating next
3009 hierarchy = m_frame->Schematic().Hierarchy();
3010 }
3011
3012 std::map<SCH_SHEET_PATH, SCH_REFERENCE_LIST> annotatedSymbols;
3013
3014 // Update the list of symbol instances that satisfy the annotation criteria.
3015 for( const SCH_SHEET_PATH& sheetPath : sheetPathsForScreen )
3016 {
3017 for( size_t i = 0; i < pastedSymbols[sheetPath].GetCount(); i++ )
3018 {
3019 if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS || pastedSymbols[sheetPath][i].AlwaysAnnotate() )
3020 annotatedSymbols[sheetPath].AddItem( pastedSymbols[sheetPath][i] );
3021 }
3022
3023 for( const SCH_SHEET_PATH& pastedSheetPath : pastedSheets[sheetPath] )
3024 {
3025 for( size_t i = 0; i < pastedSymbols[pastedSheetPath].GetCount(); i++ )
3026 {
3027 if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS || pastedSymbols[pastedSheetPath][i].AlwaysAnnotate() )
3028 annotatedSymbols[pastedSheetPath].AddItem( pastedSymbols[pastedSheetPath][i] );
3029 }
3030 }
3031 }
3032
3033 if( !annotatedSymbols.empty() )
3034 {
3035 ANNOTATE_ORDER_T annotateOrder = static_cast<ANNOTATE_ORDER_T>( schematicSettings.m_AnnotateSortOrder );
3036 ANNOTATE_ALGO_T annotateAlgo = static_cast<ANNOTATE_ALGO_T>( schematicSettings.m_AnnotateMethod );
3037
3038 for( SCH_SHEET_PATH& path : sheetPathsForScreen )
3039 {
3040 annotatedSymbols[path].SortByReferenceOnly();
3041 annotatedSymbols[path].SetRefDesTracker( schematicSettings.m_refDesTracker );
3042
3043 if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS )
3044 {
3045 annotatedSymbols[path].ReannotateDuplicates( existingRefs, annotateAlgo );
3046 }
3047 else
3048 {
3049 annotatedSymbols[path].ReannotateByOptions( annotateOrder, annotateAlgo, annotateStartNum,
3050 existingRefs, false, &hierarchy );
3051 }
3052
3053 annotatedSymbols[path].UpdateAnnotation();
3054
3055 // Update existing refs for next iteration
3056 for( size_t i = 0; i < annotatedSymbols[path].GetCount(); i++ )
3057 existingRefs.AddItem( annotatedSymbols[path][i] );
3058
3059 for( const SCH_SHEET_PATH& pastedSheetPath : pastedSheets[path] )
3060 {
3061 annotatedSymbols[pastedSheetPath].SortByReferenceOnly();
3062 annotatedSymbols[pastedSheetPath].SetRefDesTracker( schematicSettings.m_refDesTracker );
3063
3064 if( pasteMode == PASTE_MODE::UNIQUE_ANNOTATIONS )
3065 {
3066 annotatedSymbols[pastedSheetPath].ReannotateDuplicates( existingRefs, annotateAlgo );
3067 }
3068 else
3069 {
3070 annotatedSymbols[pastedSheetPath].ReannotateByOptions( annotateOrder, annotateAlgo,
3071 annotateStartNum, existingRefs,
3072 false, &hierarchy );
3073 }
3074
3075 annotatedSymbols[pastedSheetPath].UpdateAnnotation();
3076
3077 // Update existing refs for next iteration
3078 for( size_t i = 0; i < annotatedSymbols[pastedSheetPath].GetCount(); i++ )
3079 existingRefs.AddItem( annotatedSymbols[pastedSheetPath][i] );
3080 }
3081 }
3082 }
3083
3084 m_frame->GetCurrentSheet().UpdateAllScreenReferences();
3085
3086 // The copy operation creates instance paths that are not valid for the current project or
3087 // saved as part of another project. Prune them now so they do not accumulate in the saved
3088 // schematic file.
3090
3091 SCH_SHEET_LIST sheets = m_frame->Schematic().Hierarchy();
3092 SCH_SCREENS allScreens( m_frame->Schematic().Root() );
3093
3094 allScreens.PruneOrphanedSymbolInstances( m_frame->Prj().GetProjectName(), sheets );
3095 allScreens.PruneOrphanedSheetInstances( m_frame->Prj().GetProjectName(), sheets );
3096
3097 // Now clear the previous selection, select the pasted items, and fire up the "move" tool.
3098 m_toolMgr->RunAction( ACTIONS::selectionClear );
3099
3100 // If the item has a parent group, it will be part of the loadedItems, and will handle
3101 // the move action. Iterate backwards to avoid invalidating the iterator.
3102 for( int i = loadedItems.size() - 1; i >= 0; i-- )
3103 {
3104 EDA_ITEM* item = loadedItems[i];
3105
3106 if( item->GetParentGroup() )
3107 {
3108 loadedItems.erase( loadedItems.begin() + i );
3109 // These were hidden before because they would be added to the move preview,
3110 // but now they need to be shown as a preview so they appear to move when
3111 // the group moves.
3112 getView()->SetVisible( item );
3113 getView()->AddToPreview( item, false );
3114 }
3115 }
3116
3117 m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &loadedItems );
3118
3119 SCH_SELECTION& selection = selTool->GetSelection();
3120
3121 if( !selection.Empty() )
3122 {
3123 if( aEvent.IsAction( &ACTIONS::duplicate ) )
3124 {
3125 int closest_dist = INT_MAX;
3126
3127 auto processPt =
3128 [&]( const VECTOR2I& pt )
3129 {
3130 int dist = ( eventPos - pt ).EuclideanNorm();
3131
3132 if( dist < closest_dist )
3133 {
3134 selection.SetReferencePoint( pt );
3135 closest_dist = dist;
3136 }
3137 };
3138
3139 // Prefer connection points (which should remain on grid)
3140 for( EDA_ITEM* item : selection.Items() )
3141 {
3142 SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item );
3143 SCH_PIN* pin = dynamic_cast<SCH_PIN*>( item );
3144
3145 if( sch_item && sch_item->IsConnectable() )
3146 {
3147 for( const VECTOR2I& pt : sch_item->GetConnectionPoints() )
3148 processPt( pt );
3149 }
3150 else if( pin )
3151 {
3152 processPt( pin->GetPosition() );
3153 }
3154
3155 // Symbols need to have their center point added since often users are trying to
3156 // move parts from their center.
3157 if( dynamic_cast<SCH_SYMBOL*>( item ) )
3158 processPt( item->GetPosition() );
3159 }
3160
3161 // Only process other points if we didn't find any connection points
3162 if( closest_dist == INT_MAX )
3163 {
3164 for( EDA_ITEM* item : selection.Items() )
3165 {
3166 switch( item->Type() )
3167 {
3168 case SCH_LINE_T:
3169 processPt( static_cast<SCH_LINE*>( item )->GetStartPoint() );
3170 processPt( static_cast<SCH_LINE*>( item )->GetEndPoint() );
3171 break;
3172
3173 case SCH_SHAPE_T:
3174 {
3175 SCH_SHAPE* shape = static_cast<SCH_SHAPE*>( item );
3176
3177 switch( shape->GetShape() )
3178 {
3179 case SHAPE_T::RECTANGLE:
3180 for( const VECTOR2I& pt : shape->GetRectCorners() )
3181 processPt( pt );
3182
3183 break;
3184
3185 case SHAPE_T::CIRCLE:
3186 processPt( shape->GetCenter() );
3187 break;
3188
3189 case SHAPE_T::POLY:
3190 for( int ii = 0; ii < shape->GetPolyShape().TotalVertices(); ++ii )
3191 processPt( shape->GetPolyShape().CVertex( ii ) );
3192
3193 break;
3194
3195 default:
3196 processPt( shape->GetStart() );
3197 processPt( shape->GetEnd() );
3198 break;
3199 }
3200
3201 break;
3202 }
3203
3204 default:
3205 processPt( item->GetPosition() );
3206 break;
3207 }
3208 }
3209 }
3210
3211 selection.SetIsHover( m_duplicateIsHoverSelection );
3212 }
3213 // We want to the first non-group item in the selection to be the reference point.
3214 else if( selection.GetTopLeftItem()->Type() == SCH_GROUP_T )
3215 {
3216 SCH_GROUP* group = static_cast<SCH_GROUP*>( selection.GetTopLeftItem() );
3217
3218 bool found = false;
3219 SCH_ITEM* item = nullptr;
3220
3221 group->RunOnChildren(
3222 [&]( SCH_ITEM* schItem )
3223 {
3224 if( !found && schItem->Type() != SCH_GROUP_T )
3225 {
3226 item = schItem;
3227 found = true;
3228 }
3229 },
3231
3232 if( found )
3233 selection.SetReferencePoint( item->GetPosition() );
3234 else
3235 selection.SetReferencePoint( group->GetPosition() );
3236 }
3237 else
3238 {
3239 SCH_ITEM* item = static_cast<SCH_ITEM*>( selection.GetTopLeftItem() );
3240
3241 selection.SetReferencePoint( item->GetPosition() );
3242 }
3243
3244 if( m_toolMgr->RunSynchronousAction( SCH_ACTIONS::move, &commit ) )
3245 {
3246 // Pushing the commit will update the connectivity.
3247 commit.Push( _( "Paste" ) );
3248
3249 if( sheetsPasted )
3250 {
3251 m_frame->UpdateHierarchyNavigator();
3252 // UpdateHierarchyNavigator() will call RefreshNetNavigator()
3253 }
3254 else
3255 {
3256 m_frame->RefreshNetNavigator();
3257 }
3258 }
3259 else
3260 {
3261 commit.Revert();
3262 }
3263
3264 getView()->ClearPreview();
3265 }
3266
3267 return 0;
3268}
3269
3270
3272{
3273 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
3274 SCH_SELECTION& selection = selTool->RequestSelection( { SCH_SYMBOL_T } );
3275 SCH_SYMBOL* symbol = nullptr;
3276 SYMBOL_EDIT_FRAME* symbolEditor;
3277
3278 if( selection.GetSize() >= 1 )
3279 symbol = (SCH_SYMBOL*) selection.Front();
3280
3281 if( selection.IsHover() )
3282 m_toolMgr->RunAction( ACTIONS::selectionClear );
3283
3284 if( !symbol )
3285 {
3286 // Giant hack: by default we assign Edit Table to the same hotkey, so give the table
3287 // tool a chance to handle it if we can't.
3288 if( SCH_EDIT_TABLE_TOOL* tableTool = m_toolMgr->GetTool<SCH_EDIT_TABLE_TOOL>() )
3289 tableTool->EditTable( aEvent );
3290
3291 return 0;
3292 }
3293
3294 if( symbol->GetEditFlags() != 0 )
3295 return 0;
3296
3297 if( symbol->IsMissingLibSymbol() )
3298 {
3299 m_frame->ShowInfoBarError( _( "Symbols with broken library symbol links cannot be edited." ) );
3300 return 0;
3301 }
3302
3304 symbolEditor = (SYMBOL_EDIT_FRAME*) m_frame->Kiway().Player( FRAME_SCH_SYMBOL_EDITOR, false );
3305
3306 if( symbolEditor )
3307 {
3308 if( wxWindow* blocking_win = symbolEditor->Kiway().GetBlockingDialog() )
3309 blocking_win->Close( true );
3310
3311 if( aEvent.IsAction( &SCH_ACTIONS::editWithLibEdit ) )
3312 {
3313 symbolEditor->LoadSymbolFromSchematic( symbol );
3314 }
3316 {
3317 symbolEditor->LoadSymbol( symbol->GetLibId(), symbol->GetUnit(), symbol->GetBodyStyle() );
3318
3319 if( !symbolEditor->IsLibraryTreeShown() )
3320 symbolEditor->ToggleLibraryTree();
3321 }
3322 }
3323
3324 return 0;
3325}
3326
3327
3329{
3330 m_frame->OnAnnotate();
3331 return 0;
3332}
3333
3334
3336{
3338 dlg.m_FirstRefDes->SetValidator( wxTextValidator( wxFILTER_EMPTY ) );
3339
3340 dlg.SetInitialFocus( dlg.m_FirstRefDes );
3341
3342 if( dlg.ShowModal() == wxID_OK )
3343 {
3344 SCH_REFERENCE startRef;
3345 startRef.SetRef( dlg.m_FirstRefDes->GetValue() );
3346
3347 if( startRef.IsSplitNeeded() )
3348 startRef.Split();
3349 else
3350 return 0;
3351
3352 int startNum = atoi( startRef.GetRefNumber().utf8_string().c_str() );
3353
3354 SCH_COMMIT commit( m_frame );
3355 SCHEMATIC* schematic = m_frame->m_schematic;
3356 SCH_REFERENCE_LIST references;
3357
3358 if( dlg.m_AllSheets->GetValue() )
3359 schematic->Hierarchy().GetSymbols( references, SYMBOL_FILTER_ALL );
3360 else
3361 schematic->CurrentSheet().GetSymbols( references, SYMBOL_FILTER_ALL );
3362
3363 references.SplitReferences();
3364
3365 for( SCH_REFERENCE& ref : references )
3366 {
3367 if( ref.GetRef() == startRef.GetRef() )
3368 {
3369 int num = atoi( ref.GetRefNumber().utf8_string().c_str() );
3370
3371 if( num >= startNum )
3372 {
3373 const SCH_SHEET_PATH& sheet = ref.GetSheetPath();
3374 wxString fullRef = ref.GetRef();
3375
3376 num += dlg.m_Increment->GetValue();
3377 fullRef << num;
3378
3379 commit.Modify( ref.GetSymbol(), sheet.LastScreen(), RECURSE_MODE::NO_RECURSE );
3380 ref.GetSymbol()->SetRef( &sheet, From_UTF8( fullRef.c_str() ) );
3381 }
3382 }
3383 }
3384
3385 if( !commit.Empty() )
3386 commit.Push( _( "Increment Annotations" ) );
3387 }
3388
3389 return 0;
3390}
3391
3392
3394{
3395 m_frame->OnOpenCvpcb();
3396 return 0;
3397}
3398
3399
3401{
3402 m_frame->OnImportProject();
3403 return 0;
3404}
3405
3406
3408{
3409 DIALOG_SYMBOL_FIELDS_TABLE* dlg = m_frame->GetSymbolFieldsTableDialog();
3410
3411 if( !dlg )
3412 return 0;
3413
3414 // Needed at least on Windows. Raise() is not enough
3415 dlg->Show( true );
3416
3417 // Bring it to the top if already open. Dual monitor users need this.
3418 dlg->Raise();
3419
3420 dlg->ShowEditTab();
3421
3422 return 0;
3423}
3424
3425
3427{
3429 m_frame->HardRedraw();
3430
3431 return 0;
3432}
3433
3434
3436{
3437 m_frame->OnOpenPcbnew();
3438 return 0;
3439}
3440
3441
3443{
3444 m_frame->OnUpdatePCB();
3445 return 0;
3446}
3447
3448
3450{
3452 dlg.ShowModal();
3453 return 0;
3454}
3455
3456
3458{
3460
3461 // If a plugin is removed or added, rebuild and reopen the new dialog
3462 while( result == NET_PLUGIN_CHANGE )
3464
3465 return 0;
3466}
3467
3468
3470{
3471 DIALOG_SYMBOL_FIELDS_TABLE* dlg = m_frame->GetSymbolFieldsTableDialog();
3472
3473 if( !dlg )
3474 return 0;
3475
3476 // Needed at least on Windows. Raise() is not enough
3477 dlg->Show( true );
3478
3479 // Bring it to the top if already open. Dual monitor users need this.
3480 dlg->Raise();
3481
3482 dlg->ShowExportTab();
3483
3484 return 0;
3485}
3486
3487
3489{
3491 return 0;
3492}
3493
3494
3496{
3497 m_frame->RecalculateConnections( nullptr, LOCAL_CLEANUP );
3498
3499 // Create a selection with all items from the current sheet
3500 SCH_SELECTION sheetSelection;
3501 SCH_SCREEN* screen = m_frame->GetScreen();
3502
3503 for( SCH_ITEM* item : screen->Items() )
3504 {
3505 sheetSelection.Add( item );
3506 }
3507
3508 // Get the full page bounding box for rendering the complete sheet
3509 BOX2I pageBBox( VECTOR2I( 0, 0 ), m_frame->GetPageSizeIU() );
3510
3511 // Render the full sheet selection including the worksheet
3512 wxImage image = renderSelectionToImageForClipboard( m_frame, sheetSelection, pageBBox, true, true );
3513
3514 if( image.IsOk() )
3515 {
3516 wxLogNull doNotLog; // disable logging of failed clipboard actions
3517
3518 if( wxTheClipboard->Open() )
3519 {
3520 wxDataObjectComposite* data = new wxDataObjectComposite();
3521
3523
3524 wxTheClipboard->SetData( data );
3525 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
3526 wxTheClipboard->Close();
3527 }
3528 }
3529 else
3530 {
3531 wxLogMessage( _( "Cannot create the schematic image" ) );
3532 }
3533
3534 return 0;
3535}
3536
3537
3539{
3541 return 0;
3542}
3543
3544
3550
3551
3557
3558
3564
3565
3571
3572
3578
3579
3581{
3582 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3584
3586 m_frame->GetCanvas()->Refresh();
3587
3588 return 0;
3589}
3590
3591
3593{
3594 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3596
3597 m_frame->GetRenderSettings()->m_ShowHiddenFields = cfg->m_Appearance.show_hidden_fields;
3598
3600 m_frame->GetCanvas()->Refresh();
3601
3602 return 0;
3603}
3604
3605
3607{
3608 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3610
3612 m_frame->GetCanvas()->Refresh();
3613
3614 return 0;
3615}
3616
3617
3619{
3620 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3622
3624 m_frame->GetCanvas()->Refresh();
3625
3626 return 0;
3627}
3628
3629
3631{
3632 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3634
3636 m_frame->GetCanvas()->Refresh();
3637
3638 return 0;
3639}
3640
3641
3643{
3644 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3646
3647 m_frame->GetCanvas()->Refresh();
3648
3649 return 0;
3650}
3651
3652
3654{
3655 SCH_SHEET_PATH* sheetPath = &m_frame->GetCurrentSheet();
3656 wxString variant = m_frame->Schematic().GetCurrentVariant();
3657 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3659
3660 m_frame->GetCanvas()->GetView()->UpdateAllItemsConditionally(
3661 [&]( KIGFX::VIEW_ITEM* aItem ) -> int
3662 {
3663 int flags = 0;
3664
3665 auto invalidateTextVars =
3666 [&flags]( EDA_TEXT* text )
3667 {
3668 if( text->HasTextVars() )
3669 {
3670 text->ClearRenderCache();
3671 text->ClearBoundingBoxCache();
3673 }
3674 };
3675
3676 if( SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aItem ) )
3677 {
3678 item->RunOnChildren(
3679 [&invalidateTextVars]( SCH_ITEM* aChild )
3680 {
3681 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aChild ) )
3682 invalidateTextVars( text );
3683 },
3685
3686 if( item->GetExcludedFromSim( sheetPath, variant ) )
3688 }
3689
3690 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem ) )
3691 invalidateTextVars( text );
3692
3693 return flags;
3694 } );
3695
3696 m_frame->GetCanvas()->Refresh();
3697
3698 return 0;
3699}
3700
3701
3703{
3704 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3706
3708 m_frame->RefreshOperatingPointDisplay();
3709 m_frame->GetCanvas()->Refresh();
3710
3711 return 0;
3712}
3713
3714
3716{
3717 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3719
3721 m_frame->RefreshOperatingPointDisplay();
3722 m_frame->GetCanvas()->Refresh();
3723
3724 return 0;
3725}
3726
3727
3729{
3730 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3732
3733 m_frame->GetRenderSettings()->m_ShowPinAltIcons = cfg->m_Appearance.show_pin_alt_icons;
3734
3736 m_frame->GetCanvas()->Refresh();
3737
3738 return 0;
3739}
3740
3741
3743{
3744 m_frame->eeconfig()->m_Drawing.line_mode = aEvent.Parameter<LINE_MODE>();
3745 m_toolMgr->PostAction( ACTIONS::refreshPreview );
3746 // Notify toolbar to update selection
3748 return 0;
3749}
3750
3751
3753{
3754 m_frame->eeconfig()->m_Drawing.line_mode++;
3755 m_frame->eeconfig()->m_Drawing.line_mode %= LINE_MODE::LINE_MODE_COUNT;
3756 m_toolMgr->PostAction( ACTIONS::refreshPreview );
3757 // Notify toolbar to update selection
3759 return 0;
3760}
3761
3762
3764{
3765 EESCHEMA_SETTINGS* cfg = m_frame->eeconfig();
3767 return 0;
3768}
3769
3770
3772{
3773 // Update the left toolbar Line modes group icon to match current mode
3774 switch( static_cast<LINE_MODE>( m_frame->eeconfig()->m_Drawing.line_mode ) )
3775 {
3776 case LINE_MODE::LINE_MODE_FREE: m_frame->SelectToolbarAction( SCH_ACTIONS::lineModeFree ); break;
3777 case LINE_MODE::LINE_MODE_90: m_frame->SelectToolbarAction( SCH_ACTIONS::lineMode90 ); break;
3778 default:
3779 case LINE_MODE::LINE_MODE_45: m_frame->SelectToolbarAction( SCH_ACTIONS::lineMode45 ); break;
3780 }
3781
3782 return 0;
3783}
3784
3785
3787{
3788 if( !Pgm().GetCommonSettings()->m_Input.hotkey_feedback )
3789 return 0;
3790
3791 GRID_SETTINGS& gridSettings = m_toolMgr->GetSettings()->m_Window.grid;
3792 int currentIdx = m_toolMgr->GetSettings()->m_Window.grid.last_size_idx;
3793
3794 wxArrayString gridsLabels;
3795
3796 for( const GRID& grid : gridSettings.grids )
3797 gridsLabels.Add( grid.UserUnitsMessageText( m_frame ) );
3798
3799 if( !m_frame->GetHotkeyPopup() )
3800 m_frame->CreateHotkeyPopup();
3801
3802 HOTKEY_CYCLE_POPUP* popup = m_frame->GetHotkeyPopup();
3803
3804 if( popup )
3805 popup->Popup( _( "Grid" ), gridsLabels, currentIdx );
3806
3807 return 0;
3808}
3809
3810
3812{
3813 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3814
3815 if( !editFrame )
3816 return 1;
3817
3818 // Need to have a group selected and it needs to have a linked design block
3819 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
3820 SCH_SELECTION selection = selTool->GetSelection();
3821
3822 if( selection.Size() != 1 || selection[0]->Type() != SCH_GROUP_T )
3823 return 1;
3824
3825 SCH_GROUP* group = static_cast<SCH_GROUP*>( selection[0] );
3826
3827 if( !group->HasDesignBlockLink() )
3828 return 1;
3829
3830 // Get the associated design block
3831 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
3832 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
3833 true, true ) );
3834
3835 if( !designBlock )
3836 {
3837 wxString msg;
3838 msg.Printf( _( "Could not find design block %s." ), group->GetDesignBlockLibId().GetUniStringLibId() );
3839 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
3840 return 1;
3841 }
3842
3843 if( designBlock->GetSchematicFile().IsEmpty() )
3844 {
3845 wxString msg;
3846 msg.Printf( _( "Design block %s does not have a schematic file." ),
3847 group->GetDesignBlockLibId().GetUniStringLibId() );
3848 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
3849 return 1;
3850 }
3851
3852 editFrame->GetDesignBlockPane()->SelectLibId( group->GetDesignBlockLibId() );
3853
3854 return m_toolMgr->RunAction( SCH_ACTIONS::placeDesignBlock, designBlock.release() );
3855}
3856
3857
3859{
3860 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3861
3862 if( !editFrame )
3863 return 1;
3864
3865 // Need to have a group selected and it needs to have a linked design block
3866 SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
3867 SCH_SELECTION selection = selTool->GetSelection();
3868
3869 if( selection.Size() != 1 || selection[0]->Type() != SCH_GROUP_T )
3870 return 1;
3871
3872 SCH_GROUP* group = static_cast<SCH_GROUP*>( selection[0] );
3873
3874 if( !group->HasDesignBlockLink() )
3875 return 1;
3876
3877 // Get the associated design block
3878 DESIGN_BLOCK_PANE* designBlockPane = editFrame->GetDesignBlockPane();
3879 std::unique_ptr<DESIGN_BLOCK> designBlock( designBlockPane->GetDesignBlock( group->GetDesignBlockLibId(),
3880 true, true ) );
3881
3882 if( !designBlock )
3883 {
3884 wxString msg;
3885 msg.Printf( _( "Could not find design block %s." ), group->GetDesignBlockLibId().GetUniStringLibId() );
3886 m_frame->GetInfoBar()->ShowMessageFor( msg, 5000, wxICON_WARNING );
3887 return 1;
3888 }
3889
3890 editFrame->GetDesignBlockPane()->SelectLibId( group->GetDesignBlockLibId() );
3891
3892 return m_toolMgr->RunAction( SCH_ACTIONS::updateDesignBlockFromSelection ) ? 1 : 0;
3893}
3894
3895
3897{
3898 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3899
3900 if( !editFrame )
3901 return 1;
3902
3903 editFrame->AddVariant();
3904
3905 return 0;
3906}
3907
3908
3910{
3911 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3912
3913 if( !editFrame )
3914 return 1;
3915
3916 editFrame->RemoveVariant();
3917 return 0;
3918}
3919
3920
3922{
3923 SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
3924
3925 if( !editFrame )
3926 return 1;
3927
3928 editFrame->EditVariantDescription();
3929 return 0;
3930}
3931
3932
3934{
3935 Go( &SCH_EDITOR_CONTROL::New, ACTIONS::doNew.MakeEvent() );
3936 Go( &SCH_EDITOR_CONTROL::Open, ACTIONS::open.MakeEvent() );
3937 Go( &SCH_EDITOR_CONTROL::Save, ACTIONS::save.MakeEvent() );
3944 Go( &SCH_EDITOR_CONTROL::Plot, ACTIONS::plot.MakeEvent() );
3945
3948
3954
3957
3969
3972
3973 Go( &SCH_EDITOR_CONTROL::Undo, ACTIONS::undo.MakeEvent() );
3974 Go( &SCH_EDITOR_CONTROL::Redo, ACTIONS::redo.MakeEvent() );
3975 Go( &SCH_EDITOR_CONTROL::Cut, ACTIONS::cut.MakeEvent() );
3976 Go( &SCH_EDITOR_CONTROL::Copy, ACTIONS::copy.MakeEvent() );
3981
3983
4000
4008
4025
4027
4030
4034}
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)
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:96
Define a library symbol object.
Definition lib_symbol.h:79
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:148
bool IsPower() const override
wxString GetName() const override
Definition lib_symbol.h:141
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:92
const wxString & GetNumber() const
Definition sch_pin.h:127
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition sch_pin.h:218
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...
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:845
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:846
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:775
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)
#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:70
std::string refName
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
std::string path
IbisParser parser & reporter
KIBIS_MODEL * model
KIBIS_PIN * pin
KIBIS_PIN * pinA
const SHAPE_LINE_CHAIN chain
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