KiCad PCB EDA Suite
Loading...
Searching...
No Matches
symbol_edit_frame_tabs.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
26
27#include <symbol_edit_frame.h>
28
29#include <kidialog.h>
30#include <lib_symbol.h>
32#include <sch_screen.h>
33#include <sch_view.h>
36#include <tool/actions.h>
37#include <tool/selection.h>
38#include <tool/tool_manager.h>
40#include <view/view.h>
41#include <view/view_controls.h>
43#include <widgets/lib_tree.h>
45
46
48{
50
51 if( KIGFX::VIEW* view = GetCanvas() ? GetCanvas()->GetView() : nullptr )
52 {
53 snapshot.scale = view->GetScale();
54 snapshot.center = view->GetCenter();
55 snapshot.valid = true;
56 }
57
58 return snapshot;
59}
60
61
63{
64 if( !aSnapshot.valid )
65 return;
66
67 if( KIGFX::VIEW* view = GetCanvas() ? GetCanvas()->GetView() : nullptr )
68 {
69 view->SetScale( aSnapshot.scale );
70 view->SetCenter( aSnapshot.center );
71 }
72}
73
74
76{
77 std::vector<KIID> kiids;
78
81 : nullptr;
82
83 if( !selTool )
84 return kiids;
85
86 for( EDA_ITEM* item : selTool->GetSelection() )
87 {
88 if( item )
89 kiids.push_back( item->m_Uuid );
90 }
91
92 return kiids;
93}
94
95
96void SYMBOL_EDIT_FRAME::restoreSymbolSelectionKiids( const std::vector<KIID>& aKiids )
97{
98 if( aKiids.empty() )
99 return;
100
103 : nullptr;
104 SCH_SCREEN* screen = GetScreen();
105
106 if( !selTool || !screen )
107 return;
108
109 for( SCH_ITEM* item : screen->Items() )
110 {
111 for( const KIID& kiid : aKiids )
112 {
113 if( item->m_Uuid == kiid )
114 {
115 selTool->AddItemToSel( item, true );
116 break;
117 }
118 }
119 }
120}
121
122
124{
125 if( !m_activeTab )
126 return;
127
128 m_activeTab->ViewSnapshot() = captureSymbolViewSnapshot();
129 m_activeTab->SavedSelection() = captureSymbolSelectionKiids();
130 m_activeTab->SetUnit( m_unit );
131 m_activeTab->SetBodyStyle( m_bodyStyle );
132
133 // m_symbol may have been replaced by undo/redo since activation.
134 m_activeTab->AdoptWorkingObjects( m_symbol, static_cast<SCH_SCREEN*>( GetScreen() ) );
135
136 m_activeTab->UndoList().m_CommandsList.swap( m_undoList.m_CommandsList );
137 m_activeTab->RedoList().m_CommandsList.swap( m_redoList.m_CommandsList );
138}
139
140
142{
143 wxCHECK( m_toolManager, /* void */ );
144
145 if( !aContext )
146 return;
147
148 if( aContext == m_activeTab )
149 {
150 // Already active, but the caller may have requested a different unit/body style; apply it.
151 m_unit = aContext->GetUnit();
152 m_bodyStyle = aContext->GetBodyStyle();
153
158
161 GetCanvas()->Refresh();
162 return;
163 }
164
166 m_activeTab = aContext;
167
168 m_undoList.m_CommandsList.swap( aContext->UndoList().m_CommandsList );
169 m_redoList.m_CommandsList.swap( aContext->RedoList().m_CommandsList );
170
172
173 aContext->ReleaseToFrame();
174
175 // Restore the frame's schematic-source state from the incoming tab so the existing save path
176 // (SaveSymbolToSchematic vs the library) keys off the active tab, not whichever tab loaded last.
179 m_reference = aContext->GetReference();
180
181 m_symbol = aContext->GetSymbol();
182 m_unit = aContext->GetUnit();
183 m_bodyStyle = aContext->GetBodyStyle();
184
185 // Install the new screen before SetScreen, whose ResetTools would otherwise deref the freed one.
186 m_toolManager->SetEnvironment( aContext->GetScreen(), GetCanvas()->GetView(),
187 GetCanvas()->GetViewControls(), GetSettings(), this );
188 SetScreen( aContext->GetScreen() );
189
190 SetCurLib( aContext->GetLibrary() );
191
192 if( m_symbol )
193 {
194 wxLogTrace( wxT( "KICAD_TABS_DBG" ),
195 wxT( "activateSymbolTab SelectLibId '%s'" ),
196 m_symbol->GetLibId().Format().wx_str() );
197 GetLibTree()->SelectLibId( m_symbol->GetLibId() );
198 }
199
200 m_SyncPinEdit = m_symbol && m_symbol->IsRoot() && m_symbol->IsMultiUnit()
201 && !m_symbol->UnitsLocked();
202
203 m_toolManager->SetEnvironment( GetScreen(), GetCanvas()->GetView(),
204 GetCanvas()->GetViewControls(), GetSettings(), this );
205
210
214
215 // MODEL_RELOAD clears the selection, so restore the saved one afterwards.
217
218 if( aContext->ViewSnapshot().valid )
219 {
221 }
222 else
223 {
224 // First time this tab is shown there is no saved view
226 }
227
229
230 UpdateTitle();
232
234 m_propertiesPanel->UpdateData();
235
237 GetCanvas()->Refresh();
238}
239
240
241void SYMBOL_EDIT_FRAME::OnTabCharHook( wxKeyEvent& aEvent )
242{
243 // Only plain Ctrl+Tab and Ctrl+Shift+Tab are ours; anything else falls through.
244 const bool isTab = aEvent.GetKeyCode() == WXK_TAB;
245 const bool ctrlOnly = aEvent.ControlDown() && !aEvent.AltDown() && !aEvent.MetaDown();
246
247 // Ctrl+W closes the active tab while tabs are open, else falls through to close-window. The
248 // keycode arrives as 'W' or the control char 0x17 depending on platform, so accept both.
249 const int keyCode = aEvent.GetKeyCode();
250 const bool isCtrlW = ctrlOnly && !aEvent.ShiftDown()
251 && ( keyCode == 'W' || keyCode == ( 'W' - '@' ) );
252
253 if( isCtrlW && m_tabsPanel && m_tabsPanel->Model().Entries().size() >= 1 )
254 {
255 // Route through CloseTab so the unsaved-changes prompt still runs.
256 m_tabsPanel->CloseTab( m_tabsPanel->GetActiveTab() );
257 return;
258 }
259
260 if( !isTab || !ctrlOnly || !m_tabsPanel )
261 {
262 aEvent.Skip();
263 return;
264 }
265
266 m_tabsPanel->AdvanceTab( !aEvent.ShiftDown() );
267
268 // Consume the event so GTK's default Tab focus-traversal does not also run.
269}
270
271
273 const LIB_SYMBOL* aLiveSymbol )
274{
275 for( PICKED_ITEMS_LIST* cmd : aList.m_CommandsList )
276 {
277 // The undo copy is the picked ITEM flagged UR_TRANSIENT, not the wrapper, so the shared
278 // deleters skip it. Free exactly the items that carry UR_TRANSIENT here.
279 for( unsigned ii = 0; ii < cmd->GetCount(); ++ii )
280 {
281 EDA_ITEM* item = cmd->GetPickedItem( ii );
282
283 if( !item || !item->HasFlag( UR_TRANSIENT ) )
284 continue;
285
286 // The live working symbol clears UR_TRANSIENT when it becomes m_symbol; guard anyway
287 // against a double-free of the live symbol.
288 wxCHECK2_MSG( item != aLiveSymbol, continue,
289 wxT( "Live working symbol flagged UR_TRANSIENT in undo/redo list" ) );
290
291 delete item;
292 }
293
294 cmd->ClearItemsList();
295 delete cmd;
296 }
297
298 aList.m_CommandsList.clear();
299}
300
301
303{
304 // The context is detached here, so no undo copy is the live working object.
305 freeTransientUndoCommands( aContext.UndoList(), nullptr );
306 freeTransientUndoCommands( aContext.RedoList(), nullptr );
307}
308
309
311{
312 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
313 {
314 if( ctx->GetLibrary() != aLibrary )
315 continue;
316
317 // An active tab's screen aliases the frame's current screen, so this clears the live flag too.
318 if( SCH_SCREEN* screen = ctx->GetScreen() )
319 screen->SetContentModified( false );
320 }
321}
322
323
325{
326 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
327 {
328 if( ctx->GetTabKey() == aKey )
329 return ctx.get();
330 }
331
332 return nullptr;
333}
334
335
336void SYMBOL_EDIT_FRAME::dropSymbolTabContext( const wxString& aKey )
337{
339
340 // The active context is still on screen and owned by the frame, so never drop it here; only an
341 // evicted, inactive preview reaches this path.
342 if( !ctx || ctx == m_activeTab )
343 return;
344
346
347 std::erase_if( m_tabContexts,
348 [ctx]( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& aOwned )
349 {
350 return aOwned.get() == ctx;
351 } );
352}
353
354
356{
357 if( !m_tabsPanel )
358 return nullptr;
359
360 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
361
362 if( aIdx < 0 || aIdx >= static_cast<int>( entries.size() ) )
363 return nullptr;
364
365 return symbolTabContextForKey( entries[aIdx].key );
366}
367
368
370 const wxString& aName,
371 int aUnit, int aBodyStyle,
372 bool aAsPreview,
373 bool* aWasCreated )
374{
375 const wxString key = SYMBOL_EDITOR_TAB_CONTEXT::MakeTabKey( aLib, aName );
376 const int unit = aUnit > 0 ? aUnit : 1;
377 const int bodyStyle = aBodyStyle > 0 ? aBodyStyle : 1;
378
380
381 if( aWasCreated )
382 *aWasCreated = false;
383
384 if( !ctx )
385 {
386 SYMBOL_BUFFER* buffer = m_libMgr ? m_libMgr->GetBuffer( aName, aLib ) : nullptr;
387
388 if( !buffer )
389 return nullptr;
390
391 m_tabContexts.push_back(
392 std::make_unique<SYMBOL_EDITOR_TAB_CONTEXT>( aLib, aName, buffer ) );
393 ctx = m_tabContexts.back().get();
394
395 if( aWasCreated )
396 *aWasCreated = true;
397 }
398
399 ctx->SetUnit( unit );
400 ctx->SetBodyStyle( bodyStyle );
401
402 if( m_tabsPanel )
403 {
404 // A previewed open reuses the existing preview slot in the panel instead of adding a tab.
405 // The panel drops the evicted key from its model, but the matching context lingers in
406 // m_tabContexts and would be persisted as a phantom tab, so capture the evicted key and drop
407 // its context once the reuse completes.
408 wxString replacedKey;
409
410 if( aAsPreview )
411 {
412 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
413 const int previewIdx = m_tabsPanel->Model().PreviewIndex();
414
415 if( previewIdx >= 0 && previewIdx < static_cast<int>( entries.size() )
416 && entries[previewIdx].key != key )
417 {
418 replacedKey = entries[previewIdx].key;
419 }
420 }
421
422 m_tabsPanel->AddTab( key, aName, aAsPreview );
423
424 if( !replacedKey.empty() )
425 dropSymbolTabContext( replacedKey );
426 }
427 else
428 {
429 activateSymbolTab( ctx );
430 }
431
432 return ctx;
433}
434
435
438 const KIID& aSchematicSymbolUUID,
439 const wxString& aReference, int aUnit,
440 int aBodyStyle )
441{
442 const wxString key = SYMBOL_EDITOR_TAB_CONTEXT::MakeInstanceTabKey( aSchematicSymbolUUID );
443 const int unit = aUnit > 0 ? aUnit : 1;
444 const int bodyStyle = aBodyStyle > 0 ? aBodyStyle : 1;
445
447 {
448 // Re-editing the same placed symbol focuses the live tab, so free the redundant new objects.
449 delete aSymbol;
450 delete aScreen;
451
452 existing->SetUnit( unit );
453 existing->SetBodyStyle( bodyStyle );
454
455 if( m_tabsPanel )
456 m_tabsPanel->AddTab( key, existing->GetReference(), false );
457 else
458 activateSymbolTab( existing );
459
460 return existing;
461 }
462
463 m_tabContexts.push_back( std::make_unique<SYMBOL_EDITOR_TAB_CONTEXT>(
464 aSymbol, aScreen, aSchematicSymbolUUID, aReference ) );
465 SYMBOL_EDITOR_TAB_CONTEXT* ctx = m_tabContexts.back().get();
466
467 ctx->SetUnit( unit );
468 ctx->SetBodyStyle( bodyStyle );
469
470 if( m_tabsPanel )
471 m_tabsPanel->AddTab( key, aReference, false );
472 else
473 activateSymbolTab( ctx );
474
475 return ctx;
476}
477
478
480{
482
483 if( !ctx )
484 return true;
485
486 if( ctx->IsModified() && !m_silentSymbolTabClose )
487 {
488 wxString msg = wxString::Format( _( "Save changes to '%s' before closing?" ),
489 ctx->GetDisplayName() );
490
491 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxYES_NO | wxCANCEL | wxICON_WARNING );
492 dlg.SetYesNoCancelLabels( _( "Save" ), _( "Discard Changes" ), _( "Cancel" ) );
493
494 switch( dlg.ShowModal() )
495 {
496 case wxID_YES:
497 // saveCurrentSymbol operates on the active tab, so activate this one first to save it.
498 if( ctx != m_activeTab )
499 activateSymbolTab( ctx );
500
501 if( !saveCurrentSymbol() )
502 return false;
503
504 if( IsLibraryTreeShown() )
505 m_treePane->GetLibTree()->RefreshLibTree();
506
507 UpdateTitle();
508 break;
509
510 case wxID_NO:
511 break;
512
513 default:
514 return false;
515 }
516 }
517
518 // If this is the active tab the frame holds its objects, so repoint at the dummy screen and drop
519 // m_symbol before destroying the context, then let the context free them once.
520 if( ctx == m_activeTab )
521 {
522 // Clear the frame's undo/redo so nothing references the about-to-be-deleted working symbol.
524 ctx->AdoptWorkingObjects( m_symbol, static_cast<SCH_SCREEN*>( GetScreen() ) );
525
526 m_activeTab = nullptr;
527 m_symbol = nullptr;
529
530 // Clear the mirrored schematic-source state so the frame no longer looks like it holds an
531 // instance symbol; a successor tab's activateSymbolTab restores these from its own context.
534 m_reference = wxEmptyString;
535 }
536 else
537 {
538 // An inactive tab's undo/redo still holds transient copies; free them before destroying it.
540 }
541
542 std::erase_if( m_tabContexts,
543 [ctx]( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& aOwned )
544 {
545 return aOwned.get() == ctx;
546 } );
547
548 return true;
549}
550
551
553{
554 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
555 {
556 if( ctx.get() != m_activeTab && ctx->IsTransient() && ctx->IsModified() )
557 return true;
558 }
559
560 return false;
561}
562
563
565{
566 // Collect first; saving activates a tab, which mutates m_activeTab and m_tabContexts ordering.
567 std::vector<SYMBOL_EDITOR_TAB_CONTEXT*> dirty;
568
569 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
570 {
571 // The active tab and library tabs are handled by the existing close checks.
572 if( ctx.get() != m_activeTab && ctx->IsTransient() && ctx->IsModified() )
573 dirty.push_back( ctx.get() );
574 }
575
576 // Saving activates each dirty tab in turn; restore the tab the user was on so a vetoed close leaves
577 // the editor where it was and a successful close persists the real active tab, not a discarded one.
578 SYMBOL_EDITOR_TAB_CONTEXT* originalActive = m_activeTab;
579
580 for( SYMBOL_EDITOR_TAB_CONTEXT* ctx : dirty )
581 {
582 wxString msg = wxString::Format( _( "Save changes to '%s' before closing?" ),
583 ctx->GetDisplayName() );
584
585 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxYES_NO | wxCANCEL | wxICON_WARNING );
586 dlg.SetYesNoCancelLabels( _( "Save" ), _( "Discard Changes" ), _( "Cancel" ) );
587
588 const int answer = dlg.ShowModal();
589
590 if( answer == wxID_YES )
591 {
592 // saveCurrentSymbol saves the active tab via the mirrored frame state, so activate this
593 // one first; it clears the screen's modified flag on success.
594 activateSymbolTab( ctx );
595
596 if( !saveCurrentSymbol() )
597 {
598 activateSymbolTab( originalActive );
599 return false;
600 }
601 }
602 else if( answer != wxID_NO )
603 {
604 activateSymbolTab( originalActive );
605 return false;
606 }
607 }
608
609 activateSymbolTab( originalActive );
610
611 return true;
612}
613
614
616{
617 if( m_tabContexts.empty() )
618 return;
619
621
622 if( m_tabsPanel )
623 {
624 // Remove through the panel so its widget pages and the contexts stay in sync.
625 m_tabsPanel->CloseAll();
626 }
627
628 // Repoint the frame before the active tab's objects return to its soon-deleted context.
629 if( m_activeTab )
630 {
632 m_activeTab->AdoptWorkingObjects( m_symbol, static_cast<SCH_SCREEN*>( GetScreen() ) );
633 m_activeTab = nullptr;
634 m_symbol = nullptr;
636 }
637
638 // Free undo/redo for any contexts the panel path did not already close.
639 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
641
642 m_tabContexts.clear();
643
645}
646
647
649{
650 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "restoreSymbolTabsFromSettings enter" ) );
651
652 if( !m_tabsPanel || !m_settings )
653 return;
654
655 m_loadingSymbolTab = true;
656
657 wxString activeKey = m_settings->m_ActiveTabKey;
658 int activeIdx = -1;
659
660 for( const SYMBOL_EDITOR_SETTINGS::OPEN_TAB& tab : m_settings->m_OpenTabs )
661 {
662 if( !m_libMgr->LibraryExists( tab.lib )
663 || !m_libMgr->SymbolExists( tab.name, tab.lib ) )
664 {
665 wxLogTrace( "KICAD_TABS", "Dropping unresolved persisted symbol tab '%s:%s'.",
666 tab.lib, tab.name );
667 continue;
668 }
669
671 findOrCreateSymbolTab( tab.lib, tab.name, tab.unit, tab.bodyStyle, tab.preview );
672
673 if( !ctx )
674 {
675 wxLogTrace( "KICAD_TABS", "Dropping persisted symbol tab '%s:%s'; buffer unavailable.",
676 tab.lib, tab.name );
677 continue;
678 }
679
680 const int idx = m_tabsPanel->FindTab( ctx->GetTabKey() );
681
682 if( ctx->GetTabKey() == activeKey )
683 activeIdx = idx;
684 }
685
686 m_loadingSymbolTab = false;
687
688 if( activeIdx >= 0 )
689 m_tabsPanel->SelectTab( activeIdx );
690
691 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "restoreSymbolTabsFromSettings exit (activeIdx=%d)" ),
692 activeIdx );
693}
694
695
697{
698 if( !m_settings )
699 return;
700
701 m_settings->m_OpenTabs.clear();
702 m_settings->m_ActiveTabKey.clear();
703
704 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
705 {
706 // Instance tabs are session-only and never persisted.
707 if( ctx->IsTransient() )
708 continue;
709
711 tab.lib = ctx->GetLibrary();
712 tab.name = ctx->GetName();
713 tab.unit = ctx->GetUnit();
714 tab.bodyStyle = ctx->GetBodyStyle();
715
716 if( m_tabsPanel )
717 {
718 const int idx = m_tabsPanel->FindTab( ctx->GetTabKey() );
719 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
720
721 if( idx >= 0 && idx < static_cast<int>( entries.size() ) )
722 tab.preview = entries[idx].preview;
723 }
724
725 m_settings->m_OpenTabs.push_back( tab );
726 }
727
728 // Never restore an instance tab as the active tab, since it is not persisted.
729 if( m_activeTab && !m_activeTab->IsTransient() )
730 m_settings->m_ActiveTabKey = m_activeTab->GetTabKey();
731}
static TOOL_ACTION zoomFitScreen
Definition actions.h:138
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:220
UNDO_REDO_CONTAINER m_undoList
virtual void ClearUndoRedoList()
Clear the undo and redo list using ClearUndoORRedoList()
UNDO_REDO_CONTAINER m_redoList
PROPERTIES_PANEL * m_propertiesPanel
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:156
VIEW_SNAPSHOT & ViewSnapshot()
std::vector< KIID > & SavedSelection()
Selection saved as resolved KIIDs, restored after the view is rebuilt.
UNDO_REDO_CONTAINER & RedoList()
UNDO_REDO_CONTAINER & UndoList()
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
void HideDrawingSheet()
Definition sch_view.cpp:266
void ClearHiddenFlags()
Clear the hide flag of all items in the view.
Definition sch_view.cpp:254
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
Definition kiid.h:44
Define a library symbol object.
Definition lib_symbol.h:79
void SelectLibId(const LIB_ID &aLibId)
Select an item in the tree widget.
Definition lib_tree.cpp:371
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
SCH_RENDER_SETTINGS * GetRenderSettings()
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
void DisplaySymbol(LIB_SYMBOL *aSymbol)
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:162
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:115
SCH_SELECTION & GetSelection()
int AddItemToSel(const TOOL_EVENT &aEvent)
One open symbol tab owning a working LIB_SYMBOL and screen lent to the frame while active.
void ReleaseToFrame()
Hand the working symbol/screen to the frame as the tab becomes active.
wxString GetDisplayName() const override
Short label shown on the tab.
LIB_SYMBOL * GetSymbol() const
Observe the working symbol/screen.
const wxString & GetReference() const
static wxString MakeTabKey(const wxString &aLib, const wxString &aName)
De-duplication key for a library:symbol pair.
static wxString MakeInstanceTabKey(const KIID &aSchematicSymbolUUID)
De-duplication key for a placed schematic instance, in a namespace disjoint from library keys.
wxString GetTabKey() const override
Stable identity for persistence and de-duplication.
const KIID & GetSchematicSymbolUUID() const
bool IsModified() const override
True when the working screen carries unsaved edits.
void AdoptWorkingObjects(LIB_SYMBOL *aSymbol, SCH_SCREEN *aScreen)
Take ownership back on detach, capturing whatever the frame's symbol now points at.
const wxString & GetLibrary() const
std::vector< std::unique_ptr< SYMBOL_EDITOR_TAB_CONTEXT > > m_tabContexts
void restoreSymbolTabsFromSettings()
Recreate tabs from the persisted open-tab list once the libraries have loaded.
bool promptToSaveInactiveInstanceTabs()
Prompt to save each dirty instance (schematic) tab that is not the active one, since the active tab's...
bool hasDirtyInactiveInstanceTabs() const
True if any non-active instance (schematic) tab has unsaved edits.
bool IsLibraryTreeShown() const override
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...
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 restoreSymbolSelectionKiids(const std::vector< KIID > &aKiids)
Reselect the items named by aKiids after a reload rebuilt the view.
void RebuildSymbolUnitAndBodyStyleLists()
void OnTabCharHook(wxKeyEvent &aEvent)
Cycle symbol tabs from the char hook, since GTK cannot register WXK_TAB as an accelerator.
LIB_SYMBOL_LIBRARY_MANAGER * m_libMgr
bool IsSymbolAlias() const
Return true if aLibId is an alias for the editor screen symbol.
SYMBOL_EDITOR_SETTINGS * m_settings
bool m_SyncPinEdit
Set to true to synchronize pins at the same position when editing symbols with multiple units or mult...
void dropSymbolTabContext(const wxString &aKey)
Drop the inactive context for aKey from m_tabContexts, freeing its undo/redo.
bool IsSymbolFromLegacyLibrary() const
bool IsSymbolFromSchematic() const
void SetScreen(BASE_SCREEN *aScreen) override
SYMBOL_EDITOR_TAB_CONTEXT * m_activeTab
SYMBOL_EDITOR_SETTINGS * GetSettings() const
SCH_SCREEN * m_dummyScreen
< Helper screen used when no symbol is loaded
KIID m_schematicSymbolUUID
RefDes of the symbol (only valid if symbol was loaded from schematic)
EDITOR_TAB_CONTEXT::VIEW_SNAPSHOT captureSymbolViewSnapshot() const
Capture the current view zoom/center for the active tab's snapshot.
void restoreSymbolViewSnapshot(const EDITOR_TAB_CONTEXT::VIEW_SNAPSHOT &aSnapshot)
Restore a previously captured view zoom/center.
SYMBOL_EDITOR_TAB_CONTEXT * findOrCreateSymbolTab(const wxString &aLib, const wxString &aName, int aUnit, int aBodyStyle, bool aAsPreview, bool *aWasCreated=nullptr)
Open aName from aLib in a tab, creating it when absent, and return the activated context.
SYMBOL_EDITOR_TAB_CONTEXT * symbolTabContextForKey(const wxString &aKey) const
Resolve the tab context for a tab key, or nullptr.
void storeSymbolTabsToSettings()
Write the current tab set into the editor settings for the next session.
void UpdateSymbolMsgPanelInfo()
Display the documentation of the selected symbol.
int m_bodyStyle
Flag if the symbol being edited was loaded directly from a schematic.
LIB_TREE * GetLibTree() const override
wxString SetCurLib(const wxString &aLibNickname)
Set the current library nickname and returns the old library nickname.
void UpdateTitle()
Update the main window title bar with the current library name and read only status of the library.
bool promptAndCloseSymbolTab(int aIdx)
Prompt for unsaved changes on the tab and drop its context.
SYMBOL_TREE_PANE * m_treePane
std::vector< KIID > captureSymbolSelectionKiids() const
Capture the KIIDs of the current selection for the active tab's snapshot.
bool saveCurrentSymbol()
Store the currently modified symbol in the library manager buffer.
void clearSymbolTabsModifiedForLibrary(const wxString &aLibrary)
Clear the unsaved-edits flag on every tab in a saved library so its dirty indicator clears.
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 detachActiveSymbolTab()
Snapshot the active tab's view and selection into its context without deleting the document.
void activateSymbolTab(SYMBOL_EDITOR_TAB_CONTEXT *aContext)
Make aContext the active tab, borrowing its working symbol, undo/redo, view and selection,...
void closeAllSymbolTabsSilently()
Close every tab without prompting and return the frame to the empty state.
TOOL_MANAGER * m_toolManager
@ MODEL_RELOAD
Model changes (the sheet for a schematic)
Definition tool_base.h:76
A holder to handle a list of undo (or redo) commands.
std::vector< PICKED_ITEMS_LIST * > m_CommandsList
#define _(s)
#define UR_TRANSIENT
indicates the item is owned by the undo/redo stack
KIID niluuid(0)
View snapshot captured on detach, restored on activate.
One persisted open editor tab, restored on the next session.