KiCad PCB EDA Suite
Loading...
Searching...
No Matches
symbol_edit_frame.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) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2008 Wayne Stambaugh <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <bitmaps.h>
26#include <api/api_server.h>
28#include <api/api_utils.h>
29#include <wx/hyperlink.h>
30#include <base_screen.h>
31#include <confirm.h>
32#include <core/kicad_algo.h>
33#include <core/throttle.h>
34#include <eeschema_id.h>
35#include <eeschema_settings.h>
36#include <env_paths.h>
38#include <kidialog.h>
39#include <kiface_base.h>
40#include <kiplatform/app.h>
41#include <kiplatform/io.h>
42#include <kiway_mail.h>
43#include <symbol_edit_frame.h>
44#include <sch_edit_frame.h>
48#include <paths.h>
49#include <pgm_base.h>
50#include <project_sch.h>
51#include <sch_painter.h>
52#include <sch_view.h>
56#include <tool/action_manager.h>
57#include <tool/action_toolbar.h>
58#include <tool/common_control.h>
59#include <tool/common_tools.h>
61#include <tool/embed_tool.h>
63#include <tool/picker_tool.h>
65#include <tool/selection.h>
67#include <tool/tool_manager.h>
68#include <tool/zoom_tool.h>
69#include <tools/sch_actions.h>
81#include <view/view_controls.h>
83#include <widgets/wx_infobar.h>
89#include <widgets/lib_tree.h>
94#include <panel_sym_lib_table.h>
95#include <string_utils.h>
97#include <wx/dir.h>
98#include <wx/msgdlg.h>
99#include <wx/combobox.h>
100#include <wx/log.h>
101#include <wx/wfstream.h>
102#include <wx/zipstrm.h>
103#include <trace_helpers.h>
104
105
107
108
112class UNPACKED_SYMBOL_LIBRARY_DIR_TRAVERSER : public wxDirTraverser
113{
114public:
115 UNPACKED_SYMBOL_LIBRARY_DIR_TRAVERSER( std::vector<wxString>& aFiles ) :
116 m_files( aFiles) { }
117
118 virtual wxDirTraverseResult OnFile( const wxString& aFilename ) override
119 {
120 wxFileName fn( aFilename );
122
123 if( ext.CmpNoCase( fn.GetExt() ) == 0 )
124 m_files.push_back( aFilename );
125
126 return wxDIR_CONTINUE;
127 }
128
129 virtual wxDirTraverseResult OnDir( const wxString& WXUNUSED( aDirname ) ) override
130 {
131 return wxDIR_CONTINUE;
132 }
133
134private:
135 std::vector<wxString>& m_files;
136};
137
138
139BEGIN_EVENT_TABLE( SYMBOL_EDIT_FRAME, SCH_BASE_FRAME )
142
143 // menubar commands
146
147 // Update user interface elements.
150
153
154 // Drop files event
155 EVT_DROP_FILES( SYMBOL_EDIT_FRAME::OnDropFiles )
156
157END_EVENT_TABLE()
158
159
160SYMBOL_EDIT_FRAME::SYMBOL_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
161 SCH_BASE_FRAME( aKiway, aParent, FRAME_SCH_SYMBOL_EDITOR, _( "Symbol Editor" ),
162 wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE,
164 m_unitSelectBox( nullptr ),
165 m_bodyStyleSelectBox( nullptr ),
166 m_drawSpecificUnit( false ),
170{
171 m_symbol = nullptr;
172 m_treePane = nullptr;
173 m_libMgr = nullptr;
174 m_unit = 1;
175 m_bodyStyle = 1;
177 m_aboutTitle = _HKI( "KiCad Symbol Editor" );
178
179 wxIcon icon;
180 wxIconBundle icon_bundle;
181
182 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_libedit, 48 ) );
183 icon_bundle.AddIcon( icon );
184 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_libedit, 256 ) );
185 icon_bundle.AddIcon( icon );
186 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_libedit, 128 ) );
187 icon_bundle.AddIcon( icon );
188 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_libedit_32 ) );
189 icon_bundle.AddIcon( icon );
190 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_libedit_16 ) );
191 icon_bundle.AddIcon( icon );
192
193 SetIcons( icon_bundle );
194
197
199
200 m_treePane = new SYMBOL_TREE_PANE( this, m_libMgr );
201 m_treePane->GetLibTree()->SetSortMode( (LIB_TREE_MODEL_ADAPTER::SORT_MODE) m_settings->m_LibrarySortMode );
202
204
205 // Ensure axis are always drawn
207 gal_opts.m_axesEnabled = true;
208
211 GetScreen()->m_Center = true;
212
213 GetCanvas()->GetViewControls()->SetCrossHairCursorPosition( VECTOR2D( 0, 0 ), false );
214
215 GetRenderSettings()->LoadColors( GetColorSettings() );
216 GetRenderSettings()->m_IsSymbolEditor = true;
217 GetCanvas()->GetGAL()->SetAxesColor( m_colorSettings->GetColor( LAYER_SCHEMATIC_GRID_AXES ) );
218
219 setupTools();
221
223
226
230
233
234 m_propertiesPanel = new SCH_PROPERTIES_PANEL( this, this );
235 m_propertiesPanel->SetSplitterProportion( m_settings->m_AuiPanels.properties_splitter );
236
238
239 m_auimgr.SetManagedWindow( this );
240
242
243 // Rows; layers 4 - 6
244 m_auimgr.AddPane( m_tbTopMain, EDA_PANE().HToolbar().Name( "TopMainToolbar" )
245 .Top().Layer( 6 ) );
246
247 m_auimgr.AddPane( m_messagePanel, EDA_PANE().Messages().Name( "MsgPanel" )
248 .Bottom().Layer( 6 ) );
249
250 m_auimgr.AddPane( m_tbLeft, EDA_PANE().VToolbar().Name( "LeftToolbar" )
251 .Left().Layer( 2 ) );
252
253 m_auimgr.AddPane( m_tbRight, EDA_PANE().VToolbar().Name( "RightToolbar" )
254 .Right().Layer( 2 ) );
255
256 m_tabsPanel = new EDITOR_TABS_PANEL( this, GetCanvas() );
257
258 m_tabsPanel->onActivateTab =
259 [this]( int aIdx )
260 {
262 activateSymbolTab( ctx );
263 };
264
265 m_tabsPanel->onCloseTabRequested =
266 [this]( int aIdx ) -> bool
267 {
268 return promptAndCloseSymbolTab( aIdx );
269 };
270
271 m_tabsPanel->onQueryVisualState =
272 [this]( int aIdx ) -> TAB_VISUAL_STATE
273 {
274 // The panel model owns preview. Read modified from the live context.
275 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
276
277 if( aIdx < 0 || aIdx >= static_cast<int>( entries.size() ) )
278 return TAB_VISUAL_STATE{};
279
280 bool modified = entries[aIdx].modified;
281
283 modified = ctx->IsModified();
284
285 return ResolveTabVisualState( entries[aIdx].preview, modified );
286 };
287
288 m_auimgr.AddPane( m_tabsPanel, wxAuiPaneInfo().Name( "DrawFrame" )
289 .CentrePane() );
290
291 // Columns; layers 1 - 3
292 m_auimgr.AddPane( m_treePane, EDA_PANE().Palette().Name( "LibraryTree" )
293 .Left().Layer( 3 )
294 .TopDockable( false ).BottomDockable( false )
295 .Caption( _( "Libraries" ) )
296 // Don't use -1 for don't-change-height on a growable panel; it has side-effects.
297 .MinSize( FromDIP( 250 ), FromDIP( 80 ) )
298 .BestSize( FromDIP( 250 ), -1 ) );
299
302
303 // Can be called only when all panes are created, because (at least on Windows) when items
304 // managed by m_auimgr are not the same as those existing when saved by Perspective()
305 // in config, broken settings can happen.
307
308 // Protect against broken saved Perspective() due to bugs in previous version
309 // This is currently a workaround.
310 m_auimgr.GetPane( "TopMainToolbar" ).Top().Layer( 6 ).Position(0).Show( true );
311 m_auimgr.GetPane( "LeftToolbar" ).Position(0).Show( true );
312 m_auimgr.GetPane( "RightToolbar" ).Show( true );
313
314 // Show or hide m_propertiesPanel depending on current settings:
315 wxAuiPaneInfo& propertiesPaneInfo = m_auimgr.GetPane( PropertiesPaneName() );
316 wxAuiPaneInfo& selectionFilterPane = m_auimgr.GetPane( wxS( "SelectionFilter" ) );
317 // The selection filter doesn't need to grow in the vertical direction when docked
318 selectionFilterPane.dock_proportion = 0;
319
320 // wx 3.3.3 turns a -1 min height into 1, and a legacy perspective restores one
321 selectionFilterPane.min_size.y = m_selectionFilterPanel->GetBestSize().y;
322
323 propertiesPaneInfo.Show( m_settings->m_AuiPanels.show_properties );
325
327
328 // Can't put this in LoadSettings, because it has to be called before setupTools :/
330 selTool->GetFilter() = GetSettings()->m_SelectionFilter;
331 m_selectionFilterPanel->SetCheckboxesFromFilter( selTool->GetFilter() );
332
333 if( m_settings->m_LibWidth > 0 )
334 SetAuiPaneSize( m_auimgr, m_auimgr.GetPane( "LibraryTree" ), m_settings->m_LibWidth, -1 );
335
336 Raise();
337 Show( true );
338
339 SyncView();
340 GetCanvas()->GetView()->UseDrawPriority( true );
341 GetCanvas()->GetGAL()->SetAxesEnabled( true );
342
344
345 // Set the working/draw area size to display a symbol to a reasonable value:
346 // A 600mm x 600mm with a origin at the area center looks like a large working area
347 double max_size_x = schIUScale.mmToIU( 600 );
348 double max_size_y = schIUScale.mmToIU( 600 );
349 BOX2D bbox;
350 bbox.SetOrigin( -max_size_x /2, -max_size_y/2 );
351 bbox.SetSize( max_size_x, max_size_y );
352 GetCanvas()->GetView()->SetBoundary( bbox );
353
355
357 m_acceptedExts.emplace( wxS( "dxf" ), &SCH_ACTIONS::ddImportGraphics );
359 DragAcceptFiles( true );
360
361 KIPLATFORM::APP::SetShutdownBlockReason( this, _( "Library changes are unsaved" ) );
362
363 // Catch unhandled accelerator command characters that were no handled by the library tree
364 // panel.
366 Bind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
367
368 // GTK rejects WXK_TAB as an accelerator so cycle tabs from the char hook ahead of the dispatcher.
369 Bind( wxEVT_CHAR_HOOK, &SYMBOL_EDIT_FRAME::OnTabCharHook, this );
370
371 // Ensure the window is on top
372 Raise();
373
374 // run SyncLibraries with progress reporter enabled. The progress reporter is useful
375 // in debug mode because the loading time of ecah library can be really noticeable
376 SyncLibraries( true );
377
378 m_apiHandler = std::make_unique<API_HANDLER_SYMBOL>( this );
380
381 if( Kiface().IsSingle() )
382 {
383 m_apiHandlerCommon = std::make_unique<API_HANDLER_COMMON>();
385 m_apiLibrariesHandler = std::make_unique<API_HANDLER_LIBRARIES>(
388 }
389
390 // Must follow SyncLibraries so persisted tabs can resolve against the loaded libraries.
392}
393
394
396{
397 // Ensure that teardowns without doCloseWindow() are fully unregistered
399
400 if( Kiface().IsSingle() )
401 {
404 }
405
406 // Hand the borrowed canvas back before the base destructor frees it, else the panel reparents
407 // freed memory on its own teardown.
408 m_tabsPanel->ReleaseSharedCanvas();
409
410 // Shutdown all running tools
411 if( m_toolManager )
412 m_toolManager->ShutdownAllTools();
413
414 setSymWatcher( nullptr );
415
416 if( m_activeTab )
417 {
418 // Hand the working objects back so the context deletes them exactly once below; raw deleting
419 // here would double-free with the context dtor and leak the swapped-in undo list. Covers an
420 // active instance tab too, whose m_isSymbolFromSchematic mirror is only frame state.
422 m_activeTab->AdoptWorkingObjects( m_symbol, static_cast<SCH_SCREEN*>( GetScreen() ) );
423 m_activeTab = nullptr;
424 m_symbol = nullptr;
426 }
427 else
428 {
429 // No active tab owns the current screen, so let EDA_DRAW_FRAME free it.
431 }
432
433 // Free each detached context's undo/redo with the frame on the dummy screen to avoid double-frees.
434 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
436
437 m_tabContexts.clear();
438
440 Pgm().GetSettingsManager().Save( cfg );
441
442 delete m_libMgr;
443}
444
445
447{
448 wxCHECK_RET( m_settings, "Call to SYMBOL_EDIT_FRAME::LoadSettings with null m_settings" );
449
451
452 GetRenderSettings()->m_ShowPinsElectricalType = m_settings->m_ShowPinElectricalType;
453 GetRenderSettings()->m_ShowHiddenPins = m_settings->m_ShowHiddenPins;
454 GetRenderSettings()->m_ShowHiddenFields = m_settings->m_ShowHiddenFields;
455 GetRenderSettings()->m_ShowPinAltIcons = m_settings->m_ShowPinAltIcons;
456 GetRenderSettings()->SetDefaultFont( wxEmptyString );
457}
458
459
461{
462 wxCHECK_RET( m_settings, "Call to SYMBOL_EDIT_FRAME:SaveSettings with null m_settings" );
463
465
466 // The library tree is hidden while editing a symbol from the schematic. Force it visible in the
467 // serialized AUI layout so the user's preference survives a restart, but only touch the pane
468 // metadata (not ToggleLibraryTree) to avoid a mid-session repaint/flicker and a spurious tree
469 // width capture below.
470 wxAuiPaneInfo& treePane = m_auimgr.GetPane( m_treePane );
471 wxAuiPaneInfo& filterPane = m_auimgr.GetPane( wxS( "SelectionFilter" ) );
472
473 const bool treeShown = treePane.IsShown();
474 const bool filterShown = filterPane.IsShown();
475
476 // Gate on the pending-restore flag alone, not the active-tab schematic state, which is cleared
477 // when a schematic tab closes while the tree stays auto-hidden.
478 const bool forceTreeShown = m_libTreeAutoHiddenForSchematicEdit && !treeShown;
479
480 if( forceTreeShown )
481 {
482 treePane.Show( true );
484 }
485
487
488 if( forceTreeShown )
489 {
490 treePane.Show( treeShown );
491 filterPane.Show( filterShown );
492 }
493
494 m_settings->m_ShowPinElectricalType = GetRenderSettings()->m_ShowPinsElectricalType;
495 m_settings->m_ShowHiddenPins = GetRenderSettings()->m_ShowHiddenPins;
496 m_settings->m_ShowHiddenFields = GetRenderSettings()->m_ShowHiddenFields;
497 m_settings->m_ShowPinAltIcons = GetRenderSettings()->m_ShowPinAltIcons;
498
499 m_settings->m_LibWidth = m_treePane->GetSize().x;
500
501 m_settings->m_LibrarySortMode = GetLibTree()->GetSortMode();
502
503 m_settings->m_AuiPanels.properties_splitter = m_propertiesPanel->SplitterProportion();
504 bool prop_shown = m_auimgr.GetPane( PropertiesPaneName() ).IsShown();
505 m_settings->m_AuiPanels.show_properties = prop_shown;
506
507 if( TOOL_MANAGER* toolMgr = GetToolManager() )
508 {
509 if( SCH_SELECTION_TOOL* selTool = toolMgr->GetTool<SCH_SELECTION_TOOL>() )
510 m_settings->m_SelectionFilter = selTool->GetFilter();
511 }
512
514}
515
516
521
522
524{
526
527 if( cfg && static_cast<SYMBOL_EDITOR_SETTINGS*>( cfg )->m_UseEeschemaColorSettings )
528 cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" );
529
530 return ::GetColorSettings( cfg ? cfg->m_ColorTheme : DEFAULT_THEME );
531}
532
533
535{
536 // Create the manager and dispatcher & route draw panel events to the dispatcher
538 m_toolManager->SetEnvironment( GetScreen(), GetCanvas()->GetView(), GetCanvas()->GetViewControls(), GetSettings(),
539 this );
540 m_actions = new SCH_ACTIONS();
542
543 // Register tools
544 m_toolManager->RegisterTool( new COMMON_CONTROL );
545 m_toolManager->RegisterTool( new COMMON_TOOLS );
546 m_toolManager->RegisterTool( new ZOOM_TOOL );
547 m_toolManager->RegisterTool( new SCH_SELECTION_TOOL );
548 m_toolManager->RegisterTool( new PICKER_TOOL );
549 m_toolManager->RegisterTool( new SCH_INSPECTION_TOOL );
550 m_toolManager->RegisterTool( new SYMBOL_EDITOR_PIN_TOOL );
551 m_toolManager->RegisterTool( new SYMBOL_EDITOR_DRAWING_TOOLS );
552 m_toolManager->RegisterTool( new EE_GRAPHIC_TOOL );
553 m_toolManager->RegisterTool( new SCH_POINT_EDITOR );
554 m_toolManager->RegisterTool( new SCH_FIND_REPLACE_TOOL );
555 m_toolManager->RegisterTool( new SYMBOL_EDITOR_MOVE_TOOL );
556 m_toolManager->RegisterTool( new SYMBOL_EDITOR_EDIT_TOOL );
557 m_toolManager->RegisterTool( new LIBRARY_EDITOR_CONTROL );
558 m_toolManager->RegisterTool( new SYMBOL_EDITOR_CONTROL );
559 m_toolManager->RegisterTool( new PROPERTIES_TOOL );
560 m_toolManager->RegisterTool( new EMBED_TOOL );
561 m_toolManager->InitTools();
562
563 // Run the selection tool, it is supposed to be always active
564 m_toolManager->InvokeTool( "common.InteractiveSelection" );
565
567}
568
569
571{
573
574 ACTION_MANAGER* mgr = m_toolManager->GetActionManager();
575 EDITOR_CONDITIONS cond( this );
576
577 wxASSERT( mgr );
578
579#define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
580#define CHECK( x ) ACTION_CONDITIONS().Check( x )
581
582 auto haveSymbolCond =
583 [this]( const SELECTION& )
584 {
585 return m_symbol;
586 };
587
588 auto isGraphicallyEditableCond =
589 [this]( const SELECTION& )
590 {
592 };
593
594 auto isEditableInAliasCond =
595 [this]( const SELECTION& )
596 {
597 // Less restrictive than isGraphicallyEditableCond
598 // Symbols fields (root symbols and aliases) from the new s-expression libraries
599 // or in the schematic are editable.
600 return IsSymbolEditable();
601 };
602
603 auto canUpdateFieldsCond =
604 [this]( const SELECTION& )
605 {
606 return IsSymbolEditable() && m_symbol && m_symbol->CanUpdateFieldsFromParent();
607 };
608
609 auto symbolModifiedCondition =
610 [this]( const SELECTION& sel )
611 {
612 return m_libMgr && m_libMgr->IsSymbolModified( GetTargetLibId().GetLibItemName(),
613 GetTargetLibId().GetLibNickname() );
614 };
615
616 auto libSelectedCondition =
617 [this]( const SELECTION& sel )
618 {
619 return !GetTargetLibId().GetLibNickname().empty();
620 };
621
622 auto canEditProperties =
623 [this]( const SELECTION& sel )
624 {
626 };
627
628 auto symbolSelectedInTreeCondition =
629 [this]( const SELECTION& sel )
630 {
631 LIB_ID targetLibId = GetTargetLibId();
632 return !targetLibId.GetLibNickname().empty() && !targetLibId.GetLibItemName().empty();
633 };
634
635 auto saveSymbolAsCondition =
636 [this]( const SELECTION& aSel )
637 {
638 return getTargetSymbol() != nullptr;
639 };
640
641 const auto isSymbolFromSchematicCond =
642 [this]( const SELECTION& )
643 {
644 return IsSymbolFromSchematic();
645 };
646
647 // clang-format off
650 mgr->SetConditions( SCH_ACTIONS::saveLibraryAs, ENABLE( libSelectedCondition ) );
651 mgr->SetConditions( SCH_ACTIONS::saveSymbolAs, ENABLE( saveSymbolAsCondition ) );
652 mgr->SetConditions( SCH_ACTIONS::saveSymbolCopyAs, ENABLE( saveSymbolAsCondition ) );
655 mgr->SetConditions( SCH_ACTIONS::editLibSymbolWithLibEdit, ENABLE( isSymbolFromSchematicCond ) );
656
657 mgr->SetConditions( ACTIONS::undo, ENABLE( haveSymbolCond && cond.UndoAvailable() ) );
658 mgr->SetConditions( ACTIONS::redo, ENABLE( haveSymbolCond && cond.RedoAvailable() ) );
659 mgr->SetConditions( ACTIONS::revert, ENABLE( symbolModifiedCondition ) );
660
663
664 mgr->SetConditions( ACTIONS::cut, ENABLE( isGraphicallyEditableCond ) );
665 mgr->SetConditions( ACTIONS::copy, ENABLE( haveSymbolCond ) );
666 mgr->SetConditions( ACTIONS::copyAsText, ENABLE( haveSymbolCond ) );
667 mgr->SetConditions( ACTIONS::paste, ENABLE( isGraphicallyEditableCond && SELECTION_CONDITIONS::Idle && cond.NoActiveTool() ) );
668 mgr->SetConditions( ACTIONS::doDelete, ENABLE( isGraphicallyEditableCond ) );
669 mgr->SetConditions( ACTIONS::duplicate, ENABLE( isGraphicallyEditableCond ) );
670 mgr->SetConditions( ACTIONS::selectAll, ENABLE( haveSymbolCond ) );
671 mgr->SetConditions( ACTIONS::unselectAll, ENABLE( haveSymbolCond ) );
672
673 // These actions in symbol editor when editing alias field rotations are allowed.
675 .HotkeyEnable( isEditableInAliasCond ) );
677 .HotkeyEnable( isEditableInAliasCond ) );
678
679 mgr->SetConditions( SCH_ACTIONS::mirrorH, ENABLE( SELECTION_CONDITIONS::NotEmpty && isGraphicallyEditableCond )
680 .HotkeyEnable( isGraphicallyEditableCond ) );
681 mgr->SetConditions( SCH_ACTIONS::mirrorV, ENABLE( SELECTION_CONDITIONS::NotEmpty && isGraphicallyEditableCond )
682 .HotkeyEnable( isGraphicallyEditableCond ) );
683
686 // clang-format on
687
688 auto pinTypeCond =
689 [this]( const SELECTION& )
690 {
692 };
693
694 auto hiddenPinCond =
695 [this]( const SELECTION& )
696 {
698 };
699
700 auto hiddenFieldCond =
701 [this]( const SELECTION& )
702 {
704 };
705
706 auto showPinAltIconsCond =
707 [this]( const SELECTION& )
708 {
710 };
711
712 auto showLibraryTreeCond =
713 [this]( const SELECTION& )
714 {
715 return IsLibraryTreeShown();
716 };
717
718 auto propertiesCond =
719 [this] ( const SELECTION& )
720 {
721 return m_auimgr.GetPane( PropertiesPaneName() ).IsShown();
722 };
723
726 mgr->SetConditions( ACTIONS::showLibraryTree, CHECK( showLibraryTreeCond ) );
727 mgr->SetConditions( ACTIONS::showProperties, CHECK( propertiesCond ) );
728 mgr->SetConditions( SCH_ACTIONS::showHiddenPins, CHECK( hiddenPinCond ) );
729 mgr->SetConditions( SCH_ACTIONS::showHiddenFields, CHECK( hiddenFieldCond ) );
730 mgr->SetConditions( SCH_ACTIONS::togglePinAltIcons, CHECK( showPinAltIconsCond ) );
731
732 auto multiUnitModeCond =
733 [this]( const SELECTION& )
734 {
735 return m_symbol && m_symbol->IsMultiUnit() && !m_symbol->UnitsLocked();
736 };
737
738 auto multiBodyStyleModeCond =
739 [this]( const SELECTION& )
740 {
741 return m_symbol && m_symbol->IsMultiBodyStyle();
742 };
743
744 auto syncedPinsModeCond =
745 [this]( const SELECTION& )
746 {
747 return SynchronizePins();
748 };
749
750 auto haveDatasheetCond =
751 [this]( const SELECTION& )
752 {
753 return m_symbol && !m_symbol->GetDatasheetField().GetText().IsEmpty();
754 };
755
756 mgr->SetConditions( ACTIONS::showDatasheet, ENABLE( haveDatasheetCond ) );
757 mgr->SetConditions( SCH_ACTIONS::symbolProperties, ENABLE( symbolSelectedInTreeCondition || ( canEditProperties && haveSymbolCond ) ) );
758 mgr->SetConditions( SCH_ACTIONS::runERC, ENABLE( haveSymbolCond ) );
759 mgr->SetConditions( SCH_ACTIONS::pinTable, ENABLE( isGraphicallyEditableCond && haveSymbolCond ) );
760 mgr->SetConditions( SCH_ACTIONS::editSymbolPinMaps, ENABLE( isGraphicallyEditableCond && haveSymbolCond ) );
761 mgr->SetConditions( SCH_ACTIONS::updateSymbolFields, ENABLE( canUpdateFieldsCond ) );
762 mgr->SetConditions( SCH_ACTIONS::cycleBodyStyle, ENABLE( multiBodyStyleModeCond ) );
763
764 mgr->SetConditions( SCH_ACTIONS::toggleSyncedPinsMode, ACTION_CONDITIONS().Enable( multiUnitModeCond ).Check( syncedPinsModeCond ) );
765
766// Only enable a tool if the symbol is edtable
767#define EDIT_TOOL( tool ) ACTION_CONDITIONS().Enable( isGraphicallyEditableCond ).Check( cond.CurrentTool( tool ) )
768
778 setArcModeConditions( SCH_ACTIONS::drawArc, isGraphicallyEditableCond );
784
785#undef CHECK
786#undef ENABLE
787#undef EDIT_TOOL
788}
789
790
792{
793 wxLogTrace( traceApi, "Symbol editor frame: EDA_EVT_PLUGIN_AVAILABILITY_CHANGED" );
796 aEvt.Skip();
797}
798
799
801{
802 if( IsContentModified() )
803 {
804 wxString msg = _( "Save changes to '%s' before closing?" );
805
806 if( !HandleUnsavedChanges( this, wxString::Format( msg, m_reference ),
807 [&]() -> bool
808 {
809 SCH_EDIT_FRAME* schframe = (SCH_EDIT_FRAME*) Kiway().Player( FRAME_SCH, false );
810 LIB_SYMBOL* symbol = GetCurSymbol();
811
812 if( schframe && symbol ) // Should be always the case
813 return schframe->SaveSymbolToSchematic( *symbol, m_schematicSymbolUUID );
814
815 return false;
816 } ) )
817 {
818 return false;
819 }
820 }
821
822 if( doClose )
823 SetCurSymbol( nullptr, false );
824
825 return true;
826}
827
828
829bool SYMBOL_EDIT_FRAME::canCloseWindow( wxCloseEvent& aEvent )
830{
831 // Shutdown blocks must be determined and vetoed as early as possible, before any modal prompt.
832 // IsContentModified only sees the active tab, so also account for dirty inactive instance tabs.
834 && aEvent.GetId() == wxEVT_QUERY_END_SESSION
836 {
837 aEvent.Veto();
838 return false;
839 }
840
842 {
843 aEvent.Veto();
844 return false;
845 }
846
847 // Prompt for any dirty inactive instance (symbols from the schematic) tabs, which the active-tab
848 // checks above miss.
850 return false;
851
852 // A dirty unsaved tab has no library buffer for saveAllLibraries to prompt about, so ask here
853 if( m_activeTab && m_activeTab->IsUnsaved() && GetScreen()->IsContentModified() )
854 {
855 wxString msg = wxString::Format( _( "Save changes to '%s' before closing?" ),
856 m_activeTab->GetDisplayName( true ) );
857
858 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxYES_NO | wxCANCEL | wxICON_WARNING );
859 dlg.SetYesNoCancelLabels( _( "Save" ), _( "Discard Changes" ), _( "Cancel" ) );
860
861 switch( dlg.ShowModal() )
862 {
863 case wxID_YES:
864 if( !saveCurrentSymbol() )
865 {
866 aEvent.Veto();
867 return false;
868 }
869
870 break;
871
872 case wxID_NO:
873 break;
874
875 default:
876 aEvent.Veto();
877 return false;
878 }
879 }
880
881 if( !saveAllLibraries( true ) )
882 return false;
883
884 // Save symbol tree column widths
885 m_libMgr->GetAdapter()->SaveSettings();
886
887 return true;
888}
889
890
892{
894
895 if( Pgm().ApiServerOrNull() )
896 {
898
899 if( Kiface().IsSingle() )
900 {
903 }
904 }
905
906 wxTheApp->Unbind( EDA_EVT_PLUGIN_AVAILABILITY_CHANGED,
908
909 if( GetLibTree() )
911
912 delete m_toolManager;
913 m_toolManager = nullptr;
914
915 Destroy();
916}
917
918
920{
921 if( m_unitSelectBox )
922 {
923 if( m_unitSelectBox->GetCount() != 0 )
924 m_unitSelectBox->Clear();
925
926 if( !m_symbol || m_symbol->GetUnitCount() <= 1 )
927 {
928 m_unit = 1;
929 m_unitSelectBox->Append( wxEmptyString );
930 }
931 else
932 {
933 for( int i = 0; i < m_symbol->GetUnitCount(); i++ )
934 m_unitSelectBox->Append( m_symbol->GetUnitDisplayName( i + 1, true ) );
935 }
936
937 // Ensure the selected unit is compatible with the number of units of the current symbol:
938 if( m_symbol && m_symbol->GetUnitCount() < m_unit )
939 m_unit = 1;
940
941 m_unitSelectBox->SetSelection( ( m_unit > 0 ) ? m_unit - 1 : 0 );
942 }
943
945 {
946 if( m_bodyStyleSelectBox->GetCount() != 0 )
947 m_bodyStyleSelectBox->Clear();
948
949 if( !m_symbol || !m_symbol->IsMultiBodyStyle() )
950 {
951 m_bodyStyle = 1;
952 m_bodyStyleSelectBox->Append( wxEmptyString );
953 }
954 else if( m_symbol && m_symbol->HasDeMorganBodyStyles() )
955 {
956 m_bodyStyleSelectBox->Append( wxGetTranslation( DEMORGAN_STD ) );
957 m_bodyStyleSelectBox->Append( wxGetTranslation( DEMORGAN_ALT ) );
958 }
959 else
960 {
961 for( int i = 0; i < m_symbol->GetBodyStyleCount(); i++ )
962 m_bodyStyleSelectBox->Append( m_symbol->GetBodyStyleNames()[i] );
963 }
964
965 // Ensure the selected body style is compatible with the number of body styles of the current symbol:
966 if( m_symbol && m_symbol->GetBodyStyleCount() < m_bodyStyle )
967 m_bodyStyle = 1;
968
969 m_bodyStyleSelectBox->SetSelection( ( m_bodyStyle > 0 ) ? m_bodyStyle - 1 : 0 );
970 }
971}
972
973
975{
976 if( !m_propertiesPanel )
977 return;
978
979 bool show = !m_propertiesPanel->IsShownOnScreen();
980
981 wxAuiPaneInfo& propertiesPaneInfo = m_auimgr.GetPane( PropertiesPaneName() );
982 propertiesPaneInfo.Show( show );
984
985 if( show )
986 SetAuiPaneSize( m_auimgr, propertiesPaneInfo, m_settings->m_AuiPanels.properties_panel_width, -1 );
987 else
988 m_settings->m_AuiPanels.properties_panel_width = m_propertiesPanel->GetSize().x;
989
990 m_auimgr.Update();
991 Refresh();
992}
993
994
996{
997 // An explicit toggle makes the live visibility authoritative, so drop any pending restore that
998 // LoadSymbolFromSchematic's auto-hide left behind.
1000
1001 wxAuiPaneInfo& treePane = m_auimgr.GetPane( m_treePane );
1002 treePane.Show( !IsLibraryTreeShown() );
1004 m_auimgr.Update();
1005 Refresh();
1006}
1007
1008
1010{
1011 return const_cast<wxAuiManager&>( m_auimgr ).GetPane( m_treePane ).IsShown();
1012}
1013
1014
1019
1020
1022{
1023 m_treePane->Freeze();
1024 m_libMgr->GetAdapter()->Freeze();
1025}
1026
1027
1029{
1030 m_libMgr->GetAdapter()->Thaw();
1031 m_treePane->Thaw();
1032}
1033
1034
1035void SYMBOL_EDIT_FRAME::OnExitKiCad( wxCommandEvent& event )
1036{
1037 Kiway().OnKiCadExit();
1038}
1039
1040
1041void SYMBOL_EDIT_FRAME::OnUpdateUnitNumber( wxUpdateUIEvent& event )
1042{
1043 event.Enable( m_symbol && m_symbol->GetUnitCount() > 1 );
1044}
1045
1046
1047void SYMBOL_EDIT_FRAME::OnSelectUnit( wxCommandEvent& event )
1048{
1049 if( event.GetSelection() == wxNOT_FOUND )
1050 return;
1051
1052 SetUnit( event.GetSelection() + 1 );
1053}
1054
1055
1056void SYMBOL_EDIT_FRAME::OnUpdateBodyStyle( wxUpdateUIEvent& event )
1057{
1058 event.Enable( m_symbol && m_symbol->GetBodyStyleCount() > 1 );
1059}
1060
1061
1062void SYMBOL_EDIT_FRAME::OnSelectBodyStyle( wxCommandEvent& event )
1063{
1064 if( event.GetSelection() == wxNOT_FOUND )
1065 return;
1066
1067 SetBodyStyle( event.GetSelection() + 1 );
1068}
1069
1070
1072{
1073 if( m_symbol )
1074 {
1076
1077 if( std::optional<LIBRARY_TABLE_ROW*> row = adapter->GetRow( m_symbol->GetLibNickname() ); row.has_value() )
1078 {
1079 if( ( *row )->Type() == SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_LEGACY ) )
1080 return true;
1081 }
1082 }
1083
1084 return false;
1085}
1086
1087
1089{
1090 // Use CallAfter so that we update the canvas before waiting for the infobar animation
1091 CallAfter(
1092 [this]()
1093 {
1094 WX_INFOBAR& infobar = *GetInfoBar();
1095 infobar.RemoveAllButtons();
1096
1097 wxArrayString msgs;
1098 int infobarFlags = wxICON_INFORMATION;
1099 wxString symbolName;
1100 wxString libName;
1101
1102 if( m_symbol )
1103 {
1104 symbolName = m_symbol->GetName();
1105 libName = m_symbol->GetLibId().GetLibNickname().wx_str();
1106 }
1107
1108 if( IsSymbolFromSchematic() )
1109 {
1110 msgs.push_back( wxString::Format( _( "Editing %s from schematic. Saving will update the "
1111 "schematic only." ),
1112 m_reference ) );
1113
1114 infobar.AddLink( wxString::Format( _( "Open symbol from library %s" ), UnescapeString( libName ) ),
1115 [this]( wxHyperlinkEvent& aEvent )
1116 {
1118 } );
1119 }
1120 else if( IsSymbolFromLegacyLibrary() )
1121 {
1122 msgs.push_back( _( "Symbols in legacy libraries are not editable. Use Manage Symbol "
1123 "Libraries to migrate to current format." ) );
1124
1125 infobar.AddLink( _( "Manage symbol libraries" ),
1126 [this]( wxHyperlinkEvent& aEvent )
1127 {
1129 } );
1130 }
1131 else if( IsSymbolAlias() )
1132 {
1133 msgs.push_back( wxString::Format( _( "Symbol %s is a derived symbol. Symbol graphics will "
1134 "not be editable." ),
1135 UnescapeString( symbolName ) ) );
1136
1137 // Don't assume the parent symbol shared pointer is still valid.
1138 if( std::shared_ptr<LIB_SYMBOL> rootSymbol = m_symbol->GetRootSymbol() )
1139 {
1140 int unit = GetUnit();
1141 int bodyStyle = GetBodyStyle();
1142 wxString rootSymbolName = rootSymbol->GetName();
1143
1144 infobar.AddLink( wxString::Format( _( "Open %s" ), UnescapeString( rootSymbolName ) ),
1145 [this, libName, rootSymbolName, unit, bodyStyle]( wxHyperlinkEvent& aEvent )
1146 {
1147 LoadSymbolFromLib( libName, rootSymbolName, unit, bodyStyle );
1148 } );
1149 }
1150 }
1151
1152 if( m_symbol
1154 && m_libMgr->IsLibraryReadOnly( m_symbol->GetLibId().GetFullLibraryName() ) )
1155 {
1156 msgs.push_back( _( "Library is read-only. Changes cannot be saved to this library." ) );
1157
1158 infobar.AddLink( _( "Create an editable copy" ),
1159 [this, libName]( wxHyperlinkEvent& aEvent )
1160 {
1161 wxString msg = wxString::Format( _( "Create an editable copy of the symbol or "
1162 "the entire library (%s)?" ),
1163 UnescapeString( libName ) );
1164
1165 KIDIALOG errorDlg( this, msg, _( "Select type of item to save" ),
1166 wxYES_NO | wxCANCEL | wxICON_QUESTION );
1167 // These buttons are in a weird order(?)
1168 errorDlg.SetYesNoCancelLabels( _( "Copy symbol" ), _( "Cancel" ), _( "Copy library" ) );
1169
1170 int choice = errorDlg.ShowModal();
1171
1172 switch( choice )
1173 {
1174 case wxID_YES: SaveSymbolCopyAs( true ); break;
1175 case wxID_CANCEL: SaveLibraryAs(); break;
1176 default: return;
1177 }
1178
1179 // Get rid of the save-will-update-schematic-only (or any other dismissable warning)
1180 WX_INFOBAR* local_infobar = GetInfoBar();
1181
1182 if( local_infobar->IsShownOnScreen() && local_infobar->HasCloseButton() )
1183 local_infobar->Dismiss();
1184
1186 } );
1187 }
1188
1189 if( msgs.empty() )
1190 {
1191 infobar.Dismiss();
1192 }
1193 else
1194 {
1195 wxString msg = wxJoin( msgs, '\n', '\0' );
1196 infobar.AddCloseButton();
1197 infobar.ShowMessage( msg, infobarFlags );
1198 }
1199 } );
1200}
1201
1202
1203void SYMBOL_EDIT_FRAME::SetCurSymbol( LIB_SYMBOL* aSymbol, bool aUpdateZoom )
1204{
1205 wxCHECK( m_toolManager, /* void */ );
1206
1208 GetCanvas()->GetView()->Clear();
1209
1210 // Install the replacement and refresh the active context before freeing the old symbol, so the
1211 // context never observes a freed pointer.
1212 LIB_SYMBOL* oldSymbol = m_symbol;
1213
1214 m_symbol = aSymbol;
1215
1216 if( m_activeTab )
1217 m_activeTab->RefreshFrameOwnedObjects( m_symbol, static_cast<SCH_SCREEN*>( GetScreen() ) );
1218
1219 delete oldSymbol;
1220
1221 // select the current symbol in the tree widget
1223 GetLibTree()->SelectLibId( m_symbol->GetLibId() );
1224 else
1225 GetLibTree()->Unselect();
1226
1228
1236
1237 if( aUpdateZoom )
1239
1240 GetCanvas()->Refresh();
1241 m_propertiesPanel->UpdateData();
1242 updateInfoBar();
1243}
1244
1245
1251
1252
1254{
1256
1258
1259 if( !IsSymbolFromSchematic() && !( m_activeTab && m_activeTab->IsUnsaved() ) )
1260 {
1262 m_libMgr->UpdateSymbol( m_symbol, m_symbol->GetLibNickname() ); // UpdateSymbol() makes a copy
1263 }
1264
1265 if( m_isClosing )
1266 return;
1267
1268 // Clear preview so a later library-open gets its own tab instead of replacing this edited one.
1269 if( m_activeTab )
1270 {
1271 m_activeTab->SetPreview( false );
1272
1273 if( int idx = m_tabsPanel->FindTab( m_activeTab->GetTabKey() ); idx >= 0 )
1274 m_tabsPanel->MarkModified( idx, true );
1275 }
1276
1278}
1279
1280
1282{
1283 wxCHECK( aUnit > 0 && aUnit <= GetCurSymbol()->GetUnitCount(), /* void*/ );
1284
1285 if( m_unit == aUnit )
1286 return;
1287
1290
1291 m_unit = aUnit;
1292
1293 if( m_unitSelectBox->GetSelection() != ( m_unit - 1 ) )
1294 m_unitSelectBox->SetSelection( m_unit - 1 );
1295
1297 RebuildView();
1299}
1300
1301
1303{
1304 wxCHECK( aBodyStyle > 0 && aBodyStyle <= GetCurSymbol()->GetBodyStyleCount(), /* void */ );
1305
1306 if( m_bodyStyle == aBodyStyle )
1307 return;
1308
1311
1312 m_bodyStyle = aBodyStyle;
1313
1314 if( m_bodyStyleSelectBox->GetSelection() != ( m_bodyStyle - 1 ) )
1315 m_bodyStyleSelectBox->SetSelection( m_bodyStyle - 1 );
1316
1317
1319 RebuildView();
1321}
1322
1323
1325{
1326 return m_settings && m_settings->m_SyncPinEdit && m_symbol && m_symbol->IsMultiUnit() && !m_symbol->UnitsLocked();
1327}
1328
1329
1330wxString SYMBOL_EDIT_FRAME::AddLibraryFile( bool aCreateNew )
1331{
1332 wxFileName fn = m_libMgr->GetUniqueLibraryName();
1333 bool useGlobalTable = true;
1334 FILEDLG_HOOK_NEW_LIBRARY tableChooser( useGlobalTable );
1335
1336 if( !LibraryFileBrowser( aCreateNew ? _( "New Symbol Library" ) : _( "Add Symbol Library" ),
1337 !aCreateNew, fn, FILEEXT::KiCadSymbolLibFileWildcard(),
1339 Pgm().GetSettingsManager().IsProjectOpenNotDummy() ? &tableChooser : nullptr ) )
1340 {
1341 return wxEmptyString;
1342 }
1343
1346
1347 LIBRARY_MANAGER& manager = Pgm().GetLibraryManager();
1348 std::optional<LIBRARY_TABLE*> optTable = manager.Table( LIBRARY_TABLE_TYPE::SYMBOL, scope );
1349
1350 wxCHECK( optTable.has_value(), wxEmptyString );
1351 LIBRARY_TABLE* table = optTable.value();
1352
1353 wxString libName = fn.GetName();
1354
1355 if( libName.IsEmpty() )
1356 return wxEmptyString;
1357
1359
1360 if( adapter->HasLibrary( libName ) )
1361 {
1362 DisplayError( this, wxString::Format( _( "Library '%s' already exists." ), libName ) );
1363 return wxEmptyString;
1364 }
1365
1366 if( aCreateNew )
1367 {
1368 // The file browser already asked to overwrite, so drop the old file here.
1369 // CreateLibrary fails on an existing path.
1370 if( fn.FileExists() && !wxRemoveFile( fn.GetFullPath() ) )
1371 {
1372 DisplayError( this, wxString::Format( _( "Could not overwrite the library file '%s'.\n"
1373 "Make sure you have write permissions and try again." ),
1374 fn.GetFullPath() ) );
1375 return wxEmptyString;
1376 }
1377
1378 if( !m_libMgr->CreateLibrary( fn.GetFullPath(), scope ) )
1379 {
1380 DisplayError( this, wxString::Format( _( "Could not create the library file '%s'.\n"
1381 "Make sure you have write permissions and try again." ),
1382 fn.GetFullPath() ) );
1383 return wxEmptyString;
1384 }
1385 }
1386 else
1387 {
1388 if( !m_libMgr->AddLibrary( fn.GetFullPath(), scope ) )
1389 {
1390 DisplayError( this, _( "Could not open the library file." ) );
1391 return wxEmptyString;
1392 }
1393 }
1394
1395 bool success = true;
1396
1397 // Tables are reinitialized by m_libMgr->AddLibrary(). So reinit table reference.
1398 optTable = manager.Table( LIBRARY_TABLE_TYPE::SYMBOL, scope );
1399 wxCHECK( optTable.has_value(), wxEmptyString );
1400 table = optTable.value();
1401
1402 table->Save().map_error(
1403 [&]( const LIBRARY_ERROR& aError )
1404 {
1405 KICAD_MESSAGE_DIALOG dlg( this, _( "Error saving library table." ), _( "File Save Error" ),
1406 wxOK | wxICON_ERROR );
1407 dlg.SetExtendedMessage( aError.message );
1408 dlg.ShowModal();
1409
1410 success = false;
1411 } );
1412
1413 if( success )
1414 adapter->LoadOne( fn.GetName() );
1415
1416 SyncLibraries( false );
1417
1418 if( m_treePane )
1419 {
1420 LIB_ID libId( fn.GetName(), wxEmptyString );
1421 GetLibTree()->SelectLibId( libId );
1422 GetLibTree()->CenterLibId( libId );
1423 }
1424
1425 return fn.GetFullPath();
1426}
1427
1428
1429void SYMBOL_EDIT_FRAME::DdAddLibrary( wxString aLibFile )
1430{
1431 wxFileName fn = wxFileName( aLibFile );
1432 wxString libName = fn.GetName();
1433
1434 if( libName.IsEmpty() )
1435 return;
1436
1437 LIBRARY_MANAGER& manager = Pgm().GetLibraryManager();
1439
1440 if( adapter->HasLibrary( libName ) )
1441 {
1442 DisplayError( this, wxString::Format( _( "Library '%s' already exists." ), libName ) );
1443 return;
1444 }
1445
1446 if( !m_libMgr->AddLibrary( fn.GetFullPath(), LIBRARY_TABLE_SCOPE::PROJECT ) )
1447 {
1448 DisplayError( this, _( "Could not open the library file." ) );
1449 return;
1450 }
1451
1452 std::optional<LIBRARY_TABLE*> optTable = manager.Table( LIBRARY_TABLE_TYPE::SYMBOL, LIBRARY_TABLE_SCOPE::PROJECT );
1453 wxCHECK( optTable.has_value(), /* void */ );
1454 LIBRARY_TABLE* table = optTable.value();
1455 bool success = true;
1456
1457 table->Save().map_error(
1458 [&]( const LIBRARY_ERROR& aError )
1459 {
1460 KICAD_MESSAGE_DIALOG dlg( this, _( "Error saving library table." ), _( "File Save Error" ),
1461 wxOK | wxICON_ERROR );
1462 dlg.SetExtendedMessage( aError.message );
1463 dlg.ShowModal();
1464
1465 success = false;
1466 } );
1467
1468 if( success )
1469 adapter->LoadOne( libName );
1470
1471 std::string packet = fn.GetFullPath().ToStdString();
1474}
1475
1476
1478{
1479 return GetLibTree()->GetSelectedLibId( aUnit );
1480}
1481
1482
1487
1488int SYMBOL_EDIT_FRAME::GetTreeLIBIDs( std::vector<LIB_ID>& aSelection ) const
1489{
1490 return GetLibTree()->GetSelectedLibIds( aSelection );
1491}
1492
1493
1495{
1496 if( IsLibraryTreeShown() )
1497 {
1498 LIB_ID libId = GetTreeLIBID();
1499
1500 if( libId.IsValid() )
1501 return m_libMgr->GetSymbol( libId.GetLibItemName(), libId.GetLibNickname() );
1502 }
1503
1504 return m_symbol;
1505}
1506
1507
1509{
1510 LIB_ID id;
1511
1512 if( IsLibraryTreeShown() )
1513 id = GetTreeLIBID();
1514
1515 if( id.GetLibNickname().empty() && m_symbol )
1516 id = m_symbol->GetLibId();
1517
1518 return id;
1519}
1520
1521
1522std::vector<LIB_ID> SYMBOL_EDIT_FRAME::GetSelectedLibIds() const
1523{
1524 std::vector<LIB_ID> ids;
1525 GetTreeLIBIDs( ids );
1526 return ids;
1527}
1528
1529
1531{
1532 return GetTargetLibId().GetLibNickname();
1533}
1534
1535
1536void SYMBOL_EDIT_FRAME::SyncLibraries( bool aShowProgress, bool aPreloadCancelled, const wxString& aForceRefresh )
1537{
1538 wxLogTrace( wxT( "KICAD_TABS_DBG" ),
1539 wxT( "SYMBOL_EDIT_FRAME::SyncLibraries enter (progress=%d, forceRefresh='%s')" ),
1540 aShowProgress, aForceRefresh );
1541
1542 // Prevent re-entrant calls. The progress dialog yields the event loop during Sync(),
1543 // which can dispatch queued UI events (e.g. menu clicks queued while the app was busy
1544 // loading libraries). A re-entrant call would corrupt the library tree mid-rebuild.
1546 {
1547 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "SYMBOL_EDIT_FRAME::SyncLibraries re-entrant; skipping" ) );
1548 return;
1549 }
1550
1552
1553 auto resetGuard =
1554 [this]( bool* )
1555 {
1557 };
1558
1559 std::unique_ptr<bool, decltype( resetGuard )> guard( &m_syncLibrariesInProgress, resetGuard );
1560
1561 LIB_ID selected;
1562 std::vector<LIB_ID> expanded;
1563
1564 if( m_treePane )
1565 {
1566 selected = GetLibTree()->GetSelectedLibId();
1567 expanded = GetLibTree()->GetExpandedLibraries();
1568 }
1569
1570 // Ensure any in-progress background library preloading is complete before syncing the
1571 // tree. Without this, libraries still in LOADING state get skipped by Sync(), resulting
1572 // in an incomplete tree that requires a manual refresh to fully populate.
1574 adapter->BlockUntilLoaded();
1575
1576 if( aShowProgress )
1577 {
1578 APP_PROGRESS_DIALOG progressDlg( _( "Loading Symbol Libraries" ), wxEmptyString,
1579 m_libMgr->GetAdapter()->GetLibrariesCount(), this );
1580
1581 THROTTLE progressThrottle( std::chrono::milliseconds( 350 ) );
1582 int pendingProgress = 0;
1583 bool callbackFired = false;
1584 wxString pendingLibName;
1585
1586 m_libMgr->Sync( aForceRefresh,
1587 [&]( int progress, int max, const wxString& libName )
1588 {
1589 pendingProgress = progress;
1590 pendingLibName = libName;
1591 callbackFired = true;
1592
1593 if( progressThrottle.Ready() )
1594 progressDlg.Update( progress, wxString::Format( _( "Loading library '%s'..." ), libName ) );
1595 } );
1596
1597 if( callbackFired )
1598 progressDlg.Update( pendingProgress, wxString::Format( _( "Loading library '%s'..." ), pendingLibName ) );
1599 }
1600 else if( !aPreloadCancelled )
1601 {
1602 m_libMgr->Sync( aForceRefresh, [&]( int progress, int max, const wxString& libName ) {} );
1603 }
1604
1605 if( m_treePane )
1606 {
1607 wxDataViewItem found;
1608
1609 if( selected.IsValid() )
1610 {
1611 // Check if the previously selected item is still valid,
1612 // if not - it has to be unselected to prevent crash
1613 found = m_libMgr->GetAdapter()->FindItem( selected );
1614
1615 if( !found )
1616 GetLibTree()->Unselect();
1617 }
1618
1619 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "SYMBOL_EDIT_FRAME::SyncLibraries Regenerate" ) );
1620 GetLibTree()->Regenerate( true );
1621
1622 // Sync() collapsed the tree, so re-expand the libraries that were open before it.
1623 for( const LIB_ID& libId : expanded )
1624 GetLibTree()->ExpandLibId( libId );
1625
1626 // Try to select the parent library, in case the symbol is not found
1627 if( !found && selected.IsValid() )
1628 {
1629 selected.SetLibItemName( "" );
1630 found = m_libMgr->GetAdapter()->FindItem( selected );
1631
1632 if( found )
1633 GetLibTree()->SelectLibId( selected );
1634 }
1635 }
1636
1637 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "SYMBOL_EDIT_FRAME::SyncLibraries exit" ) );
1638}
1639
1640
1645
1646
1648{
1649 GetLibTree()->SelectLibId( aLibID );
1650}
1651
1652
1653void SYMBOL_EDIT_FRAME::UpdateLibraryTree( const wxDataViewItem& aTreeItem, LIB_SYMBOL* aSymbol )
1654{
1655 if( aTreeItem.IsOk() ) // Can be not found in tree if the current footprint is imported
1656 // from file therefore not yet in tree.
1657 {
1658 static_cast<LIB_TREE_NODE_ITEM*>( aTreeItem.GetID() )->Update( aSymbol );
1660 }
1661}
1662
1663
1664bool SYMBOL_EDIT_FRAME::backupLibrary( const wxFileName& aOriginalFile, wxString& aErrorMsg )
1665{
1666 wxFileName backupFileName;
1667
1668 if( !aOriginalFile.IsDir() && aOriginalFile.FileExists() )
1669 {
1670 backupFileName = aOriginalFile;
1671 backupFileName.SetExt( wxT( "bak" ) );
1672
1673 if( backupFileName.FileExists() )
1674 {
1675 if( !wxRemoveFile( backupFileName.GetFullPath() ) )
1676 {
1677 aErrorMsg.Printf( _( "Failed to remove existing library backup file '%s'." ),
1678 backupFileName.GetFullPath() );
1679 return false;
1680 }
1681 }
1682
1683 if( !wxCopyFile( aOriginalFile.GetFullPath(), backupFileName.GetFullPath() ) )
1684 {
1685 aErrorMsg.Printf( _( "Failed to save backup to '%s'." ), backupFileName.GetFullPath() );
1686 return false;
1687 }
1688 }
1689 else if( aOriginalFile.IsDir() && aOriginalFile.DirExists() )
1690 {
1691 backupFileName.SetPath( aOriginalFile.GetPath() );
1692 backupFileName.SetName( backupFileName.GetDirs().Last() + wxString( "_backup" ) );
1693 backupFileName.SetExt( "zip" );
1694
1695 std::vector<wxString> libFiles;
1696 wxDir libDir( aOriginalFile.GetPath() );
1697 UNPACKED_SYMBOL_LIBRARY_DIR_TRAVERSER libTraverser( libFiles );
1698
1699 if( backupFileName.FileExists() )
1700 {
1701 if( !wxRemoveFile( backupFileName.GetFullPath() ) )
1702 {
1703 aErrorMsg.Printf( _( "Failed to remove existing library backup file '%s'." ),
1704 backupFileName.GetFullPath() );
1705 return false;
1706 }
1707 }
1708
1709 if( !libDir.IsOpened() )
1710 {
1711 aErrorMsg.Printf( _( "Error opening unpacked library directory: '%s'." ), aOriginalFile.GetPath() );
1712 return false;
1713 }
1714
1715 libDir.Traverse( libTraverser, wxEmptyString, wxDIR_FILES );
1716
1717 wxFFileOutputStream ostream( backupFileName.GetFullPath() );
1718
1719 if( !ostream.IsOk() )
1720 {
1721 aErrorMsg.Printf( _( "Failed to create library backup file '%s'." ), backupFileName.GetFullPath() );
1722 return false;
1723 }
1724
1725 // Use a large I/O buffer to improve compatibility with cloud-synced folders.
1726 if( FILE* fp = ostream.GetFile()->fp() )
1727 setvbuf( fp, nullptr, _IOFBF, KIPLATFORM::IO::CLOUD_SYNC_BUFFER_SIZE );
1728
1729 wxZipOutputStream zipstream( ostream, -1, wxConvUTF8 );
1730
1731 for( const wxString& fileName : libFiles )
1732 {
1733 wxFileName fn( fileName );
1734 wxFileSystem fsFile;
1735
1736 fn.MakeRelativeTo( aOriginalFile.GetPath() );
1737
1738 wxString relativeFn = fn.GetFullPath();
1739
1740 // Read input file and add it to the zip file:
1741 wxFSFile* infile = nullptr;
1742 wxString sysError;
1743
1744 {
1745 // Failures are reported through an error dialog, prevent wx from popping its own dialog.
1746 wxLogNull suppressSysErrorPopups;
1747 infile = fsFile.OpenFile( fileName );
1748
1749 if( !infile )
1750 {
1751 if( unsigned long code = wxSysErrorCode() )
1752 sysError = wxSysErrorMsgStr( code );
1753 }
1754 }
1755
1756 if( infile )
1757 {
1758 zipstream.PutNextEntry( relativeFn, infile->GetModificationTime() );
1759 infile->GetStream()->Read( zipstream );
1760 zipstream.CloseEntry();
1761
1762 delete infile;
1763 }
1764 else
1765 {
1766 if( sysError.IsEmpty() )
1767 aErrorMsg.Printf( _( "Failed to archive file '%s'." ), relativeFn );
1768 else
1769 aErrorMsg.Printf( _( "Failed to archive file '%s': %s" ), relativeFn, sysError );
1770
1771 zipstream.Close();
1772 return false;
1773 }
1774 }
1775
1776 if( !zipstream.Close() )
1777 {
1778 aErrorMsg.Printf( _( "Failed to create file '%s'." ), backupFileName.GetFullPath() );
1779 return false;
1780 }
1781 }
1782
1783 return true;
1784}
1785
1786
1788{
1789 // This will return the root symbol of any alias
1790 LIB_SYMBOL* symbol = m_libMgr->GetBufferedSymbol( aLibId.GetLibItemName(), aLibId.GetLibNickname() );
1791
1792 // Now we can compare the libId of the current symbol and the root symbol
1793 return ( symbol && m_symbol && symbol->GetLibId() == m_symbol->GetLibId() );
1794}
1795
1796
1798{
1799 GetLibTree()->Unselect();
1800
1801 // Tear down every tab first so no context observes the about-to-be-deleted working symbol.
1803
1804 SetCurSymbol( nullptr, false );
1808 Refresh();
1809}
1810
1811
1813{
1815
1817 {
1818 GetRenderSettings()->m_ShowPinsElectricalType = cfg->m_ShowPinElectricalType;
1819 GetRenderSettings()->m_ShowHiddenPins = cfg->m_ShowHiddenPins;
1820 GetRenderSettings()->m_ShowHiddenFields = cfg->m_ShowHiddenFields;
1821 GetRenderSettings()->m_ShowPinAltIcons = cfg->m_ShowPinAltIcons;
1822
1823 // This editor always shows the axes, whatever a settings file not yet saved by it says
1824 cfg->m_Window.grid.axes_enabled = true;
1825 GetGalDisplayOptions().ReadWindowSettings( cfg->m_Window );
1826 }
1827
1828 if( m_symbol )
1829 m_symbol->ClearCaches();
1830
1832
1834 GetCanvas()->Refresh();
1835
1837
1838 if( aFlags & ENVVARS_CHANGED )
1839 SyncLibraries( true );
1840
1841 Layout();
1842 SendSizeEvent();
1843}
1844
1845
1847{
1848 // call my base class
1850
1851 // tooltips in toolbars
1853
1854 // For some obscure reason, the AUI manager hides the first modified pane.
1855 // So force show panes
1856 wxAuiPaneInfo& tree_pane_info = m_auimgr.GetPane( m_treePane );
1857 bool tree_shown = tree_pane_info.IsShown();
1858 tree_pane_info.Caption( _( "Libraries" ) );
1859 tree_pane_info.Show( tree_shown );
1860 m_auimgr.Update();
1861
1863
1864 // status bar
1866
1867 if( GetRenderSettings()->m_ShowPinsElectricalType )
1868 {
1870 GetCanvas()->Refresh();
1871 }
1872
1873 UpdateTitle();
1874}
1875
1876
1878{
1879 SCH_BASE_FRAME::SetScreen( aScreen );
1880
1881 if( m_toolManager )
1882 {
1883 m_toolManager->SetEnvironment( aScreen, GetCanvas()->GetView(), GetCanvas()->GetViewControls(), GetSettings(),
1884 this );
1886 }
1887}
1888
1889
1907
1908
1910{
1911 SyncLibraries( true );
1912
1913 if( m_symbol )
1914 {
1915 SCH_SELECTION_TOOL* selectionTool = m_toolManager->GetTool<SCH_SELECTION_TOOL>();
1916 SCH_SELECTION& selection = selectionTool->GetSelection();
1917
1918 for( SCH_ITEM& item : m_symbol->GetDrawItems() )
1919 {
1920 if( !alg::contains( selection, &item ) )
1921 item.ClearSelected();
1922 else
1923 item.SetSelected();
1924 }
1925
1926 m_symbol->ClearCaches();
1927 }
1928
1929 RebuildView();
1930}
1931
1932
1933const BOX2I SYMBOL_EDIT_FRAME::GetDocumentExtents( bool aIncludeAllVisible ) const
1934{
1935 if( !m_symbol )
1936 {
1937 // Gives a reasonable drawing area size
1938 int width = schIUScale.mmToIU( 50 );
1939 int height = schIUScale.mmToIU( 30 );
1940
1941 return BOX2I( VECTOR2I( -width/2, -height/2 ), VECTOR2I( width, height ) );
1942 }
1943 else
1944 {
1945 return m_symbol->Flatten()->GetUnitBoundingBox( m_unit, m_bodyStyle );
1946 }
1947}
1948
1949
1950void SYMBOL_EDIT_FRAME::FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll )
1951{
1952 static KIID lastBrightenedItemID( niluuid );
1953
1954 SCH_ITEM* lastItem = nullptr;
1955
1956 // nullptr will clear the current focus
1957 if( aItem != nullptr && !aItem->IsSCH_ITEM() )
1958 return;
1959
1960 if( m_symbol )
1961 {
1962 for( SCH_PIN* pin : m_symbol->GetGraphicalPins( 0, 0 ) )
1963 {
1964 if( pin->m_Uuid == lastBrightenedItemID )
1965 lastItem = pin;
1966 }
1967
1968 std::vector<SCH_FIELD*> fields;
1969 m_symbol->GetFields( fields );
1970
1971 for( SCH_FIELD* field : fields )
1972 {
1973 if( field->m_Uuid == lastBrightenedItemID )
1974 lastItem = field;
1975 }
1976 }
1977
1978 if( lastItem && lastItem != aItem )
1979 {
1980 lastItem->ClearBrightened();
1981
1982 UpdateItem( lastItem );
1983 lastBrightenedItemID = niluuid;
1984 }
1985
1986 if( aItem )
1987 {
1988 if( aItem->IsSCH_ITEM() )
1989 {
1990 SCH_ITEM* item = static_cast<SCH_ITEM*>( aItem );
1991
1992 if( int unit = item->GetUnit() )
1993 SetUnit( unit );
1994
1995 if( int bodyStyle = item->GetBodyStyle() )
1996 SetBodyStyle( bodyStyle );
1997 }
1998
1999 if( !aItem->IsBrightened() )
2000 {
2001 aItem->SetBrightened();
2002
2003 UpdateItem( aItem );
2004 lastBrightenedItemID = aItem->m_Uuid;
2005 }
2006
2007 FocusOnLocation( VECTOR2I( aItem->GetFocusPosition().x, aItem->GetFocusPosition().y ), aAllowScroll );
2008 }
2009}
2010
2011
2013{
2014 const std::string& payload = mail.GetPayload();
2015
2016 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "SYMBOL_EDIT_FRAME::KiwayMailIn cmd=%d" ), (int) mail.Command() );
2017
2018 switch( mail.Command() )
2019 {
2020 case MAIL_LIB_EDIT:
2021 if( !payload.empty() )
2022 {
2023 wxString uri( payload );
2024 wxString libNickname;
2025 wxString msg;
2026
2028 std::optional<const LIBRARY_TABLE_ROW*> libTableRow = adapter->FindRowByURI( uri );
2029
2030 if( !libTableRow )
2031 {
2032 msg.Printf( _( "The current configuration does not include the symbol library '%s'." ),
2033 uri );
2034 msg += wxS( "\n" ) + _( "Use Manage Symbol Libraries to edit the configuration." );
2035 DisplayErrorMessage( this, _( "Library not found in symbol library table." ), msg );
2036 break;
2037 }
2038
2039 libNickname = ( *libTableRow )->Nickname();
2040
2041 if( !adapter->HasLibrary( libNickname, true ) )
2042 {
2043 msg.Printf( _( "The symbol library '%s' is not enabled in the current configuration." ),
2044 UnescapeString( libNickname ) );
2045 msg += wxS( "\n" ) + _( "Use Manage Symbol Libraries to edit the configuration." );
2046 DisplayErrorMessage( this, _( "Symbol library not enabled." ), msg );
2047 break;
2048 }
2049
2050 if( m_treePane )
2051 {
2052 LIB_ID id( libNickname, wxEmptyString );
2053 GetLibTree()->SelectLibId( id );
2054 GetLibTree()->ExpandLibId( id );
2055 GetLibTree()->CenterLibId( id );
2056 }
2057 }
2058
2059 break;
2060
2062 {
2063 LIB_ID libId;
2064 const int badPos = libId.Parse( wxString::FromUTF8( payload ) );
2065
2066 if( badPos == -1 && libId.IsValid() )
2067 {
2068 LoadSymbol( libId, 1, BODY_STYLE::BASE );
2069 Raise();
2070 }
2071
2072 break;
2073 }
2074
2075 case MAIL_RELOAD_LIB:
2076 {
2077 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "SYMBOL_EDIT_FRAME::KiwayMailIn MAIL_RELOAD_LIB -> SyncLibraries" ) );
2078
2080
2081 // Suppress the progress dialog for this background reload. It would steal focus from the
2082 // editor that broadcast the reload, and the tree is already frozen around the sync.
2083 SyncLibraries( false );
2086
2087 break;
2088 }
2089
2091 {
2093 LIB_SYMBOL* symbol = GetCurSymbol();
2094
2095 wxLogTrace( traceLibWatch, "Received refresh symbol request for %s", payload );
2096
2097 if( !symbol )
2098 break;
2099
2100 // Capture the name now. UpdateLibraryBuffer() recreates the buffer, so reading it from the
2101 // buffer copy afterwards would be a use-after-free.
2102 const wxString refreshSymbolName = symbol->GetName();
2103
2104 // A modal dialog may be registered before wxGTK disables the frame. Refreshing the
2105 // symbol in either state would delete the LIB_SYMBOL being edited by the dialog.
2106 if( !IsEnabled() || Kiway().HasBlockingDialog() )
2107 {
2108 wxLogTrace( traceLibWatch, "Deferring symbol refresh; dialog is open on the symbol editor." );
2109 break;
2110 }
2111 // Defensive backstop for refresh mail that did not originate from this frame's debounce
2112 // timer (which already defers while a tool is active). An interactive tool holds
2113 // references into the current symbol, so replacing it here would crash; drop this refresh
2114 // and let the originating watcher retry.
2115 else if( !ToolStackIsEmpty() )
2116 {
2117 wxLogTrace( traceLibWatch, "Deferring symbol refresh; an interactive tool is active." );
2118 break;
2119 }
2120
2121 wxString libName = symbol->GetLibId().GetLibNickname();
2122 std::optional<const LIBRARY_TABLE_ROW*> row = adapter->GetRow( libName );
2123
2124 if( !row )
2125 return;
2126
2127 wxFileName libfullname( LIBRARY_MANAGER::GetFullURI( *row, true ) );
2128
2129 wxFileName changedLib( mail.GetPayload() );
2130
2131 wxLogTrace( traceLibWatch, "Received refresh symbol request for %s, current symbols is %s",
2132 changedLib.GetFullPath(), libfullname.GetFullPath() );
2133
2134 if( changedLib == libfullname )
2135 {
2136 wxLogTrace( traceLibWatch, "Refreshing symbol %s", refreshSymbolName );
2137
2138 m_libMgr->UpdateLibraryBuffer( libName );
2139
2140 if( LIB_SYMBOL* lib_symbol = m_libMgr->GetBufferedSymbol( refreshSymbolName, libName ) )
2141 {
2142 SetCurSymbol( new LIB_SYMBOL( *lib_symbol ), false );
2144
2145 if( m_toolManager )
2147 }
2148 }
2149
2150 break;
2151 }
2152
2153 default:
2154 break;
2155 }
2156}
2157
2158
2159std::unique_ptr<GRID_HELPER> SYMBOL_EDIT_FRAME::MakeGridHelper()
2160{
2161 return std::make_unique<EE_GRID_HELPER>( m_toolManager );
2162}
2163
2164
2166{
2167 // switches currently used canvas ( Cairo / OpenGL):
2168 SCH_BASE_FRAME::SwitchCanvas( aCanvasType );
2169
2170 // Set options specific to symbol editor (axies are always enabled):
2171 GetCanvas()->GetGAL()->SetAxesEnabled( true );
2173}
2174
2175
2177{
2178 wxCHECK( m_libMgr, false );
2179
2180 return m_libMgr->HasModifications();
2181}
2182
2183
2185{
2186 wxCHECK( m_libMgr, false );
2187
2188 // Test if the currently edited symbol is modified
2190 return true;
2191
2192 // Test if any library has been modified
2193 for( const wxString& libName : m_libMgr->GetLibraryNames() )
2194 {
2195 if( m_libMgr->IsLibraryModified( libName ) && !m_libMgr->IsLibraryReadOnly( libName ) )
2196 return true;
2197 }
2198
2199 return false;
2200}
2201
2202
2204{
2205 if( aItemCount == 0 )
2206 return;
2207
2208 UNDO_REDO_CONTAINER& list = ( whichList == UNDO_LIST ) ? m_undoList : m_redoList;
2209
2210 // UR_TRANSIENT is flagged on the picked item, not the wrapper, so the shared deleters miss it.
2211 // Free the items carrying UR_TRANSIENT. m_symbol never carries it, so the live copy is safe.
2212 if( aItemCount < 0 )
2213 {
2215 }
2216 else
2217 {
2218 for( int ii = 0; ii < aItemCount; ii++ )
2219 {
2220 if( list.m_CommandsList.size() == 0 )
2221 break;
2222
2223 PICKED_ITEMS_LIST* curr_cmd = list.m_CommandsList[0];
2224 list.m_CommandsList.erase( list.m_CommandsList.begin() );
2225
2226 for( unsigned jj = 0; jj < curr_cmd->GetCount(); ++jj )
2227 {
2228 EDA_ITEM* item = curr_cmd->GetPickedItem( jj );
2229
2230 if( item && item->HasFlag( UR_TRANSIENT ) && item != m_symbol )
2231 delete item;
2232 }
2233
2234 curr_cmd->ClearItemsList();
2235 delete curr_cmd; // Delete command
2236 }
2237 }
2238}
2239
2240
2242{
2243 return m_toolManager->GetTool<SCH_SELECTION_TOOL>()->GetSelection();
2244}
2245
2246
2248 bool aRestorePending, bool aTreeShownNow )
2249{
2250 // Auto-hiding a visible tree schedules its restore. A chained schematic edit finds the tree
2251 // already auto-hidden, so keep the pending restore rather than dropping it. An explicit user
2252 // toggle clears the flag elsewhere, so a tree hidden without a pending restore stays that way.
2253 if( aTreeShownNow )
2254 return true;
2255
2256 return aWasFromSchematic && aRestorePending;
2257}
2258
2259
2261{
2262 std::unique_ptr<LIB_SYMBOL> symbol = aSymbol->GetLibSymbolRef()->Flatten();
2263 wxCHECK( symbol, /* void */ );
2264
2265 symbol->SetLibId( aSymbol->GetLibId() );
2266
2267 // Take in account the symbol orientation and mirroring. to calculate the field
2268 // positions in symbol editor (i.e. no rotation, no mirroring)
2269 int orientation = aSymbol->GetOrientation() & ~( SYM_MIRROR_X | SYM_MIRROR_Y );
2270 int mirror = aSymbol->GetOrientation() & ( SYM_MIRROR_X | SYM_MIRROR_Y );
2271
2272 std::vector<SCH_FIELD> fullSetOfFields;
2273
2274 for( const SCH_FIELD& field : aSymbol->GetFields() )
2275 {
2276 VECTOR2I pos = field.GetPosition() - aSymbol->GetPosition();
2277 SCH_FIELD libField( symbol.get(), field.GetId() );
2278
2279 libField = field;
2280
2281 // The inverse transform is mirroring before, rotate after
2282 switch( mirror )
2283 {
2284 case SYM_MIRROR_X: pos.y = -pos.y; break;
2285 case SYM_MIRROR_Y: pos.x = -pos.x; break;
2286 default: break;
2287 }
2288
2289 switch( orientation )
2290 {
2291 case SYM_ORIENT_90:
2292 std::swap( pos.x, pos.y );
2293 pos.x = - pos.x;
2294 break;
2295 case SYM_ORIENT_270:
2296 std::swap( pos.x, pos.y );
2297 pos.y = - pos.y;
2298 break;
2299 case SYM_ORIENT_180:
2300 pos.x = - pos.x;
2301 pos.y = - pos.y;
2302 break;
2303 default:
2304 break;
2305 }
2306
2307 libField.SetPosition( pos );
2308
2309 fullSetOfFields.emplace_back( std::move( libField ) );
2310 }
2311
2312 symbol->SetFields( fullSetOfFields );
2313
2314 const wxString reference = symbol->GetReferenceField().GetText();
2315 const int unit = std::max( 1, aSymbol->GetUnit() );
2316 const int bodyStyle = std::max( 1, aSymbol->GetBodyStyle() );
2317
2318 // Optimize default edit options for this symbol
2319 // Usually if units are locked, graphic items are specific to each unit
2320 // and if units are interchangeable, graphic items are common to units
2321 SetDrawSpecificUnit( symbol->UnitsLocked() );
2322
2323 // Hand the transient working symbol/screen to a session-only instance tab, whose activation
2324 // restores the frame's schematic-source state so the save path routes back to the schematic.
2325 SCH_SCREEN* tmpScreen = new SCH_SCREEN();
2326
2327 setSymWatcher( nullptr );
2328
2329 SYMBOL_EDITOR_TAB_CONTEXT* ctx = findOrCreateSymbolInstanceTab( symbol.release(), tmpScreen,
2330 aSymbol->m_Uuid, reference, unit,
2331 bodyStyle );
2332 wxCHECK( ctx, /* void */ );
2333
2336
2337 // Auto-hide the tree while editing a schematic symbol, remembering to restore it in SaveSettings
2338 // so the user's preference survives a restart. Hide via the pane directly, not ToggleLibraryTree,
2339 // which would treat this as a user toggle and drop the pending restore.
2342
2343 if( IsLibraryTreeShown() )
2344 {
2345 m_auimgr.GetPane( m_treePane ).Show( false );
2347 m_auimgr.Update();
2348 Refresh();
2349 }
2350
2353 updateInfoBar();
2354
2355 // Let tools add things to the view if necessary
2356 if( m_toolManager )
2358
2360 GetCanvas()->Refresh();
2361}
2362
2363
2364bool SYMBOL_EDIT_FRAME::addLibTableEntry( const wxString& aLibFile, LIBRARY_TABLE_SCOPE aScope )
2365{
2366 wxFileName fn = aLibFile;
2367 wxFileName libTableFileName( Prj().GetProjectPath(), FILEEXT::SymbolLibraryTableFileName );
2368 wxString libNickname = fn.GetName();
2370 LIBRARY_MANAGER& manager = Pgm().GetLibraryManager();
2371 const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
2372
2373 if( adapter->HasLibrary( libNickname ) )
2374 {
2375 wxString tmp;
2376 int suffix = 1;
2377
2378 while( adapter->HasLibrary( libNickname ) )
2379 {
2380 tmp.Printf( "%s%d", fn.GetName(), suffix );
2381 libNickname = tmp;
2382 suffix += 1;
2383 }
2384 }
2385
2386 std::optional<LIBRARY_TABLE*> optTable = manager.Table( LIBRARY_TABLE_TYPE::SYMBOL, aScope );
2387 wxCHECK( optTable.has_value(), false );
2388 LIBRARY_TABLE* table = optTable.value();
2389
2390 LIBRARY_TABLE_ROW* row = &table->InsertRow();
2391
2392 row->SetNickname( libNickname );
2393
2394 // We cannot normalize against the current project path when saving to global table.
2395 wxString normalizedPath = NormalizePath( aLibFile, &envVars,
2396 aScope == LIBRARY_TABLE_SCOPE::PROJECT ? Prj().GetProjectPath()
2397 : wxString( wxEmptyString ) );
2398
2399 row->SetURI( normalizedPath );
2401
2402 bool success = true;
2403
2404 table->Save().map_error(
2405 [&]( const LIBRARY_ERROR& aError )
2406 {
2407 KICAD_MESSAGE_DIALOG dlg( this, _( "Error saving library table." ), _( "File Save Error" ),
2408 wxOK | wxICON_ERROR );
2409 dlg.SetExtendedMessage( aError.message );
2410 dlg.ShowModal();
2411
2412 success = false;
2413 } );
2414
2415 if( success )
2416 {
2417 manager.ReloadTables( aScope, { LIBRARY_TABLE_TYPE::SYMBOL } );
2418 adapter->LoadOne( libNickname );
2419 }
2420
2421 return success;
2422}
2423
2424
2425bool SYMBOL_EDIT_FRAME::replaceLibTableEntry( const wxString& aLibNickname, const wxString& aLibFile )
2426{
2428 LIBRARY_MANAGER& manager = Pgm().GetLibraryManager();
2429 LIBRARY_TABLE* table = nullptr;
2431
2432 // Check the global library table first because checking the project library table
2433 // checks the global library table as well due to library chaining.
2434 if( adapter->GetRow( aLibNickname, scope ) )
2435 {
2436 std::optional<LIBRARY_TABLE*> optTable = manager.Table( LIBRARY_TABLE_TYPE::SYMBOL, scope );
2437 wxCHECK( optTable.has_value(), false );
2438 table = optTable.value();
2439 }
2440 else
2441 {
2443
2444 if( adapter->GetRow( aLibNickname, scope ) )
2445 {
2446 std::optional<LIBRARY_TABLE*> optTable = manager.Table( LIBRARY_TABLE_TYPE::SYMBOL, scope );
2447
2448 if( optTable.has_value() )
2449 table = optTable.value();
2450 }
2451 }
2452
2453 wxCHECK( table, false );
2454
2455 std::optional<LIBRARY_TABLE_ROW*> optRow = adapter->GetRow( aLibNickname, scope );
2456 wxCHECK( optRow.has_value(), false );
2457 LIBRARY_TABLE_ROW* row = optRow.value();
2458
2459 const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables();
2460
2461 wxString projectPath;
2462
2463 if( scope == LIBRARY_TABLE_SCOPE::PROJECT )
2464 projectPath = Prj().GetProjectPath();
2465
2466 wxString normalizedPath = NormalizePath( aLibFile, &envVars, projectPath );
2467
2468 row->SetURI( normalizedPath );
2469 row->SetType( "KiCad" );
2470
2471 bool success = true;
2472
2473 table->Save().map_error(
2474 [&]( const LIBRARY_ERROR& aError )
2475 {
2476 KICAD_MESSAGE_DIALOG dlg( this, _( "Error saving library table." ), _( "File Save Error" ),
2477 wxOK | wxICON_ERROR );
2478 dlg.SetExtendedMessage( aError.message );
2479 dlg.ShowModal();
2480
2481 success = false;
2482 } );
2483
2484 if( success )
2485 {
2486 manager.ReloadTables( scope, { LIBRARY_TABLE_TYPE::SYMBOL } );
2487 adapter->LoadOne( aLibNickname );
2488 }
2489
2490 return success;
2491}
2492
2493
2495{
2496 return m_symbol && !m_symbol->IsRoot();
2497}
2498
2499
2504
2505
2507{
2508 // Cannot edit graphics of symbols from legacy libraries, or of symbol aliases
2509 // unless the symbol is from a schematic (in which case it is a working copy of the symbol).
2511}
2512
2513
2514void SYMBOL_EDIT_FRAME::UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete, bool aUpdateRtree )
2515{
2516 SCH_BASE_FRAME::UpdateItem( aItem, isAddOrDelete, aUpdateRtree );
2517
2518 if( EDA_TEXT* eda_text = dynamic_cast<EDA_TEXT*>( aItem ) )
2519 {
2520 eda_text->ClearBoundingBoxCache();
2521 eda_text->ClearRenderCache();
2522 }
2523}
2524
2525
2527{
2528 wxAuiPaneInfo& treePane = m_auimgr.GetPane( m_treePane );
2529 wxAuiPaneInfo& propertiesPane = m_auimgr.GetPane( PropertiesPaneName() );
2530 wxAuiPaneInfo& selectionFilterPane = m_auimgr.GetPane( wxS( "SelectionFilter" ) );
2531
2532 // Don't give the selection filter its own visibility controls; instead show it if
2533 // anything else is visible
2534 bool showFilter = ( treePane.IsShown() && treePane.IsDocked() )
2535 || ( propertiesPane.IsShown() && propertiesPane.IsDocked() );
2536
2537 selectionFilterPane.Show( showFilter );
2538}
2539
2540
2542{
2543 // Returns the current render option for invisible fields
2545}
2546
2547
2549{
2550 // Returns the current render option for invisible pins
2552}
const KICOMMON_API wxEventTypeTag< wxCommandEvent > EDA_EVT_PLUGIN_AVAILABILITY_CHANGED
Notifies other parts of KiCad when plugin availability changes.
BASE_SCREEN class implementation.
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:130
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition bitmap.cpp:100
@ icon_libedit_32
@ icon_libedit_16
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
BOX2< VECTOR2D > BOX2D
Definition box2.h:915
static TOOL_ACTION toggleGrid
Definition actions.h:194
static TOOL_ACTION paste
Definition actions.h:76
static TOOL_ACTION cancelInteractive
Definition actions.h:68
static TOOL_ACTION unselectAll
Definition actions.h:79
static TOOL_ACTION revert
Definition actions.h:58
static TOOL_ACTION showLibraryTree
Definition actions.h:160
static TOOL_ACTION copy
Definition actions.h:74
static TOOL_ACTION showDatasheet
Definition actions.h:264
static TOOL_ACTION toggleBoundingBoxes
Definition actions.h:153
static TOOL_ACTION saveAll
Definition actions.h:57
static TOOL_ACTION undo
Definition actions.h:71
static TOOL_ACTION duplicate
Definition actions.h:80
static TOOL_ACTION doDelete
Definition actions.h:81
static TOOL_ACTION selectionTool
Definition actions.h:247
static TOOL_ACTION save
Definition actions.h:54
static TOOL_ACTION zoomFitScreen
Definition actions.h:138
static TOOL_ACTION redo
Definition actions.h:72
static TOOL_ACTION deleteTool
Definition actions.h:82
static TOOL_ACTION zoomTool
Definition actions.h:142
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
static TOOL_ACTION showProperties
Definition actions.h:262
static TOOL_ACTION cut
Definition actions.h:73
static TOOL_ACTION ddAddLibrary
Definition actions.h:63
static TOOL_ACTION copyAsText
Definition actions.h:75
static TOOL_ACTION toggleGridOverrides
Definition actions.h:195
static TOOL_ACTION selectAll
Definition actions.h:78
Manage TOOL_ACTION objects.
void SetConditions(const TOOL_ACTION &aAction, const ACTION_CONDITIONS &aConditions)
Set the conditions the UI elements for activating a specific tool action should use for determining t...
wxProgressDialog with the option to also update the application progress on the taskbar
virtual bool Update(int aValue, const wxString &aNewMsg=wxEmptyString, bool *aSkip=nullptr) override
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
wxString m_ColorTheme
Active color theme name.
Handles how to draw a screen (a board, a schematic ...)
Definition base_screen.h:37
void SetContentModified(bool aModified=true)
Definition base_screen.h:55
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:234
constexpr void SetSize(const SizeVec &size)
Definition box2.h:245
Color settings are a bit different than most of the settings objects in that there can be more than o...
Handle actions that are shared between different applications.
Handles action that are shared between different applications.
UNDO_REDO_CONTAINER m_undoList
void ShowChangedLanguage() override
Redraw the menus and what not in current language.
virtual void setupUIConditions()
Setup the UI conditions for the various actions and their controls in this frame.
virtual void ClearUndoRedoList()
Clear the undo and redo list using ClearUndoORRedoList()
SETTINGS_MANAGER * GetSettingsManager() const
UNDO_REDO_LIST
Specify whether we are interacting with the undo or redo stacks.
virtual void OnModify()
Must be called after a model change in order to set the "modify" flag and do other frame-specific pro...
ACTION_TOOLBAR * m_tbRight
TOOLBAR_SETTINGS * m_toolbarSettings
wxAuiManager m_auimgr
virtual void RecreateToolbars()
UNDO_REDO_CONTAINER m_redoList
ACTION_TOOLBAR * m_tbLeft
virtual void OnDropFiles(wxDropFilesEvent &aEvent)
Handle event fired when a file is dropped to the window.
std::map< const wxString, TOOL_ACTION * > m_acceptedExts
Associate file extensions with action to execute.
ACTION_TOOLBAR * m_tbTopMain
wxString m_aboutTitle
bool m_isClosing
Set by the close window event handler after frames are asked if they can close.
void ReCreateMenuBar()
Recreate the menu bar.
WX_INFOBAR * GetInfoBar()
COLOR_SETTINGS * m_colorSettings
void OnSelectGrid(wxCommandEvent &event)
Command event handler for selecting grid sizes.
void setupUnits(APP_SETTINGS_BASE *aCfg)
void setArcModeConditions(const TOOL_ACTION &aDrawArc, const std::function< bool(const SELECTION &)> &aEnable)
Check each arc mode's tool action while the arc tool runs in that mode.
virtual void SwitchCanvas(EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType)
Change the current rendering backend.
virtual void OnSelectZoom(wxCommandEvent &event)
Set the zoom factor when selected by the zoom list box in the main tool bar.
GAL_DISPLAY_OPTIONS_IMPL & GetGalDisplayOptions()
Return a reference to the gal rendering options used by GAL for rendering.
virtual void resolveCanvasType()
Determine the canvas type to load (with prompt if required) and initializes m_canvasType.
static const wxString PropertiesPaneName()
EDA_MSG_PANEL * m_messagePanel
virtual void SetScreen(BASE_SCREEN *aScreen)
bool LibraryFileBrowser(const wxString &aTitle, bool doOpen, wxFileName &aFilename, const wxString &wildcard, const wxString &ext, bool isDirectory, FILEDLG_HOOK_NEW_LIBRARY *aFileDlgHook=nullptr)
void FocusOnLocation(const VECTOR2I &aPos, bool aAllowScroll=true)
Useful to focus on a particular location, in find functions.
PROPERTIES_PANEL * m_propertiesPanel
void ForceRefresh()
Force a redraw.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
KIGFX::GAL * GetGAL() const
Return a pointer to the GAL instance used in the panel.
void SetEventDispatcher(TOOL_DISPATCHER *aEventDispatcher)
Set a dispatcher that processes events and forwards them to tools.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
virtual const VECTOR2I GetFocusPosition() const
Similar to GetPosition() but allows items to return their visual center rather than their anchor.
Definition eda_item.h:355
const KIID m_Uuid
Definition eda_item.h:599
void ClearBrightened()
Definition eda_item.h:154
void SetBrightened()
Definition eda_item.h:151
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:168
bool IsBrightened() const
Definition eda_item.h:136
Specialization of the wxAuiPaneInfo class for KiCad panels.
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:94
Class that groups generic conditions for editor states.
SELECTION_CONDITION NoActiveTool()
Create a functor testing if there are no tools active in the frame.
SELECTION_CONDITION BoundingBoxes()
SELECTION_CONDITION RedoAvailable()
Create a functor that tests if there are any items in the redo queue.
SELECTION_CONDITION CurrentTool(const TOOL_ACTION &aTool)
Create a functor testing if the specified tool is the current active tool in the frame.
virtual SELECTION_CONDITION UndoAvailable()
Create a functor that tests if there are any items in the undo queue.
SELECTION_CONDITION GridVisible()
Create a functor testing if the grid is visible in a frame.
SELECTION_CONDITION GridOverrides()
Create a functor testing if the grid overrides wires is enabled in a frame.
The tab strip plus the single shared GAL canvas.
Tool responsible for drawing graphical shapes (rectangles, circles, arcs, beziers,...
void ReadWindowSettings(WINDOW_SETTINGS &aCfg)
Read GAL config options from application-level config.
void RegisterHandler(API_HANDLER *aHandler)
Adds a new request handler to the server.
void DeregisterHandler(API_HANDLER *aHandler)
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:38
int ShowModal() override
Definition kidialog.cpp:89
bool m_axesEnabled
Whether or not to draw the coordinate system axes.
void SetAxesEnabled(bool aAxesEnabled)
Enable drawing the axes.
void SetAxesColor(const COLOR4D &aAxesColor)
Set the axes color.
void SetDefaultFont(const wxString &aFont)
void HideDrawingSheet()
Definition sch_view.cpp:317
void ClearHiddenFlags()
Clear the hide flag of all items in the view.
Definition sch_view.cpp:305
bool IsSCH_ITEM() const
Definition view_item.h:97
void Clear()
Remove all items from the view.
Definition view.cpp:1774
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition view.cpp:2475
Definition kiid.h:46
Carry a payload from one KIWAY_PLAYER to another within a PROJECT.
Definition kiway_mail.h:34
std::string & GetPayload()
Return the payload, which can be any text but it typically self identifying s-expression.
Definition kiway_mail.h:52
MAIL_T Command()
Returns the MAIL_T associated with this mail.
Definition kiway_mail.h:44
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:348
void OnKiCadExit()
Definition kiway.cpp:803
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:401
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr, bool aFromOtherThread=false)
Send aPayload to aDestination from aSource.
Definition kiway.cpp:499
Module editor specific tools.
std::optional< LIBRARY_TABLE_ROW * > FindRowByURI(const wxString &aUri, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::FindRowByURI but filtered to the LIBRARY_TABLE_TYPE of this adapter.
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
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.
void ReloadTables(LIBRARY_TABLE_SCOPE aScope, std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
std::optional< LIBRARY_TABLE * > Table(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
Retrieves a given table; creating a new empty project table if a valid project is loaded and the give...
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...
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
void SetURI(const wxString &aUri)
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:65
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition lib_id.cpp:124
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
Symbol library management helper that is specific to the symbol library editor frame.
Define a library symbol object.
Definition lib_symbol.h:114
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:190
wxString GetName() const override
Definition lib_symbol.h:183
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
Node type: LIB_ID.
void Update(LIB_TREE_ITEM *aItem)
Update the node using data from a LIB_ALIAS object.
void RefreshLibTree()
Refresh the tree (mainly to update highlighting and asterisking)
Definition lib_tree.cpp:492
void CenterLibId(const LIB_ID &aLibId)
Ensure that an item is visible (preferably centered).
Definition lib_tree.cpp:382
int GetSelectionCount() const
Definition lib_tree.h:85
void ShutdownPreviews()
Definition lib_tree.cpp:282
void ShowChangedLanguage()
Definition lib_tree.cpp:299
void FocusSearchFieldIfExists()
Focus the search widget if it exists.
Definition lib_tree.cpp:507
std::vector< LIB_ID > GetExpandedLibraries() const
Definition lib_tree.cpp:402
void SelectLibId(const LIB_ID &aLibId)
Select an item in the tree widget.
Definition lib_tree.cpp:370
LIB_TREE_MODEL_ADAPTER::SORT_MODE GetSortMode() const
Definition lib_tree.h:151
int GetSelectedLibIds(std::vector< LIB_ID > &aSelection, std::vector< int > *aUnit=nullptr) const
Retrieve a list of selections for trees that allow multi-selection.
Definition lib_tree.cpp:329
void Unselect()
Unselect currently selected item in wxDataViewCtrl.
Definition lib_tree.cpp:388
LIB_ID GetSelectedLibId(int *aUnit=nullptr) const
For multi-unit symbols, if the user selects the symbol itself rather than picking an individual unit,...
Definition lib_tree.cpp:309
void ExpandLibId(const LIB_ID &aLibId)
Expand and item i the tree widget.
Definition lib_tree.cpp:396
void Regenerate(bool aKeepState)
Regenerate the tree.
Definition lib_tree.cpp:474
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition pgm_base.cpp:808
KICAD_API_SERVER & GetApiServer()
Definition pgm_base.h:141
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:123
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:125
A holder to handle information on schematic or board items.
unsigned GetCount() const
void ClearItemsList()
Delete only the list of pickers NOT the picked data itself.
EDA_ITEM * GetPickedItem(unsigned int aIdx) const
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:276
Action handler for the Properties panel.
Gather all the actions that are shared by tools.
Definition sch_actions.h:46
static TOOL_ACTION rotateCCW
static TOOL_ACTION editSymbolPinMaps
static TOOL_ACTION importSymbol
static TOOL_ACTION newSymbol
static TOOL_ACTION saveLibraryAs
static TOOL_ACTION mirrorV
static TOOL_ACTION drawEllipseArc
static TOOL_ACTION editLibSymbolWithLibEdit
static TOOL_ACTION drawArc
static TOOL_ACTION pinTable
static TOOL_ACTION drawSymbolLines
static TOOL_ACTION placeSymbolPin
static TOOL_ACTION drawSymbolTextBox
static TOOL_ACTION ddImportGraphics
static TOOL_ACTION drawRectangle
static TOOL_ACTION drawEllipse
static TOOL_ACTION drawCircle
static TOOL_ACTION importGraphics
static TOOL_ACTION drawBezier
static TOOL_ACTION saveSymbolCopyAs
static TOOL_ACTION rotateCW
static TOOL_ACTION showElectricalTypes
static TOOL_ACTION drawSymbolPolygon
static TOOL_ACTION showHiddenFields
static TOOL_ACTION placeSymbolAnchor
static TOOL_ACTION showHiddenPins
static TOOL_ACTION cycleBodyStyle
static TOOL_ACTION mirrorH
static TOOL_ACTION runERC
Inspection and Editing.
static TOOL_ACTION symbolProperties
static TOOL_ACTION placeSymbolText
static TOOL_ACTION toggleSyncedPinsMode
static TOOL_ACTION togglePinAltIcons
static TOOL_ACTION updateSymbolFields
static TOOL_ACTION saveSymbolAs
A shim class between EDA_DRAW_FRAME and several derived classes: SYMBOL_EDIT_FRAME,...
SCH_BASE_FRAME(KIWAY *aKiway, wxWindow *aParent, FRAME_T aWindowType, const wxString &aTitle, const wxPoint &aPosition, const wxSize &aSize, long aStyle, const wxString &aFrameName)
SCH_RENDER_SETTINGS * GetRenderSettings()
void doCloseWindow() override
void SaveSettings(APP_SETTINGS_BASE *aCfg) override
Save common frame parameters to a configuration data file.
void LoadSettings(APP_SETTINGS_BASE *aCfg) override
Load common frame parameters from a configuration file.
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
SYMBOL_EDITOR_SETTINGS * libeditconfig() const
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void CommonSettingsChanged(int aFlags) override
Notification event that some of the common (suite-wide) settings have changed.
void SyncView()
Mark all items for refresh.
PANEL_SCH_SELECTION_FILTER * m_selectionFilterPanel
virtual void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false, bool aUpdateRtree=false)
Mark an item for refresh.
void setSymWatcher(const LIB_ID *aSymbol)
Creates (or removes) a watcher on the specified symbol library.
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the KIGFX::VIEW instance used in the panel.
void DisplaySymbol(LIB_SYMBOL *aSymbol)
Schematic editor (Eeschema) main window.
bool SaveSymbolToSchematic(const LIB_SYMBOL &aSymbol, const KIID &aSchematicSymbolUUID)
Update a schematic symbol from a LIB_SYMBOL.
void SetPosition(const VECTOR2I &aPosition) override
Handle actions specific to the schematic editor.
static const wxString ShowType(SCH_FILE_T aFileType)
Return a brief name for a plugin, given aFileType enum.
static SCH_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath, int aCtl=0)
Return a plugin type given a symbol library using the file extension of aLibPath.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
int GetBodyStyle() const
Definition sch_item.h:253
int GetUnit() const
Definition sch_item.h:243
Tool that displays edit points allowing to modify items by dragging the points.
SCH_SELECTION & GetSelection()
SCH_SELECTION_FILTER_OPTIONS & GetFilter()
Schematic symbol object.
Definition sch_symbol.h:75
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
VECTOR2I GetPosition() const override
Definition sch_symbol.h:908
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:165
int GetOrientation() const override
Get the display symbol orientation.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:184
static bool NotEmpty(const SELECTION &aSelection)
Test if there are any items selected.
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
Handle actions for the various symbol editor and viewers.
One open symbol tab owning a working LIB_SYMBOL and screen lent to the frame while active.
The symbol library editor main window.
std::vector< std::unique_ptr< SYMBOL_EDITOR_TAB_CONTEXT > > m_tabContexts
bool m_isSymbolFromSchematic
Flag if the symbol being edited was loaded directly from a schematic.
void restoreSymbolTabsFromSettings()
Recreate tabs from the persisted open-tab list once the libraries have loaded.
void OnExitKiCad(wxCommandEvent &event)
void LoadSettings(APP_SETTINGS_BASE *aCfg) override
Load common frame parameters from a configuration file.
bool promptToSaveInactiveInstanceTabs()
Prompt to save each dirty instance (symbol from schematic) tab that is not the active one,...
std::unique_ptr< GRID_HELPER > MakeGridHelper() override
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false, bool aUpdateRtree=false) override
Mark an item for refresh.
void setupUIConditions() override
Setup the UI conditions for the various actions and their controls in this frame.
APP_SETTINGS_BASE * config() const override
Return the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
std::unique_ptr< API_HANDLER_COMMON > m_apiHandlerCommon
bool hasDirtyInactiveInstanceTabs() const
True if any non-active instance (schematic) tab has unsaved edits.
bool IsLibraryTreeShown() const override
const BOX2I GetDocumentExtents(bool aIncludeAllVisible=true) const override
Return bounding box of document with option to not include some items.
SELECTION & GetCurrentSelection() override
Get the current selection from the canvas area.
wxString getTargetLib() const
Return either the library selected in the symbol tree, if context menu is active or the library that ...
bool LoadSymbolFromLib(const wxString &aLibName, const wxString &aSymbolName, int aUnit=0, int aBodyStyle=0)
Load a symbol from a library, optionally setting the selected unit and body style.
bool IsCurrentSymbol(const LIB_ID &aLibId) const
Return true if aLibId is an alias for the editor screen symbol.
bool backupLibrary(const wxFileName &aOriginalFile, wxString &aErrorMsg)
Create a backup copy of a symbol library.
static void freeTransientUndoCommands(UNDO_REDO_CONTAINER &aList, const LIB_SYMBOL *aLiveSymbol)
Free every command in the list and the UR_TRANSIENT-flagged copies it owns, which the shared deleters...
void OnSelectBodyStyle(wxCommandEvent &event)
wxString m_reference
RefDes of the symbol (only valid if symbol was loaded from schematic)
EDITOR_TABS_PANEL * m_tabsPanel
SYMBOL_EDITOR_TAB_CONTEXT * findOrCreateSymbolInstanceTab(LIB_SYMBOL *aSymbol, SCH_SCREEN *aScreen, const KIID &aSchematicSymbolUUID, const wxString &aReference, int aUnit, int aBodyStyle)
Find or create the instance tab for a placed schematic symbol and make it active.
void RefreshLibraryTree()
Redisplay the library tree.
void updateSelectionFilterVisbility() override
Selection filter panel doesn't have a dedicated visibility control, so show it if any other AUI panel...
void CommonSettingsChanged(int aFlags) override
Called after the preferences dialog is run.
void FocusLibraryTreeInput() override
wxComboBox * m_unitSelectBox
bool m_drawSpecificBodyStyle
When editing a symbol: only apply new graphic items to the current body style.
void RebuildSymbolUnitAndBodyStyleLists()
int GetTreeLIBIDs(std::vector< LIB_ID > &aSelection) const
void OnTabCharHook(wxKeyEvent &aEvent)
Cycle symbol tabs from the char hook, since GTK cannot register WXK_TAB as an accelerator.
LIB_ID GetTreeLIBID(int *aUnit=nullptr) const
Return the LIB_ID of the library or symbol selected in the symbol tree.
LIB_SYMBOL_LIBRARY_MANAGER * m_libMgr
void FocusOnLibId(const LIB_ID &aLibID)
void SaveLibraryAs(SAVE_LIBRARY_AS aSaveType=SAVE_LIBRARY_AS::NEW)
Save the currently selected library to a new file.
void ToggleProperties() override
SYMBOL_EDITOR_SETTINGS * m_settings
void LoadSymbol(const wxString &aLibrary, const wxString &aSymbol, int Unit)
void onPluginAvailabilityChanged(wxCommandEvent &aEvt)
void HardRedraw() override
Rebuild the GAL and redraw the screen.
int GetTreeSelectionCount() const
bool addLibTableEntry(const wxString &aLibFile, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::GLOBAL)
Add aLibFile to the symbol library table defined by aScope.
void SaveSettings(APP_SETTINGS_BASE *aCfg) override
Save common frame parameters to a configuration data file.
int m_unit
The unit number to edit and show.
bool CanCloseSymbolFromSchematic(bool doClose)
bool IsSymbolFromLegacyLibrary() const
bool replaceLibTableEntry(const wxString &aLibNickname, const wxString &aLibFile)
Replace the file path of the symbol library table entry aLibNickname with aLibFile.
bool IsSymbolFromSchematic() const
void SetScreen(BASE_SCREEN *aScreen) override
void KiwayMailIn(KIWAY_MAIL_EVENT &mail) override
Receive KIWAY_MAIL_EVENT messages from other players.
void emptyScreen()
Restore the empty editor screen, without any symbol or library selected.
SYMBOL_EDITOR_TAB_CONTEXT * m_activeTab
SYMBOL_EDITOR_SETTINGS * GetSettings() const
SCH_SCREEN * m_dummyScreen
Helper screen used when no symbol is loaded.
void SetCurSymbol(LIB_SYMBOL *aSymbol, bool aUpdateZoom)
Take ownership of aSymbol and notes that it is the one currently being edited.
SYMBOL_EDIT_FRAME(KIWAY *aKiway, wxWindow *aParent)
static bool libTreeAutoHiddenForSchematicEdit(bool aWasFromSchematic, bool aRestorePending, bool aTreeShownNow)
Resolve whether the library tree's auto-hide for a schematic edit still needs restoring on save.
bool IsSymbolEditable() const
Test if a symbol is loaded and can be edited.
std::unique_ptr< API_HANDLER_SYMBOL > m_apiHandler
std::vector< LIB_ID > GetSelectedLibIds() const
void SyncLibraries(bool aShowProgress, bool aPreloadCancelled=false, const wxString &aForceRefresh=wxEmptyString)
Synchronize the library manager to the symbol library table, and then the symbol tree to the library ...
void OnSelectUnit(wxCommandEvent &event)
void storeSymbolTabsToSettings()
Write the current tab set into the editor settings for the next session.
LIB_SYMBOL * GetCurSymbol() const
Return the current symbol being edited or NULL if none selected.
void UpdateSymbolMsgPanelInfo()
Display the documentation of the selected symbol.
bool canCloseWindow(wxCloseEvent &aCloseEvent) override
LIB_ID GetTargetLibId() const override
Return either the symbol selected in the symbol tree (if context menu is active) or the symbol on the...
bool m_libTreeAutoHiddenForSchematicEdit
True while a schematic-edit auto-hide of the library tree still needs restoring on save.
void SetBodyStyle(int aBodyStyle)
int m_bodyStyle
Show the normal shape (m_bodyStyle <= 1) or the DeMorgan converted shape (m_bodyStyle > 1)
bool saveAllLibraries(bool aRequireConfirmation)
Return true when the operation has succeeded (all requested libraries have been saved or none was sel...
void UpdateMsgPanel() override
Redraw the message panel.
void ClearUndoORRedoList(UNDO_REDO_LIST whichList, int aItemCount=-1) override
Free the undo or redo list from aList element.
LIB_TREE * GetLibTree() const override
void UpdateTitle()
Update the main window title bar with the current library name and read only status of the library.
bool HasLibModifications() const
Check if any pending libraries have been modified.
std::unique_ptr< API_HANDLER_LIBRARIES > m_apiLibrariesHandler
bool promptAndCloseSymbolTab(int aIdx)
Prompt for unsaved changes on the tab and drop its context.
SYMBOL_TREE_PANE * m_treePane
void SetDrawSpecificUnit(bool aSpecific)
void LoadSymbolFromSchematic(SCH_SYMBOL *aSymbol)
Load a symbol from the schematic to edit in place.
bool m_drawSpecificUnit
When editing a symbol: only apply new graphic items to the current unit.
bool saveCurrentSymbol()
Save the current symbol.
bool IsSymbolGraphicallyEditable() const
Test if a symbol is loaded and can be edited graphically.
COLOR_SETTINGS * GetColorSettings(bool aForceRefresh=false) const override
Returns a pointer to the active color theme settings.
LIB_SYMBOL_LIBRARY_MANAGER & GetLibManager()
void OnUpdateBodyStyle(wxUpdateUIEvent &event)
void SaveSymbolCopyAs(bool aOpenCopy)
Save the currently selected symbol to a new name and/or location.
void SwitchCanvas(EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType) override
Switch currently used canvas ( Cairo / OpenGL).
void doCloseWindow() override
SYMBOL_EDITOR_TAB_CONTEXT * symbolTabContextForIndex(int aIdx) const
Resolve the tab context for a panel tab index, or nullptr.
static void clearSymbolTabUndoRedo(SYMBOL_EDITOR_TAB_CONTEXT &aContext)
Free a detached context's undo/redo, which the frame's own teardown path never reaches.
void DdAddLibrary(wxString aLibFile)
Add a library dropped file to the symbol library table.
wxString AddLibraryFile(bool aCreateNew)
Create or add an existing library to the symbol library table.
void FocusOnItem(EDA_ITEM *aItem, bool aAllowScroll=true) override
Focus on a particular canvas item.
void configureToolbars() override
void CloseWindow(wxCommandEvent &event)
Trigger the wxCloseEvent, which is handled by the function given to EVT_CLOSE() macro:
wxComboBox * m_bodyStyleSelectBox
void activateSymbolTab(SYMBOL_EDITOR_TAB_CONTEXT *aContext)
Make aContext the active tab, borrowing its working symbol, undo/redo, view and selection,...
void UpdateLibraryTree(const wxDataViewItem &aTreeItem, LIB_SYMBOL *aSymbol)
Update a symbol node in the library tree.
void closeAllSymbolTabsSilently()
Close every tab without prompting and return the frame to the empty state.
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current symbol.
void ShowChangedLanguage() override
Redraw the menus and what not in current language.
bool IsContentModified() const override
Get if any symbols or libraries have been modified but not saved.
void ToggleLibraryTree() override
LIB_SYMBOL * getTargetSymbol() const
Return currently edited symbol.
void OnUpdateUnitNumber(wxUpdateUIEvent &event)
An interface to the global shared library manager that is schematic-specific and linked to one projec...
std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib) override
Loads or reloads the given library, if it exists.
Library Editor pane with symbol tree and symbol library table selector.
Rate-limiter that fires at most once per interval.
Definition throttle.h:31
bool Ready()
Definition throttle.h:44
TOOL_MANAGER * m_toolManager
TOOL_DISPATCHER * m_toolDispatcher
bool ToolStackIsEmpty()
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
ACTIONS * m_actions
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition tool_base.h:76
virtual void DispatchWxEvent(wxEvent &aEvent)
Process wxEvents (mostly UI events), translate them to TOOL_EVENTs, and make tools handle those.
Master controller class:
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
A holder to handle a list of undo (or redo) commands.
A wxDirTraverser to filter out symbol (.kicad_sym) files in an unpacked symbol library.
virtual wxDirTraverseResult OnFile(const wxString &aFilename) override
virtual wxDirTraverseResult OnDir(const wxString &WXUNUSED(aDirname)) override
UNPACKED_SYMBOL_LIBRARY_DIR_TRAVERSER(std::vector< wxString > &aFiles)
bool empty() const
Definition utf8.h:105
A modified version of the wxInfoBar class that allows us to:
Definition wx_infobar.h:76
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
bool HasCloseButton() const
void AddLink(const wxString &aLinkText, const std::function< void(wxHyperlinkEvent &)> &aFn)
Add a hypertext link to the infobar.
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition confirm.cpp:146
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:192
This file is part of the common library.
#define KICAD_MESSAGE_DIALOG
Definition confirm.h:48
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Definition cvpcb.cpp:165
#define CHECK(x)
#define ENABLE(x)
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
#define KICAD_DEFAULT_DRAWFRAME_STYLE
#define LIB_EDIT_FRAME_NAME
#define UR_TRANSIENT
indicates the item is owned by the undo/redo stack
@ ID_LIBEDIT_SELECT_UNIT_NUMBER
Definition eeschema_id.h:59
@ ID_LIBEDIT_SELECT_BODY_STYLE
Definition eeschema_id.h:60
const wxAuiPaneInfo & defaultSchSelectionFilterPaneInfo(wxWindow *aWindow)
const wxAuiPaneInfo & defaultPropertiesPaneInfo(wxWindow *aWindow)
wxString NormalizePath(const wxFileName &aFilePath, const ENV_VAR_MAP *aEnvVars, const wxString &aProjectPath)
Normalize a file path to an environmental variable, if possible.
Definition env_paths.cpp:73
Helper functions to substitute paths with environmental variables.
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:31
@ FRAME_SCH
Definition frame_type.h:30
static const std::string SymbolLibraryTableFileName
static const std::string KiCadSymbolLibFileExtension
static const std::string SVGFileExtension
static wxString KiCadSymbolLibFileWildcard()
const wxChar *const traceLibWatch
Flag to enable debug output for library file watch refreshes.
const wxChar *const traceApi
Flag to enable debug output related to the IPC API and its plugin system.
Definition api_utils.cpp:33
@ ID_ON_GRID_SELECT
Definition id.h:113
@ ID_ON_ZOOM_SELECT
Definition id.h:112
std::map< wxString, ENV_VAR_ITEM > ENV_VAR_MAP
PROJECT & Prj()
Definition kicad.cpp:737
EVT_MENU(ID_COMPARE_PROJECT_BRANCHES, KICAD_MANAGER_FRAME::OnCompareProjectBranches) KICAD_MANAGER_FRAME
TAB_VISUAL_STATE ResolveTabVisualState(bool aPreview, bool aModified)
Resolve a tab's decorations from its document state flags.
KIID niluuid(0)
@ LAYER_SCHEMATIC_GRID_AXES
Definition layer_ids.h:515
LIBRARY_TABLE_SCOPE
@ MAIL_SCH_EDIT_LIBID
Definition mail_type.h:54
@ MAIL_LIB_EDIT
Definition mail_type.h:51
@ MAIL_REFRESH_SYMBOL
Definition mail_type.h:57
@ MAIL_RELOAD_LIB
Definition mail_type.h:55
@ ALL
All except INITIAL_ADD.
Definition view_item.h:55
void SetShutdownBlockReason(wxWindow *aWindow, const wxString &aReason)
Sets the block reason why the window/application is preventing OS shutdown.
Definition unix/app.cpp:108
bool SupportsShutdownBlockReason()
Whether or not the window supports setting a shutdown block reason.
Definition unix/app.cpp:97
static constexpr size_t CLOUD_SYNC_BUFFER_SIZE
Buffer size for file I/O operations on cloud-synced folders.
Definition io.h:169
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
static std::string normalizedPath(std::string aPath)
#define _HKI(x)
Definition page_info.cpp:40
void InvokeSchEditSymbolLibTable(KIWAY *aKiway, wxWindow *aParent)
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
@ BASE
Definition sch_item.h:64
#define DEFAULT_THEME
COLOR_SETTINGS * GetColorSettings(const wxString &aName)
T * GetToolbarSettings(const wxString &aFilename)
T * GetAppSettings(const char *aFilename)
KIWAY Kiway(KFCTL_STANDALONE)
wxString UnescapeString(const wxString &aSource)
Functors that can be used to figure out how the action controls should be displayed in the UI and if ...
wxString message
Visual decorations derived from document state: preview is italic, modified is bold with a leading as...
@ SYM_ORIENT_270
Definition symbol.h:39
@ SYM_MIRROR_Y
Definition symbol.h:41
@ SYM_ORIENT_180
Definition symbol.h:38
@ SYM_MIRROR_X
Definition symbol.h:40
@ SYM_ORIENT_90
Definition symbol.h:37
#define EDIT_TOOL(tool)
#define DEMORGAN_ALT
#define DEMORGAN_STD
KIBIS_PIN * pin
#define ENVVARS_CHANGED
wxLogTrace helper definitions.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707
Definition of file extensions used in Kicad.
void SetAuiPaneSize(wxAuiManager &aManager, wxAuiPaneInfo &aPane, int aWidth, int aHeight)
Sets the size of an AUI pane, working around http://trac.wxwidgets.org/ticket/13180.