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