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 if( m_symbol )
191 {
192 wxLogTrace( wxT( "KICAD_TABS_DBG" ),
193 wxT( "activateSymbolTab SelectLibId '%s'" ),
194 m_symbol->GetLibId().Format().wx_str() );
195 GetLibTree()->SelectLibId( m_symbol->GetLibId() );
196 }
197
198 m_SyncPinEdit = m_symbol && m_symbol->IsRoot() && m_symbol->IsMultiUnit() && !m_symbol->UnitsLocked();
199
200 m_toolManager->SetEnvironment( GetScreen(), GetCanvas()->GetView(),
201 GetCanvas()->GetViewControls(), GetSettings(), this );
202
207
211
212 // MODEL_RELOAD clears the selection, so restore the saved one afterwards.
214
215 if( aContext->ViewSnapshot().valid )
216 {
218 }
219 else
220 {
221 // First time this tab is shown there is no saved view
223 }
224
226
228
230 m_propertiesPanel->UpdateData();
231
233 GetCanvas()->Refresh();
234}
235
236
237void SYMBOL_EDIT_FRAME::OnTabCharHook( wxKeyEvent& aEvent )
238{
239 // Only plain Ctrl+Tab and Ctrl+Shift+Tab are ours; anything else falls through.
240 const bool isTab = aEvent.GetKeyCode() == WXK_TAB;
241 const bool ctrlOnly = aEvent.ControlDown() && !aEvent.AltDown() && !aEvent.MetaDown();
242
243 // Ctrl+W closes the active tab while tabs are open, else falls through to close-window. The
244 // keycode arrives as 'W' or the control char 0x17 depending on platform, so accept both.
245 const int keyCode = aEvent.GetKeyCode();
246 const bool isCtrlW = ctrlOnly && !aEvent.ShiftDown()
247 && ( keyCode == 'W' || keyCode == ( 'W' - '@' ) );
248
249 if( isCtrlW && m_tabsPanel && m_tabsPanel->Model().Entries().size() >= 1 )
250 {
251 // Route through CloseTab so the unsaved-changes prompt still runs.
252 m_tabsPanel->CloseTab( m_tabsPanel->GetActiveTab() );
253 return;
254 }
255
256 if( !isTab || !ctrlOnly || !m_tabsPanel )
257 {
258 aEvent.Skip();
259 return;
260 }
261
262 m_tabsPanel->AdvanceTab( !aEvent.ShiftDown() );
263
264 // Consume the event so GTK's default Tab focus-traversal does not also run.
265}
266
267
269 const LIB_SYMBOL* aLiveSymbol )
270{
271 for( PICKED_ITEMS_LIST* cmd : aList.m_CommandsList )
272 {
273 // The undo copy is the picked ITEM flagged UR_TRANSIENT, not the wrapper, so the shared
274 // deleters skip it. Free exactly the items that carry UR_TRANSIENT here.
275 for( unsigned ii = 0; ii < cmd->GetCount(); ++ii )
276 {
277 EDA_ITEM* item = cmd->GetPickedItem( ii );
278
279 if( !item || !item->HasFlag( UR_TRANSIENT ) )
280 continue;
281
282 // The live working symbol clears UR_TRANSIENT when it becomes m_symbol; guard anyway
283 // against a double-free of the live symbol.
284 wxCHECK2_MSG( item != aLiveSymbol, continue,
285 wxT( "Live working symbol flagged UR_TRANSIENT in undo/redo list" ) );
286
287 delete item;
288 }
289
290 cmd->ClearItemsList();
291 delete cmd;
292 }
293
294 aList.m_CommandsList.clear();
295}
296
297
299{
300 // The context is detached here, so no undo copy is the live working object.
301 freeTransientUndoCommands( aContext.UndoList(), nullptr );
302 freeTransientUndoCommands( aContext.RedoList(), nullptr );
303}
304
305
307 EDITOR_TABS_MODEL& aModel )
308{
309 // An active tab's screen aliases the frame's current screen, so this clears the live flag too.
310 if( SCH_SCREEN* screen = aContext.GetScreen() )
311 screen->SetContentModified( false );
312
313 aModel.MarkModified( aContext.GetTabKey(), false );
314}
315
316
318{
319 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
320 {
321 if( ctx->GetLibrary() != aLibrary )
322 continue;
323
324 if( m_tabsPanel )
325 clearTabModifiedState( *ctx, m_tabsPanel->MutableModel() );
326 else if( SCH_SCREEN* screen = ctx->GetScreen() )
327 screen->SetContentModified( false );
328 }
329
330 // The strip queries the dirty flag only on repaint, so without this the cleared asterisk lingers
331 // until the next stray paint event reaches the tab the user was on.
332 if( m_tabsPanel )
333 m_tabsPanel->RefreshTabLabels();
334}
335
336
338{
339 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
340 {
341 if( ctx->GetTabKey() == aKey )
342 return ctx.get();
343 }
344
345 return nullptr;
346}
347
348
349void SYMBOL_EDIT_FRAME::dropSymbolTabContext( const wxString& aKey )
350{
352
353 // The active context is still on screen and owned by the frame, so never drop it here; only an
354 // evicted, inactive preview reaches this path.
355 if( !ctx || ctx == m_activeTab )
356 return;
357
359
360 std::erase_if( m_tabContexts,
361 [ctx]( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& aOwned )
362 {
363 return aOwned.get() == ctx;
364 } );
365}
366
367
369{
370 if( !m_tabsPanel )
371 return nullptr;
372
373 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
374
375 if( aIdx < 0 || aIdx >= static_cast<int>( entries.size() ) )
376 return nullptr;
377
378 return symbolTabContextForKey( entries[aIdx].key );
379}
380
381
383 const wxString& aName,
384 int aUnit, int aBodyStyle,
385 bool aAsPreview,
386 bool* aWasCreated )
387{
388 const wxString key = SYMBOL_EDITOR_TAB_CONTEXT::MakeTabKey( aLib, aName );
389 const int unit = aUnit > 0 ? aUnit : 1;
390 const int bodyStyle = aBodyStyle > 0 ? aBodyStyle : 1;
391
393
394 if( aWasCreated )
395 *aWasCreated = false;
396
397 if( !ctx )
398 {
399 SYMBOL_BUFFER* buffer = m_libMgr ? m_libMgr->GetBuffer( aName, aLib ) : nullptr;
400
401 if( !buffer )
402 return nullptr;
403
404 m_tabContexts.push_back( std::make_unique<SYMBOL_EDITOR_TAB_CONTEXT>( aLib, aName, buffer ) );
405 ctx = m_tabContexts.back().get();
406
407 if( aWasCreated )
408 *aWasCreated = true;
409 }
410
411 ctx->SetUnit( unit );
412 ctx->SetBodyStyle( bodyStyle );
413
414 if( m_tabsPanel )
415 {
416 // A previewed open reuses the existing preview slot in the panel instead of adding a tab.
417 // The panel drops the evicted key from its model, but the matching context lingers in
418 // m_tabContexts and would be persisted as a phantom tab, so capture the evicted key and drop
419 // its context once the reuse completes.
420 wxString replacedKey;
421
422 if( aAsPreview )
423 {
424 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
425 const int previewIdx = m_tabsPanel->Model().PreviewIndex();
426
427 if( previewIdx >= 0 && previewIdx < static_cast<int>( entries.size() ) && entries[previewIdx].key != key )
428 replacedKey = entries[previewIdx].key;
429 }
430
431 m_tabsPanel->AddTab( key, aName, aAsPreview );
432
433 if( !replacedKey.empty() )
434 dropSymbolTabContext( replacedKey );
435 }
436 else
437 {
438 activateSymbolTab( ctx );
439 }
440
441 return ctx;
442}
443
444
447 const KIID& aSchematicSymbolUUID,
448 const wxString& aReference, int aUnit,
449 int aBodyStyle )
450{
451 const wxString key = SYMBOL_EDITOR_TAB_CONTEXT::MakeInstanceTabKey( aSchematicSymbolUUID );
452 const int unit = aUnit > 0 ? aUnit : 1;
453 const int bodyStyle = aBodyStyle > 0 ? aBodyStyle : 1;
454
456 {
457 // Re-editing the same placed symbol focuses the live tab, so free the redundant new objects.
458 delete aSymbol;
459 delete aScreen;
460
461 existing->SetUnit( unit );
462 existing->SetBodyStyle( bodyStyle );
463
464 if( m_tabsPanel )
465 m_tabsPanel->AddTab( key, existing->GetReference() + wxS( " " ) + _( "[from schematic]" ), false );
466 else
467 activateSymbolTab( existing );
468
469 return existing;
470 }
471
472 m_tabContexts.push_back( std::make_unique<SYMBOL_EDITOR_TAB_CONTEXT>( aSymbol, aScreen, aSchematicSymbolUUID,
473 aReference ) );
474 SYMBOL_EDITOR_TAB_CONTEXT* ctx = m_tabContexts.back().get();
475
476 ctx->SetUnit( unit );
477 ctx->SetBodyStyle( bodyStyle );
478
479 if( m_tabsPanel )
480 m_tabsPanel->AddTab( key, aReference + wxS( " " ) + _( "[from schematic]" ), false );
481 else
482 activateSymbolTab( ctx );
483
484 return ctx;
485}
486
487
489{
491
492 if( !ctx )
493 return true;
494
495 if( ctx->IsModified() && !m_silentSymbolTabClose )
496 {
497 wxString msg = wxString::Format( _( "Save changes to '%s' before closing?" ),
498 ctx->GetDisplayName() );
499
500 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxYES_NO | wxCANCEL | wxICON_WARNING );
501 dlg.SetYesNoCancelLabels( _( "Save" ), _( "Discard Changes" ), _( "Cancel" ) );
502
503 switch( dlg.ShowModal() )
504 {
505 case wxID_YES:
506 // saveCurrentSymbol operates on the active tab, so activate this one first to save it.
507 if( ctx != m_activeTab )
508 activateSymbolTab( ctx );
509
510 if( !saveCurrentSymbol() )
511 return false;
512
513 if( IsLibraryTreeShown() )
514 m_treePane->GetLibTree()->RefreshLibTree();
515
516 break;
517
518 case wxID_NO:
519 break;
520
521 default:
522 return false;
523 }
524 }
525
526 // If this is the active tab the frame holds its objects, so repoint at the dummy screen and drop
527 // m_symbol before destroying the context, then let the context free them once.
528 if( ctx == m_activeTab )
529 {
530 // Clear the frame's undo/redo so nothing references the about-to-be-deleted working symbol.
532 ctx->AdoptWorkingObjects( m_symbol, static_cast<SCH_SCREEN*>( GetScreen() ) );
533
534 m_activeTab = nullptr;
535 m_symbol = nullptr;
537
538 // Clear the mirrored schematic-source state so the frame no longer looks like it holds an
539 // instance symbol; a successor tab's activateSymbolTab restores these from its own context.
542 m_reference = wxEmptyString;
543 }
544 else
545 {
546 // An inactive tab's undo/redo still holds transient copies; free them before destroying it.
548 }
549
550 std::erase_if( m_tabContexts,
551 [ctx]( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& aOwned )
552 {
553 return aOwned.get() == ctx;
554 } );
555
556 return true;
557}
558
559
561{
562 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
563 {
564 if( ctx.get() != m_activeTab && ctx->IsTransient() && ctx->IsModified() )
565 return true;
566 }
567
568 return false;
569}
570
571
573{
574 // Collect first; saving activates a tab, which mutates m_activeTab and m_tabContexts ordering.
575 std::vector<SYMBOL_EDITOR_TAB_CONTEXT*> dirty;
576
577 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
578 {
579 // The active tab and library tabs are handled by the existing close checks.
580 if( ctx.get() != m_activeTab && ctx->IsTransient() && ctx->IsModified() )
581 dirty.push_back( ctx.get() );
582 }
583
584 // Saving activates each dirty tab in turn; restore the tab the user was on so a vetoed close leaves
585 // the editor where it was and a successful close persists the real active tab, not a discarded one.
586 SYMBOL_EDITOR_TAB_CONTEXT* originalActive = m_activeTab;
587
588 for( SYMBOL_EDITOR_TAB_CONTEXT* ctx : dirty )
589 {
590 wxString msg = wxString::Format( _( "Save changes to '%s' before closing?" ),
591 ctx->GetDisplayName() );
592
593 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxYES_NO | wxCANCEL | wxICON_WARNING );
594 dlg.SetYesNoCancelLabels( _( "Save" ), _( "Discard Changes" ), _( "Cancel" ) );
595
596 const int answer = dlg.ShowModal();
597
598 if( answer == wxID_YES )
599 {
600 // saveCurrentSymbol saves the active tab via the mirrored frame state, so activate this
601 // one first; it clears the screen's modified flag on success.
602 activateSymbolTab( ctx );
603
604 if( !saveCurrentSymbol() )
605 {
606 activateSymbolTab( originalActive );
607 return false;
608 }
609 }
610 else if( answer != wxID_NO )
611 {
612 activateSymbolTab( originalActive );
613 return false;
614 }
615 }
616
617 activateSymbolTab( originalActive );
618
619 return true;
620}
621
622
624{
625 if( m_tabContexts.empty() )
626 return;
627
629
630 if( m_tabsPanel )
631 {
632 // Remove through the panel so its widget pages and the contexts stay in sync.
633 m_tabsPanel->CloseAll();
634 }
635
636 // Repoint the frame before the active tab's objects return to its soon-deleted context.
637 if( m_activeTab )
638 {
640 m_activeTab->AdoptWorkingObjects( m_symbol, static_cast<SCH_SCREEN*>( GetScreen() ) );
641 m_activeTab = nullptr;
642 m_symbol = nullptr;
644 }
645
646 // Free undo/redo for any contexts the panel path did not already close.
647 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
649
650 m_tabContexts.clear();
651
653}
654
655
657{
658 if( !m_tabsPanel )
659 return;
660
661 const wxString key = SYMBOL_EDITOR_TAB_CONTEXT::MakeTabKey( aLibId.GetLibNickname(), aLibId.GetLibItemName() );
662
663 const int idx = m_tabsPanel->FindTab( key );
664
665 if( idx < 0 )
666 return;
667
668 // The caller already confirmed the deletion, so close without re-prompting. The panel selects a
669 // successor tab when this was the active one.
671 m_tabsPanel->CloseTab( idx );
673}
674
675
676void SYMBOL_EDIT_FRAME::RenameSymbolTab( const LIB_ID& aOldId, const LIB_ID& aNewId )
677{
678 if( !m_tabsPanel )
679 return;
680
681 const wxString oldKey = SYMBOL_EDITOR_TAB_CONTEXT::MakeTabKey( aOldId.GetLibNickname(), aOldId.GetLibItemName() );
682
684 {
685 const wxString newName = aNewId.GetLibItemName();
686 const wxString newKey = SYMBOL_EDITOR_TAB_CONTEXT::MakeTabKey( aNewId.GetLibNickname(), newName );
687
688 ctx->SetName( newName );
689 m_tabsPanel->RenameTab( oldKey, newKey, newName );
690 }
691}
692
693
695{
696 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "restoreSymbolTabsFromSettings enter" ) );
697
698 if( !m_tabsPanel || !m_settings )
699 return;
700
701 m_loadingSymbolTab = true;
702
703 wxString activeKey = m_settings->m_ActiveTabKey;
704 int activeIdx = -1;
705
706 for( const SYMBOL_EDITOR_SETTINGS::OPEN_TAB& tab : m_settings->m_OpenTabs )
707 {
708 if( !m_libMgr->LibraryExists( tab.lib )
709 || !m_libMgr->SymbolExists( tab.name, tab.lib ) )
710 {
711 wxLogTrace( "KICAD_TABS", "Dropping unresolved persisted symbol tab '%s:%s'.",
712 tab.lib, tab.name );
713 continue;
714 }
715
717 findOrCreateSymbolTab( tab.lib, tab.name, tab.unit, tab.bodyStyle, tab.preview );
718
719 if( !ctx )
720 {
721 wxLogTrace( "KICAD_TABS", "Dropping persisted symbol tab '%s:%s'; buffer unavailable.",
722 tab.lib, tab.name );
723 continue;
724 }
725
726 const int idx = m_tabsPanel->FindTab( ctx->GetTabKey() );
727
728 if( ctx->GetTabKey() == activeKey )
729 activeIdx = idx;
730 }
731
732 m_loadingSymbolTab = false;
733
734 if( activeIdx >= 0 )
735 m_tabsPanel->SelectTab( activeIdx );
736
737 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "restoreSymbolTabsFromSettings exit (activeIdx=%d)" ),
738 activeIdx );
739}
740
741
743{
744 if( !m_settings )
745 return;
746
747 m_settings->m_OpenTabs.clear();
748 m_settings->m_ActiveTabKey.clear();
749
750 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
751 {
752 // Instance tabs are session-only and never persisted.
753 if( ctx->IsTransient() )
754 continue;
755
757 tab.lib = ctx->GetLibrary();
758 tab.name = ctx->GetName();
759 tab.unit = ctx->GetUnit();
760 tab.bodyStyle = ctx->GetBodyStyle();
761
762 if( m_tabsPanel )
763 {
764 const int idx = m_tabsPanel->FindTab( ctx->GetTabKey() );
765 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
766
767 if( idx >= 0 && idx < static_cast<int>( entries.size() ) )
768 tab.preview = entries[idx].preview;
769 }
770
771 m_settings->m_OpenTabs.push_back( tab );
772 }
773
774 // Never restore an instance tab as the active tab, since it is not persisted.
775 if( m_activeTab && !m_activeTab->IsTransient() )
776 m_settings->m_ActiveTabKey = m_activeTab->GetTabKey();
777}
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
GUI-free preview/dirty/close state machine.
void MarkModified(const wxString &aKey, bool aModified)
Update the modified flag.
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:306
void ClearHiddenFlags()
Clear the hide flag of all items in the view.
Definition sch_view.cpp:294
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:46
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
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
Define a library symbol object.
Definition lib_symbol.h:114
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.
std::vector< std::unique_ptr< SYMBOL_EDITOR_TAB_CONTEXT > > m_tabContexts
bool m_isSymbolFromSchematic
True while a schematic-edit auto-hide of the library tree still needs restoring on save.
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
void RenameSymbolTab(const LIB_ID &aOldId, const LIB_ID &aNewId)
Update the open tab for aOldId, if any, to the renamed symbol aNewId so its label and key track the r...
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.
static void clearTabModifiedState(SYMBOL_EDITOR_TAB_CONTEXT &aContext, EDITOR_TABS_MODEL &aModel)
Clear a tab's dirty state on both the context (read on repaint) and the strip model (read on close),...
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.
LIB_TREE * GetLibTree() const override
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.
void closeSymbolTab(const LIB_ID &aLibId)
Close the open tab for aLibId, if any, without prompting and leaving the other tabs open.
bool saveCurrentSymbol()
Rename LIB_SYMBOL aliases to avoid conflicts before adding a symbol to a library.
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.