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 <sch_render_settings.h>
28#include <symbol_edit_frame.h>
29
30#include <kidialog.h>
31#include <lib_symbol.h>
33#include <sch_screen.h>
34#include <sch_view.h>
37#include <tool/actions.h>
38#include <tool/selection.h>
39#include <tool/tool_manager.h>
41#include <view/view.h>
42#include <view/view_controls.h>
44#include <widgets/lib_tree.h>
46
47
49{
51
52 if( KIGFX::VIEW* view = GetCanvas() ? GetCanvas()->GetView() : nullptr )
53 {
54 snapshot.scale = view->GetScale();
55 snapshot.center = view->GetCenter();
56 snapshot.valid = true;
57 }
58
59 return snapshot;
60}
61
62
64{
65 if( !aSnapshot.valid )
66 return;
67
68 if( KIGFX::VIEW* view = GetCanvas() ? GetCanvas()->GetView() : nullptr )
69 {
70 view->SetScale( aSnapshot.scale );
71 view->SetCenter( aSnapshot.center );
72 }
73}
74
75
77{
78 std::vector<KIID> kiids;
79
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
102 : nullptr;
103 SCH_SCREEN* screen = GetScreen();
104
105 if( !selTool || !screen )
106 return;
107
108 for( SCH_ITEM* item : screen->Items() )
109 {
110 for( const KIID& kiid : aKiids )
111 {
112 if( item->m_Uuid == kiid )
113 {
114 selTool->AddItemToSel( item, true );
115 break;
116 }
117 }
118 }
119}
120
121
123{
124 if( !m_activeTab )
125 return;
126
127 m_activeTab->ViewSnapshot() = captureSymbolViewSnapshot();
128 m_activeTab->SavedSelection() = captureSymbolSelectionKiids();
129 m_activeTab->SetUnit( m_unit );
130 m_activeTab->SetBodyStyle( m_bodyStyle );
131
132 // m_symbol may have been replaced by undo/redo since activation.
133 m_activeTab->AdoptWorkingObjects( m_symbol, static_cast<SCH_SCREEN*>( GetScreen() ) );
134
135 m_activeTab->UndoList().m_CommandsList.swap( m_undoList.m_CommandsList );
136 m_activeTab->RedoList().m_CommandsList.swap( m_redoList.m_CommandsList );
137}
138
139
141{
142 wxCHECK( m_toolManager, /* void */ );
143
144 if( !aContext )
145 return;
146
147 if( aContext == m_activeTab )
148 {
149 // Already active, but the caller may have requested a different unit/body style; apply it.
150 m_unit = aContext->GetUnit();
151 m_bodyStyle = aContext->GetBodyStyle();
152
157
160 GetCanvas()->Refresh();
161 return;
162 }
163
165 m_activeTab = aContext;
166
167 m_undoList.m_CommandsList.swap( aContext->UndoList().m_CommandsList );
168 m_redoList.m_CommandsList.swap( aContext->RedoList().m_CommandsList );
169
171
172 aContext->ReleaseToFrame();
173
174 // Restore the frame's schematic-source state from the incoming tab so the existing save path
175 // (SaveSymbolToSchematic vs the library) keys off the active tab, not whichever tab loaded last.
178 m_reference = aContext->GetReference();
179
180 m_symbol = aContext->GetSymbol();
181 m_unit = aContext->GetUnit();
182 m_bodyStyle = aContext->GetBodyStyle();
183
184 // Install the new screen before SetScreen, whose ResetTools would otherwise deref the freed one.
185 m_toolManager->SetEnvironment( aContext->GetScreen(), GetCanvas()->GetView(), GetCanvas()->GetViewControls(),
186 GetSettings(), this );
187 SetScreen( aContext->GetScreen() );
188
189 if( m_symbol )
190 {
191 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "activateSymbolTab SelectLibId '%s'" ),
192 m_symbol->GetLibId().Format().wx_str() );
193 GetLibTree()->SelectLibId( m_symbol->GetLibId() );
194 }
195
196 m_toolManager->SetEnvironment( GetScreen(), GetCanvas()->GetView(), GetCanvas()->GetViewControls(),
197 GetSettings(), this );
198
203
207
208 // MODEL_RELOAD clears the selection, so restore the saved one afterwards.
210
211 if( aContext->ViewSnapshot().valid )
212 {
214 }
215 else
216 {
217 // First time this tab is shown there is no saved view
219 }
220
222
224
226 m_propertiesPanel->UpdateData();
227
230 GetCanvas()->Refresh();
231}
232
233
234void SYMBOL_EDIT_FRAME::OnTabCharHook( wxKeyEvent& aEvent )
235{
236 // Only plain Ctrl+Tab and Ctrl+Shift+Tab are ours; anything else falls through.
237 const bool isTab = aEvent.GetKeyCode() == WXK_TAB;
238 const bool ctrlOnly = aEvent.ControlDown() && !aEvent.AltDown() && !aEvent.MetaDown();
239
240 // Ctrl+W closes the active tab while tabs are open, else falls through to close-window. The
241 // keycode arrives as 'W' or the control char 0x17 depending on platform, so accept both.
242 const int keyCode = aEvent.GetKeyCode();
243 const bool isCtrlW = ctrlOnly && !aEvent.ShiftDown()
244 && ( keyCode == 'W' || keyCode == ( 'W' - '@' ) );
245
246 if( isCtrlW && m_tabsPanel && m_tabsPanel->Model().Entries().size() >= 1 )
247 {
248 // Route through CloseTab so the unsaved-changes prompt still runs.
249 m_tabsPanel->CloseTab( m_tabsPanel->GetActiveTab() );
250 return;
251 }
252
253 if( !isTab || !ctrlOnly || !m_tabsPanel )
254 {
255 aEvent.Skip();
256 return;
257 }
258
259 m_tabsPanel->AdvanceTab( !aEvent.ShiftDown() );
260
261 // Consume the event so GTK's default Tab focus-traversal does not also run.
262}
263
264
266 const LIB_SYMBOL* aLiveSymbol )
267{
268 for( PICKED_ITEMS_LIST* cmd : aList.m_CommandsList )
269 {
270 // The undo copy is the picked ITEM flagged UR_TRANSIENT, not the wrapper, so the shared
271 // deleters skip it. Free exactly the items that carry UR_TRANSIENT here.
272 for( unsigned ii = 0; ii < cmd->GetCount(); ++ii )
273 {
274 EDA_ITEM* item = cmd->GetPickedItem( ii );
275
276 if( !item || !item->HasFlag( UR_TRANSIENT ) )
277 continue;
278
279 // The live working symbol clears UR_TRANSIENT when it becomes m_symbol; guard anyway
280 // against a double-free of the live symbol.
281 wxCHECK2_MSG( item != aLiveSymbol, continue,
282 wxT( "Live working symbol flagged UR_TRANSIENT in undo/redo list" ) );
283
284 delete item;
285 }
286
287 cmd->ClearItemsList();
288 delete cmd;
289 }
290
291 aList.m_CommandsList.clear();
292}
293
294
296{
297 // The context is detached here, so no undo copy is the live working object.
298 freeTransientUndoCommands( aContext.UndoList(), nullptr );
299 freeTransientUndoCommands( aContext.RedoList(), nullptr );
300}
301
302
304 EDITOR_TABS_MODEL& aModel )
305{
306 // An active tab's screen aliases the frame's current screen, so this clears the live flag too.
307 if( SCH_SCREEN* screen = aContext.GetScreen() )
308 screen->SetContentModified( false );
309
310 aModel.MarkModified( aContext.GetTabKey(), false );
311}
312
313
315{
316 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
317 {
318 if( ctx->GetLibrary() != aLibrary )
319 continue;
320
321 if( m_tabsPanel )
322 clearTabModifiedState( *ctx, m_tabsPanel->MutableModel() );
323 else if( SCH_SCREEN* screen = ctx->GetScreen() )
324 screen->SetContentModified( false );
325 }
326
327 // The strip queries the dirty flag only on repaint, so without this the cleared asterisk lingers
328 // until the next stray paint event reaches the tab the user was on.
329 if( m_tabsPanel )
330 m_tabsPanel->RefreshTabLabels();
331}
332
333
335{
336 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
337 {
338 if( ctx->GetTabKey() == aKey )
339 return ctx.get();
340 }
341
342 return nullptr;
343}
344
345
346void SYMBOL_EDIT_FRAME::dropSymbolTabContext( const wxString& aKey )
347{
349
350 // The active context is still on screen and owned by the frame, so never drop it here; only an
351 // evicted, inactive preview reaches this path.
352 if( !ctx || ctx == m_activeTab )
353 return;
354
356
357 std::erase_if( m_tabContexts,
358 [ctx]( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& aOwned )
359 {
360 return aOwned.get() == ctx;
361 } );
362}
363
364
366{
367 if( !m_tabsPanel )
368 return nullptr;
369
370 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
371
372 if( aIdx < 0 || aIdx >= static_cast<int>( entries.size() ) )
373 return nullptr;
374
375 return symbolTabContextForKey( entries[aIdx].key );
376}
377
378
379SYMBOL_EDITOR_TAB_CONTEXT* SYMBOL_EDIT_FRAME::findOrCreateSymbolTab( const wxString& aLib, const wxString& aName,
380 int aUnit, int aBodyStyle, bool aAsPreview,
381 bool* aWasCreated )
382{
383 const wxString key = SYMBOL_EDITOR_TAB_CONTEXT::MakeTabKey( aLib, aName );
384 const int unit = aUnit > 0 ? aUnit : 1;
385 const int bodyStyle = aBodyStyle > 0 ? aBodyStyle : 1;
386
388
389 if( aWasCreated )
390 *aWasCreated = false;
391
392 if( !ctx )
393 {
394 SYMBOL_BUFFER* buffer = m_libMgr ? m_libMgr->GetBuffer( aName, aLib ) : nullptr;
395
396 if( !buffer )
397 return nullptr;
398
399 m_tabContexts.push_back( std::make_unique<SYMBOL_EDITOR_TAB_CONTEXT>( aLib, aName, buffer ) );
400 ctx = m_tabContexts.back().get();
401
402 if( aWasCreated )
403 *aWasCreated = true;
404 }
405
406 ctx->SetUnit( unit );
407 ctx->SetBodyStyle( bodyStyle );
408
409 if( m_tabsPanel )
410 {
411 // A previewed open reuses the existing preview slot in the panel instead of adding a tab.
412 // The panel drops the evicted key from its model, but the matching context lingers in
413 // m_tabContexts and would be persisted as a phantom tab, so capture the evicted key and drop
414 // its context once the reuse completes.
415 wxString replacedKey;
416
417 if( aAsPreview )
418 {
419 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
420 const int previewIdx = m_tabsPanel->Model().PreviewIndex();
421
422 if( previewIdx >= 0 && previewIdx < static_cast<int>( entries.size() ) && entries[previewIdx].key != key )
423 replacedKey = entries[previewIdx].key;
424 }
425
426 m_tabsPanel->AddTab( key, aName, aAsPreview );
427
428 if( !replacedKey.empty() )
429 dropSymbolTabContext( replacedKey );
430 }
431 else
432 {
433 activateSymbolTab( ctx );
434 }
435
436 return ctx;
437}
438
439
442 const KIID& aSchematicSymbolUUID, const wxString& aReference,
443 int aUnit, int aBodyStyle )
444{
445 const wxString key = SYMBOL_EDITOR_TAB_CONTEXT::MakeInstanceTabKey( aSchematicSymbolUUID );
446 const int unit = aUnit > 0 ? aUnit : 1;
447 const int bodyStyle = aBodyStyle > 0 ? aBodyStyle : 1;
448
450 {
451 // Re-editing the same placed symbol focuses the live tab, so free the redundant new objects.
452 delete aSymbol;
453 delete aScreen;
454
455 existing->SetUnit( unit );
456 existing->SetBodyStyle( bodyStyle );
457
458 activateSymbolTab( existing );
459
460 return existing;
461 }
462
463 m_tabContexts.push_back( std::make_unique<SYMBOL_EDITOR_TAB_CONTEXT>( aSymbol, aScreen, aSchematicSymbolUUID,
464 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, ctx->GetDisplayName(), false );
472 else
473 activateSymbolTab( ctx );
474
475 return ctx;
476}
477
478
480{
481 auto ctx = std::make_unique<SYMBOL_EDITOR_TAB_CONTEXT>( aSymbol, aScreen );
482 SYMBOL_EDITOR_TAB_CONTEXT* raw = ctx.get();
483
484 m_tabContexts.push_back( std::move( ctx ) );
485
486 if( m_tabsPanel )
487 m_tabsPanel->AddTab( raw->GetTabKey(), raw->GetDisplayName(), false );
488 else
489 activateSymbolTab( raw );
490
491 return raw;
492}
493
494
496{
498
499 if( !ctx )
500 return true;
501
502 if( ctx->IsModified() && !m_silentSymbolTabClose )
503 {
504 wxString msg = wxString::Format( _( "Save changes to '%s' before closing?" ), ctx->GetDisplayName( true ) );
505
506 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxYES_NO | wxCANCEL | wxICON_WARNING );
507 dlg.SetYesNoCancelLabels( _( "Save" ), _( "Discard Changes" ), _( "Cancel" ) );
508
509 switch( dlg.ShowModal() )
510 {
511 case wxID_YES:
512 // saveCurrentSymbol operates on the active tab, so activate this one first to save it.
513 if( ctx != m_activeTab )
514 activateSymbolTab( ctx );
515
516 if( !saveCurrentSymbol() )
517 return false;
518
519 if( IsLibraryTreeShown() )
520 m_treePane->GetLibTree()->RefreshLibTree();
521
522 break;
523
524 case wxID_NO:
525 break;
526
527 default:
528 return false;
529 }
530 }
531
532 // If this is the active tab the frame holds its objects, so repoint at the dummy screen and drop
533 // m_symbol before destroying the context, then let the context free them once.
534 if( ctx == m_activeTab )
535 {
536 // Clear the frame's undo/redo so nothing references the about-to-be-deleted working symbol.
538 ctx->AdoptWorkingObjects( m_symbol, static_cast<SCH_SCREEN*>( GetScreen() ) );
539
540 m_activeTab = nullptr;
541 m_symbol = nullptr;
543
544 // Clear the mirrored schematic-source state so the frame no longer looks like it holds an
545 // instance symbol; a successor tab's activateSymbolTab restores these from its own context.
548 m_reference = wxEmptyString;
549 }
550 else
551 {
552 // An inactive tab's undo/redo still holds transient copies; free them before destroying it.
554 }
555
556 std::erase_if( m_tabContexts,
557 [ctx]( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& aOwned )
558 {
559 return aOwned.get() == ctx;
560 } );
561
562 return true;
563}
564
565
567{
568 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
569 {
570 if( ctx.get() != m_activeTab && ctx->IsTransient() && ctx->IsModified() )
571 return true;
572 }
573
574 return false;
575}
576
577
579{
580 // Collect first; saving activates a tab, which mutates m_activeTab and m_tabContexts ordering.
581 std::vector<SYMBOL_EDITOR_TAB_CONTEXT*> dirty;
582
583 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
584 {
585 // The active tab and library tabs are handled by the existing close checks.
586 if( ctx.get() != m_activeTab && ctx->IsTransient() && ctx->IsModified() )
587 dirty.push_back( ctx.get() );
588 }
589
590 // Saving activates each dirty tab in turn; restore the tab the user was on so a vetoed close leaves
591 // the editor where it was and a successful close persists the real active tab, not a discarded one.
592 SYMBOL_EDITOR_TAB_CONTEXT* originalActive = m_activeTab;
593
594 for( SYMBOL_EDITOR_TAB_CONTEXT* ctx : dirty )
595 {
596 wxString msg = wxString::Format( _( "Save changes to '%s' before closing?" ), ctx->GetDisplayName() );
597
598 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxYES_NO | wxCANCEL | wxICON_WARNING );
599 dlg.SetYesNoCancelLabels( _( "Save" ), _( "Discard Changes" ), _( "Cancel" ) );
600
601 const int answer = dlg.ShowModal();
602
603 if( answer == wxID_YES )
604 {
605 // saveCurrentSymbol saves the active tab via the mirrored frame state, so activate this
606 // one first; it clears the screen's modified flag on success.
607 activateSymbolTab( ctx );
608
609 if( !saveCurrentSymbol() )
610 {
611 activateSymbolTab( originalActive );
612 return false;
613 }
614 }
615 else if( answer != wxID_NO )
616 {
617 activateSymbolTab( originalActive );
618 return false;
619 }
620 }
621
622 activateSymbolTab( originalActive );
623
624 return true;
625}
626
627
629{
630 if( m_tabContexts.empty() )
631 return;
632
634
635 if( m_tabsPanel )
636 {
637 // Remove through the panel so its widget pages and the contexts stay in sync.
638 m_tabsPanel->CloseAll();
639 }
640
641 // Repoint the frame before the active tab's objects return to its soon-deleted context.
642 if( m_activeTab )
643 {
645 m_activeTab->AdoptWorkingObjects( m_symbol, static_cast<SCH_SCREEN*>( GetScreen() ) );
646 m_activeTab = nullptr;
647 m_symbol = nullptr;
649 }
650
651 // Free undo/redo for any contexts the panel path did not already close.
652 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
654
655 m_tabContexts.clear();
656
658}
659
660
662{
663 if( !m_tabsPanel )
664 return;
665
666 const wxString key = SYMBOL_EDITOR_TAB_CONTEXT::MakeTabKey( aLibId.GetLibNickname(), aLibId.GetLibItemName() );
667
668 const int idx = m_tabsPanel->FindTab( key );
669
670 if( idx < 0 )
671 return;
672
673 // The caller already confirmed the deletion, so close without re-prompting. The panel selects a
674 // successor tab when this was the active one.
676 m_tabsPanel->CloseTab( idx );
678}
679
680
681void SYMBOL_EDIT_FRAME::RenameSymbolTab( const LIB_ID& aOldId, const LIB_ID& aNewId )
682{
683 if( !m_tabsPanel )
684 return;
685
686 const wxString newLib = aNewId.GetLibNickname();
687 const wxString newName = aNewId.GetLibItemName();
688
689 if( m_activeTab && m_activeTab->IsUnsaved() && aOldId.GetLibNickname().empty() && !newLib.IsEmpty() )
690 {
691 const wxString unsavedKey = m_activeTab->GetTabKey();
692
693 m_activeTab->PromoteToLibrary( newLib, newName );
694 m_tabsPanel->RenameTab( unsavedKey, m_activeTab->GetTabKey(), m_activeTab->GetDisplayName() );
695
696 return;
697 }
698
699 const wxString oldKey = SYMBOL_EDITOR_TAB_CONTEXT::MakeTabKey( aOldId.GetLibNickname(), aOldId.GetLibItemName() );
700
702 {
703 ctx->SetName( newName );
704 m_tabsPanel->RenameTab( oldKey, SYMBOL_EDITOR_TAB_CONTEXT::MakeTabKey( newLib, newName ), newName );
705 }
706}
707
708
710{
711 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "restoreSymbolTabsFromSettings enter" ) );
712
713 if( !m_tabsPanel || !m_settings )
714 return;
715
716 m_loadingSymbolTab = true;
717
718 wxString activeKey = m_settings->m_ActiveTabKey;
719 int activeIdx = -1;
720
721 for( const SYMBOL_EDITOR_SETTINGS::OPEN_TAB& tab : m_settings->m_OpenTabs )
722 {
723 if( !m_libMgr->LibraryExists( tab.lib ) || !m_libMgr->SymbolExists( tab.name, tab.lib ) )
724 {
725 wxLogTrace( "KICAD_TABS", "Dropping unresolved persisted symbol tab '%s:%s'.", tab.lib, tab.name );
726 continue;
727 }
728
730 findOrCreateSymbolTab( tab.lib, tab.name, tab.unit, tab.bodyStyle, tab.preview );
731
732 if( !ctx )
733 {
734 wxLogTrace( "KICAD_TABS", "Dropping persisted symbol tab '%s:%s'; buffer unavailable.", tab.lib, tab.name );
735 continue;
736 }
737
738 const int idx = m_tabsPanel->FindTab( ctx->GetTabKey() );
739
740 if( ctx->GetTabKey() == activeKey )
741 activeIdx = idx;
742 }
743
744 m_loadingSymbolTab = false;
745
746 if( activeIdx >= 0 )
747 m_tabsPanel->SelectTab( activeIdx );
748
749 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "restoreSymbolTabsFromSettings exit (activeIdx=%d)" ), activeIdx );
750}
751
752
754{
755 if( !m_settings )
756 return;
757
758 m_settings->m_OpenTabs.clear();
759 m_settings->m_ActiveTabKey.clear();
760
761 for( const std::unique_ptr<SYMBOL_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
762 {
763 // Instance tabs are session-only and never persisted.
764 if( ctx->IsTransient() )
765 continue;
766
768 tab.lib = ctx->GetLibrary();
769 tab.name = ctx->GetName();
770 tab.unit = ctx->GetUnit();
771 tab.bodyStyle = ctx->GetBodyStyle();
772
773 if( m_tabsPanel )
774 {
775 const int idx = m_tabsPanel->FindTab( ctx->GetTabKey() );
776 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
777
778 if( idx >= 0 && idx < static_cast<int>( entries.size() ) )
779 tab.preview = entries[idx].preview;
780 }
781
782 m_settings->m_OpenTabs.push_back( tab );
783 }
784
785 // Never restore an instance tab as the active tab, since it is not persisted.
786 if( m_activeTab && !m_activeTab->IsTransient() )
787 m_settings->m_ActiveTabKey = m_activeTab->GetTabKey();
788}
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:98
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:168
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:370
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 KIGFX::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:170
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:122
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.
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.
wxString GetDisplayName(bool aShortForm=false) const override
Short label shown on the tab.
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
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.
bool promptToSaveInactiveInstanceTabs()
Prompt to save each dirty instance (symbol from schematic) tab that is not the active one,...
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...
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 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
SYMBOL_EDITOR_SETTINGS * m_settings
void dropSymbolTabContext(const wxString &aKey)
Drop the inactive context for aKey from m_tabContexts, freeing its undo/redo.
int m_unit
The unit number to edit and show.
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.
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.
bool m_silentSymbolTabClose
While true, promptAndCloseSymbolTab() skips the unsaved-changes dialog.
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
Show the normal shape (m_bodyStyle <= 1) or the DeMorgan converted shape (m_bodyStyle > 1)
LIB_TREE * GetLibTree() const override
SYMBOL_EDITOR_TAB_CONTEXT * CreateUnsavedSymbolTab(LIB_SYMBOL *aSymbol, SCH_SCREEN *aScreen)
Open a new tab over a transient working symbol and screen and make it active.
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()
Save the current symbol.
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
bool empty() const
Definition utf8.h:105
#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.