KiCad PCB EDA Suite
Loading...
Searching...
No Matches
footprint_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) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2015 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2015-2016 Wayne Stambaugh <[email protected]>
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software: you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your
12 * option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include "tool/embed_tool.h"
24#include "tools/convert_tool.h"
25#include "tools/drawing_tool.h"
26#include "tools/edit_tool.h"
29#include "tools/pad_tool.h"
30#include "tools/pcb_actions.h"
31#include "tools/pcb_control.h"
37#include <bitmaps.h>
40#include <api/api_server.h>
41#include <board.h>
43#include <widgets/wx_infobar.h>
44#include <footprint.h>
45#include <confirm.h>
46#include <drc/drc_item.h>
47#include <kidialog.h>
53#include <pcb_painter.h>
54#include <render_settings.h>
55#include <view/view.h>
56#include <kiface_base.h>
57#include <kiplatform/app.h>
58#include <kiplatform/ui.h>
59#include <kiway.h>
60#include <macros.h>
61#include <pcbnew_id.h>
62#include <pgm_base.h>
63#include <project.h>
64#include <project_pcb.h>
65#include <string_utils.h>
67#include <tool/action_toolbar.h>
68#include <tool/common_control.h>
69#include <tool/common_tools.h>
71#include <tool/selection.h>
74#include <tool/tool_manager.h>
75#include <tool/zoom_tool.h>
76#include <tools/array_tool.h>
84#include <widgets/lib_tree.h>
90
91#include <algorithm>
92
93#include <wx/filedlg.h>
94#include <wx/hyperlink.h>
95
96BEGIN_EVENT_TABLE( FOOTPRINT_EDIT_FRAME, PCB_BASE_FRAME )
99
101
104
106
107 // Drop files event
108 EVT_DROP_FILES( FOOTPRINT_EDIT_FRAME::OnDropFiles )
109
110END_EVENT_TABLE()
111
112
113FOOTPRINT_EDIT_FRAME::FOOTPRINT_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
114 PCB_BASE_EDIT_FRAME( aKiway, aParent, FRAME_FOOTPRINT_EDITOR, wxEmptyString, wxDefaultPosition, wxDefaultSize,
117 m_tabsPanel( nullptr ),
118 m_activeTab( nullptr ),
121{
122 m_showBorderAndTitleBlock = false; // true to show the frame references
123 m_aboutTitle = _HKI( "KiCad Footprint Editor" );
124 m_editorSettings = nullptr;
125
126 // Give an icon
127 wxIcon icon;
128 wxIconBundle icon_bundle;
129
130 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit, 48 ) );
131 icon_bundle.AddIcon( icon );
132 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit, 128 ) );
133 icon_bundle.AddIcon( icon );
134 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit, 256 ) );
135 icon_bundle.AddIcon( icon );
136 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit_32 ) );
137 icon_bundle.AddIcon( icon );
138 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit_16 ) );
139 icon_bundle.AddIcon( icon );
140
141 SetIcons( icon_bundle );
142
143 // Create GAL canvas
145
146 PCB_DRAW_PANEL_GAL* drawPanel = new PCB_DRAW_PANEL_GAL( this, -1, wxPoint( 0, 0 ), m_frameSize,
148 SetCanvas( drawPanel );
149
150 SetBoard( new BOARD() );
151
152 // This board will only be used to hold a footprint for editing
153 GetBoard()->SetBoardUse( BOARD_USE::FPHOLDER );
154
155 // In Footprint Editor, the default net clearance is not known (it depends on the actual
156 // board). So we do not show the default clearance, by setting it to 0. The footprint or
157 // pad specific clearance will be shown.
158 GetBoard()->GetDesignSettings().m_NetSettings->GetDefaultNetclass()->SetClearance( 0 );
159
160 // Don't show the default board solder mask expansion in the footprint editor. Only the
161 // footprint or pad mask expansions settings should be shown.
162 GetBoard()->GetDesignSettings().m_SolderMaskExpansion = 0;
163
164 // Ensure all layers and items are visible:
165 // In footprint editor, some layers have no meaning or cannot be used, but we show all of
166 // them, at least to be able to edit a bad layer
167 GetBoard()->SetVisibleAlls();
168
169 GetGalDisplayOptions().m_axesEnabled = true;
170
171 // In Footprint Editor, set the default paper size to A4 for plot/print
173 SetScreen( new PCB_SCREEN( GetPageSettings().GetSizeIU( pcbIUScale.IU_PER_MILS ) ) );
174
175 // Create the manager and dispatcher & route draw panel events to the dispatcher
176 setupTools();
178
180 m_treePane = new FOOTPRINT_TREE_PANE( this );
181
185 ReCreateLayerBox( false );
186
188
190 m_appearancePanel = new APPEARANCE_CONTROLS( this, GetCanvas(), true );
191 m_propertiesPanel = new PCB_PROPERTIES_PANEL( this, this );
192
193 // LoadSettings() *after* creating m_LayersManager, because LoadSettings() initialize
194 // parameters in m_LayersManager
195 // NOTE: KifaceSettings() will return PCBNEW_SETTINGS if we started from pcbnew
197
199
200 float proportion = GetFootprintEditorSettings()->m_AuiPanels.properties_splitter;
201 m_propertiesPanel->SetSplitterProportion( proportion );
202
204
205 // Fetch a COPY of the config as a lot of these initializations are going to overwrite our
206 // data.
207 int libWidth = 0;
209
211 {
212 libWidth = cfg->m_LibWidth;
213 aui_cfg = cfg->m_AuiPanels;
214 }
215 else
216 {
217 // keep gcc quiet about uninitalized vars:
218 aui_cfg.appearance_panel_tab = 0;
219 aui_cfg.right_panel_width = -1;
220 }
221
222 m_auimgr.SetManagedWindow( this );
223
224 // Create the infobar pane only after the AUI manager owns this frame. Registering it before
225 // SetManagedWindow() leaves the Top/Layer-1 pane mispositioned once the tabbed center pane
226 // mounts and the perspective restores, so ShowMessage() never reveals it.
228
229 unsigned int auiFlags = wxAUI_MGR_DEFAULT;
230#if !defined( _WIN32 )
231 // Windows cannot redraw the UI fast enough during a live resize and may lead to all kinds
232 // of graphical glitches
233 auiFlags |= wxAUI_MGR_LIVE_RESIZE;
234#endif
235 m_auimgr.SetFlags( auiFlags );
236
237 // Rows; layers 4 - 6
238 m_auimgr.AddPane( m_tbTopMain, EDA_PANE().HToolbar().Name( "TopMainToolbar" )
239 .Top().Layer( 6 ) );
240
241 m_auimgr.AddPane( m_messagePanel, EDA_PANE().Messages().Name( "MsgPanel" )
242 .Bottom().Layer( 6 ) );
243
244 // Columns; layers 1 - 3
245 m_auimgr.AddPane( m_treePane, EDA_PANE().Palette().Name( "Footprints" )
246 .Left().Layer( 4 )
247 .Caption( _( "Libraries" ) )
248 // Don't use -1 for don't-change-height on a growable panel; it has side-effects.
249 .MinSize( FromDIP( 250 ), FromDIP( 80 ) )
250 .BestSize( FromDIP( 250 ), -1 ) );
252 .Left().Layer( 3 )
253 .Caption( _( "Properties" ) ).PaneBorder( false )
254 .MinSize( FromDIP( wxSize( 240, 60 ) ) ).BestSize( FromDIP( wxSize( 300, 200 ) ) ) );
255 m_auimgr.AddPane( m_tbLeft, EDA_PANE().VToolbar().Name( "LeftToolbar" )
256 .Left().Layer( 2 ) );
257
258 m_auimgr.AddPane( m_tbRight, EDA_PANE().VToolbar().Name( "RightToolbar" )
259 .Right().Layer(2) );
260 m_auimgr.AddPane( m_appearancePanel, EDA_PANE().Name( "LayersManager" )
261 .Right().Layer( 3 )
262 .Caption( _( "Appearance" ) ).PaneBorder( false )
263 // Don't use -1 for don't-change-height on a growable panel; it has side-effects.
264 .MinSize( FromDIP( 180 ), FromDIP( 80 ) )
265 .BestSize( FromDIP( 180 ), -1 ) );
266 m_auimgr.AddPane( m_selectionFilterPanel, EDA_PANE().Palette().Name( "SelectionFilter" )
267 .Right().Layer( 3 ).Position( 2 )
268 .Caption( _( "Selection Filter" ) ).PaneBorder( false )
269 // Fixed-size pane; -1 for MinSize height is required
270 .MinSize( FromDIP( 180 ), -1 )
271 .BestSize( FromDIP( 180 ), -1 ) );
272
273 // Center: the tabbed-document strip owns the tab bar above a single, never-reparented canvas.
274 // The panel borrows the canvas; the frame keeps ownership through GetCanvas().
275 m_tabsPanel = new EDITOR_TABS_PANEL( this, GetCanvas() );
276
277 m_tabsPanel->onActivateTab =
278 [this]( int aIdx )
279 {
280 // Ignore activation during a full clear, when each tab close re-selects a fallback
281 // that would re-borrow a tab-owned board into m_pcb just before it is freed.
283 return;
284
285 if( aIdx >= 0 && aIdx < static_cast<int>( m_tabContexts.size() ) )
286 activateFootprintTab( m_tabContexts[aIdx].get() );
287 };
288
289 m_tabsPanel->onCloseTabRequested =
290 [this]( int aIdx ) -> bool
291 {
292 return promptAndCloseFootprintTab( aIdx );
293 };
294
295 // onCloseTabRequested installs the successor board atomically, so the panel must not re-activate
296 // the fallback after a close and re-borrow a just-installed or just-freed index.
297 m_tabsPanel->SetSuppressActivateOnClose( true );
298
299 m_tabsPanel->onQueryVisualState =
300 [this]( int aIdx ) -> TAB_VISUAL_STATE
301 {
302 // The panel model owns preview, but the live dirty flag lives on the shared frame
303 // screen folded into the context, so read modified from the context.
304 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
305
306 if( aIdx < 0 || aIdx >= static_cast<int>( entries.size() ) )
307 return TAB_VISUAL_STATE{};
308
310 aIdx < static_cast<int>( m_tabContexts.size() ) ? m_tabContexts[aIdx].get()
311 : nullptr;
312 const bool modified = ctx ? ctx->IsModified() : entries[aIdx].modified;
313
314 return ResolveTabVisualState( entries[aIdx].preview, modified );
315 };
316
317 m_auimgr.AddPane( m_tabsPanel, EDA_PANE().Canvas().Name( "DrawFrame" )
318 .Center() );
319
321
322 m_auimgr.GetPane( "LayersManager" ).Show( m_show_layer_manager_tools );
323 m_auimgr.GetPane( "SelectionFilter" ).Show( m_show_layer_manager_tools );
324 m_auimgr.GetPane( PropertiesPaneName() ).Show( GetSettings()->m_AuiPanels.show_properties );
325
326 // The selection filter doesn't need to grow in the vertical direction when docked
327 m_auimgr.GetPane( "SelectionFilter" ).dock_proportion = 0;
328
331 DragAcceptFiles( true );
332
334
335 // Apply saved visibility stuff at the end
336 wxAuiPaneInfo& treePane = m_auimgr.GetPane( "Footprints" );
337 wxAuiPaneInfo& layersManager = m_auimgr.GetPane( "LayersManager" );
338
339 if( libWidth > 0 )
340 SetAuiPaneSize( m_auimgr, treePane, libWidth, -1 );
341
342 if( aui_cfg.right_panel_width > 0 )
343 SetAuiPaneSize( m_auimgr, layersManager, aui_cfg.right_panel_width, -1 );
344
345 m_appearancePanel->SetTabIndex( aui_cfg.appearance_panel_tab );
346
348 {
349 m_appearancePanel->SetUserLayerPresets( cfg->m_LayerPresets );
350 m_appearancePanel->ApplyLayerPreset( cfg->m_ActiveLayerPreset );
351 }
352
353 // restore the last footprint from the project, if any, after the library has been init'ed
354 // N.B. This needs to happen after the AUI manager has been initialized so that we can
355 // properly call the WX_INFOBAR without crashing on some systems.
357
358 m_apiHandler = std::make_unique<API_HANDLER_FOOTPRINT>( this );
360
361 if( Kiface().IsSingle() )
362 {
363 m_apiHandlerCommon = std::make_unique<API_HANDLER_COMMON>();
365 }
366
367 // This displays the last footprint loaded, if any, so it must be done after restoreLastFootprint()
369
370 GetToolManager()->PostAction( ACTIONS::zoomFitScreen );
371 UpdateTitle();
373
375
376 // Default shutdown reason until a file is loaded
377 KIPLATFORM::APP::SetShutdownBlockReason( this, _( "Footprint changes are unsaved" ) );
378
379 // Catch unhandled accelerator command characters that were no handled by the library tree
380 // panel.
382 Bind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
383
384 // GTK rejects WXK_TAB as a menu accelerator, so handle Ctrl+Tab cycling from the CHAR_HOOK
385 // stream. Binding after the dispatcher runs this handler first so it can consume the event.
386 Bind( wxEVT_CHAR_HOOK, &FOOTPRINT_EDIT_FRAME::OnTabCharHook, this );
387
388 // Ensure the window is on top
389 Raise();
390 Show( true );
391
392 // Register a call to update the toolbar sizes. It can't be done immediately because
393 // it seems to require some sizes calculated that aren't yet (at least on GTK).
394 CallAfter(
395 [this]()
396 {
397 // Ensure the controls on the toolbars all are correctly sized
399 m_treePane->FocusSearchFieldIfExists();
400
401 // Update the angle snap mode toolbar button to reflect the current preference
403 } );
404}
405
406
408{
409 // Hand the borrowed canvas back before the base destructor deletes it, or the later-destroyed
410 // panel would reparent already-freed memory. The canvas then frees exactly once.
411 if( m_tabsPanel )
412 m_tabsPanel->ReleaseSharedCanvas();
413
414 // Shutdown all running tools
415 if( m_toolManager )
416 m_toolManager->ShutdownAllTools();
417
418 // save the footprint in the PROJECT
420
421 // Clear the watched file
422 setFPWatcher( nullptr );
423
424 // When a tab context owns the active board, null the frame pointer so the base destructor does
425 // not double-free it. A frame-owned bootstrap board is left for the base class to delete.
427 m_pcb = nullptr;
428
429 // We passed ownership of these to wxAuiManager.
430 // delete m_selectionFilterPanel;
431 // delete m_appearancePanel;
432 // delete m_treePane;
433}
434
435
437{
439
440 FOOTPRINT* fp = static_cast<FOOTPRINT*>( GetModel() );
441
442 if( fp )
443 {
444 std::vector<MSG_PANEL_ITEM> msgItems;
445 fp->GetMsgPanelInfo( this, msgItems );
446 SetMsgPanel( msgItems );
447 }
448}
449
450
456
457
459{
460 return m_toolManager->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
461}
462
463
465{
466 // switches currently used canvas (Cairo / OpenGL).
467 PCB_BASE_FRAME::SwitchCanvas( aCanvasType );
468
469 GetCanvas()->GetGAL()->SetAxesEnabled( true );
470
471 // The base class method *does not reinit* the layers manager. We must update the layer
472 // widget to match board visibility states, both layers and render columns, and and some
473 // settings dependent on the canvas.
475}
476
477
483
484
486{
487 wxAuiPaneInfo& treePane = m_auimgr.GetPane( m_treePane );
488 treePane.Show( !IsLibraryTreeShown() );
489
490 if( IsLibraryTreeShown() )
491 {
492 // SetAuiPaneSize also updates m_auimgr
493 SetAuiPaneSize( m_auimgr, treePane, m_editorSettings->m_LibWidth, -1 );
494 }
495 else
496 {
497 m_editorSettings->m_LibWidth = m_treePane->GetSize().x;
498 m_auimgr.Update();
499 }
500}
501
502
504{
505 m_treePane->FocusSearchFieldIfExists();
506}
507
508
510{
512 wxAuiPaneInfo& layersManager = m_auimgr.GetPane( "LayersManager" );
513 wxAuiPaneInfo& selectionFilter = m_auimgr.GetPane( "SelectionFilter" );
514
515 // show auxiliary Vertical layers and visibility manager toolbar
517 layersManager.Show( m_show_layer_manager_tools );
518 selectionFilter.Show( m_show_layer_manager_tools );
519
521 {
522 SetAuiPaneSize( m_auimgr, layersManager, settings->m_AuiPanels.right_panel_width, -1 );
523 }
524 else
525 {
526 settings->m_AuiPanels.right_panel_width = m_appearancePanel->GetSize().x;
527 m_auimgr.Update();
528 }
529}
530
531
533{
534 return const_cast<wxAuiManager&>( m_auimgr ).GetPane( m_treePane ).IsShown();
535}
536
537
539{
540 // A tab close transiently leaves the frame with no board while UI repaints can still run.
541 if( !GetBoard() )
542 return nullptr;
543
544 return GetBoard()->GetFirstFootprint();
545}
546
547
549{
550 LIB_ID id;
551
552 if( IsLibraryTreeShown() )
554
555 if( id.GetLibNickname().empty() )
556 id = GetLoadedFPID();
557
558 return id;
559}
560
561
563{
564 // The board pointer is transiently null during a tab close while the library tree adapter can
565 // still repaint, so tolerate having no board.
566 if( !GetBoard() )
567 return LIB_ID();
568
569 FOOTPRINT* footprint = GetBoard()->GetFirstFootprint();
570
571 if( footprint )
572 return LIB_ID( footprint->GetFPID().GetLibNickname(), m_footprintNameWhenLoaded );
573 else
574 return LIB_ID();
575}
576
577
579{
580 if( GetBoard() && GetBoard()->GetFirstFootprint() )
581 {
584 }
585
586 GetScreen()->SetContentModified( false );
587
588 // OnModify() mirrors the dirty flag onto the active tab context and the panel model, so clear both
589 // here too. Tab rendering and close prompting read the context's flag, so a save that only cleared
590 // the shared screen would leave the tab starred and re-prompting to save.
591 if( m_tabsPanel && m_activeTab )
592 {
593 m_activeTab->SetModified( false );
594
595 if( int idx = m_tabsPanel->FindTab( m_activeTab->GetTabKey() ); idx >= 0 )
596 m_tabsPanel->MarkModified( idx, false );
597 }
598}
599
600
602{
603 // If we've already vetted closing this window, then we have no FP anymore
604 if( m_isClosing || !GetBoard() )
605 return false;
606
607 FOOTPRINT* footprint = GetBoard()->GetFirstFootprint();
608
609 return ( footprint && footprint->GetLink() != niluuid );
610}
611
612
614{
615 LIB_ID id = GetLoadedFPID();
616
617 if( id.IsValid() )
618 {
620 Prj().SetRString( PROJECT::PCB_FOOTPRINT_EDITOR_FP_NAME, id.GetLibItemName() );
621 }
622}
623
624
626{
627 // Restore the persisted tab set first. The active tab is loaded last so it ends up focused, and
628 // tabs that no longer resolve are silently dropped.
629 if( FOOTPRINT_EDITOR_SETTINGS* cfg = GetSettings(); cfg && !cfg->m_OpenTabs.empty() )
630 {
631 const wxString activeKey = cfg->m_ActiveTab;
632
633 const auto loadTab =
634 [this]( const FOOTPRINT_EDITOR_SETTINGS::OPEN_TAB& aTab ) -> bool
635 {
636 LIB_ID id;
637 id.SetLibNickname( aTab.m_lib );
638 id.SetLibItemName( aTab.m_fpName );
639
640 if( FOOTPRINT* footprint = LoadFootprint( id ) )
641 {
642 AddFootprintToBoard( footprint );
643
644 if( m_tabsPanel )
645 findOrCreateFootprintTab( id, aTab.m_preview );
646
647 return true;
648 }
649
650 // LoadFootprint swallows the IO_ERROR when the library no longer resolves, so
651 // log the dropped tab to keep a failed restore diagnosable.
652 wxLogTrace( wxT( "KICAD_FP_TABS" ),
653 wxT( "Dropping persisted footprint tab '%s:%s' (failed to load)" ),
654 aTab.m_lib, aTab.m_fpName );
655
656 return false;
657 };
658
659 const FOOTPRINT_EDITOR_SETTINGS::OPEN_TAB* activeTab = nullptr;
660
661 for( const FOOTPRINT_EDITOR_SETTINGS::OPEN_TAB& tab : cfg->m_OpenTabs )
662 {
663 const wxString key = tab.m_lib + wxT( ":" ) + tab.m_fpName;
664
665 if( key == activeKey )
666 activeTab = &tab;
667 else
668 loadTab( tab );
669 }
670
671 if( activeTab )
672 loadTab( *activeTab );
673
674 if( !m_tabContexts.empty() )
675 return;
676 }
677
678 const wxString& footprintName = Prj().GetRString( PROJECT::PCB_FOOTPRINT_EDITOR_FP_NAME );
679 const wxString& libNickname = Prj().GetRString( PROJECT::PCB_FOOTPRINT_EDITOR_LIB_NICKNAME );
680
681 if( libNickname.Length() && footprintName.Length() )
682 {
683 LIB_ID id;
684 id.SetLibNickname( libNickname );
685 id.SetLibItemName( footprintName );
686
687 FOOTPRINT* footprint = LoadFootprint( id );
688
689 if( footprint )
690 {
691 AddFootprintToBoard( footprint );
692
693 // The last-session footprint is a real document, so promote its tab to permanent.
694 if( m_tabsPanel )
695 findOrCreateFootprintTab( id, false );
696 }
697 }
698}
699
700
702{
703 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( GetModel() );
704 BOARD& board = *GetBoard();
705
706 // All FPs have these layers enabled
707 LSET enabledLayers = LSET::AllTechMask() | LSET::UserMask();
708
709 const auto configureStackup =
710 [&]( FOOTPRINT_STACKUP aMode, const LSET& aLayerSet )
711 {
712 const LSET cuLayers = aLayerSet & LSET::AllCuMask();
713 board.SetCopperLayerCount( cuLayers.count() );
714
715 switch( aMode )
716 {
718 {
719 enabledLayers |= LSET{ F_Cu, In1_Cu, B_Cu };
720 board.SetLayerName( In1_Cu, _( "Inner layers" ) );
721 break;
722 }
723
725 {
726 // Nothing extra to add
727
728 // Clear layer name defaults
729 board.SetLayerName( In1_Cu, wxEmptyString );
730 break;
731 }
732
733 }
734
735 enabledLayers |= aLayerSet;
736 };
737
738 if( footprint )
739 {
740 configureStackup( footprint->GetStackupMode(), footprint->GetStackupLayers() );
741 }
742 else
743 {
744 // If no footprint is loaded, we assume the default stackup mode
745 configureStackup( FOOTPRINT_STACKUP::EXPAND_INNER_LAYERS, LSET{} );
746 }
747
749 {
750 m_originalFootprintCopy->RunOnChildren(
751 [&]( BOARD_ITEM* child )
752 {
753 LSET childLayers = child->GetLayerSet() & LSET::UserDefinedLayersMask();
754
755 for( PCB_LAYER_ID layer : childLayers )
756 enabledLayers.set( layer );
757 },
759 }
760
761 // Enable the user-configured number of user layers, plus any specifically named layers
763 {
764 int userLayerCount = cfg->m_DesignSettings.GetUserDefinedLayerCount();
765 enabledLayers |= LSET::UserDefinedLayersMask( userLayerCount );
766
767 for( const PCB_LAYER_ID& user : LSET::UserDefinedLayersMask() )
768 {
769 if( cfg->m_DesignSettings.m_UserLayerNames.contains( LSET::Name( user ).ToStdString() ) )
770 enabledLayers.set( user );
771 }
772 }
773
774 board.SetEnabledLayers( enabledLayers );
775
776 // Footprint Editor layer visibility is kept in the view, not the board (because the board
777 // just delegates to the project file, which we don't have).
778 for( const PCB_LAYER_ID& layer : GetBoard()->GetEnabledLayers() )
779 GetCanvas()->GetView()->SetLayerVisible( layer, true );
780}
781
782
784{
786
787 m_originalFootprintCopy.reset( static_cast<FOOTPRINT*>( aFootprint->Clone() ) );
788 m_originalFootprintCopy->SetParent( nullptr );
789
791
792 // Mirror the load baseline into the active tab context so it survives a tab switch (the frame
793 // members are only a borrowed view of the active context's baseline).
794 if( m_activeTab )
795 {
796 m_activeTab->SetOriginalFootprintCopy(
797 std::unique_ptr<FOOTPRINT>( static_cast<FOOTPRINT*>( m_originalFootprintCopy
798 ? m_originalFootprintCopy->Clone()
799 : nullptr ) ) );
800 m_activeTab->SetFootprintNameWhenLoaded( m_footprintNameWhenLoaded );
801 m_activeTab->SetName( aFootprint->GetFPID().GetLibItemName() );
802 }
803
805 // Ensure item UUIDs are valid
806 // ("old" footprints can have null uuids that create issues in fp editor)
807 aFootprint->FixUuids();
808
810
811 // Use CallAfter so that we update the canvas before waiting for the infobar animation
812 CallAfter(
813 [this]()
814 {
816 wxString libName = fp->GetFPID().GetLibNickname();
817 wxString msg, link;
818
820 {
821 msg.Printf( _( "Editing %s from board. Saving will update the board only." ), fp->GetReference() );
822 link.Printf( _( "Open in library %s" ), UnescapeString( libName ) );
823
824 const auto openLibraryCopy =
825 [this]( wxHyperlinkEvent& aEvent )
826 {
828 };
829
830 if( WX_INFOBAR* infobar = GetInfoBar() )
831 {
832 wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY, link, wxEmptyString );
833 button->Bind( wxEVT_COMMAND_HYPERLINK, openLibraryCopy );
834
835 infobar->RemoveAllButtons();
836 infobar->AddButton( button );
837 infobar->AddCloseButton();
838 infobar->ShowMessage( msg, wxICON_INFORMATION );
839 }
840 }
841 // An empty libname is OK - you get that when creating a new footprint from the main menu
842 // In that case. treat is as editable, and the user will be prompted for save-as when saving.
843 else if( !libName.empty()
844 && !PROJECT_PCB::FootprintLibAdapter( &Prj() )->IsFootprintLibWritable( libName ) )
845 {
846 msg.Printf( _( "Editing footprint from read-only library %s." ), UnescapeString( libName ) );
847
848 if( WX_INFOBAR* infobar = GetInfoBar() )
849 {
850 link = _( "Save as editable copy" );
851
852 const auto saveAsEditableCopy =
853 [this]( wxHyperlinkEvent& aEvent )
854 {
855 SaveFootprintAs( GetBoard()->GetFirstFootprint() );
856 GetCanvas()->GetView()->Update( GetBoard()->GetFirstFootprint() );
857 ClearModify();
858
859 // Get rid of the save-will-update-board-only (or any other dismissable warning)
860 WX_INFOBAR* loc_infobar = GetInfoBar();
861
862 if( loc_infobar->IsShownOnScreen() && loc_infobar->HasCloseButton() )
863 loc_infobar->Dismiss();
864
866 SyncLibraryTree( true );
867 };
868
869 wxHyperlinkCtrl* button = new wxHyperlinkCtrl( infobar, wxID_ANY, link, wxEmptyString );
870 button->Bind( wxEVT_COMMAND_HYPERLINK, saveAsEditableCopy );
871
872 infobar->RemoveAllButtons();
873 infobar->AddButton( button );
874 infobar->AddCloseButton();
875 infobar->ShowMessage( msg, wxICON_INFORMATION );
876 }
877 }
878 else
879 {
880 if( WX_INFOBAR* infobar = GetInfoBar() )
881 infobar->Dismiss();
882 }
883 } );
884
887}
888
889
891{
892 // Route the load through the tab strip so the footprint lands on its own tab. Tabs only apply to
893 // library footprints with a resolvable identity; board-sourced and new-footprint loads keep the
894 // legacy single-board behavior.
895 const bool fromBoard = aFootprint && aFootprint->GetLink() != niluuid;
896
897 // Opening from the library is a preview that the next library-open reuses; editing promotes it
898 // to a permanent tab.
899 if( m_tabsPanel && aFootprint && !fromBoard && aFootprint->GetFPID().IsValid() )
900 findOrCreateFootprintTab( aFootprint->GetFPID(), true );
901
902 ReloadFootprint( aFootprint );
903
905 setFPWatcher( nullptr );
906 else
907 setFPWatcher( aFootprint );
908}
909
910
912{
913 return std::any_of( m_tabContexts.begin(), m_tabContexts.end(),
914 [this]( const std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT>& aCtx )
915 {
916 return aCtx->GetBoard() == m_pcb;
917 } );
918}
919
920
922{
923 // Swap the board pointer without the SetBoard delete, since on a tab switch the outgoing board
924 // is owned by its tab context. Reproduce only the side effects SetBoard applies to the incoming
925 // board.
926 if( m_pcb == aBoard )
927 return;
928
929 // The only frame-owned board is the constructor's bootstrap board. Delete it when we first
930 // switch away so it does not leak; tab-owned boards are left to their contexts.
931 if( m_pcb && !activeBoardOwnedByTab() )
932 delete m_pcb;
933
934 m_pcb = aBoard;
935
936 if( GetBoard() )
938
939 if( GetBoard() && GetCanvas() )
940 {
941 if( KIGFX::RENDER_SETTINGS* rs = GetCanvas()->GetView()->GetPainter()->GetSettings() )
942 {
943 rs->SetDashLengthRatio( GetBoard()->GetPlotOptions().GetDashedLineDashRatio() );
944 rs->SetGapLengthRatio( GetBoard()->GetPlotOptions().GetDashedLineGapRatio() );
945 }
946 }
947
948 wxCommandEvent e( EDA_EVT_BOARD_CHANGED );
949 ProcessEventLocally( e );
950}
951
952
954{
955 if( !m_activeTab )
956 return;
957
958 KIGFX::VIEW* view = GetCanvas()->GetView();
959
960 EDITOR_TAB_CONTEXT::VIEW_SNAPSHOT& snap = m_activeTab->ViewSnapshot();
961 snap.scale = view->GetScale();
962 snap.center = view->GetCenter();
963 snap.valid = true;
964
965 std::vector<KIID>& sel = m_activeTab->SavedSelection();
966 sel.clear();
967
968 for( EDA_ITEM* item : GetCurrentSelection() )
969 sel.push_back( item->m_Uuid );
970
971 // Dirty state lives on the shared frame screen, so fold it into the context to survive the switch.
972 if( GetScreen() )
973 m_activeTab->SetModified( GetScreen()->IsContentModified() );
974
975 // Swap the raw vectors since UNDO_REDO_CONTAINER is non-copyable; ownership transfers intact.
976 m_activeTab->UndoList().m_CommandsList.swap( m_undoList.m_CommandsList );
977 m_activeTab->RedoList().m_CommandsList.swap( m_redoList.m_CommandsList );
978
979 m_activeTab = nullptr;
980}
981
982
984{
985 if( !aCtx || aCtx == m_activeTab )
986 return;
987
988 installFootprintTabBoard( aCtx, aCtx->GetBoard() );
989}
990
991
993 BOARD* aBoard )
994{
995 // Install the successor board and tool environment before the caller frees the outgoing context
996 // so no tool Reset() or repaint ever sees a freed or null m_pcb. Never calls the base SetBoard,
997 // which would delete m_pcb and reset tools while the model still aliases it.
998
1000
1001 // Drop the live selection while the outgoing board is still valid.
1002 if( m_toolManager )
1004
1005 m_activeTab = aCtx;
1006
1007 borrowBoardNonDestructive( aBoard );
1008
1009 if( aCtx )
1010 {
1011 m_undoList.m_CommandsList.swap( aCtx->UndoList().m_CommandsList );
1012 m_redoList.m_CommandsList.swap( aCtx->RedoList().m_CommandsList );
1013 }
1014 else
1015 {
1016 // Discard the swapped-in lists with their transient items so nothing references a freed board.
1018 }
1019
1021 ? static_cast<FOOTPRINT*>(
1022 aCtx->GetOriginalFootprintCopy()->Clone() )
1023 : nullptr );
1024 m_footprintNameWhenLoaded = aCtx ? aCtx->GetFootprintNameWhenLoaded() : wxString();
1025
1026 // Mirror the incoming tab's board-uuid remap onto the frame so SaveFootprintToBoard saves an
1027 // instance edit back to the originating board items. A library tab has an empty map.
1028 if( aCtx )
1030 else
1031 m_boardFootprintUuids.clear();
1032
1033 if( GetScreen() )
1034 GetScreen()->SetContentModified( aCtx ? aCtx->IsModified() : false );
1035
1036 // Point the tool environment at the incoming board before ResetTools so tools never dereference
1037 // a freed model.
1038 m_toolManager->SetEnvironment( GetBoard(), GetCanvas()->GetView(),
1039 GetCanvas()->GetViewControls(), config(), this );
1040
1043
1045
1046 if( !aCtx )
1047 {
1052 return;
1053 }
1054
1055 const EDITOR_TAB_CONTEXT::VIEW_SNAPSHOT& snap = aCtx->ViewSnapshot();
1056
1057 if( snap.valid )
1058 {
1059 GetCanvas()->GetView()->SetScale( snap.scale );
1060 GetCanvas()->GetView()->SetCenter( snap.center );
1061 }
1062 else
1063 {
1064 // First time this tab is shown there is no saved view
1066 }
1067
1068 if( !aCtx->SavedSelection().empty() )
1069 {
1071
1072 if( selTool )
1073 {
1074 for( const KIID& id : aCtx->SavedSelection() )
1075 {
1076 if( BOARD_ITEM* item = GetBoard()->ResolveItem( id, true ) )
1077 selTool->select( item );
1078 }
1079 }
1080 }
1081
1082 if( m_appearancePanel )
1083 m_appearancePanel->OnBoardChanged();
1084
1085 if( m_propertiesPanel )
1086 m_propertiesPanel->UpdateData();
1087
1092}
1093
1094
1097{
1098 if( !m_tabsPanel )
1099 return nullptr;
1100
1101 const wxString lib = aLibId.GetLibNickname();
1102 const wxString name = aLibId.GetLibItemName();
1103 const wxString key = lib + wxT( ":" ) + name;
1104
1105 if( int existing = m_tabsPanel->FindTab( key ); existing >= 0 )
1106 {
1107 m_tabsPanel->AddTab( key, name, aAsPreview );
1108 return m_tabContexts[existing].get();
1109 }
1110
1111 auto board = std::make_unique<BOARD>();
1112 board->SetBoardUse( BOARD_USE::FPHOLDER );
1113 board->GetDesignSettings().m_NetSettings->GetDefaultNetclass()->SetClearance( 0 );
1114 board->GetDesignSettings().m_SolderMaskExpansion = 0;
1115 board->SetVisibleAlls();
1116
1117 auto ctx = std::make_unique<FOOTPRINT_EDITOR_TAB_CONTEXT>( lib, name, std::move( board ) );
1118 ctx->SetPreview( aAsPreview );
1119
1120 FOOTPRINT_EDITOR_TAB_CONTEXT* raw = ctx.get();
1121
1122 // Keep m_tabContexts index-aligned with the panel model. A previewed open reuses the preview
1123 // slot in place; otherwise the context is appended. It must be at its final index before AddTab
1124 // fires onActivateTab.
1125 const int reuseSlot = aAsPreview ? m_tabsPanel->Model().PreviewIndex() : -1;
1126
1127 if( reuseSlot >= 0 && reuseSlot < static_cast<int>( m_tabContexts.size() ) )
1128 {
1129 // Tear the active document down while the outgoing board is still alive, before it is
1130 // displaced and freed.
1131 if( m_tabContexts[reuseSlot].get() == m_activeTab )
1132 {
1133 if( m_toolManager )
1135
1137 m_activeTab = nullptr;
1138 }
1139
1140 // Drop the frame's alias so borrowBoardNonDestructive cannot delete the displaced board while
1141 // placeReusedTabContext still owns it.
1142 if( m_pcb == m_tabContexts[reuseSlot]->GetBoard() )
1143 m_pcb = nullptr;
1144
1145 return placeReusedTabContext( m_tabContexts, reuseSlot, std::move( ctx ),
1146 [&]() { m_tabsPanel->AddTab( key, name, aAsPreview ); } );
1147 }
1148
1149 m_tabContexts.push_back( std::move( ctx ) );
1150
1151 m_tabsPanel->AddTab( key, name, aAsPreview );
1152
1153 return raw;
1154}
1155
1156
1158 std::vector<std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT>>& aContexts, int aSlot,
1159 std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT> aNew,
1160 const std::function<void()>& aInstallSuccessor )
1161{
1162 // Hold the displaced context, and its still-displayed board, alive across aInstallSuccessor, which
1163 // repoints the canvas VIEW at the incoming board. Freeing the old board first would leave
1164 // VIEW::Clear() dereferencing items from a destroyed board.
1165 std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT> displaced = std::move( aContexts[aSlot] );
1166 aContexts[aSlot] = std::move( aNew );
1167
1168 FOOTPRINT_EDITOR_TAB_CONTEXT* raw = aContexts[aSlot].get();
1169
1170 aInstallSuccessor();
1171
1172 return raw;
1173}
1174
1175
1178{
1179 if( !m_tabsPanel || !aBoardFootprint )
1180 return nullptr;
1181
1182 const KIID sourceUuid = aBoardFootprint->m_Uuid;
1183 const wxString key = FOOTPRINT_EDITOR_TAB_CONTEXT::MakeInstanceTabKey( sourceUuid );
1184 const wxString reference = aBoardFootprint->GetReference();
1185
1186 // Re-editing the same placed footprint focuses the live tab rather than duplicating it.
1187 if( int existing = m_tabsPanel->FindTab( key ); existing >= 0 )
1188 {
1189 m_tabsPanel->AddTab( key, reference, false );
1190 return m_tabContexts[existing].get();
1191 }
1192
1193 auto board = std::make_unique<BOARD>();
1194 board->SetBoardUse( BOARD_USE::FPHOLDER );
1195 board->GetDesignSettings().m_NetSettings->GetDefaultNetclass()->SetClearance( 0 );
1196 board->GetDesignSettings().m_SolderMaskExpansion = 0;
1197 board->SetVisibleAlls();
1198 board->GetDesignSettings().m_DRCSeverities[DRCE_MISSING_COURTYARD] = RPT_SEVERITY_WARNING;
1199
1200 auto ctx = std::make_unique<FOOTPRINT_EDITOR_TAB_CONTEXT>( sourceUuid, reference,
1201 std::move( board ) );
1202 BOARD* ctxBoard = ctx->GetBoard();
1203 std::map<KIID, KIID>& uuidMap = ctx->BoardFootprintUuids();
1204 FOOTPRINT_EDITOR_TAB_CONTEXT* raw = ctx.get();
1205
1206 const auto recordAndUpdateUuid =
1207 [&]( BOARD_ITEM* aItem )
1208 {
1209 KIID newId;
1210 uuidMap[newId] = aItem->m_Uuid;
1211 aItem->SetUuid( newId );
1212 };
1213
1214 // Clone keeps the existing uuids, which the remap then swaps for fresh editor-local ones so
1215 // SaveFootprintToBoard can map them back to the original board items.
1216 FOOTPRINT* clone = static_cast<FOOTPRINT*>( aBoardFootprint->Clone() );
1217 clone->SetParent( ctxBoard );
1218 clone->SetParentGroup( nullptr );
1219 clone->SetLink( aBoardFootprint->m_Uuid );
1220 clone->ClearFlags();
1221 clone->SetLocked( false );
1222
1223 recordAndUpdateUuid( clone );
1224 clone->RunOnChildren(
1225 [&]( BOARD_ITEM* aItem )
1226 {
1227 if( aItem->Type() == PCB_PAD_T )
1228 aItem->SetLocked( false );
1229
1230 aItem->ClearFlags();
1231 recordAndUpdateUuid( aItem );
1232 },
1234
1235 ctxBoard->Add( clone );
1236
1237 // The editor knows nothing of the board's nets, so force the orphaned dummy net on every pad to
1238 // avoid saving a reference to an unknown net into the library cache.
1239 clone->ClearAllNets();
1240
1241 // Normalize placement to the footprint-editor defaults so the editor view matches a library load.
1242 clone->SetPosition( VECTOR2I( 0, 0 ) );
1243
1244 if( clone->GetLayer() != F_Cu )
1245 clone->Flip( clone->GetPosition(), GetPcbNewSettings()->m_FlipDirection );
1246
1247 clone->SetOrientation( ANGLE_0 );
1248
1249 m_tabContexts.push_back( std::move( ctx ) );
1250
1251 // Index-aligned with the panel model; the context is at its final index before AddTab fires
1252 // onActivateTab.
1253 m_tabsPanel->AddTab( key, reference, false );
1254
1255 return raw;
1256}
1257
1258
1260 UNDO_REDO_CONTAINER& aRedo )
1261{
1262 // Free the UR_TRANSIENT board items each command owns and the command wrappers. The frame's own
1263 // ClearUndoRedoList() and the bare container destructor delete only the wrappers and leak the
1264 // transient items, so a discarded tab history must come through here.
1265 for( UNDO_REDO_CONTAINER* list : { &aUndo, &aRedo } )
1266 {
1267 for( PICKED_ITEMS_LIST* cmd : list->m_CommandsList )
1268 {
1270 delete cmd;
1271 }
1272
1273 list->m_CommandsList.clear();
1274 }
1275}
1276
1277
1279{
1280 // The context is detached here, so the transient items in its lists are never the live objects.
1282}
1283
1284
1286{
1287 if( aIdx < 0 || aIdx >= static_cast<int>( m_tabContexts.size() ) )
1288 return false;
1289
1291
1292 // The active tab's live dirty state lives on the shared frame screen, so ctx->IsModified() is
1293 // stale for it. Fold the screen state back in so an unsaved active tab still prompts.
1294 if( ctx == m_activeTab && GetScreen() )
1296
1297 if( ctx->IsModified() && !m_silentFootprintTabClose )
1298 {
1299 // Prompt while the closing tab is still fully live so a save reads its real board.
1300 wxString msg = wxString::Format( _( "Save changes to '%s' before closing?" ),
1301 ctx->GetDisplayName() );
1302
1303 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxYES_NO | wxCANCEL | wxICON_WARNING );
1304 dlg.SetYesNoCancelLabels( _( "Save" ), _( "Discard Changes" ), _( "Cancel" ) );
1305
1306 switch( dlg.ShowModal() )
1307 {
1308 case wxID_YES:
1309 {
1310 // SaveFootprint reads the active tab's load baseline for rename detection, so an inactive
1311 // tab must be made active first or it saves against the wrong baseline. Restore the prior
1312 // active tab afterwards so closing an inactive tab stays an inactive close, keeping the
1313 // panel's suppressed fallback selection aligned with the live board. Veto the close if the
1314 // save did not complete so the edits and history are not silently dropped.
1315 FOOTPRINT_EDITOR_TAB_CONTEXT* activeBeforeSave = m_activeTab;
1316 const bool activatedForSave = ( ctx != m_activeTab );
1317
1318 if( activatedForSave )
1319 activateFootprintTab( ctx );
1320
1321 const bool saved = SaveFootprint( ctx->GetBoard()->GetFirstFootprint() );
1322
1323 if( activatedForSave && activeBeforeSave )
1324 activateFootprintTab( activeBeforeSave );
1325
1326 if( !saved )
1327 return false;
1328
1329 break;
1330 }
1331
1332 case wxID_NO: break;
1333 default:
1334 case wxID_CANCEL: return false;
1335 }
1336 }
1337
1338 const bool closingActive = ( ctx == m_activeTab );
1339
1340 if( !closingActive )
1341 {
1342 // m_pcb aliases a different live tab's board, so freeing this context dangles nothing.
1344 m_tabContexts.erase( m_tabContexts.begin() + aIdx );
1345 return true;
1346 }
1347
1348 // The closing tab's lists are currently the frame's live lists. Free them now with their
1349 // transient items, so the install's detach swaps empty lists into the closing context.
1351
1352 const int newCount = static_cast<int>( m_tabContexts.size() ) - 1;
1353 const int successorIdx = newCount > 0 ? std::min( aIdx, newCount - 1 ) : -1;
1354
1355 if( successorIdx >= 0 )
1356 {
1357 // Map the successor's post-erase position back to a pre-erase index. Indices above the closed
1358 // one shift down by one after the erase.
1359 const int preEraseSuccessor = successorIdx < aIdx ? successorIdx : successorIdx + 1;
1360
1361 FOOTPRINT_EDITOR_TAB_CONTEXT* successor = m_tabContexts[preEraseSuccessor].get();
1362
1363 installFootprintTabBoard( successor, successor->GetBoard() );
1364 }
1365 else
1366 {
1367 // Last tab: the fresh empty board is frame-owned like the bootstrap board.
1368 BOARD* emptyBoard = new BOARD();
1369 emptyBoard->SetBoardUse( BOARD_USE::FPHOLDER );
1371 emptyBoard->GetDesignSettings().m_SolderMaskExpansion = 0;
1372 emptyBoard->SetVisibleAlls();
1373
1374 installFootprintTabBoard( nullptr, emptyBoard );
1375 }
1376
1377 // The install swapped m_pcb off the closing board, so erasing the context frees it safely.
1378 m_tabContexts.erase( m_tabContexts.begin() + aIdx );
1379
1380 return true;
1381}
1382
1383
1385{
1386 if( !m_tabsPanel )
1387 return;
1388
1389 const wxString lib = aFPID.GetLibNickname();
1390 const wxString name = aFPID.GetLibItemName();
1391 const int idx = m_tabsPanel->FindTab( lib + wxT( ":" ) + name );
1392
1393 if( idx < 0 )
1394 return;
1395
1396 // The caller already confirmed the deletion, so close without re-prompting. The panel selects a
1397 // successor when the closed tab was active.
1399 m_tabsPanel->CloseTab( idx );
1401}
1402
1403
1404void FOOTPRINT_EDIT_FRAME::RenameFootprintTab( const LIB_ID& aOldId, const LIB_ID& aNewId )
1405{
1406 if( !m_tabsPanel )
1407 return;
1408
1409 const wxString oldLib = aOldId.GetLibNickname();
1410 const wxString oldName = aOldId.GetLibItemName();
1411 const wxString oldKey = oldLib + wxT( ":" ) + oldName;
1412 const int idx = m_tabsPanel->FindTab( oldKey );
1413
1414 if( idx < 0 )
1415 return;
1416
1417 const wxString newLib = aNewId.GetLibNickname();
1418 const wxString newName = aNewId.GetLibItemName();
1419
1420 if( idx < static_cast<int>( m_tabContexts.size() ) )
1421 m_tabContexts[idx]->SetName( newName );
1422
1423 m_tabsPanel->RenameTab( oldKey, newLib + wxT( ":" ) + newName, newName );
1424 UpdateTitle();
1425}
1426
1427
1429{
1430 for( const std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
1431 {
1432 if( ctx.get() != m_activeTab && ctx->IsTransient() && ctx->IsModified() )
1433 return true;
1434 }
1435
1436 return false;
1437}
1438
1439
1441{
1442 // Collect first; saving activates a tab, which mutates m_activeTab and the live board pointer.
1443 std::vector<FOOTPRINT_EDITOR_TAB_CONTEXT*> dirty;
1444
1445 for( const std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
1446 {
1447 // The active tab and library tabs are handled by the main canCloseWindow check.
1448 if( ctx.get() != m_activeTab && ctx->IsTransient() && ctx->IsModified() )
1449 dirty.push_back( ctx.get() );
1450 }
1451
1452 // Saving activates each dirty tab in turn; restore the tab the user was on so a vetoed close leaves
1453 // the editor where it was and a successful close persists the real active tab, not a discarded one.
1454 FOOTPRINT_EDITOR_TAB_CONTEXT* originalActive = m_activeTab;
1455
1456 for( FOOTPRINT_EDITOR_TAB_CONTEXT* ctx : dirty )
1457 {
1458 wxString msg = wxString::Format( _( "Save changes to '%s' before closing?" ),
1459 ctx->GetDisplayName() );
1460
1461 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxYES_NO | wxCANCEL | wxICON_WARNING );
1462 dlg.SetYesNoCancelLabels( _( "Save" ), _( "Discard Changes" ), _( "Cancel" ) );
1463
1464 const int answer = dlg.ShowModal();
1465
1466 if( answer == wxID_YES )
1467 {
1468 // SaveFootprint reads the active tab's load baseline and uuid remap, so make this tab
1469 // active first; it does not clear the dirty flag, so ClearModify below does it or a
1470 // vetoed close would re-prompt an already-saved tab.
1471 activateFootprintTab( ctx );
1472
1473 if( !SaveFootprint( ctx->GetBoard()->GetFirstFootprint() ) )
1474 {
1475 activateFootprintTab( originalActive );
1476 return false;
1477 }
1478
1479 ClearModify();
1480 }
1481 else if( answer != wxID_NO )
1482 {
1483 activateFootprintTab( originalActive );
1484 return false;
1485 }
1486 }
1487
1488 activateFootprintTab( originalActive );
1489
1490 return true;
1491}
1492
1493
1495{
1496 if( m_tabsPanel )
1497 m_tabsPanel->RefreshTabLabels();
1498}
1499
1500
1502{
1503 wxCHECK( aReplacement, /* void */ );
1504
1505 // Install the fresh frame-owned board and reset the tools against it before any tab board is
1506 // freed, so no ResetTools or repaint sees a freed or null m_pcb.
1507 installFootprintTabBoard( nullptr, aReplacement );
1508
1509 // Tear the strip down without re-prompting to save, since unsaved changes were already handled.
1510 // Suppress the host close callback and tab activation so CloseAll only does panel bookkeeping.
1511 if( m_tabsPanel )
1512 {
1513 std::function<bool( int )> savedCb = std::move( m_tabsPanel->onCloseTabRequested );
1514 m_tabsPanel->onCloseTabRequested = []( int ) { return true; };
1515
1517 m_tabsPanel->CloseAll();
1519
1520 m_tabsPanel->onCloseTabRequested = std::move( savedCb );
1521 }
1522
1523 wxASSERT_MSG( m_pcb == aReplacement,
1524 wxT( "m_pcb must alias the frame-owned replacement before contexts are freed" ) );
1525
1526 for( const std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
1528
1529 m_tabContexts.clear();
1530}
1531
1532
1534{
1535 if( m_tabsPanel )
1536 m_tabsPanel->AdvanceTab( aForward );
1537}
1538
1539
1541{
1542 if( m_tabsPanel )
1543 m_tabsPanel->CloseTab( m_tabsPanel->GetActiveTab() );
1544}
1545
1546
1551
1552
1557
1558
1560{
1561 wxFAIL_MSG( wxT( "Plotting not supported in Footprint Editor" ) );
1562
1564}
1565
1566
1568{
1569 wxFAIL_MSG( wxT( "Plotting not supported in Footprint Editor" ) );
1570}
1571
1572
1580
1581
1589
1590
1592{
1593 // Get our own settings; aCfg will be the PCBNEW_SETTINGS because we're part of the pcbnew
1594 // compile unit
1596
1597 if( cfg )
1598 {
1600
1602
1605
1607 m_selectionFilterPanel->SetCheckboxesFromFilter( cfg->m_SelectionFilter );
1608
1610
1611 for( auto& [source_name, dest_name] : cfg->m_DesignSettings.m_UserLayerNames )
1612 {
1613 wxString wx_source_name = source_name;
1614 PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( LSET::NameToLayer( wx_source_name ) );
1615
1616 if( IsUserLayer( layer ) )
1617 GetBoard()->SetLayerName( layer, dest_name );
1618 }
1619
1620 }
1621}
1622
1623
1625{
1626 // Load canvas type from the FOOTPRINT_EDITOR_SETTINGS:
1628
1629 // If we had an OpenGL failure this session, use the fallback GAL but don't update the
1630 // user preference silently:
1631
1634}
1635
1636
1638{
1640
1641 // Get our own settings; aCfg will be the PCBNEW_SETTINGS because we're part of the pcbnew
1642 // compile unit
1644
1645 if( cfg )
1646 {
1648
1651 cfg->m_LibWidth = m_treePane->GetSize().x;
1652
1653 if( TOOL_MANAGER* toolMgr = GetToolManager() )
1654 {
1655 if( PCB_SELECTION_TOOL* selTool = toolMgr->GetTool<PCB_SELECTION_TOOL>() )
1656 cfg->m_SelectionFilter = selTool->GetFilter();
1657 }
1658
1660
1661 if( m_propertiesPanel )
1662 {
1663 cfg->m_AuiPanels.show_properties = m_propertiesPanel->IsShownOnScreen();
1665 cfg->m_AuiPanels.properties_splitter = m_propertiesPanel->SplitterProportion();
1666 }
1667
1669
1670 if( m_appearancePanel )
1671 {
1674 cfg->m_LayerPresets = m_appearancePanel->GetUserLayerPresets();
1675 cfg->m_ActiveLayerPreset = m_appearancePanel->GetActiveLayerPreset();
1676 }
1677
1678 cfg->m_OpenTabs.clear();
1679 cfg->m_ActiveTab.Clear();
1680
1681 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
1682
1683 for( size_t i = 0; i < m_tabContexts.size(); ++i )
1684 {
1685 const FOOTPRINT_EDITOR_TAB_CONTEXT* ctx = m_tabContexts[i].get();
1686
1687 // Instance tabs are session-only and never persisted.
1688 if( ctx->IsTransient() )
1689 continue;
1690
1691 const bool preview = i < entries.size() && entries[i].preview;
1692
1693 cfg->m_OpenTabs.push_back( { ctx->GetLib(), ctx->GetName(), preview } );
1694
1695 if( ctx == m_activeTab )
1696 cfg->m_ActiveTab = ctx->GetTabKey();
1697 }
1698 }
1699}
1700
1701
1702
1704{
1705 FOOTPRINT_EDITOR_SETTINGS* cfg = const_cast<FOOTPRINT_EDIT_FRAME*>( this )->GetSettings();
1706
1707 return cfg ? cfg->m_RotationAngle : ANGLE_90;
1708}
1709
1710
1711
1713{
1715 return ::GetColorSettings( cfg ? cfg->m_ColorTheme : DEFAULT_THEME );
1716}
1717
1718
1720{
1721 static MAGNETIC_SETTINGS fallback;
1722
1724 return &cfg->m_MagneticItems;
1725
1726 return &fallback;
1727}
1728
1729
1730const BOX2I FOOTPRINT_EDIT_FRAME::GetDocumentExtents( bool aIncludeAllVisible ) const
1731{
1732 FOOTPRINT* footprint = GetBoard()->GetFirstFootprint();
1733
1734 if( footprint )
1735 {
1736 bool hasGraphicalItem = footprint->Pads().size() || footprint->Zones().size();
1737
1738 if( !hasGraphicalItem )
1739 {
1740 for( const BOARD_ITEM* item : footprint->GraphicalItems() )
1741 {
1742 if( item->Type() == PCB_TEXT_T || item->Type() == PCB_TEXTBOX_T )
1743 continue;
1744
1745 hasGraphicalItem = true;
1746 break;
1747 }
1748 }
1749
1750 if( hasGraphicalItem )
1751 {
1752 return footprint->GetBoundingBox( false );
1753 }
1754 else
1755 {
1756 BOX2I newFootprintBB( { 0, 0 }, { 0, 0 } );
1757 newFootprintBB.Inflate( pcbIUScale.mmToIU( 12 ) );
1758 return newFootprintBB;
1759 }
1760 }
1761
1762 return GetBoardBoundingBox( false );
1763}
1764
1765
1767{
1768 if( IsContentModified() )
1769 {
1770 wxString footprintName = GetBoard()->GetFirstFootprint()->GetReference();
1771 wxString msg = _( "Save changes to '%s' before closing?" );
1772
1773 if( !HandleUnsavedChanges( this, wxString::Format( msg, footprintName ),
1774 [&]() -> bool
1775 {
1776 return SaveFootprint( GetBoard()->GetFirstFootprint() );
1777 } ) )
1778 {
1779 return false;
1780 }
1781 }
1782
1783 if( doClose )
1784 {
1785 GetInfoBar()->ShowMessageFor( wxEmptyString, 1 );
1786 Clear_Pcb( false );
1787 UpdateTitle();
1788 }
1789
1790 return true;
1791}
1792
1793
1794bool FOOTPRINT_EDIT_FRAME::canCloseWindow( wxCloseEvent& aEvent )
1795{
1796 // Shutdown blocks must be determined and vetoed as early as possible, before any modal prompt.
1797 // IsContentModified only sees the active tab, so also account for dirty inactive instance tabs.
1800 && aEvent.GetId() == wxEVT_QUERY_END_SESSION )
1801 {
1802 aEvent.Veto();
1803 return false;
1804 }
1805
1806 if( IsContentModified() )
1807 {
1808 wxString footprintName = GetBoard()->GetFirstFootprint()->GetFPID().GetLibItemName();
1809
1810 if( IsCurrentFPFromBoard() )
1811 footprintName = GetBoard()->GetFirstFootprint()->GetReference();
1812
1813 wxString msg = _( "Save changes to '%s' before closing?" );
1814
1815 if( !HandleUnsavedChanges( this, wxString::Format( msg, footprintName ),
1816 [&]() -> bool
1817 {
1818 return SaveFootprint( GetBoard()->GetFirstFootprint() );
1819 } ) )
1820 {
1821 aEvent.Veto();
1822 return false;
1823 }
1824 }
1825
1826 // Prompt for any dirty inactive instance tabs, which the active-tab check above misses.
1828 {
1829 aEvent.Veto();
1830 return false;
1831 }
1832
1833 PAD_TOOL* padTool = m_toolManager->GetTool<PAD_TOOL>();
1834
1835 if( padTool->InPadEditMode() )
1836 padTool->ExitPadEditMode();
1837
1838 // Save footprint tree column widths
1839 m_adapter->SaveSettings();
1840
1841 return PCB_BASE_EDIT_FRAME::canCloseWindow( aEvent );
1842}
1843
1844
1846{
1847 // No more vetos
1848 GetCanvas()->SetEventDispatcher( nullptr );
1850
1852
1853 if( GetLibTree() )
1855
1856 // Do not show the layer manager during closing to avoid flicker
1857 // on some platforms (Windows) that generate useless redraw of items in
1858 // the Layer Manager
1859 m_auimgr.GetPane( wxT( "LayersManager" ) ).Show( false );
1860 m_auimgr.GetPane( wxT( "SelectionFilter" ) ).Show( false );
1861
1862 Clear_Pcb( false );
1863}
1864
1865
1866void FOOTPRINT_EDIT_FRAME::OnExitKiCad( wxCommandEvent& event )
1867{
1868 Kiway().OnKiCadExit();
1869}
1870
1871
1873{
1874 Close();
1875}
1876
1877
1879{
1880 // call my base class
1882
1883 // We have 2 panes to update.
1884 // For some obscure reason, the AUI manager hides the first modified pane.
1885 // So force show panes
1886 wxAuiPaneInfo& tree_pane_info = m_auimgr.GetPane( m_treePane );
1887 bool tree_shown = tree_pane_info.IsShown();
1888 tree_pane_info.Caption( _( "Libraries" ) );
1889
1890 wxAuiPaneInfo& lm_pane_info = m_auimgr.GetPane( m_appearancePanel );
1891 bool lm_shown = lm_pane_info.IsShown();
1892 lm_pane_info.Caption( _( "Appearance" ) );
1893 wxAuiPaneInfo& sf_pane_info = m_auimgr.GetPane( m_selectionFilterPanel );
1894 sf_pane_info.Caption( _( "Selection Filter" ) );
1895
1896 // update the layer manager
1898
1899 // Now restore the visibility:
1900 lm_pane_info.Show( lm_shown );
1901 tree_pane_info.Show( tree_shown );
1902 m_auimgr.Update();
1903
1905
1906 UpdateTitle();
1907}
1908
1909
1911{
1913
1914 if( m_isClosing )
1915 return;
1916
1917 // An edit promotes the active tab from preview to permanent and flags it dirty. Reflect the
1918 // shared screen's dirty state onto the context and panel model so the tab shows bold + "*" and a
1919 // later library-open opens its own tab instead of replacing this one.
1920 if( m_tabsPanel && m_activeTab )
1921 {
1922 m_activeTab->SetPreview( false );
1923 m_activeTab->SetModified( true );
1924
1925 if( int idx = m_tabsPanel->FindTab( m_activeTab->GetTabKey() ); idx >= 0 )
1926 m_tabsPanel->MarkModified( idx, true );
1927 }
1928
1929 Update3DView( true, true );
1931
1932 if( !GetTitle().StartsWith( wxT( "*" ) ) )
1933 UpdateTitle();
1934}
1935
1936
1938{
1939 wxString title;
1940 LIB_ID fpid = GetLoadedFPID();
1941 FOOTPRINT* footprint = GetBoard() ? GetBoard()->GetFirstFootprint() : nullptr;
1942 bool writable = true;
1943
1944 if( IsCurrentFPFromBoard() )
1945 {
1946 if( IsContentModified() )
1947 title = wxT( "*" );
1948
1949 title += footprint->GetReference();
1950 title += wxS( " " ) + wxString::Format( _( "[from %s]" ), Prj().GetProjectName()
1951 + wxT( "." )
1952 + FILEEXT::PcbFileExtension );
1953 }
1954 else if( fpid.IsValid() )
1955 {
1956 try
1957 {
1959 }
1960 catch( const IO_ERROR& )
1961 {
1962 // best efforts...
1963 }
1964
1965 // Note: don't used GetLoadedFPID(); footprint name may have been edited
1966 if( IsContentModified() )
1967 title = wxT( "*" );
1968
1969 title += From_UTF8( footprint->GetFPID().Format().c_str() );
1970
1971 if( !writable )
1972 title += wxS( " " ) + _( "[Read Only]" );
1973 }
1974 else if( !fpid.GetLibItemName().empty() )
1975 {
1976 // Note: don't used GetLoadedFPID(); footprint name may have been edited
1977 if( IsContentModified() )
1978 title = wxT( "*" );
1979
1980 title += From_UTF8( footprint->GetFPID().GetLibItemName().c_str() );
1981 title += wxS( " " ) + _( "[Unsaved]" );
1982 }
1983 else
1984 {
1985 title = _( "[no footprint loaded]" );
1986 }
1987
1988 title += wxT( " \u2014 " ) + _( "Footprint Editor" );
1989
1990 SetTitle( title );
1991}
1992
1993
1995{
1996 m_appearancePanel->OnBoardChanged();
1997}
1998
1999
2001{
2005 m_propertiesPanel->UpdateData();
2006 UpdateTitle();
2007}
2008
2009
2011{
2013
2015 auto adapter = static_cast<FP_TREE_SYNCHRONIZING_ADAPTER*>( m_adapter.get() );
2016
2017 adapter->AddLibraries( this );
2018}
2019
2020
2021void FOOTPRINT_EDIT_FRAME::SyncLibraryTree( [[maybe_unused]] bool aProgress )
2022{
2023 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "FOOTPRINT_EDIT_FRAME::SyncLibraryTree enter" ) );
2024
2026 auto adapter = static_cast<FP_TREE_SYNCHRONIZING_ADAPTER*>( m_adapter.get() );
2027 LIB_ID target = GetTargetFPID();
2028 bool targetSelected = ( target == GetLibTree()->GetSelectedLibId() );
2029 std::vector<LIB_ID> expanded = GetLibTree()->GetExpandedLibraries();
2030
2031 // Unselect before syncing to avoid null reference in the adapter
2032 // if a selected item is removed during the sync
2033 GetLibTree()->Unselect();
2034
2035 // Sync the LIB_TREE to the FOOTPRINT_INFO list
2036 adapter->Sync( footprints );
2037
2038 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "FOOTPRINT_EDIT_FRAME::SyncLibraryTree Regenerate" ) );
2039 GetLibTree()->Regenerate( true );
2040
2041 // Sync() collapsed the tree, so re-expand the libraries that were open before it.
2042 for( const LIB_ID& libId : expanded )
2043 GetLibTree()->ExpandLibId( libId );
2044
2045 if( target.IsValid() )
2046 {
2047 if( adapter->FindItem( target ) )
2048 {
2049 if( targetSelected )
2050 GetLibTree()->SelectLibId( target );
2051 else
2052 GetLibTree()->CenterLibId( target );
2053 }
2054 else
2055 {
2056 // Try to focus on parent
2057 target.SetLibItemName( wxEmptyString );
2058 GetLibTree()->CenterLibId( target );
2059 }
2060 }
2061
2062 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "FOOTPRINT_EDIT_FRAME::SyncLibraryTree exit" ) );
2063}
2064
2065
2070
2071
2073{
2074 GetLibTree()->SelectLibId( aLibID );
2075}
2076
2077
2079{
2080 m_appearancePanel->UpdateDisplayOptions();
2081}
2082
2083
2085{
2086 // Create the manager and dispatcher & route draw panel events to the dispatcher
2088 m_toolManager->SetEnvironment( GetBoard(), GetCanvas()->GetView(),
2089 GetCanvas()->GetViewControls(), config(), this );
2090 m_actions = new PCB_ACTIONS();
2092
2094
2095 m_toolManager->RegisterTool( new COMMON_CONTROL );
2096 m_toolManager->RegisterTool( new COMMON_TOOLS );
2097 m_toolManager->RegisterTool( new PCB_SELECTION_TOOL );
2098 m_toolManager->RegisterTool( new ZOOM_TOOL );
2099 m_toolManager->RegisterTool( new EDIT_TOOL );
2100 m_toolManager->RegisterTool( new PCB_EDIT_TABLE_TOOL );
2101 m_toolManager->RegisterTool( new PAD_TOOL );
2102 m_toolManager->RegisterTool( new DRAWING_TOOL );
2103 m_toolManager->RegisterTool( new PCB_POINT_EDITOR );
2104 m_toolManager->RegisterTool( new PCB_CONTROL ); // copy/paste
2105 m_toolManager->RegisterTool( new LIBRARY_EDITOR_CONTROL );
2106 m_toolManager->RegisterTool( new FOOTPRINT_EDITOR_CONTROL );
2107 m_toolManager->RegisterTool( new ALIGN_DISTRIBUTE_TOOL );
2108 m_toolManager->RegisterTool( new PCB_PICKER_TOOL );
2109 m_toolManager->RegisterTool( new POSITION_RELATIVE_TOOL );
2110 m_toolManager->RegisterTool( new ARRAY_TOOL );
2111 m_toolManager->RegisterTool( new PCB_VIEWER_TOOLS );
2112 m_toolManager->RegisterTool( new PCB_GROUP_TOOL );
2113 m_toolManager->RegisterTool( new CONVERT_TOOL );
2114 m_toolManager->RegisterTool( new PROPERTIES_TOOL );
2115 m_toolManager->RegisterTool( new EMBED_TOOL );
2116
2117 for( TOOL_BASE* tool : m_toolManager->Tools() )
2118 {
2119 if( PCB_TOOL_BASE* pcbTool = dynamic_cast<PCB_TOOL_BASE*>( tool ) )
2120 pcbTool->SetIsFootprintEditor( true );
2121 }
2122
2123 m_toolManager->GetTool<PCB_VIEWER_TOOLS>()->SetFootprintFrame( true );
2124 m_toolManager->InitTools();
2125
2126 m_toolManager->InvokeTool( "common.InteractiveSelection" );
2127
2128 // Load or reload wizard plugins in case they changed since the last time the frame opened
2129 // Because the board editor has also a plugin python menu,
2130 // call the PCB_EDIT_FRAME RunAction() if the board editor is running
2131 // Otherwise run the current RunAction().
2132 PCB_EDIT_FRAME* pcbframe = static_cast<PCB_EDIT_FRAME*>( Kiway().Player( FRAME_PCB_EDITOR, false ) );
2133
2134 if( pcbframe )
2136 else
2138}
2139
2140
2142{
2144
2145 ACTION_MANAGER* mgr = m_toolManager->GetActionManager();
2146 PCB_EDITOR_CONDITIONS cond( this );
2147
2148 wxASSERT( mgr );
2149
2150#define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
2151#define CHECK( x ) ACTION_CONDITIONS().Check( x )
2152
2153 auto haveFootprintCond =
2154 [this]( const SELECTION& )
2155 {
2156 return GetBoard() && GetBoard()->GetFirstFootprint() != nullptr;
2157 };
2158
2159 auto footprintTargettedCond =
2160 [this]( const SELECTION& )
2161 {
2162 return !GetTargetFPID().GetLibItemName().empty();
2163 };
2164
2165 auto footprintSelectedInTreeCond =
2166 [this]( const SELECTION& )
2167 {
2169 return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty();
2170 };
2171
2172 const auto footprintFromBoardCond =
2173 [this]( const SELECTION& )
2174 {
2175 return IsCurrentFPFromBoard();
2176 };
2177
2178 auto pcbFrameExistsCond =
2179 [this]( const SELECTION& )
2180 {
2181 PCB_EDIT_FRAME* frame = dynamic_cast<PCB_EDIT_FRAME*>( Kiway().Player( FRAME_PCB_EDITOR, false ) );
2182
2183 return ( frame != nullptr );
2184 };
2185
2186 auto boardFootprintExistsCond =
2187 [this]( const SELECTION& )
2188 {
2189 PCB_EDIT_FRAME* frame = dynamic_cast<PCB_EDIT_FRAME*>( Kiway().Player( FRAME_PCB_EDITOR, false ) );
2190
2191 FOOTPRINT* editorFootprint = GetBoard()->GetFirstFootprint();
2192 bool canInsert = frame && editorFootprint && editorFootprint->GetLink() == niluuid;
2193
2194 // If the source was deleted, the footprint can inserted but not updated in the board.
2195 if( frame && editorFootprint && editorFootprint->GetLink() != niluuid )
2196 {
2197 BOARD* mainpcb = frame->GetBoard();
2198 canInsert = true;
2199
2200 // search if the source footprint was not deleted:
2201 for( FOOTPRINT* candidate : mainpcb->Footprints() )
2202 {
2203 if( editorFootprint->GetLink() == candidate->m_Uuid )
2204 {
2205 canInsert = false;
2206 break;
2207 }
2208 }
2209 }
2210
2211 return canInsert;
2212 };
2213
2214 // clang-format off
2215 mgr->SetConditions( ACTIONS::saveAs, ENABLE( footprintTargettedCond ) );
2218 mgr->SetConditions( PCB_ACTIONS::editLibFpInFpEditor,ENABLE( footprintFromBoardCond ) );
2219
2220 mgr->SetConditions( PCB_ACTIONS::saveFpToBoard, ENABLE( boardFootprintExistsCond ) );
2221 mgr->SetConditions( PCB_ACTIONS::loadFpFromBoard, ENABLE( pcbFrameExistsCond ) );
2222
2225
2228
2229 mgr->SetConditions( ACTIONS::cut, ENABLE( cond.HasItems() ) );
2230 mgr->SetConditions( ACTIONS::copy, ENABLE( cond.HasItems() ) );
2237
2239 ENABLE( SELECTION_CONDITIONS::NotEmpty ).HotkeyEnable( cond.HasItems() ) );
2241 ENABLE( SELECTION_CONDITIONS::NotEmpty ).HotkeyEnable( cond.HasItems() ) );
2243 ENABLE( SELECTION_CONDITIONS::NotEmpty ).HotkeyEnable( cond.HasItems() ) );
2245 ENABLE( SELECTION_CONDITIONS::NotEmpty ).HotkeyEnable( cond.HasItems() ) );
2248
2252
2257 // clang-format on
2258
2259 auto highContrastCond =
2260 [this]( const SELECTION& )
2261 {
2263 };
2264
2265 auto boardFlippedCond = [this]( const SELECTION& )
2266 {
2268 };
2269
2270 auto libraryTreeCond =
2271 [this](const SELECTION& )
2272 {
2273 return IsLibraryTreeShown();
2274 };
2275
2276 auto layerManagerCond =
2277 [this]( const SELECTION& )
2278 {
2279 return m_auimgr.GetPane( "LayersManager" ).IsShown();
2280 };
2281
2282 auto propertiesCond =
2283 [this] ( const SELECTION& )
2284 {
2285 return m_auimgr.GetPane( PropertiesPaneName() ).IsShown();
2286 };
2287
2288 mgr->SetConditions( ACTIONS::highContrastMode, CHECK( highContrastCond ) );
2289 mgr->SetConditions( PCB_ACTIONS::flipBoard, CHECK( boardFlippedCond ) );
2291
2292 mgr->SetConditions( ACTIONS::showLibraryTree, CHECK( libraryTreeCond ) );
2293 mgr->SetConditions( PCB_ACTIONS::showLayersManager, CHECK( layerManagerCond ) );
2294 mgr->SetConditions( ACTIONS::showProperties, CHECK( propertiesCond ) );
2295
2296 mgr->SetConditions( ACTIONS::print, ENABLE( haveFootprintCond ) );
2297 mgr->SetConditions( PCB_ACTIONS::exportFootprint, ENABLE( haveFootprintCond ) );
2298 mgr->SetConditions( PCB_ACTIONS::placeImportedGraphics, ENABLE( haveFootprintCond ) );
2299
2300 mgr->SetConditions( PCB_ACTIONS::footprintProperties, ENABLE( footprintSelectedInTreeCond || haveFootprintCond ) );
2301 mgr->SetConditions( PCB_ACTIONS::padTable, ENABLE( haveFootprintCond ) );
2302 mgr->SetConditions( PCB_ACTIONS::editTextAndGraphics, ENABLE( haveFootprintCond ) );
2303 mgr->SetConditions( PCB_ACTIONS::checkFootprint, ENABLE( haveFootprintCond ) );
2304 mgr->SetConditions( PCB_ACTIONS::repairFootprint, ENABLE( haveFootprintCond ) );
2305 mgr->SetConditions( PCB_ACTIONS::cleanupGraphics, ENABLE( haveFootprintCond ) );
2306 mgr->SetConditions( ACTIONS::showDatasheet, ENABLE( haveFootprintCond ) );
2307
2308 const auto isArcKeepCenterMode =
2309 [this]( const SELECTION& )
2310 {
2312 };
2313
2314 const auto isArcKeepEndpointMode =
2315 [this]( const SELECTION& )
2316 {
2318 };
2319
2320 const auto isArcKeepRadiusMode =
2321 [this]( const SELECTION& )
2322 {
2324 };
2325
2326 // clang-format off
2327 mgr->SetConditions( ACTIONS::pointEditorArcKeepCenter, CHECK( isArcKeepCenterMode ) );
2328 mgr->SetConditions( ACTIONS::pointEditorArcKeepEndpoint, CHECK( isArcKeepEndpointMode ) );
2329 mgr->SetConditions( ACTIONS::pointEditorArcKeepRadius, CHECK( isArcKeepRadiusMode ) );
2330 // clang-format on
2331
2332// Only enable a tool if the part is edtable
2333#define CURRENT_EDIT_TOOL( action ) \
2334 mgr->SetConditions( action, ACTION_CONDITIONS().Enable( haveFootprintCond ) \
2335 .Check( cond.CurrentTool( action ) ) )
2336
2363
2364#undef CURRENT_EDIT_TOOL
2365#undef ENABLE
2366#undef CHECK
2367}
2368
2369
2371{
2373
2374 // Be sure the axis are enabled
2375 GetCanvas()->GetGAL()->SetAxesEnabled( true );
2376
2377 UpdateView();
2378
2379 // Ensure the m_Layers settings are using the canvas type:
2381}
2382
2383
2385{
2387 m_appearancePanel->CommonSettingsChanged( aFlags );
2388
2390 {
2391 GetGalDisplayOptions().ReadWindowSettings( cfg->m_Window );
2392
2393 GetBoard()->GetDesignSettings() = cfg->m_DesignSettings;
2395 }
2396
2400
2402
2403 if( aFlags & ENVVARS_CHANGED )
2404 SyncLibraryTree( true );
2405
2406 Layout();
2407 SendSizeEvent();
2408}
2409
2410
2411std::unique_ptr<GRID_HELPER> FOOTPRINT_EDIT_FRAME::MakeGridHelper()
2412{
2413 return std::make_unique<PCB_GRID_HELPER>( m_toolManager, GetMagneticItemsSettings() );
2414}
2415
2416
2418{
2419 LIB_ID id = GetLoadedFPID();
2420
2421 if( id.empty() )
2422 {
2423 DisplayErrorMessage( this, _( "No footprint selected." ) );
2424 return;
2425 }
2426
2427 wxFileName fn( id.GetLibItemName() );
2428 fn.SetExt( wxT( "png" ) );
2429
2430 wxString projectPath = wxPathOnly( Prj().GetProjectFullName() );
2431
2432 wxFileDialog dlg( this, _( "Export View as PNG" ), projectPath, fn.GetFullName(),
2433 FILEEXT::PngFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
2434
2436
2437 if( dlg.ShowModal() == wxID_CANCEL || dlg.GetPath().IsEmpty() )
2438 return;
2439
2440 // calling wxYield is mandatory under Linux, after closing the file selector dialog
2441 // to refresh the screen before creating the PNG or JPEG image from screen
2442 wxYield();
2443 this->SaveCanvasImageToFile( dlg.GetPath(), BITMAP_TYPE::PNG );
2444}
const char * name
@ KEEP_ENDPOINTS_OR_START_DIRECTION
Whe editing endpoints, the other end remains in place.
@ KEEP_CENTER_ENDS_ADJUST_ANGLE
When editing endpoints, only the angle is adjusted.
@ KEEP_CENTER_ADJUST_ANGLE_RADIUS
When editing endpoints, the angle and radius are adjusted.
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
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_modedit_32
@ icon_modedit_16
@ FPHOLDER
Definition board.h:365
@ NORMAL
Inactive layers are shown normally (no high-contrast mode)
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
static TOOL_ACTION toggleGrid
Definition actions.h:194
static TOOL_ACTION paste
Definition actions.h:76
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 saveAs
Definition actions.h:55
static TOOL_ACTION copy
Definition actions.h:74
static TOOL_ACTION pluginsReload
Definition actions.h:290
static TOOL_ACTION selectSetLasso
Definition actions.h:217
static TOOL_ACTION selectSetRect
Set lasso selection mode.
Definition actions.h:216
static TOOL_ACTION group
Definition actions.h:235
static TOOL_ACTION pasteSpecial
Definition actions.h:77
static TOOL_ACTION showDatasheet
Definition actions.h:263
static TOOL_ACTION pointEditorArcKeepCenter
Definition actions.h:269
static TOOL_ACTION ungroup
Definition actions.h:236
static TOOL_ACTION toggleBoundingBoxes
Definition actions.h:153
static TOOL_ACTION pointEditorArcKeepRadius
Definition actions.h:271
static TOOL_ACTION undo
Definition actions.h:71
static TOOL_ACTION duplicate
Definition actions.h:80
static TOOL_ACTION highContrastMode
Definition actions.h:151
static TOOL_ACTION embeddedFiles
Definition actions.h:293
static TOOL_ACTION measureTool
Definition actions.h:248
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 print
Definition actions.h:60
static TOOL_ACTION showProperties
Definition actions.h:262
static TOOL_ACTION cut
Definition actions.h:73
static TOOL_ACTION gridSetOrigin
Definition actions.h:191
static TOOL_ACTION ddAddLibrary
Definition actions.h:63
static TOOL_ACTION toggleGridOverrides
Definition actions.h:195
static TOOL_ACTION selectAll
Definition actions.h:78
static TOOL_ACTION pointEditorArcKeepEndpoint
Definition actions.h:270
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...
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
wxString m_ColorTheme
Active color theme name.
The array tool.
Definition array_tool.h:44
bool IsContentModified() const
Definition base_screen.h:56
void SetContentModified(bool aModified=true)
Definition base_screen.h:55
BASE_SET & set(size_t pos)
Definition base_set.h:116
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
std::map< std::string, wxString > m_UserLayerNames
Abstract interface for BOARD_ITEMs capable of storing other items inside.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
void SetLocked(bool aLocked) override
Definition board_item.h:356
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:285
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:373
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition board.cpp:1346
void SetBoardUse(BOARD_USE aUse)
Set what the board is going to be used for.
Definition board.h:385
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition board.cpp:811
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition board.h:595
void SetVisibleAlls()
Change the bit-mask of visible element categories and layers.
Definition board.cpp:1083
const FOOTPRINTS & Footprints() const
Definition board.h:421
void DeleteAllFootprints()
Remove all footprints from the deque and free the memory associated with them.
Definition board.cpp:1873
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1149
void SetUserUnits(EDA_UNITS aUnits)
Definition board.h:910
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.
Tool responsible for drawing graphical elements like lines, arcs, circles, etc.
void CommonSettingsChanged(int aFlags) override
Notification event that some of the common (suite-wide) settings have changed.
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 UpdateToolbarControlSizes()
Update the sizes of any controls in the toolbars of the frame.
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 OnSize(wxSizeEvent &aEvent)
virtual bool canCloseWindow(wxCloseEvent &aCloseEvent)
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()
EDA_DRAW_PANEL_GAL::GAL_TYPE m_canvasType
The current canvas type.
void OnSelectGrid(wxCommandEvent &event)
Command event handler for selecting grid sizes.
void setupUnits(APP_SETTINGS_BASE *aCfg)
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
bool SaveCanvasImageToFile(const wxString &aFileName, BITMAP_TYPE aBitmapType)
Save the current view as an image file.
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.
static bool m_openGLFailureOccured
Has any failure occurred when switching to OpenGL in any EDA_DRAW_FRAME?
static const wxString PropertiesPaneName()
EDA_MSG_PANEL * m_messagePanel
void SetCanvas(EDA_DRAW_PANEL_GAL *aPanel)
virtual void SetScreen(BASE_SCREEN *aScreen)
virtual void UpdateMsgPanel()
Redraw the message panel.
EDA_DRAW_PANEL_GAL::GAL_TYPE loadCanvasTypeSetting()
Return the canvas type stored in the application settings.
PROPERTIES_PANEL * m_propertiesPanel
bool m_showBorderAndTitleBlock
static constexpr GAL_TYPE GAL_FALLBACK
void StopDrawing()
Prevent the GAL canvas from further drawing until it is recreated or StartDrawing() is called.
void ForceRefresh()
Force a redraw.
@ GAL_TYPE_OPENGL
OpenGL implementation.
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:96
const KIID m_Uuid
Definition eda_item.h:531
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:154
virtual void SetParentGroup(EDA_GROUP *aGroup)
Definition eda_item.h:113
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:89
Specialization of the wxAuiPaneInfo class for KiCad panels.
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 ContentModified()
Create a functor that tests if the content of the frame is modified.
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.
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()
The interactive edit tool.
Definition edit_tool.h:52
Module editor specific tools.
BOARD_DESIGN_SETTINGS m_DesignSettings
Only some of these settings are actually used for footprint editing.
std::vector< OPEN_TAB > m_OpenTabs
wxString m_ActiveTab
Tab key ("lib:fpName") of the tab that was active when the editor last closed.
std::vector< LAYER_PRESET > m_LayerPresets
PCB_SELECTION_FILTER_OPTIONS m_SelectionFilter
One open footprint tab owning its fp-holder board, lent to the frame by raw pointer while active.
std::map< KIID, KIID > & BoardFootprintUuids()
Editor-to-board UUID remap captured at load, used by SaveFootprintToBoard to restore the original boa...
bool IsTransient() const
True for an instance (board) tab, which is session-only and never persisted.
BOARD * GetBoard() const
The fp-holder board owned by this context.
wxString GetDisplayName() const override
Short label shown on the tab.
static wxString MakeInstanceTabKey(const KIID &aSourceUuid)
De-duplication key for a placed board footprint, in a namespace disjoint from library keys.
const wxString & GetFootprintNameWhenLoaded() const
bool IsModified() const override
True only when dirty and the board actually holds a footprint to edit.
FOOTPRINT * GetOriginalFootprintCopy() const
Baseline clone captured at load, used to detect edits and to revert.
wxString GetTabKey() const override
Stable identity for persistence and de-duplication.
void CloseFootprintEditor(wxCommandEvent &Event)
static FOOTPRINT_EDITOR_TAB_CONTEXT * placeReusedTabContext(std::vector< std::unique_ptr< FOOTPRINT_EDITOR_TAB_CONTEXT > > &aContexts, int aSlot, std::unique_ptr< FOOTPRINT_EDITOR_TAB_CONTEXT > aNew, const std::function< void()> &aInstallSuccessor)
Replace the tab context at aSlot with aNew, running aInstallSuccessor before the displaced context is...
BOARD_DESIGN_SETTINGS & GetDesignSettings() const override
Return the BOARD_DESIGN_SETTINGS for the open project.
void setupUIConditions() override
Setup the UI conditions for the various actions and their controls in this frame.
void ActivateGalCanvas() override
Use to start up the GAL drawing canvas.
void detachTabsForFullClear(BOARD *aReplacement)
Install aReplacement as the active document non-destructively, then drop every tab context and free t...
void HardRedraw() override
Refresh the library tree and redraw the window.
static const wxChar * GetFootprintEditorFrameName()
void SyncLibraryTree(bool aProgress)
Synchronize the footprint library tree to the current state of the footprint library table.
FOOTPRINT_EDITOR_TAB_CONTEXT * m_activeTab
void OnSaveFootprintAsPng(wxCommandEvent &event)
bool SaveFootprintAs(FOOTPRINT *aFootprint)
bool promptToSaveInactiveInstanceTabs()
Prompt to save each dirty instance (board) tab that is not the active one, since the active tab's uns...
void FocusLibraryTreeInput() override
BOARD_ITEM_CONTAINER * GetModel() const override
void ReCreateLayerBox(bool aForceResizeToolbar=true)
Re create the layer Box by clearing the old list, and building a new one from the new layers names an...
LIB_TREE * GetLibTree() const override
bool canCloseWindow(wxCloseEvent &Event) override
void UpdateMsgPanel() override
Redraw the message panel.
LIB_ID GetTargetFPID() const
Return the LIB_ID of the part selected in the footprint tree, or the loaded part if there is no selec...
LIB_ID GetLoadedFPID() const
Return the LIB_ID of the part being edited.
APP_SETTINGS_BASE * config() const override
Return the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
void refreshFootprintTabState()
Re-query and re-render the tab labels from the active context's modified state.
EDITOR_TABS_PANEL * m_tabsPanel
FOOTPRINT_EDITOR_TAB_CONTEXT * findOrCreateFootprintInstanceTab(FOOTPRINT *aBoardFootprint)
Find or create the instance tab for a placed board footprint and make it the active tab.
void detachActiveFootprintTab()
Snapshot the active tab's view/selection, fold the dirty state back into it, and clear m_activeTab.
void SetPlotSettings(const PCB_PLOT_PARAMS &aSettings) override
bool SaveFootprint(FOOTPRINT *aFootprint)
Save in an existing library a given footprint.
void OnTabCharHook(wxKeyEvent &aEvent)
Cycle footprint tabs from the CHAR_HOOK stream, since GTK cannot register WXK_TAB as a menu accelerat...
void CloseFootprintTab(const LIB_ID &aFPID)
Close the open tab for aFPID, if any, without prompting and leaving the other tabs open.
std::unique_ptr< API_HANDLER_FOOTPRINT > m_apiHandler
void initLibraryTree()
Make sure the footprint info list is loaded (with a progress dialog) and then initialize the footprin...
bool hasDirtyInactiveInstanceTabs() const
True if any non-active instance (board) tab has unsaved edits.
bool m_silentFootprintTabClose
While true, promptAndCloseFootprintTab() skips the unsaved-changes dialog.
std::map< KIID, KIID > m_boardFootprintUuids
void LoadSettings(APP_SETTINGS_BASE *aCfg) override
Load common frame parameters from a configuration file.
std::unique_ptr< API_HANDLER_COMMON > m_apiHandlerCommon
void ShowChangedLanguage() override
Update visible items after a language change.
void resolveCanvasType() override
Determines the Canvas type to load (with prompt if required) and initializes m_canvasType.
void CommonSettingsChanged(int aFlags) override
Called after the preferences dialog is run.
bool IsContentModified() const override
Get if any footprints or libraries have been modified but not saved.
void UpdateUserInterface()
Update the layer manager and other widgets from the board setup (layer and items visibility,...
wxObjectDataPtr< LIB_TREE_MODEL_ADAPTER > m_adapter
bool IsLibraryTreeShown() const override
FOOTPRINT_EDITOR_SETTINGS * m_editorSettings
const BOX2I GetDocumentExtents(bool aIncludeAllVisible=true) const override
Return bounding box of document with option to not include some items.
bool Clear_Pcb(bool doAskAboutUnsavedChanges)
Delete all and reinitialize the current board.
Definition initpcb.cpp:104
void RenameFootprintTab(const LIB_ID &aOldId, const LIB_ID &aNewId)
Update the open tab for aOldId, if any, to the renamed footprint aNewId so its label and key track th...
void borrowBoardNonDestructive(BOARD *aBoard)
Swap the frame's borrowed board pointer to aBoard without deleting the previous board,...
FOOTPRINT_EDIT_FRAME(KIWAY *aKiway, wxWindow *aParent)
protected so only friend PCB::IFACE::CreateWindow() can act as sole factory.
SELECTION & GetCurrentSelection() override
Get the current selection from the canvas area.
void AdvanceFootprintTab(bool aForward)
Advance the active tab forward or backward in MRU order.
bool CanCloseFPFromBoard(bool doClose)
void activateFootprintTab(FOOTPRINT_EDITOR_TAB_CONTEXT *aCtx)
Make aCtx the active tab, borrowing its board without deleting the outgoing one.
void freeFootprintTabUndoRedo(FOOTPRINT_EDITOR_TAB_CONTEXT &aCtx)
Free the transient board items a detached context's lists own before it is destroyed,...
void SetActiveLayer(PCB_LAYER_ID aLayer) override
void AddFootprintToBoard(FOOTPRINT *aFootprint) override
Override from PCB_BASE_EDIT_FRAME which adds a footprint to the editor's dummy board,...
bool activeBoardOwnedByTab() const
True when a tab context owns the frame's borrowed board, so the frame must not delete it.
void OnModify() override
Must be called after a footprint change in order to set the "modify" flag of the current screen and p...
std::vector< std::unique_ptr< FOOTPRINT_EDITOR_TAB_CONTEXT > > m_tabContexts
void CloseActiveFootprintTab()
Request closing the active tab, prompting to save if it is modified.
FOOTPRINT_TREE_PANE * m_treePane
std::unique_ptr< GRID_HELPER > MakeGridHelper() override
void OnDisplayOptionsChanged() override
void FocusOnLibID(const LIB_ID &aLibID)
const PCB_PLOT_PARAMS & GetPlotSettings() const override
Return the PCB_PLOT_PARAMS for the BOARD owned by this frame.
bool m_suppressTabActivation
Set while a full clear tears the tab strip down so the panel's close-driven re-activation does not re...
std::unique_ptr< FOOTPRINT > m_originalFootprintCopy
void ReloadFootprint(FOOTPRINT *aFootprint) override
Override from PCB_BASE_FRAME which reloads the footprint from the library without setting the footpri...
EDA_ANGLE GetRotationAngle() const override
Return the angle used for rotate operations.
void RefreshLibraryTree()
Redisplay the library tree.
void installFootprintTabBoard(FOOTPRINT_EDITOR_TAB_CONTEXT *aCtx, BOARD *aBoard)
Install aBoard as the active document non-destructively, wiring the tool environment and resetting th...
void OnExitKiCad(wxCommandEvent &aEvent)
bool promptAndCloseFootprintTab(int aIdx)
Prompt to save if needed, then drop the tab context at aIdx.
void SaveSettings(APP_SETTINGS_BASE *aCfg) override
Save common frame parameters to a configuration data file.
MAGNETIC_SETTINGS * GetMagneticItemsSettings() override
FOOTPRINT_EDITOR_SETTINGS * GetSettings()
FOOTPRINT_EDITOR_TAB_CONTEXT * findOrCreateFootprintTab(const LIB_ID &aLibId, bool aAsPreview)
Find or create the tab for aLibId over its own fp-holder board and make it the active tab.
void SwitchCanvas(EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType) override
Switch the currently used canvas (Cairo / OpenGL).
void freeUndoRedoCommandsWithItems(UNDO_REDO_CONTAINER &aUndo, UNDO_REDO_CONTAINER &aRedo)
Free both the transient board items and the command wrappers in the given lists.
COLOR_SETTINGS * GetColorSettings(bool aForceRefresh=false) const override
Helper to retrieve the current color settings.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
bool IsFootprintLibWritable(const wxString &aNickname)
Return true if the library given by aNickname is writable.
Footprint Editor pane with footprint library tree.
bool FixUuids()
Old footprints do not always have a valid UUID (some can be set to null uuid) However null UUIDs,...
void SetPosition(const VECTOR2I &aPos) override
void SetLink(const KIID &aLink)
Definition footprint.h:1176
void SetLocked(bool isLocked) override
Set the #MODULE_is_LOCKED bit in the m_ModuleStatus.
Definition footprint.h:644
ZONES & Zones()
Definition footprint.h:381
void SetOrientation(const EDA_ANGLE &aNewAngle)
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction, RECURSE_MODE aMode) const override
Invoke a function on all children.
EDA_ITEM * Clone() const override
Invoke a function on all children.
std::deque< PAD * > & Pads()
Definition footprint.h:375
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition footprint.h:417
const LIB_ID & GetFPID() const
Definition footprint.h:441
const LSET & GetStackupLayers() const
Definition footprint.h:505
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
void ClearAllNets()
Clear (i.e.
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
KIID GetLink() const
Definition footprint.h:1175
const wxString & GetReference() const
Definition footprint.h:841
FOOTPRINT_STACKUP GetStackupMode() const
Definition footprint.h:498
VECTOR2I GetPosition() const override
Definition footprint.h:403
DRAWINGS & GraphicalItems()
Definition footprint.h:378
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void AddLibraries(EDA_BASE_FRAME *aParent)
static wxObjectDataPtr< LIB_TREE_MODEL_ADAPTER > Create(FOOTPRINT_EDIT_FRAME *aFrame, FOOTPRINT_LIBRARY_ADAPTER *aLibs)
void ReadWindowSettings(WINDOW_SETTINGS &aCfg)
Read GAL config options from application-level config.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
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
Crosshair drawing mode.
void SetAxesEnabled(bool aAxesEnabled)
Enable drawing the axes.
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition pcb_view.cpp:87
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
double GetScale() const
Definition view.h:281
const VECTOR2D & GetCenter() const
Return the center point of this VIEW (in world space coordinates).
Definition view.h:351
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition view.cpp:637
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition view.cpp:844
void SetLayerVisible(int aLayer, bool aVisible=true)
Control the visibility of a particular layer.
Definition view.h:405
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition view.cpp:663
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition view.h:657
Definition kiid.h:44
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:311
void OnKiCadExit()
Definition kiway.cpp:796
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:398
Module editor specific tools.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
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
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:113
UTF8 Format() const
Definition lib_id.cpp:132
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition lib_id.h:108
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
void RefreshLibTree()
Refresh the tree (mainly to update highlighting and asterisking)
Definition lib_tree.cpp:493
void CenterLibId(const LIB_ID &aLibId)
Ensure that an item is visible (preferably centered).
Definition lib_tree.cpp:383
void ShutdownPreviews()
Definition lib_tree.cpp:283
void ShowChangedLanguage()
Definition lib_tree.cpp:300
std::vector< LIB_ID > GetExpandedLibraries() const
Definition lib_tree.cpp:403
void SelectLibId(const LIB_ID &aLibId)
Select an item in the tree widget.
Definition lib_tree.cpp:371
LIB_TREE_MODEL_ADAPTER::SORT_MODE GetSortMode() const
Definition lib_tree.h:154
void Unselect()
Unselect currently selected item in wxDataViewCtrl.
Definition lib_tree.cpp:389
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:310
void ExpandLibId(const LIB_ID &aLibId)
Expand and item i the tree widget.
Definition lib_tree.cpp:397
void Regenerate(bool aKeepState)
Regenerate the tree.
Definition lib_tree.cpp:475
void SetSortMode(LIB_TREE_MODEL_ADAPTER::SORT_MODE aMode)
Save/restore the sorting mode.
Definition lib_tree.h:153
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
static const LSET & UserMask()
Definition lset.cpp:686
static int NameToLayer(wxString &aName)
Return the layer number from a layer name.
Definition lset.cpp:113
static const LSET & AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
Definition lset.cpp:672
static LSET UserDefinedLayersMask(int aUserDefinedLayerCount=MAX_USER_DEFINED_LAYERS)
Return a mask with the requested number of user defined layers.
Definition lset.cpp:700
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:184
void SetClearance(int aClearance)
Definition netclass.h:125
std::shared_ptr< NETCLASS > GetDefaultNetclass() const
Gets the default netclass for the project.
void ExitPadEditMode()
Definition pad_tool.cpp:800
bool InPadEditMode()
Definition pad_tool.h:59
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:75
Gather all the actions that are shared by tools.
Definition pcb_actions.h:47
static TOOL_ACTION drawRuleArea
static TOOL_ACTION drawBezier
static TOOL_ACTION placeText
static TOOL_ACTION drawOrthogonalDimension
static TOOL_ACTION drawRectangle
static TOOL_ACTION setAnchor
static TOOL_ACTION padDisplayMode
static TOOL_ACTION placeReferenceImage
static TOOL_ACTION showLayersManager
static TOOL_ACTION drawCircle
static TOOL_ACTION mirrorH
Mirroring of selected items.
static TOOL_ACTION exportFootprint
static TOOL_ACTION drawEllipseArc
static TOOL_ACTION drawTable
static TOOL_ACTION drawTextBox
static TOOL_ACTION drawPolygon
static TOOL_ACTION placePad
Activation of the drawing tool (placing a PAD)
static TOOL_ACTION drawRadialDimension
static TOOL_ACTION padTable
static TOOL_ACTION editTextAndGraphics
static TOOL_ACTION drawLeader
static TOOL_ACTION angleSnapModeChanged
Notification event when angle mode changes.
static TOOL_ACTION drawEllipse
static TOOL_ACTION ddImportFootprint
static TOOL_ACTION placeImportedGraphics
static TOOL_ACTION drawArc
static TOOL_ACTION graphicsOutlines
Display footprint graphics as outlines.
static TOOL_ACTION loadFpFromBoard
static TOOL_ACTION drawCenterDimension
static TOOL_ACTION footprintProperties
static TOOL_ACTION flipBoard
static TOOL_ACTION textOutlines
Display texts as lines.
static TOOL_ACTION checkFootprint
static TOOL_ACTION placeBarcode
static TOOL_ACTION placePoint
static TOOL_ACTION editLibFpInFpEditor
static TOOL_ACTION mirrorV
static TOOL_ACTION repairFootprint
static TOOL_ACTION saveFpToBoard
static TOOL_ACTION drawLine
static TOOL_ACTION cleanupGraphics
static TOOL_ACTION rotateCw
Rotation of selected objects.
static TOOL_ACTION rotateCcw
static TOOL_ACTION drawAlignedDimension
void ClearListAndDeleteItems(PICKED_ITEMS_LIST *aList)
virtual void SetBoard(BOARD *aBoard, PROGRESS_REPORTER *aReporter=nullptr) override
Set the #m_Pcb member in such as way as to ensure deleting any previous BOARD.
void configureToolbars() override
PCB_BASE_EDIT_FRAME(KIWAY *aKiway, wxWindow *aParent, FRAME_T aFrameType, const wxString &aTitle, const wxPoint &aPos, const wxSize &aSize, long aStyle, const wxString &aFrameName)
APPEARANCE_CONTROLS * m_appearancePanel
PANEL_SELECTION_FILTER * m_selectionFilterPanel
void ActivateGalCanvas() override
Set the #m_Pcb member in such as way as to ensure deleting any previous BOARD.
Base PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer.
virtual const PCB_PLOT_PARAMS & GetPlotSettings() const
Return the PCB_PLOT_PARAMS for the BOARD owned by this frame.
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
void LoadSettings(APP_SETTINGS_BASE *aCfg) override
Load common frame parameters from a configuration file.
void setFPWatcher(FOOTPRINT *aFootprint)
Create or removes a watcher on the specified footprint.
PCBNEW_SETTINGS * GetPcbNewSettings() const
void OnModify() override
Must be called after a change in order to set the "modify" flag and update other data structures and ...
const PAGE_INFO & GetPageSettings() const override
BOX2I GetBoardBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
EDA_ITEM * ResolveItem(const KIID &aId, bool aAllowNullptrReturn=false) const override
Fetch an item by KIID.
FOOTPRINT * LoadFootprint(const LIB_ID &aFootprintId)
Attempt to load aFootprintId from the footprint library table.
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
virtual void SetPageSettings(const PAGE_INFO &aPageSettings) override
void SaveSettings(APP_SETTINGS_BASE *aCfg) override
Save common frame parameters to a configuration data file.
PCB_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
BOARD * GetBoard() const
virtual void AddFootprintToBoard(FOOTPRINT *aFootprint)
Add the given footprint to the board.
PCB_DISPLAY_OPTIONS m_displayOptions
FOOTPRINT_EDITOR_SETTINGS * GetFootprintEditorSettings() const
virtual void Update3DView(bool aMarkDirty, bool aRefresh, const wxString *aTitle=nullptr)
Update the 3D view, if the viewer is opened by this frame.
Handle actions that are shared between different frames in PcbNew.
Definition pcb_control.h:43
bool m_FlipBoardView
true if the board is flipped to show the mirrored view
HIGH_CONTRAST_MODE m_ContrastModeDisplay
How inactive layers are displayed.
void UpdateColors()
Update the color settings in the painter and GAL.
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
void DisplayBoard(BOARD *aBoard, PROGRESS_REPORTER *aReporter=nullptr)
Add all items from the current board to the VIEW, so they can be displayed by GAL.
Group generic conditions for PCB editor states.
SELECTION_CONDITION PadFillDisplay()
Create a functor that tests if the frame fills the pads.
SELECTION_CONDITION HasItems()
Create a functor that tests if there are items in the board.
SELECTION_CONDITION GraphicsFillDisplay()
Create a functor that tests if the frame fills graphics items.
SELECTION_CONDITION TextFillDisplay()
Create a functor that tests if the frame fills text items.
The main frame for Pcbnew.
Generic tool for picking an item.
Parameters and options when plotting/printing a board.
Tool that displays edit points allowing to modify items by dragging the points.
The selection tool: currently supports:
void select(EDA_ITEM *aItem) override
Take necessary action mark an item as selected.
Tool useful for viewing footprints.
KICAD_API_SERVER & GetApiServer()
Definition pgm_base.h:142
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:124
A holder to handle information on schematic or board items.
The interactive edit tool.
static FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(PROJECT *aProject)
@ PCB_FOOTPRINT_EDITOR_FP_NAME
Definition project.h:227
@ PCB_FOOTPRINT_EDITOR_LIB_NICKNAME
Definition project.h:228
virtual void SetRString(RSTRING_T aStringId, const wxString &aString)
Store a "retained string", which is any session and project specific string identified in enum RSTRIN...
Definition project.cpp:355
virtual const wxString & GetRString(RSTRING_T aStringId)
Return a "retained string", which is any session and project specific string identified in enum RSTRI...
Definition project.cpp:366
Action handler for the Properties panel.
static SELECTION_CONDITION HasType(KICAD_T aType)
Create a functor that tests if among the selected items there is at least one of a given type.
static bool NotEmpty(const SELECTION &aSelection)
Test if there are any items selected.
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
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).
T * GetAppSettings(const char *aFilename)
Return a handle to the a given settings by type.
TOOL_MANAGER * m_toolManager
TOOL_DISPATCHER * m_toolDispatcher
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
ACTIONS * m_actions
Base abstract interface for all kinds of tools.
Definition tool_base.h:62
@ 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.
std::vector< PICKED_ITEMS_LIST * > m_CommandsList
EDA_UNITS GetUserUnits() const
bool empty() const
Definition utf8.h:105
const char * c_str() const
Definition utf8.h:104
A modified version of the wxInfoBar class that allows us to:
Definition wx_infobar.h:77
void ShowMessageFor(const wxString &aMessage, int aTime, int aFlags=wxICON_INFORMATION, MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the infobar with the provided message and icon for a specific period of time.
bool HasCloseButton() const
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
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
This file is part of the common library.
#define CHECK(x)
#define ENABLE(x)
static bool empty(const wxTextEntryBase *aCtrl)
@ DRCE_MISSING_COURTYARD
Definition drc_item.h:63
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
#define KICAD_DEFAULT_DRAWFRAME_STYLE
#define FOOTPRINT_EDIT_FRAME_NAME
@ RECURSE
Definition eda_item.h:49
FOOTPRINT_STACKUP
Definition footprint.h:143
@ EXPAND_INNER_LAYERS
The 'normal' stackup handling, where there is a single inner layer (In1) and rule areas using it expa...
Definition footprint.h:148
@ CUSTOM_LAYERS
Stackup handling where the footprint can have any number of copper layers, and objects on those layer...
Definition footprint.h:153
#define CURRENT_EDIT_TOOL(action)
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ FRAME_FOOTPRINT_EDITOR
Definition frame_type.h:39
a few functions useful in geometry calculations.
static const std::string KiCadFootprintLibPathExtension
static const std::string KiCadFootprintFileExtension
static wxString PngFileWildcard()
@ ID_ON_GRID_SELECT
Definition id.h:112
@ ID_ON_ZOOM_SELECT
Definition id.h:111
PROJECT & Prj()
Definition kicad.cpp:728
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)
bool IsUserLayer(PCB_LAYER_ID aLayerId)
Test whether a layer is a non copper and a non tech layer.
Definition layer_ids.h:757
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Cu
Definition layer_ids.h:61
@ F_SilkS
Definition layer_ids.h:96
@ In1_Cu
Definition layer_ids.h:62
@ F_Cu
Definition layer_ids.h:60
This file contains miscellaneous commonly used macros and functions.
@ TARGET_NONCACHED
Auxiliary rendering target (noncached)
Definition definitions.h:34
void SetShutdownBlockReason(wxWindow *aWindow, const wxString &aReason)
Sets the block reason why the window/application is preventing OS shutdown.
Definition unix/app.cpp:102
bool SupportsShutdownBlockReason()
Whether or not the window supports setting a shutdown block reason.
Definition unix/app.cpp:91
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:448
#define _HKI(x)
Definition page_info.cpp:40
@ ID_FPEDIT_SAVE_PNG
Definition pcbnew_id.h:81
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
@ RPT_SEVERITY_WARNING
#define DEFAULT_THEME
T * GetToolbarSettings(const wxString &aFilename)
T * GetAppSettings(const char *aFilename)
KIWAY Kiway(KFCTL_STANDALONE)
wxString UnescapeString(const wxString &aSource)
wxString From_UTF8(const char *cstring)
View snapshot captured on detach, restored on activate.
One open tab persisted across sessions.
Visual decorations derived from document state: preview is italic, modified is bold with a leading as...
#define ENVVARS_CHANGED
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:104
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:86
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:85
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:80
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
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.