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"
26#include "tools/drawing_tool.h"
27#include "tools/edit_tool.h"
30#include "tools/pad_tool.h"
31#include "tools/pcb_actions.h"
32#include "tools/pcb_control.h"
40#include <bitmaps.h>
44#include <api/api_server.h>
45#include <board.h>
47#include <widgets/wx_infobar.h>
48#include <footprint.h>
49#include <confirm.h>
50#include <drc/drc_item.h>
51#include <kidialog.h>
57#include <pcb_painter.h>
58#include <render_settings.h>
59#include <scoped_set_reset.h>
60#include <view/view.h>
61#include <kiface_base.h>
62#include <kiplatform/app.h>
63#include <kiplatform/ui.h>
64#include <kiway.h>
65#include <macros.h>
66#include <pcbnew_id.h>
67#include <pgm_base.h>
68#include <project.h>
69#include <project_pcb.h>
70#include <string_utils.h>
72#include <tool/action_toolbar.h>
73#include <tool/common_control.h>
74#include <tool/common_tools.h>
76#include <tool/selection.h>
79#include <tool/tool_manager.h>
80#include <tool/zoom_tool.h>
81#include <tools/array_tool.h>
89#include <widgets/lib_tree.h>
95
96#include <algorithm>
97
98#include <wx/filedlg.h>
99#include <wx/hyperlink.h>
100
101BEGIN_EVENT_TABLE( FOOTPRINT_EDIT_FRAME, PCB_BASE_FRAME )
104
106
109
111
112 // Drop files event
113 EVT_DROP_FILES( FOOTPRINT_EDIT_FRAME::OnDropFiles )
114
115END_EVENT_TABLE()
116
117
118FOOTPRINT_EDIT_FRAME::FOOTPRINT_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
119 PCB_BASE_EDIT_FRAME( aKiway, aParent, FRAME_FOOTPRINT_EDITOR, _( "Footprint Editor" ), wxDefaultPosition,
122 m_tabsPanel( nullptr ),
123 m_activeTab( nullptr ),
125 m_protectedBorrowedBoard( nullptr ),
127{
128 m_showBorderAndTitleBlock = false; // true to show the frame references
129 m_aboutTitle = _HKI( "KiCad Footprint Editor" );
130 m_editorSettings = nullptr;
131
132 // Give an icon
133 wxIcon icon;
134 wxIconBundle icon_bundle;
135
136 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit, 48 ) );
137 icon_bundle.AddIcon( icon );
138 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit, 128 ) );
139 icon_bundle.AddIcon( icon );
140 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit, 256 ) );
141 icon_bundle.AddIcon( icon );
142 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit_32 ) );
143 icon_bundle.AddIcon( icon );
144 icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit_16 ) );
145 icon_bundle.AddIcon( icon );
146
147 SetIcons( icon_bundle );
148
149 // Create GAL canvas
151
152 PCB_DRAW_PANEL_GAL* drawPanel = new PCB_DRAW_PANEL_GAL( this, -1, wxPoint( 0, 0 ), m_frameSize,
154 SetCanvas( drawPanel );
155
156 SetBoard( new BOARD() );
157
158 // This board will only be used to hold a footprint for editing
159 GetBoard()->SetBoardUse( BOARD_USE::FPHOLDER );
160
161 // In Footprint Editor, the default net clearance is not known (it depends on the actual
162 // board). So we do not show the default clearance, by setting it to 0. The footprint or
163 // pad specific clearance will be shown.
164 GetBoard()->GetDesignSettings().m_NetSettings->GetDefaultNetclass()->SetClearance( 0 );
165
166 // Don't show the default board solder mask expansion in the footprint editor. Only the
167 // footprint or pad mask expansions settings should be shown.
168 GetBoard()->GetDesignSettings().m_SolderMaskExpansion = 0;
169
170 // Ensure all layers and items are visible:
171 // In footprint editor, some layers have no meaning or cannot be used, but we show all of
172 // them, at least to be able to edit a bad layer
173 GetBoard()->SetVisibleAlls();
174
175 GetGalDisplayOptions().m_axesEnabled = true;
176
177 // In Footprint Editor, set the default paper size to A4 for plot/print
179 SetScreen( new PCB_SCREEN( GetPageSettings().GetSizeIU( pcbIUScale.IU_PER_MILS ) ) );
180
181 // Create the manager and dispatcher & route draw panel events to the dispatcher
182 setupTools();
184
186 m_treePane = new FOOTPRINT_TREE_PANE( this );
187
191 ReCreateLayerBox( false );
192
194
196 m_appearancePanel = new APPEARANCE_CONTROLS( this, GetCanvas(), true );
197 m_propertiesPanel = new PCB_PROPERTIES_PANEL( this, this );
198
199 // LoadSettings() *after* creating m_LayersManager, because LoadSettings() initialize
200 // parameters in m_LayersManager
201 // NOTE: KifaceSettings() will return PCBNEW_SETTINGS if we started from pcbnew
203
205
206 float proportion = GetFootprintEditorSettings()->m_AuiPanels.properties_splitter;
207 m_propertiesPanel->SetSplitterProportion( proportion );
208
210
211 // Fetch a COPY of the config as a lot of these initializations are going to overwrite our data.
213 int libWidth = 0;
214
216 {
217 libWidth = cfg->m_LibWidth;
218 aui_cfg = cfg->m_AuiPanels;
219 }
220 else
221 {
222 // keep gcc quiet about uninitalized vars:
223 aui_cfg.appearance_panel_tab = 0;
224 aui_cfg.right_panel_width = -1;
225 }
226
227 m_auimgr.SetManagedWindow( this );
228
229 // Create the infobar pane only after the AUI manager owns this frame. Registering it before
230 // SetManagedWindow() leaves the Top/Layer-1 pane mispositioned once the tabbed center pane
231 // mounts and the perspective restores, so ShowMessage() never reveals it.
233
234 unsigned int auiFlags = wxAUI_MGR_DEFAULT;
235#if !defined( _WIN32 )
236 // Windows cannot redraw the UI fast enough during a live resize and may lead to all kinds
237 // of graphical glitches
238 auiFlags |= wxAUI_MGR_LIVE_RESIZE;
239#endif
240 m_auimgr.SetFlags( auiFlags );
241
242 // Rows; layers 4 - 6
243 m_auimgr.AddPane( m_tbTopMain, EDA_PANE().HToolbar().Name( "TopMainToolbar" )
244 .Top().Layer( 6 ) );
245
246 m_auimgr.AddPane( m_messagePanel, EDA_PANE().Messages().Name( "MsgPanel" )
247 .Bottom().Layer( 6 ) );
248
249 // Columns; layers 1 - 3
250 m_auimgr.AddPane( m_treePane, EDA_PANE().Palette().Name( "Footprints" )
251 .Left().Layer( 4 )
252 .Caption( _( "Libraries" ) )
253 // Don't use -1 for don't-change-height on a growable panel; it has side-effects.
254 .MinSize( FromDIP( 250 ), FromDIP( 80 ) )
255 .BestSize( FromDIP( 250 ), -1 ) );
257 .Left().Layer( 3 )
258 .Caption( _( "Properties" ) ).PaneBorder( false )
259 .MinSize( FromDIP( wxSize( 240, 60 ) ) ).BestSize( FromDIP( wxSize( 300, 200 ) ) ) );
260 m_auimgr.AddPane( m_tbLeft, EDA_PANE().VToolbar().Name( "LeftToolbar" )
261 .Left().Layer( 2 ) );
262
263 m_auimgr.AddPane( m_tbRight, EDA_PANE().VToolbar().Name( "RightToolbar" )
264 .Right().Layer(2) );
265 m_auimgr.AddPane( m_appearancePanel, EDA_PANE().Name( "LayersManager" )
266 .Right().Layer( 3 )
267 .Caption( _( "Appearance" ) ).PaneBorder( false )
268 // Don't use -1 for don't-change-height on a growable panel; it has side-effects.
269 .MinSize( FromDIP( 180 ), FromDIP( 80 ) )
270 .BestSize( FromDIP( 180 ), -1 ) );
271 m_auimgr.AddPane( m_selectionFilterPanel, EDA_PANE().Palette().Name( "SelectionFilter" )
272 .Right().Layer( 3 ).Position( 2 )
273 .Caption( _( "Selection Filter" ) ).PaneBorder( false )
274 // Fixed-size pane; -1 for MinSize height is required
275 .MinSize( FromDIP( 180 ), -1 )
276 .BestSize( FromDIP( 180 ), -1 ) );
277
278 // Center: the tabbed-document strip owns the tab bar above a single, never-reparented canvas.
279 // The panel borrows the canvas; the frame keeps ownership through GetCanvas().
280 m_tabsPanel = new EDITOR_TABS_PANEL( this, GetCanvas() );
281
282 m_tabsPanel->onActivateTab =
283 [this]( int aIdx )
284 {
285 // Ignore activation during a full clear, when each tab close re-selects a fallback
286 // that would re-borrow a tab-owned board into m_pcb just before it is freed.
288 return;
289
290 if( aIdx >= 0 && aIdx < static_cast<int>( m_tabContexts.size() ) )
291 activateFootprintTab( m_tabContexts[aIdx].get() );
292 };
293
294 m_tabsPanel->onCloseTabRequested =
295 [this]( int aIdx ) -> bool
296 {
297 return promptAndCloseFootprintTab( aIdx );
298 };
299
300 // onCloseTabRequested installs the successor board atomically, so the panel must not re-activate
301 // the fallback after a close and re-borrow a just-installed or just-freed index.
302 m_tabsPanel->SetSuppressActivateOnClose( true );
303
304 m_tabsPanel->onQueryVisualState =
305 [this]( int aIdx ) -> TAB_VISUAL_STATE
306 {
307 // The panel model owns preview, but the live dirty flag lives on the shared frame
308 // screen folded into the context, so read modified from the context.
309 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
310
311 if( aIdx < 0 || aIdx >= static_cast<int>( entries.size() ) )
312 return TAB_VISUAL_STATE{};
313
314 bool modified = entries[aIdx].modified;
315
316 if( aIdx < (int) m_tabContexts.size() && m_tabContexts[aIdx].get() )
317 modified = m_tabContexts[aIdx]->IsModified();
318
319 return ResolveTabVisualState( entries[aIdx].preview, modified );
320 };
321
322 m_auimgr.AddPane( m_tabsPanel, EDA_PANE().Canvas().Name( "DrawFrame" )
323 .Center() );
324
326
327 m_auimgr.GetPane( "LayersManager" ).Show( m_show_layer_manager_tools );
328 m_auimgr.GetPane( "SelectionFilter" ).Show( m_show_layer_manager_tools );
329 m_auimgr.GetPane( PropertiesPaneName() ).Show( GetSettings()->m_AuiPanels.show_properties );
330
331 // The selection filter doesn't need to grow in the vertical direction when docked
332 m_auimgr.GetPane( "SelectionFilter" ).dock_proportion = 0;
333
336 DragAcceptFiles( true );
337
339
340 // Apply saved visibility stuff at the end
341 wxAuiPaneInfo& treePane = m_auimgr.GetPane( "Footprints" );
342 wxAuiPaneInfo& layersManager = m_auimgr.GetPane( "LayersManager" );
343
344 if( libWidth > 0 )
345 SetAuiPaneSize( m_auimgr, treePane, libWidth, -1 );
346
347 if( aui_cfg.right_panel_width > 0 )
348 SetAuiPaneSize( m_auimgr, layersManager, aui_cfg.right_panel_width, -1 );
349
350 m_appearancePanel->SetTabIndex( aui_cfg.appearance_panel_tab );
351
353 {
354 m_appearancePanel->SetUserLayerPresets( cfg->m_LayerPresets );
355 m_appearancePanel->ApplyLayerPreset( cfg->m_ActiveLayerPreset );
356 }
357
358 // restore the last footprint from the project, if any, after the library has been init'ed
359 // N.B. This needs to happen after the AUI manager has been initialized so that we can
360 // properly call the WX_INFOBAR without crashing on some systems.
362
363 m_apiHandler = std::make_unique<API_HANDLER_FOOTPRINT>( this );
365
366 if( Kiface().IsSingle() )
367 {
368 m_apiHandlerCommon = std::make_unique<API_HANDLER_COMMON>();
370 m_apiHandlerFpLibs = std::make_unique<API_HANDLER_LIBRARIES>(
373 }
374
375 GetToolManager()->PostAction( ACTIONS::zoomFitScreen );
377
379
380 // This displays the last footprint loaded, if any, so it must be done after restoreLastFootprint()
382
383 // Default shutdown reason until a file is loaded
384 KIPLATFORM::APP::SetShutdownBlockReason( this, _( "Footprint changes are unsaved" ) );
385
386 // Catch unhandled accelerator command characters that were no handled by the library tree
387 // panel.
389 Bind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
390
391 // GTK rejects WXK_TAB as a menu accelerator, so handle Ctrl+Tab cycling from the CHAR_HOOK
392 // stream. Binding after the dispatcher runs this handler first so it can consume the event.
393 Bind( wxEVT_CHAR_HOOK, &FOOTPRINT_EDIT_FRAME::OnTabCharHook, this );
394
395 // Ensure the window is on top
396 Raise();
397 Show( true );
398
399 // Register a call to update the toolbar sizes. It can't be done immediately because
400 // it seems to require some sizes calculated that aren't yet (at least on GTK).
401 CallAfter(
402 [this]()
403 {
404 // Ensure the controls on the toolbars all are correctly sized
406 m_treePane->FocusSearchFieldIfExists();
407
408 // Update the angle snap mode toolbar button to reflect the current preference
410 } );
411}
412
413
415{
416 // Hand the borrowed canvas back before the base destructor deletes it, or the later-destroyed
417 // panel would reparent already-freed memory. The canvas then frees exactly once.
418 m_tabsPanel->ReleaseSharedCanvas();
419
420 // Shutdown all running tools
421 if( m_toolManager )
422 m_toolManager->ShutdownAllTools();
423
424 // save the footprint in the PROJECT
426
427 // Clear the watched file
428 setFPWatcher( nullptr );
429
430 // When a tab context owns the active board, null the frame pointer so the base destructor does
431 // not double-free it. A frame-owned bootstrap board is left for the base class to delete.
433 m_pcb = nullptr;
434
435 // We passed ownership of these to wxAuiManager.
436 // delete m_selectionFilterPanel;
437 // delete m_appearancePanel;
438 // delete m_treePane;
439}
440
441
443{
445
446 FOOTPRINT* fp = static_cast<FOOTPRINT*>( GetModel() );
447
448 if( fp )
449 {
450 std::vector<MSG_PANEL_ITEM> msgItems;
451 fp->GetMsgPanelInfo( this, msgItems );
452 SetMsgPanel( msgItems );
453 }
454}
455
456
463
464
466{
467 return m_toolManager->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
468}
469
470
472{
473 // switches currently used canvas (Cairo / OpenGL).
474 PCB_BASE_FRAME::SwitchCanvas( aCanvasType );
475
476 GetCanvas()->GetGAL()->SetAxesEnabled( true );
477
478 // The base class method *does not reinit* the layers manager. We must update the layer
479 // widget to match board visibility states, both layers and render columns, and and some
480 // settings dependent on the canvas.
482}
483
484
490
491
493{
494 wxAuiPaneInfo& treePane = m_auimgr.GetPane( m_treePane );
495 treePane.Show( !IsLibraryTreeShown() );
496
497 if( IsLibraryTreeShown() )
498 {
499 // SetAuiPaneSize also updates m_auimgr
500 SetAuiPaneSize( m_auimgr, treePane, m_editorSettings->m_LibWidth, -1 );
501 }
502 else
503 {
504 m_editorSettings->m_LibWidth = m_treePane->GetSize().x;
505 m_auimgr.Update();
506 }
507}
508
509
511{
512 m_treePane->FocusSearchFieldIfExists();
513}
514
515
517{
519 wxAuiPaneInfo& layersManager = m_auimgr.GetPane( "LayersManager" );
520 wxAuiPaneInfo& selectionFilter = m_auimgr.GetPane( "SelectionFilter" );
521
522 // show auxiliary Vertical layers and visibility manager toolbar
524 layersManager.Show( m_show_layer_manager_tools );
525 selectionFilter.Show( m_show_layer_manager_tools );
526
528 {
529 SetAuiPaneSize( m_auimgr, layersManager, settings->m_AuiPanels.right_panel_width, -1 );
530 }
531 else
532 {
533 settings->m_AuiPanels.right_panel_width = m_appearancePanel->GetSize().x;
534 m_auimgr.Update();
535 }
536}
537
538
540{
541 return const_cast<wxAuiManager&>( m_auimgr ).GetPane( m_treePane ).IsShown();
542}
543
544
546{
547 // A tab close transiently leaves the frame with no board while UI repaints can still run.
548 if( !GetBoard() )
549 return nullptr;
550
551 return GetBoard()->GetFirstFootprint();
552}
553
554
556{
557 LIB_ID id;
558
559 if( IsLibraryTreeShown() )
561
562 if( id.GetLibNickname().empty() )
563 id = GetLoadedFPID();
564
565 return id;
566}
567
568
570{
571 // The board pointer is transiently null during a tab close while the library tree adapter can
572 // still repaint, so tolerate having no board.
573 if( !GetBoard() )
574 return LIB_ID();
575
576 FOOTPRINT* footprint = GetBoard()->GetFirstFootprint();
577
578 if( footprint )
579 return LIB_ID( footprint->GetFPID().GetLibNickname(), m_footprintNameWhenLoaded );
580 else
581 return LIB_ID();
582}
583
584
586{
587 if( GetBoard() && GetBoard()->GetFirstFootprint() )
588 {
591 }
592
593 GetScreen()->SetContentModified( false );
594
595 // OnModify() mirrors the dirty flag onto the active tab context and the panel model, so clear both
596 // here too. Tab rendering and close prompting read the context's flag, so a save that only cleared
597 // the shared screen would leave the tab starred and re-prompting to save.
598 if( m_activeTab )
599 {
600 m_activeTab->SetModified( false );
601
602 if( int idx = m_tabsPanel->FindTab( m_activeTab->GetTabKey() ); idx >= 0 )
603 m_tabsPanel->MarkModified( idx, false );
604 }
605}
606
607
609{
610 // If we've already vetted closing this window, then we have no FP anymore
611 if( m_isClosing || !GetBoard() )
612 return false;
613
614 FOOTPRINT* footprint = GetBoard()->GetFirstFootprint();
615
616 return ( footprint && footprint->GetLink() != niluuid );
617}
618
619
621{
622 LIB_ID id = GetLoadedFPID();
623
624 if( id.IsValid() )
625 {
627 Prj().SetRString( PROJECT::PCB_FOOTPRINT_EDITOR_FP_NAME, id.GetLibItemName() );
628 }
629}
630
631
633{
634 // Restore the persisted tab set first. The active tab is loaded last so it ends up focused, and
635 // tabs that no longer resolve are silently dropped.
636 if( FOOTPRINT_EDITOR_SETTINGS* cfg = GetSettings(); cfg && !cfg->m_OpenTabs.empty() )
637 {
638 const wxString activeKey = cfg->m_ActiveTab;
639
640 const auto loadTab =
641 [this]( const FOOTPRINT_EDITOR_SETTINGS::OPEN_TAB& aTab ) -> bool
642 {
643 LIB_ID id;
644 id.SetLibNickname( aTab.m_lib );
645 id.SetLibItemName( aTab.m_fpName );
646
647 if( FOOTPRINT* footprint = LoadFootprint( id ) )
648 {
649 AddFootprintToBoard( footprint );
650 findOrCreateFootprintTab( id, aTab.m_preview );
651
652 return true;
653 }
654
655 // LoadFootprint swallows the IO_ERROR when the library no longer resolves, so
656 // log the dropped tab to keep a failed restore diagnosable.
657 wxLogTrace( wxT( "KICAD_FP_TABS" ),
658 wxT( "Dropping persisted footprint tab '%s:%s' (failed to load)" ),
659 aTab.m_lib, aTab.m_fpName );
660
661 return false;
662 };
663
664 const FOOTPRINT_EDITOR_SETTINGS::OPEN_TAB* activeTab = nullptr;
665
666 for( const FOOTPRINT_EDITOR_SETTINGS::OPEN_TAB& tab : cfg->m_OpenTabs )
667 {
668 const wxString key = tab.m_lib + wxT( ":" ) + tab.m_fpName;
669
670 if( key == activeKey )
671 activeTab = &tab;
672 else
673 loadTab( tab );
674 }
675
676 if( activeTab )
677 loadTab( *activeTab );
678
679 if( !m_tabContexts.empty() )
680 return;
681 }
682
683 const wxString& footprintName = Prj().GetRString( PROJECT::PCB_FOOTPRINT_EDITOR_FP_NAME );
684 const wxString& libNickname = Prj().GetRString( PROJECT::PCB_FOOTPRINT_EDITOR_LIB_NICKNAME );
685
686 if( libNickname.Length() && footprintName.Length() )
687 {
688 LIB_ID id;
689 id.SetLibNickname( libNickname );
690 id.SetLibItemName( footprintName );
691
692 FOOTPRINT* footprint = LoadFootprint( id );
693
694 if( footprint )
695 {
696 AddFootprintToBoard( footprint );
697
698 // The last-session footprint is a real document, so promote its tab to permanent.
699 findOrCreateFootprintTab( id, false );
700 }
701 }
702}
703
704
706{
707 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( GetModel() );
708 BOARD& board = *GetBoard();
709
710 // All FPs have these layers enabled
711 LSET enabledLayers = LSET::AllTechMask() | LSET::UserMask();
712
713 const auto configureStackup =
714 [&]( FOOTPRINT_STACKUP aMode, const LSET& aLayerSet )
715 {
716 const LSET cuLayers = aLayerSet & LSET::AllCuMask();
717 board.SetCopperLayerCount( cuLayers.count() );
718
719 switch( aMode )
720 {
722 enabledLayers |= LSET{ F_Cu, In1_Cu, B_Cu };
723 board.SetLayerName( In1_Cu, _( "Inner layers" ) );
724 break;
725
727 // Nothing extra to add
728
729 // Clear layer name defaults
730 board.SetLayerName( In1_Cu, wxEmptyString );
731 break;
732 }
733
734 enabledLayers |= aLayerSet;
735 };
736
737 if( footprint )
738 {
739 configureStackup( footprint->GetStackupMode(), footprint->GetStackupLayers() );
740 }
741 else
742 {
743 // If no footprint is loaded, we assume the default stackup mode
744 configureStackup( FOOTPRINT_STACKUP::EXPAND_INNER_LAYERS, LSET{} );
745 }
746
748 {
749 m_originalFootprintCopy->RunOnChildren(
750 [&]( BOARD_ITEM* child )
751 {
752 LSET childLayers = child->GetLayerSet() & LSET::UserDefinedLayersMask();
753
754 for( PCB_LAYER_ID layer : childLayers )
755 enabledLayers.set( layer );
756 },
758 }
759
760 // Enable the user-configured number of user layers, plus any specifically named layers
762 {
763 int userLayerCount = cfg->m_DesignSettings.GetUserDefinedLayerCount();
764 enabledLayers |= LSET::UserDefinedLayersMask( userLayerCount );
765
766 for( const PCB_LAYER_ID& user : LSET::UserDefinedLayersMask() )
767 {
768 if( cfg->m_DesignSettings.m_UserLayerNames.contains( LSET::Name( user ).ToStdString() ) )
769 enabledLayers.set( user );
770 }
771 }
772
773 board.SetEnabledLayers( enabledLayers );
774
775 // Footprint Editor layer visibility is kept in the view, not the board (because the board
776 // just delegates to the project file, which we don't have).
777 for( const PCB_LAYER_ID& layer : GetBoard()->GetEnabledLayers() )
778 GetCanvas()->GetView()->SetLayerVisible( layer, true );
779}
780
781
783{
784 // Use CallAfter so that we update the canvas before waiting for the infobar animation
785 CallAfter(
786 [this]()
787 {
788 WX_INFOBAR& infobar = *GetInfoBar();
789 infobar.RemoveAllButtons();
790
791 wxArrayString msgs;
792 int infobarFlags = wxICON_INFORMATION;
793 FOOTPRINT* footprint = GetBoard() ? GetBoard()->GetFirstFootprint() : nullptr;
794 wxString lib = footprint ? footprint->GetFPID().GetLibNickname() : UTF8();
795
797 {
798 msgs.push_back( wxString::Format( _( "Editing %s from board. Saving will update the board only." ),
799 footprint->GetReference() ) );
800
801 infobar.AddLink( wxString::Format( _( "Open footprint from library %s" ), UnescapeString( lib ) ),
802 [this]( wxHyperlinkEvent& aEvent )
803 {
805 } );
806 }
807
808 if( footprint
810 && !PROJECT_PCB::FootprintLibAdapter( &Prj() )->IsFootprintLibWritable( lib ) )
811 {
812 msgs.push_back( _( "Library is read-only. Changes cannot be saved to this library." ) );
813
814 infobar.AddLink( _( "Save as editable copy" ),
815 [this]( wxHyperlinkEvent& aEvent )
816 {
817 SaveFootprintAs( GetBoard()->GetFirstFootprint() );
818 GetCanvas()->GetView()->Update( GetBoard()->GetFirstFootprint() );
819 ClearModify();
820
821 // Get rid of the save-will-update-board-only (or any other dismissable warning)
822 WX_INFOBAR* local_infobar = GetInfoBar();
823
824 if( local_infobar->IsShownOnScreen() && local_infobar->HasCloseButton() )
825 local_infobar->Dismiss();
826
828 SyncLibraryTree( true );
829 } );
830 }
831
832 if( msgs.empty() )
833 {
834 infobar.Dismiss();
835 }
836 else
837 {
838 wxString msg = wxJoin( msgs, '\n', '\0' );
839 infobar.AddCloseButton();
840 infobar.ShowMessage( msg, infobarFlags );
841 }
842 } );
843}
844
845
847{
848 // Cancel a mid-draw tool before the footprint it points into is freed (#24975).
849 if( GetToolManager() )
851
853
854 m_originalFootprintCopy.reset( static_cast<FOOTPRINT*>( aFootprint->Clone() ) );
855 m_originalFootprintCopy->SetParent( nullptr );
856
858
859 // Mirror the load baseline into the active tab context so it survives a tab switch (the frame
860 // members are only a borrowed view of the active context's baseline).
861 if( m_activeTab )
862 {
863 FOOTPRINT* fp_copy = nullptr;
864
866 fp_copy = static_cast<FOOTPRINT*>( m_originalFootprintCopy->Clone() );
867
868 m_activeTab->SetOriginalFootprintCopy( std::unique_ptr<FOOTPRINT>( fp_copy ) );
869 m_activeTab->SetFootprintNameWhenLoaded( m_footprintNameWhenLoaded );
870 m_activeTab->SetName( aFootprint->GetFPID().GetLibItemName() );
871 }
872
874 // Ensure item UUIDs are valid
875 // ("old" footprints can have null uuids that create issues in fp editor)
876 aFootprint->FixUuids();
877
882}
883
884
886{
887 const bool fromBoard = aFootprint && aFootprint->GetLink() != niluuid;
888
889 if( !aHasTabs || !aFootprint || fromBoard || !aFootprint->GetFPID().IsValid() )
890 return false;
891
892 // A new footprint is parented to the board the tab switch is about to free, so drop the parent
893 // before the switch; ReloadFootprint reparents it to the incoming board
894 aFootprint->SetParent( nullptr );
895
896 return true;
897}
898
899
901{
902 ReloadFootprint( aFootprint );
903
905 setFPWatcher( nullptr );
906 else
907 setFPWatcher( aFootprint );
908}
909
910
912{
913 // Opening from the library is a preview that the next library-open reuses; editing promotes it
914 // to a permanent tab.
915 if( prepareFootprintTabHandoff( aFootprint, m_tabsPanel != nullptr ) )
916 findOrCreateFootprintTab( aFootprint->GetFPID(), true );
917
918 installFootprintOnActiveBoard( aFootprint );
919}
920
921
923{
925 return true;
926
927 return std::any_of( m_tabContexts.begin(), m_tabContexts.end(),
928 [this]( const std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT>& aCtx )
929 {
930 return aCtx->GetBoard() == m_pcb;
931 } );
932}
933
934
936{
937 // Swap the board pointer without the SetBoard delete, since on a tab switch the outgoing board
938 // is owned by its tab context. Reproduce only the side effects SetBoard applies to the incoming
939 // board.
940 if( m_pcb == aBoard )
941 return;
942
943 // The only frame-owned board is the constructor's bootstrap board. Delete it when we first
944 // switch away so it does not leak; tab-owned boards are left to their contexts.
945 if( m_pcb && !activeBoardOwnedByTab() )
946 delete m_pcb;
947
948 m_pcb = aBoard;
949
950 if( GetBoard() )
952
953 if( GetBoard() && GetCanvas() )
954 {
955 if( KIGFX::RENDER_SETTINGS* rs = GetCanvas()->GetView()->GetPainter()->GetSettings() )
956 {
957 rs->SetDashLengthRatio( GetBoard()->GetPlotOptions().GetDashedLineDashRatio() );
958 rs->SetGapLengthRatio( GetBoard()->GetPlotOptions().GetDashedLineGapRatio() );
959 }
960 }
961
962 wxCommandEvent e( EDA_EVT_BOARD_CHANGED );
963 ProcessEventLocally( e );
964}
965
966
968{
969 if( !m_activeTab )
970 return;
971
972 KIGFX::VIEW* view = GetCanvas()->GetView();
973
974 EDITOR_TAB_CONTEXT::VIEW_SNAPSHOT& snap = m_activeTab->ViewSnapshot();
975 snap.scale = view->GetScale();
976 snap.center = view->GetCenter();
977 snap.valid = true;
978
979 std::vector<KIID>& sel = m_activeTab->SavedSelection();
980 sel.clear();
981
982 for( EDA_ITEM* item : GetCurrentSelection() )
983 sel.push_back( item->m_Uuid );
984
985 // Dirty state lives on the shared frame screen, so fold it into the context to survive the switch.
986 if( GetScreen() )
987 m_activeTab->SetModified( GetScreen()->IsContentModified() );
988
989 // Swap the raw vectors since UNDO_REDO_CONTAINER is non-copyable; ownership transfers intact.
990 m_activeTab->UndoList().m_CommandsList.swap( m_undoList.m_CommandsList );
991 m_activeTab->RedoList().m_CommandsList.swap( m_redoList.m_CommandsList );
992
993 m_activeTab = nullptr;
994}
995
996
998{
999 if( !aCtx || aCtx == m_activeTab )
1000 return;
1001
1002 installFootprintTabBoard( aCtx, aCtx->GetBoard() );
1003}
1004
1005
1007{
1008 // Install the successor board and tool environment before the caller frees the outgoing context
1009 // so no tool Reset() or repaint ever sees a freed or null m_pcb. Never calls the base SetBoard,
1010 // which would delete m_pcb and reset tools while the model still aliases it.
1011
1013
1014 // Drop selection and unwind a mid-draw tool while the outgoing board is still valid (#24975).
1015 if( m_toolManager )
1016 {
1018 m_toolManager->DeactivateTool();
1019 }
1020
1021 m_activeTab = aCtx;
1022
1023 borrowBoardNonDestructive( aBoard );
1024
1025 if( aCtx )
1026 {
1027 m_undoList.m_CommandsList.swap( aCtx->UndoList().m_CommandsList );
1028 m_redoList.m_CommandsList.swap( aCtx->RedoList().m_CommandsList );
1029 }
1030 else
1031 {
1032 // Discard the swapped-in lists with their transient items so nothing references a freed board.
1034 }
1035
1037 ? static_cast<FOOTPRINT*>( aCtx->GetOriginalFootprintCopy()->Clone() )
1038 : nullptr );
1039 m_footprintNameWhenLoaded = aCtx ? aCtx->GetFootprintNameWhenLoaded() : wxString();
1040
1041 // Mirror the incoming tab's board-uuid remap onto the frame so SaveFootprintToBoard saves an
1042 // instance edit back to the originating board items. A library tab has an empty map.
1043 if( aCtx )
1045 else
1046 m_boardFootprintUuids.clear();
1047
1048 if( GetScreen() )
1049 GetScreen()->SetContentModified( aCtx ? aCtx->IsModified() : false );
1050
1051 // Point the tool environment at the incoming board before ResetTools so tools never dereference
1052 // a freed model.
1053 m_toolManager->SetEnvironment( GetBoard(), GetCanvas()->GetView(), GetCanvas()->GetViewControls(), config(),
1054 this );
1055
1058
1060
1061 if( !aCtx )
1062 {
1064 updateInfoBar();
1068 return;
1069 }
1070
1071 const EDITOR_TAB_CONTEXT::VIEW_SNAPSHOT& snap = aCtx->ViewSnapshot();
1072
1073 if( snap.valid )
1074 {
1075 GetCanvas()->GetView()->SetScale( snap.scale );
1076 GetCanvas()->GetView()->SetCenter( snap.center );
1077 }
1078 else
1079 {
1080 // First time this tab is shown there is no saved view
1082 }
1083
1084 if( !aCtx->SavedSelection().empty() )
1085 {
1087
1088 if( selTool )
1089 {
1090 for( const KIID& id : aCtx->SavedSelection() )
1091 {
1092 if( BOARD_ITEM* item = GetBoard()->ResolveItem( id, true ) )
1093 selTool->select( item );
1094 }
1095 }
1096 }
1097
1098 if( m_appearancePanel )
1099 m_appearancePanel->OnBoardChanged();
1100
1101 if( m_propertiesPanel )
1102 m_propertiesPanel->UpdateData();
1103
1105 updateInfoBar();
1109}
1110
1111
1112static std::unique_ptr<BOARD> makeFpHolderBoard()
1113{
1114 auto board = std::make_unique<BOARD>();
1115 board->SetBoardUse( BOARD_USE::FPHOLDER );
1116 board->GetDesignSettings().m_NetSettings->GetDefaultNetclass()->SetClearance( 0 );
1117 board->GetDesignSettings().m_SolderMaskExpansion = 0;
1118 board->SetVisibleAlls();
1119
1120 return board;
1121}
1122
1123
1125{
1126 const wxString lib = aLibId.GetLibNickname();
1127 const wxString name = aLibId.GetLibItemName();
1128 const wxString key = lib + wxT( ":" ) + name;
1129
1130 if( int existing = m_tabsPanel->FindTab( key ); existing >= 0 )
1131 {
1132 m_tabsPanel->AddTab( key, name, aAsPreview );
1133 return m_tabContexts[existing].get();
1134 }
1135
1136 auto ctx = std::make_unique<FOOTPRINT_EDITOR_TAB_CONTEXT>( lib, name, makeFpHolderBoard() );
1137 ctx->SetPreview( aAsPreview );
1138
1139 FOOTPRINT_EDITOR_TAB_CONTEXT* raw = ctx.get();
1140
1141 // Keep m_tabContexts index-aligned with the panel model. A previewed open reuses the preview
1142 // slot in place; otherwise the context is appended. It must be at its final index before AddTab
1143 // fires onActivateTab.
1144 const int reuseSlot = aAsPreview ? m_tabsPanel->Model().PreviewIndex() : -1;
1145
1146 if( reuseSlot >= 0 && reuseSlot < static_cast<int>( m_tabContexts.size() ) )
1147 {
1148 // Tear the active document down while the outgoing board is still alive, before it is
1149 // displaced and freed.
1150 if( m_tabContexts[reuseSlot].get() == m_activeTab )
1151 {
1152 if( m_toolManager )
1154
1156 m_activeTab = nullptr;
1157 }
1158
1159 return placeReusedTabContext( m_tabContexts, reuseSlot, std::move( ctx ),
1160 [&]( const FOOTPRINT_EDITOR_TAB_CONTEXT& aDisplaced )
1161 {
1162 SCOPED_SET_RESET<BOARD*> protectedBoard( m_protectedBorrowedBoard, aDisplaced.GetBoard() );
1163 m_tabsPanel->AddTab( key, name, aAsPreview );
1164 } );
1165 }
1166
1167 m_tabContexts.push_back( std::move( ctx ) );
1168
1169 m_tabsPanel->AddTab( key, name, aAsPreview );
1170
1171 return raw;
1172}
1173
1174
1176 std::vector<std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT>>& aContexts, int aSlot,
1177 std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT> aNew,
1178 const std::function<void( const FOOTPRINT_EDITOR_TAB_CONTEXT& )>& aInstallSuccessor )
1179{
1180 // Hold the displaced context, and its still-displayed board, alive across aInstallSuccessor, which
1181 // repoints the canvas VIEW at the incoming board. Freeing the old board first would leave
1182 // VIEW::Clear() dereferencing items from a destroyed board.
1183 std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT> displaced = std::move( aContexts[aSlot] );
1184 aContexts[aSlot] = std::move( aNew );
1185
1186 FOOTPRINT_EDITOR_TAB_CONTEXT* raw = aContexts[aSlot].get();
1187
1188 aInstallSuccessor( *displaced );
1189
1190 return raw;
1191}
1192
1193
1195{
1196 if( !aBoardFootprint )
1197 return nullptr;
1198
1199 const KIID sourceUuid = aBoardFootprint->m_Uuid;
1200 const wxString key = FOOTPRINT_EDITOR_TAB_CONTEXT::MakeInstanceTabKey( sourceUuid );
1201 const wxString reference = aBoardFootprint->GetReference();
1202
1203 // Re-editing the same placed footprint focuses the live tab rather than duplicating it.
1204 if( int existing = m_tabsPanel->FindTab( key ); existing >= 0 )
1205 {
1206 m_tabsPanel->AddTab( key, reference + wxS( " " ) + _( "[from board]" ), false );
1207 return m_tabContexts[existing].get();
1208 }
1209
1210 std::unique_ptr<BOARD> board = makeFpHolderBoard();
1211 board->GetDesignSettings().m_DRCSeverities[DRCE_MISSING_COURTYARD] = RPT_SEVERITY_WARNING;
1212
1213 auto ctx = std::make_unique<FOOTPRINT_EDITOR_TAB_CONTEXT>( sourceUuid, reference, std::move( board ) );
1214 BOARD* ctxBoard = ctx->GetBoard();
1215 std::map<KIID, KIID>& uuidMap = ctx->BoardFootprintUuids();
1216 FOOTPRINT_EDITOR_TAB_CONTEXT* raw = ctx.get();
1217
1218 const auto recordAndUpdateUuid =
1219 [&]( BOARD_ITEM* aItem )
1220 {
1221 KIID newId;
1222 uuidMap[newId] = aItem->m_Uuid;
1223 aItem->SetUuid( newId );
1224 };
1225
1226 // Clone keeps the existing uuids, which the remap then swaps for fresh editor-local ones so
1227 // SaveFootprintToBoard can map them back to the original board items.
1228 FOOTPRINT* clone = static_cast<FOOTPRINT*>( aBoardFootprint->Clone() );
1229 clone->SetParent( ctxBoard );
1230 clone->SetParentGroup( nullptr );
1231 clone->SetLink( aBoardFootprint->m_Uuid );
1232 clone->ClearFlags();
1233 clone->SetLocked( false );
1234
1235 recordAndUpdateUuid( clone );
1236 clone->RunOnChildren(
1237 [&]( BOARD_ITEM* aItem )
1238 {
1239 if( aItem->Type() == PCB_PAD_T )
1240 aItem->SetLocked( false );
1241
1242 aItem->ClearFlags();
1243 recordAndUpdateUuid( aItem );
1244 },
1246
1247 ctxBoard->Add( clone );
1248
1249 // The editor knows nothing of the board's nets, so force the orphaned dummy net on every pad to
1250 // avoid saving a reference to an unknown net into the library cache.
1251 clone->ClearAllNets();
1252
1253 // Normalize placement to the footprint-editor defaults so the editor view matches a library load.
1254 clone->SetPosition( VECTOR2I( 0, 0 ) );
1255
1256 if( clone->GetLayer() != F_Cu )
1257 clone->Flip( clone->GetPosition(), GetPcbNewSettings()->m_FlipDirection );
1258
1259 clone->SetOrientation( ANGLE_0 );
1260 clone->RunOnChildren(
1261 [&]( BOARD_ITEM* aItem )
1262 {
1263 if( aItem->Type() == PCB_TEXT_T )
1264 static_cast<PCB_TEXT*>( aItem )->KeepUpright();
1265 },
1267
1268 m_tabContexts.push_back( std::move( ctx ) );
1269
1270 // Index-aligned with the panel model; the context is at its final index before AddTab fires
1271 // onActivateTab.
1272 m_tabsPanel->AddTab( key, reference + wxS( " " ) + _( "[from board]" ), false );
1273
1274 return raw;
1275}
1276
1277
1279{
1280 std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT> ctx =
1282
1283 const wxString key = ctx->GetTabKey();
1284 const wxString label = ctx->GetDisplayName();
1285 FOOTPRINT_EDITOR_TAB_CONTEXT* raw = ctx.get();
1286
1287 m_tabContexts.push_back( std::move( ctx ) );
1288
1289 // At its final index before AddTab fires onActivateTab, which makes the new tab active
1290 m_tabsPanel->AddTab( key, label, false );
1291
1292 return raw;
1293}
1294
1295
1297 UNDO_REDO_CONTAINER& aRedo )
1298{
1299 // Free the UR_TRANSIENT board items each command owns and the command wrappers. The frame's own
1300 // ClearUndoRedoList() and the bare container destructor delete only the wrappers and leak the
1301 // transient items, so a discarded tab history must come through here.
1302 for( UNDO_REDO_CONTAINER* list : { &aUndo, &aRedo } )
1303 {
1304 for( PICKED_ITEMS_LIST* cmd : list->m_CommandsList )
1305 {
1307 delete cmd;
1308 }
1309
1310 list->m_CommandsList.clear();
1311 }
1312}
1313
1314
1316{
1317 // The context is detached here, so the transient items in its lists are never the live objects.
1319}
1320
1321
1323{
1324 if( aIdx < 0 || aIdx >= static_cast<int>( m_tabContexts.size() ) )
1325 return false;
1326
1328
1329 // The active tab's live dirty state lives on the shared frame screen, so ctx->IsModified() is
1330 // stale for it. Fold the screen state back in so an unsaved active tab still prompts.
1331 if( ctx == m_activeTab && GetScreen() )
1333
1334 if( ctx->IsModified() && !m_silentFootprintTabClose )
1335 {
1336 // Prompt while the closing tab is still fully live so a save reads its real board.
1337 wxString msg = wxString::Format( _( "Save changes to '%s' before closing?" ),
1338 ctx->GetDisplayName() );
1339
1340 KIDIALOG dlg( this, msg, _( "Confirmation" ), wxYES_NO | wxCANCEL | wxICON_WARNING );
1341 dlg.SetYesNoCancelLabels( _( "Save" ), _( "Discard Changes" ), _( "Cancel" ) );
1342
1343 switch( dlg.ShowModal() )
1344 {
1345 case wxID_YES:
1346 {
1347 // SaveFootprint reads the active tab's load baseline for rename detection, so an inactive
1348 // tab must be made active first or it saves against the wrong baseline. Restore the prior
1349 // active tab afterwards so closing an inactive tab stays an inactive close, keeping the
1350 // panel's suppressed fallback selection aligned with the live board. Veto the close if the
1351 // save did not complete so the edits and history are not silently dropped.
1352 FOOTPRINT_EDITOR_TAB_CONTEXT* activeBeforeSave = m_activeTab;
1353 const bool activatedForSave = ( ctx != m_activeTab );
1354
1355 if( activatedForSave )
1356 activateFootprintTab( ctx );
1357
1358 const bool saved = SaveFootprint( ctx->GetBoard()->GetFirstFootprint() );
1359
1360 if( activatedForSave && activeBeforeSave )
1361 activateFootprintTab( activeBeforeSave );
1362
1363 if( !saved )
1364 return false;
1365
1366 break;
1367 }
1368
1369 case wxID_NO:
1370 break;
1371
1372 default:
1373 case wxID_CANCEL:
1374 return false;
1375 }
1376 }
1377
1378 const bool closingActive = ( ctx == m_activeTab );
1379
1380 if( !closingActive )
1381 {
1382 // m_pcb aliases a different live tab's board, so freeing this context dangles nothing.
1384 m_tabContexts.erase( m_tabContexts.begin() + aIdx );
1385 return true;
1386 }
1387
1388 // The closing tab's lists are currently the frame's live lists. Free them now with their
1389 // transient items, so the install's detach swaps empty lists into the closing context.
1391
1392 const int newCount = static_cast<int>( m_tabContexts.size() ) - 1;
1393 const int successorIdx = newCount > 0 ? std::min( aIdx, newCount - 1 ) : -1;
1394
1395 if( successorIdx >= 0 )
1396 {
1397 // Map the successor's post-erase position back to a pre-erase index. Indices above the closed
1398 // one shift down by one after the erase.
1399 const int preEraseSuccessor = successorIdx < aIdx ? successorIdx : successorIdx + 1;
1400
1401 FOOTPRINT_EDITOR_TAB_CONTEXT* successor = m_tabContexts[preEraseSuccessor].get();
1402
1403 installFootprintTabBoard( successor, successor->GetBoard() );
1404 }
1405 else
1406 {
1407 // Last tab: the fresh empty board is frame-owned like the bootstrap board.
1408 installFootprintTabBoard( nullptr, makeFpHolderBoard().release() );
1409 }
1410
1411 // The install swapped m_pcb off the closing board, so erasing the context frees it safely.
1412 m_tabContexts.erase( m_tabContexts.begin() + aIdx );
1413
1414 return true;
1415}
1416
1417
1419{
1420 const wxString lib = aFPID.GetLibNickname();
1421 const wxString name = aFPID.GetLibItemName();
1422 const int idx = m_tabsPanel->FindTab( lib + wxT( ":" ) + name );
1423
1424 if( idx < 0 )
1425 return;
1426
1427 // The caller already confirmed the deletion, so close without re-prompting. The panel selects a
1428 // successor when the closed tab was active.
1430 m_tabsPanel->CloseTab( idx );
1432}
1433
1434
1435void FOOTPRINT_EDIT_FRAME::RenameFootprintTab( const LIB_ID& aOldId, const LIB_ID& aNewId )
1436{
1437 const wxString newLib = aNewId.GetLibNickname();
1438 const wxString newName = aNewId.GetLibItemName();
1439
1440 // An unsaved import is keyed by a session id, not by aOldId, so the save-as that named it promotes
1441 // the active tab instead. A tree-driven rename carries a nickname and never reaches this path
1442 if( m_activeTab && m_activeTab->IsUnsaved() && aOldId.GetLibNickname().empty()
1443 && !newLib.IsEmpty() )
1444 {
1445 const wxString unsavedKey = m_activeTab->GetTabKey();
1446
1447 m_activeTab->PromoteToLibrary( newLib, newName );
1448 m_tabsPanel->RenameTab( unsavedKey, m_activeTab->GetTabKey(), m_activeTab->GetDisplayName() );
1449
1450 return;
1451 }
1452
1453 const wxString oldLib = aOldId.GetLibNickname();
1454 const wxString oldName = aOldId.GetLibItemName();
1455 const wxString oldKey = oldLib + wxT( ":" ) + oldName;
1456 const int idx = m_tabsPanel->FindTab( oldKey );
1457
1458 if( idx < 0 )
1459 return;
1460
1461 if( idx < static_cast<int>( m_tabContexts.size() ) )
1462 {
1463 // A tab switch restores the context's baseline onto the frame, so it must track the rename too
1464 // or the next save would delete the pre-rename library entry
1465 m_tabContexts[idx]->SetName( newName );
1466 m_tabContexts[idx]->SetFootprintNameWhenLoaded( newName );
1467 }
1468
1469 m_tabsPanel->RenameTab( oldKey, newLib + wxT( ":" ) + newName, newName );
1470}
1471
1472
1474{
1475 for( const std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
1476 {
1477 if( ctx.get() == m_activeTab )
1478 {
1479 if( GetScreen() && GetScreen()->IsContentModified() )
1480 return true;
1481 }
1482 else if( ctx->IsModified() )
1483 {
1484 return true;
1485 }
1486 }
1487
1488 return false;
1489}
1490
1491
1493{
1494 if( !m_tabsPanel )
1495 return;
1496
1497 const LIB_ID& footprintId = aFootprint.GetFPID();
1498 const wxString key = footprintId.GetLibNickname().wx_str() + wxT( ':' ) + footprintId.GetLibItemName().wx_str();
1499 const int idx = m_tabsPanel->FindTab( key );
1500
1501 if( idx < 0 || idx >= static_cast<int>( m_tabContexts.size() ) )
1502 return;
1503
1505 FOOTPRINT_EDITOR_TAB_CONTEXT* originalActive = m_activeTab;
1506
1507 activateFootprintTab( ctx );
1508
1509 // The old history contains pointers into the footprint ReloadFootprint is about to delete.
1511 ctx->SavedSelection().clear();
1512
1513 FOOTPRINT* replacement = static_cast<FOOTPRINT*>( aFootprint.Clone() );
1514 replacement->SetParent( nullptr );
1515 installFootprintOnActiveBoard( replacement );
1516 replacement->ClearFlags();
1517 ClearModify();
1518
1519 if( originalActive && originalActive != ctx )
1520 activateFootprintTab( originalActive );
1521
1522 FOOTPRINT* activeFootprint = GetBoard()->GetFirstFootprint();
1523
1524 if( IsCurrentFPFromBoard() )
1525 setFPWatcher( nullptr );
1526 else
1527 setFPWatcher( activeFootprint );
1528
1529 UpdateView();
1531 Update3DView( true, true );
1532}
1533
1534
1536{
1537 for( const std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
1538 {
1539 if( ctx.get() != m_activeTab && ctx->IsModified() )
1540 return true;
1541 }
1542
1543 return false;
1544}
1545
1546
1548{
1549 // Active tab always goes first
1550 for( int ii = 0; ii < (int) m_tabContexts.size(); ++ii )
1551 {
1552 if( aFromBoardOnly && !m_tabContexts[ii]->IsFromBoard() )
1553 continue;
1554
1555 if( m_tabContexts[ii].get() == m_activeTab )
1556 {
1557 wxSafeYield( this, true ); // Allow frame to come to front before showing "Save Changes?"
1558
1559 if( !m_tabsPanel->CloseTab( ii ) )
1560 return false;
1561 }
1562 }
1563
1564 // Go from back so we don't have to worry about deletions
1565 for( int ii = (int) m_tabContexts.size() - 1; ii >= 0; --ii )
1566 {
1567 if( aFromBoardOnly && !m_tabContexts[ii]->IsFromBoard() )
1568 continue;
1569
1571 wxSafeYield( this, true ); // Allow tab to come to front before showing "Save Changes?"
1572
1573 if( !m_tabsPanel->CloseTab( ii ) )
1574 return false;
1575 }
1576
1577 return true;
1578}
1579
1580
1582{
1583 m_tabsPanel->RefreshTabLabels();
1584}
1585
1586
1588{
1589 wxCHECK( aReplacement, /* void */ );
1590
1591 // Install the fresh frame-owned board and reset the tools against it before any tab board is
1592 // freed, so no ResetTools or repaint sees a freed or null m_pcb.
1593 installFootprintTabBoard( nullptr, aReplacement );
1594
1595 // Tear the strip down without re-prompting to save, since unsaved changes were already handled.
1596 // Suppress the host close callback and tab activation so CloseAll only does panel bookkeeping.
1597 std::function<bool( int )> savedCb = std::move( m_tabsPanel->onCloseTabRequested );
1598 m_tabsPanel->onCloseTabRequested =
1599 []( int )
1600 {
1601 return true;
1602 };
1603
1605 m_tabsPanel->CloseAll();
1607
1608 m_tabsPanel->onCloseTabRequested = std::move( savedCb );
1609
1610 wxASSERT_MSG( m_pcb == aReplacement,
1611 wxT( "m_pcb must alias the frame-owned replacement before contexts are freed" ) );
1612
1613 for( const std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT>& ctx : m_tabContexts )
1615
1616 m_tabContexts.clear();
1617}
1618
1619
1621{
1622 m_tabsPanel->AdvanceTab( aForward );
1623}
1624
1625
1627{
1628 m_tabsPanel->CloseTab( m_tabsPanel->GetActiveTab() );
1629}
1630
1631
1636
1637
1642
1643
1645{
1646 wxFAIL_MSG( wxT( "Plotting not supported in Footprint Editor" ) );
1647
1649}
1650
1651
1653{
1654 wxFAIL_MSG( wxT( "Plotting not supported in Footprint Editor" ) );
1655}
1656
1657
1665
1666
1674
1675
1677{
1678 // Get our own settings; aCfg will be the PCBNEW_SETTINGS because we're part of the pcbnew
1679 // compile unit
1681
1682 if( cfg )
1683 {
1685
1687
1690
1692 m_selectionFilterPanel->SetCheckboxesFromFilter( cfg->m_SelectionFilter );
1693
1695
1696 for( auto& [source_name, dest_name] : cfg->m_DesignSettings.m_UserLayerNames )
1697 {
1698 wxString wx_source_name = source_name;
1699 PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( LSET::NameToLayer( wx_source_name ) );
1700
1701 if( IsUserLayer( layer ) )
1702 GetBoard()->SetLayerName( layer, dest_name );
1703 }
1704
1705 }
1706}
1707
1708
1710{
1711 // Load canvas type from the FOOTPRINT_EDITOR_SETTINGS:
1713
1714 // If we had an OpenGL failure this session, use the fallback GAL but don't update the
1715 // user preference silently:
1716
1719}
1720
1721
1723{
1725
1726 // Get our own settings; aCfg will be the PCBNEW_SETTINGS because we're part of the pcbnew
1727 // compile unit
1729
1730 if( cfg )
1731 {
1733
1736 cfg->m_LibWidth = m_treePane->GetSize().x;
1737
1738 if( TOOL_MANAGER* toolMgr = GetToolManager() )
1739 {
1740 if( PCB_SELECTION_TOOL* selTool = toolMgr->GetTool<PCB_SELECTION_TOOL>() )
1741 cfg->m_SelectionFilter = selTool->GetFilter();
1742 }
1743
1745
1746 if( m_propertiesPanel )
1747 {
1748 cfg->m_AuiPanels.show_properties = m_propertiesPanel->IsShownOnScreen();
1750 cfg->m_AuiPanels.properties_splitter = m_propertiesPanel->SplitterProportion();
1751 }
1752
1754
1755 if( m_appearancePanel )
1756 {
1759 cfg->m_LayerPresets = m_appearancePanel->GetUserLayerPresets();
1760 cfg->m_ActiveLayerPreset = m_appearancePanel->GetActiveLayerPreset();
1761 }
1762
1763 cfg->m_OpenTabs.clear();
1764 cfg->m_ActiveTab.Clear();
1765
1766 const std::vector<EDITOR_TABS_MODEL::ENTRY>& entries = m_tabsPanel->Model().Entries();
1767
1768 for( size_t i = 0; i < m_tabContexts.size(); ++i )
1769 {
1770 const FOOTPRINT_EDITOR_TAB_CONTEXT* ctx = m_tabContexts[i].get();
1771
1772 // Instance and unsaved-import tabs are session-only and never persisted
1773 if( ctx->IsTransient() )
1774 continue;
1775
1776 const bool preview = i < entries.size() && entries[i].preview;
1777
1778 cfg->m_OpenTabs.push_back( { ctx->GetLib(), ctx->GetName(), preview } );
1779
1780 if( ctx == m_activeTab )
1781 cfg->m_ActiveTab = ctx->GetTabKey();
1782 }
1783 }
1784}
1785
1786
1787
1789{
1790 FOOTPRINT_EDITOR_SETTINGS* cfg = const_cast<FOOTPRINT_EDIT_FRAME*>( this )->GetSettings();
1791
1792 return cfg ? cfg->m_RotationAngle : ANGLE_90;
1793}
1794
1795
1796
1798{
1800 return ::GetColorSettings( cfg ? cfg->m_ColorTheme : DEFAULT_THEME );
1801}
1802
1803
1805{
1806 static MAGNETIC_SETTINGS fallback;
1807
1809 return &cfg->m_MagneticItems;
1810
1811 return &fallback;
1812}
1813
1814
1815const BOX2I FOOTPRINT_EDIT_FRAME::GetDocumentExtents( bool aIncludeAllVisible ) const
1816{
1817 FOOTPRINT* footprint = GetBoard()->GetFirstFootprint();
1818
1819 if( footprint )
1820 {
1821 bool hasGraphicalItem = footprint->Pads().size() || footprint->Zones().size();
1822
1823 if( !hasGraphicalItem )
1824 {
1825 for( const BOARD_ITEM* item : footprint->GraphicalItems() )
1826 {
1827 if( item->Type() == PCB_TEXT_T || item->Type() == PCB_TEXTBOX_T )
1828 continue;
1829
1830 hasGraphicalItem = true;
1831 break;
1832 }
1833 }
1834
1835 if( hasGraphicalItem )
1836 {
1837 return footprint->GetBoundingBox( false );
1838 }
1839 else
1840 {
1841 BOX2I newFootprintBB( { 0, 0 }, { 0, 0 } );
1842 newFootprintBB.Inflate( pcbIUScale.mmToIU( 12 ) );
1843 return newFootprintBB;
1844 }
1845 }
1846
1847 return GetBoardBoundingBox( false );
1848}
1849
1850
1851bool FOOTPRINT_EDIT_FRAME::canCloseWindow( wxCloseEvent& aEvent )
1852{
1853 // Shutdown blocks must be determined and vetoed as early as possible, before any modal prompt.
1854 // IsContentModified only sees the active tab, so also account for dirty inactive tabs.
1855 if( KIPLATFORM::APP::SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION
1857 {
1858 aEvent.Veto();
1859 return false;
1860 }
1861
1862 if( !HandleUnsavedChanges( false ) )
1863 {
1864 aEvent.Veto();
1865 return false;
1866 }
1867
1868 PAD_TOOL* padTool = m_toolManager->GetTool<PAD_TOOL>();
1869
1870 if( padTool->InPadEditMode() )
1871 padTool->ExitPadEditMode();
1872
1873 // Save footprint tree column widths
1874 m_adapter->SaveSettings();
1875
1876 return PCB_BASE_EDIT_FRAME::canCloseWindow( aEvent );
1877}
1878
1879
1881{
1882 // No more vetos
1883 GetCanvas()->SetEventDispatcher( nullptr );
1885
1887
1888 if( GetLibTree() )
1890
1891 // Do not show the layer manager during closing to avoid flicker
1892 // on some platforms (Windows) that generate useless redraw of items in
1893 // the Layer Manager
1894 m_auimgr.GetPane( wxT( "LayersManager" ) ).Show( false );
1895 m_auimgr.GetPane( wxT( "SelectionFilter" ) ).Show( false );
1896
1897 Clear_Pcb();
1898}
1899
1900
1901void FOOTPRINT_EDIT_FRAME::OnExitKiCad( wxCommandEvent& event )
1902{
1903 Kiway().OnKiCadExit();
1904}
1905
1906
1908{
1909 Close();
1910}
1911
1912
1914{
1915 // call my base class
1917
1918 // We have 2 panes to update.
1919 // For some obscure reason, the AUI manager hides the first modified pane.
1920 // So force show panes
1921 wxAuiPaneInfo& tree_pane_info = m_auimgr.GetPane( m_treePane );
1922 bool tree_shown = tree_pane_info.IsShown();
1923 tree_pane_info.Caption( _( "Libraries" ) );
1924
1925 wxAuiPaneInfo& lm_pane_info = m_auimgr.GetPane( m_appearancePanel );
1926 bool lm_shown = lm_pane_info.IsShown();
1927 lm_pane_info.Caption( _( "Appearance" ) );
1928 wxAuiPaneInfo& sf_pane_info = m_auimgr.GetPane( m_selectionFilterPanel );
1929 sf_pane_info.Caption( _( "Selection Filter" ) );
1930
1931 // update the layer manager
1933
1934 // Now restore the visibility:
1935 lm_pane_info.Show( lm_shown );
1936 tree_pane_info.Show( tree_shown );
1937 m_auimgr.Update();
1938
1940
1941 UpdateTitle();
1942}
1943
1944
1946{
1948
1949 if( m_isClosing )
1950 return;
1951
1952 // An edit promotes the active tab from preview to permanent and flags it dirty. Reflect the
1953 // shared screen's dirty state onto the context and panel model so the tab shows bold + "*" and a
1954 // later library-open opens its own tab instead of replacing this one.
1955 if( m_activeTab )
1956 {
1957 m_activeTab->SetPreview( false );
1958 m_activeTab->SetModified( true );
1959
1960 if( int idx = m_tabsPanel->FindTab( m_activeTab->GetTabKey() ); idx >= 0 )
1961 m_tabsPanel->MarkModified( idx, true );
1962 }
1963
1964 Update3DView( true, true );
1966}
1967
1968
1970{
1971 SetTitle( _( "Footprint Editor" ) );
1972}
1973
1974
1976{
1977 m_appearancePanel->OnBoardChanged();
1978}
1979
1980
1982{
1986 m_propertiesPanel->UpdateData();
1987}
1988
1989
1991{
1993
1995 auto adapter = static_cast<FP_TREE_SYNCHRONIZING_ADAPTER*>( m_adapter.get() );
1996
1997 adapter->AddLibraries( this );
1998}
1999
2000
2001void FOOTPRINT_EDIT_FRAME::SyncLibraryTree( [[maybe_unused]] bool aProgress )
2002{
2003 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "FOOTPRINT_EDIT_FRAME::SyncLibraryTree enter" ) );
2004
2007 LIB_ID target = GetTargetFPID();
2008 bool targetSelected = ( target == GetLibTree()->GetSelectedLibId() );
2009 std::vector<LIB_ID> expanded = GetLibTree()->GetExpandedLibraries();
2010
2011 // Unselect before syncing to avoid null reference in the adapter
2012 // if a selected item is removed during the sync
2013 GetLibTree()->Unselect();
2014
2015 // Sync the LIB_TREE to the FOOTPRINT_INFO list
2016 adapter->Sync( footprints );
2017
2018 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "FOOTPRINT_EDIT_FRAME::SyncLibraryTree Regenerate" ) );
2019 GetLibTree()->Regenerate( true );
2020
2021 // Sync() collapsed the tree, so re-expand the libraries that were open before it.
2022 for( const LIB_ID& libId : expanded )
2023 GetLibTree()->ExpandLibId( libId );
2024
2025 if( target.IsValid() )
2026 {
2027 if( adapter->FindItem( target ) )
2028 {
2029 if( targetSelected )
2030 GetLibTree()->SelectLibId( target );
2031 else
2032 GetLibTree()->CenterLibId( target );
2033 }
2034 else
2035 {
2036 // Try to focus on parent
2037 target.SetLibItemName( wxEmptyString );
2038 GetLibTree()->CenterLibId( target );
2039 }
2040 }
2041
2042 wxLogTrace( wxT( "KICAD_TABS_DBG" ), wxT( "FOOTPRINT_EDIT_FRAME::SyncLibraryTree exit" ) );
2043}
2044
2045
2050
2051
2053{
2054 GetLibTree()->SelectLibId( aLibID );
2055}
2056
2057
2059{
2060 m_appearancePanel->UpdateDisplayOptions();
2061}
2062
2063
2065{
2066 // Create the manager and dispatcher & route draw panel events to the dispatcher
2068 m_toolManager->SetEnvironment( GetBoard(), GetCanvas()->GetView(), GetCanvas()->GetViewControls(), config(), this );
2069 m_actions = new PCB_ACTIONS();
2071
2073
2074 m_toolManager->RegisterTool( new COMMON_CONTROL );
2075 m_toolManager->RegisterTool( new COMMON_TOOLS );
2076 m_toolManager->RegisterTool( new PCB_SELECTION_TOOL );
2077 m_toolManager->RegisterTool( new ZOOM_TOOL );
2078 m_toolManager->RegisterTool( new EDIT_TOOL );
2079 m_toolManager->RegisterTool( new PCB_EDIT_TABLE_TOOL );
2080 m_toolManager->RegisterTool( new PAD_TOOL );
2081 m_toolManager->RegisterTool( new DRAWING_TOOL );
2082 m_toolManager->RegisterTool( new PCB_POINT_EDITOR );
2083 m_toolManager->RegisterTool( new PCB_CONTROL ); // copy/paste
2084 m_toolManager->RegisterTool( new LIBRARY_EDITOR_CONTROL );
2085 m_toolManager->RegisterTool( new FOOTPRINT_EDITOR_CONTROL );
2086 m_toolManager->RegisterTool( new ALIGN_DISTRIBUTE_TOOL );
2087 m_toolManager->RegisterTool( new PCB_PICKER_TOOL );
2088 m_toolManager->RegisterTool( new POSITION_RELATIVE_TOOL );
2089 m_toolManager->RegisterTool( new ARRAY_TOOL );
2090 m_toolManager->RegisterTool( new PCB_VIEWER_TOOLS );
2091 m_toolManager->RegisterTool( new PCB_GROUP_TOOL );
2092 m_toolManager->RegisterTool( new CONSTRAINT_EDIT_TOOL );
2093 m_toolManager->RegisterTool( new CONVERT_TOOL );
2094 m_toolManager->RegisterTool( new PROPERTIES_TOOL );
2095 m_toolManager->RegisterTool( new MATCH_PROPERTIES_TOOL );
2096 m_toolManager->RegisterTool( new GRAPHIC_EDIT_TOOL );
2097 m_toolManager->RegisterTool( new EMBED_TOOL );
2098
2099 for( TOOL_BASE* tool : m_toolManager->Tools() )
2100 {
2101 if( PCB_TOOL_BASE* pcbTool = dynamic_cast<PCB_TOOL_BASE*>( tool ) )
2102 pcbTool->SetIsFootprintEditor( true );
2103 }
2104
2105 m_toolManager->GetTool<PCB_VIEWER_TOOLS>()->SetFootprintFrame( true );
2106 m_toolManager->InitTools();
2107
2108 m_toolManager->InvokeTool( "common.InteractiveSelection" );
2109
2110 // Load or reload wizard plugins in case they changed since the last time the frame opened
2111 // Because the board editor has also a plugin python menu,
2112 // call the PCB_EDIT_FRAME RunAction() if the board editor is running
2113 // Otherwise run the current RunAction().
2114 PCB_EDIT_FRAME* pcbframe = static_cast<PCB_EDIT_FRAME*>( Kiway().Player( FRAME_PCB_EDITOR, false ) );
2115
2116 if( pcbframe )
2118 else
2120}
2121
2122
2124{
2126
2127 ACTION_MANAGER* mgr = m_toolManager->GetActionManager();
2128 PCB_EDITOR_CONDITIONS cond( this );
2129
2130 wxASSERT( mgr );
2131
2132#define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
2133#define CHECK( x ) ACTION_CONDITIONS().Check( x )
2134
2135 auto haveFootprintCond =
2136 [this]( const SELECTION& )
2137 {
2138 return GetBoard() && GetBoard()->GetFirstFootprint() != nullptr;
2139 };
2140
2141 auto footprintTargettedCond =
2142 [this]( const SELECTION& )
2143 {
2144 return !GetTargetFPID().GetLibItemName().empty();
2145 };
2146
2147 auto footprintSelectedInTreeCond =
2148 [this]( const SELECTION& )
2149 {
2151 return !sel.GetLibNickname().empty() && !sel.GetLibItemName().empty();
2152 };
2153
2154 const auto footprintFromBoardCond =
2155 [this]( const SELECTION& )
2156 {
2157 return IsCurrentFPFromBoard();
2158 };
2159
2160 auto pcbFrameExistsCond =
2161 [this]( const SELECTION& )
2162 {
2163 PCB_EDIT_FRAME* frame = dynamic_cast<PCB_EDIT_FRAME*>( Kiway().Player( FRAME_PCB_EDITOR, false ) );
2164
2165 return ( frame != nullptr );
2166 };
2167
2168 auto boardFootprintExistsCond =
2169 [this]( const SELECTION& )
2170 {
2171 PCB_EDIT_FRAME* frame = dynamic_cast<PCB_EDIT_FRAME*>( Kiway().Player( FRAME_PCB_EDITOR, false ) );
2172
2173 FOOTPRINT* editorFootprint = GetBoard()->GetFirstFootprint();
2174 bool canInsert = frame && editorFootprint && editorFootprint->GetLink() == niluuid;
2175
2176 // If the source was deleted, the footprint can inserted but not updated in the board.
2177 if( frame && editorFootprint && editorFootprint->GetLink() != niluuid )
2178 {
2179 BOARD* mainpcb = frame->GetBoard();
2180 canInsert = true;
2181
2182 // search if the source footprint was not deleted:
2183 for( FOOTPRINT* candidate : mainpcb->Footprints() )
2184 {
2185 if( editorFootprint->GetLink() == candidate->m_Uuid )
2186 {
2187 canInsert = false;
2188 break;
2189 }
2190 }
2191 }
2192
2193 return canInsert;
2194 };
2195
2196 // clang-format off
2197 mgr->SetConditions( ACTIONS::saveAs, ENABLE( footprintTargettedCond ) );
2200 mgr->SetConditions( PCB_ACTIONS::editLibFpInFpEditor,ENABLE( footprintFromBoardCond ) );
2201
2202 mgr->SetConditions( PCB_ACTIONS::saveFpToBoard, ENABLE( boardFootprintExistsCond ) );
2203 mgr->SetConditions( PCB_ACTIONS::loadFpFromBoard, ENABLE( pcbFrameExistsCond ) );
2204
2207
2210
2211 mgr->SetConditions( ACTIONS::cut, ENABLE( cond.HasItems() ) );
2212 mgr->SetConditions( ACTIONS::copy, ENABLE( cond.HasItems() ) );
2219
2226
2230
2235 // clang-format on
2236
2237 auto highContrastCond =
2238 [this]( const SELECTION& )
2239 {
2241 };
2242
2243 auto autoConstraintsCond = [this]( const SELECTION& )
2244 {
2246 return cfg && cfg->m_AutoConstraints;
2247 };
2248
2249 mgr->SetConditions( PCB_ACTIONS::toggleAutoConstraints, CHECK( autoConstraintsCond ) );
2250
2251 auto boardFlippedCond = [this]( const SELECTION& )
2252 {
2254 };
2255
2256 auto libraryTreeCond =
2257 [this](const SELECTION& )
2258 {
2259 return IsLibraryTreeShown();
2260 };
2261
2262 auto layerManagerCond =
2263 [this]( const SELECTION& )
2264 {
2265 return m_auimgr.GetPane( "LayersManager" ).IsShown();
2266 };
2267
2268 auto propertiesCond =
2269 [this] ( const SELECTION& )
2270 {
2271 return m_auimgr.GetPane( PropertiesPaneName() ).IsShown();
2272 };
2273
2274 mgr->SetConditions( ACTIONS::highContrastMode, CHECK( highContrastCond ) );
2275 mgr->SetConditions( PCB_ACTIONS::flipBoard, CHECK( boardFlippedCond ) );
2277
2278 mgr->SetConditions( ACTIONS::showLibraryTree, CHECK( libraryTreeCond ) );
2279 mgr->SetConditions( PCB_ACTIONS::showLayersManager, CHECK( layerManagerCond ) );
2280 mgr->SetConditions( ACTIONS::showProperties, CHECK( propertiesCond ) );
2281
2282 mgr->SetConditions( ACTIONS::print, ENABLE( haveFootprintCond ) );
2283 mgr->SetConditions( PCB_ACTIONS::exportFootprint, ENABLE( haveFootprintCond ) );
2284 mgr->SetConditions( PCB_ACTIONS::placeImportedGraphics, ENABLE( haveFootprintCond ) );
2285
2286 mgr->SetConditions( PCB_ACTIONS::footprintProperties, ENABLE( footprintSelectedInTreeCond || haveFootprintCond ) );
2287 mgr->SetConditions( PCB_ACTIONS::padTable, ENABLE( haveFootprintCond ) );
2288 mgr->SetConditions( PCB_ACTIONS::editTextAndGraphics, ENABLE( haveFootprintCond ) );
2289 mgr->SetConditions( PCB_ACTIONS::checkFootprint, ENABLE( haveFootprintCond ) );
2290 mgr->SetConditions( PCB_ACTIONS::repairFootprint, ENABLE( haveFootprintCond ) );
2291 mgr->SetConditions( PCB_ACTIONS::cleanupGraphics, ENABLE( haveFootprintCond ) );
2292 mgr->SetConditions( ACTIONS::showDatasheet, ENABLE( haveFootprintCond ) );
2293
2294 const auto isArcKeepCenterMode =
2295 [this]( const SELECTION& )
2296 {
2298 };
2299
2300 const auto isArcKeepEndpointMode =
2301 [this]( const SELECTION& )
2302 {
2304 };
2305
2306 const auto isArcKeepRadiusMode =
2307 [this]( const SELECTION& )
2308 {
2310 };
2311
2312 // clang-format off
2313 mgr->SetConditions( ACTIONS::pointEditorArcKeepCenter, CHECK( isArcKeepCenterMode ) );
2314 mgr->SetConditions( ACTIONS::pointEditorArcKeepEndpoint, CHECK( isArcKeepEndpointMode ) );
2315 mgr->SetConditions( ACTIONS::pointEditorArcKeepRadius, CHECK( isArcKeepRadiusMode ) );
2316 // clang-format on
2317
2318// Only enable a tool if the part is edtable
2319#define CURRENT_EDIT_TOOL( action ) mgr->SetConditions( action, ACTION_CONDITIONS() \
2320 .Enable( haveFootprintCond ) \
2321 .Check( cond.CurrentTool( action ) ) )
2322
2349
2368
2369#undef CURRENT_EDIT_TOOL
2370#undef ENABLE
2371#undef CHECK
2372}
2373
2374
2376{
2378
2379 // Be sure the axis are enabled
2380 GetCanvas()->GetGAL()->SetAxesEnabled( true );
2381
2382 UpdateView();
2383
2384 // Ensure the m_Layers settings are using the canvas type:
2386}
2387
2388
2390{
2392 m_appearancePanel->CommonSettingsChanged( aFlags );
2393
2395 {
2396 GetGalDisplayOptions().ReadWindowSettings( cfg->m_Window );
2397
2398 GetBoard()->GetDesignSettings() = cfg->m_DesignSettings;
2400 }
2401
2405
2407
2408 if( aFlags & ENVVARS_CHANGED )
2409 SyncLibraryTree( true );
2410
2411 Layout();
2412 SendSizeEvent();
2413}
2414
2415
2416std::unique_ptr<GRID_HELPER> FOOTPRINT_EDIT_FRAME::MakeGridHelper()
2417{
2418 return std::make_unique<PCB_GRID_HELPER>( m_toolManager, GetMagneticItemsSettings() );
2419}
2420
2421
2423{
2424 LIB_ID id = GetLoadedFPID();
2425
2426 if( id.empty() )
2427 {
2428 DisplayErrorMessage( this, _( "No footprint selected." ) );
2429 return;
2430 }
2431
2432 wxFileName fn( id.GetLibItemName() );
2433 fn.SetExt( wxT( "png" ) );
2434
2435 wxString projectPath = wxPathOnly( Prj().GetProjectFullName() );
2436
2437 wxFileDialog dlg( this, _( "Export View as PNG" ), projectPath, fn.GetFullName(), FILEEXT::PngFileWildcard(),
2438 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
2439
2441
2442 if( dlg.ShowModal() == wxID_CANCEL || dlg.GetPath().IsEmpty() )
2443 return;
2444
2445 // calling wxYield is mandatory under Linux, after closing the file selector dialog
2446 // to refresh the screen before creating the PNG or JPEG image from screen
2447 wxYield();
2448 this->SaveCanvasImageToFile( dlg.GetPath(), BITMAP_TYPE::PNG );
2449}
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:401
@ NORMAL
Inactive layers are shown normally (no high-contrast mode)
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
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:292
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:271
static TOOL_ACTION ungroup
Definition actions.h:236
static TOOL_ACTION toggleBoundingBoxes
Definition actions.h:153
static TOOL_ACTION pointEditorArcKeepRadius
Definition actions.h:273
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:295
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:272
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:126
Container for design settings for a BOARD object.
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:84
void SetLocked(bool aLocked) override
Definition board_item.h:417
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:346
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition board.cpp:1497
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition board.cpp:954
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
Definition board.h:704
const FOOTPRINTS & Footprints() const
Definition board.h:463
void DeleteAllFootprints()
Remove all footprints from the deque and free the memory associated with them.
Definition board.cpp:2077
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1299
void SetUserUnits(EDA_UNITS aUnits)
Definition board.h:1023
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.
Interactive authoring of geometric constraints (issue #2329).
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:98
const KIID m_Uuid
Definition eda_item.h:597
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:160
virtual void SetParentGroup(EDA_GROUP *aGroup)
Definition eda_item.h:115
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
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:54
Module editor specific tools.
BOARD_DESIGN_SETTINGS m_DesignSettings
Only some of these settings are actually used for footprint editing.
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 a tab that is session-only and not yet saved.
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.
static std::unique_ptr< FOOTPRINT_EDITOR_TAB_CONTEXT > MakeUnsaved(std::unique_ptr< BOARD > aBoard)
Construct a tab for an imported footprint that has no library identity yet.
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)
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 Clear_Pcb()
Delete all and reinitialize the current board.
Definition initpcb.cpp:107
FOOTPRINT_EDITOR_TAB_CONTEXT * createUnsavedFootprintTab()
Open a session-only tab for an imported footprint over a fresh fp-holder board and make it the active...
void HardRedraw() override
Refresh the library tree and redraw the window.
void updateInfoBar()
Update the infobar for the currently-active tab.
static const wxChar * GetFootprintEditorFrameName()
void SyncLibraryTree(bool aProgress)
Synchronize the footprint library tree to the current state of the footprint library table.
BOARD * m_protectedBorrowedBoard
Board still owned by a displaced preview context while AddTab() synchronously installs its successor.
FOOTPRINT_EDITOR_TAB_CONTEXT * m_activeTab
void OnSaveFootprintAsPng(wxCommandEvent &event)
bool SaveFootprintAs(FOOTPRINT *aFootprint)
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.
std::unique_ptr< API_HANDLER_LIBRARIES > m_apiHandlerFpLibs
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 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 HasModifiedFootprintTabs() const
Return true if any footprint editor tab has unsaved changes.
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...
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(const FOOTPRINT_EDITOR_TAB_CONTEXT &)> &aInstallSuccessor)
Replace the tab context at aSlot with aNew, running aInstallSuccessor before the displaced context is...
bool HandleUnsavedChanges(bool aFromBoardOnly)
Prompt to save each dirty tab that meets the requirements.
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.
bool hasDirtyInactiveTabs() const
True if any non-active tab has unsaved edits.
void RefreshLibraryFootprintTab(const FOOTPRINT &aFootprint)
Replace the clean open editor tab matching aFootprint, if any, with the saved footprint.
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.
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...
static bool prepareFootprintTabHandoff(FOOTPRINT *aFootprint, bool aHasTabs)
Decide whether aFootprint opens in its own tab and, if so, detach it from the board it arrived parent...
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.
void installFootprintOnActiveBoard(FOOTPRINT *aFootprint)
Replace the active board's footprint with aFootprint and re-point the file watcher at it.
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...
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:1259
void SetLocked(bool isLocked) override
Set the #MODULE_is_LOCKED bit in the m_ModuleStatus.
Definition footprint.h:703
ZONES & Zones()
Definition footprint.h:410
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:404
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition footprint.h:449
const LIB_ID & GetFPID() const
Definition footprint.h:473
const LSET & GetStackupLayers() const
Definition footprint.h:548
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:1258
const wxString & GetReference() const
Definition footprint.h:901
FOOTPRINT_STACKUP GetStackupMode() const
Definition footprint.h:541
VECTOR2I GetPosition() const override
Definition footprint.h:435
DRAWINGS & GraphicalItems()
Definition footprint.h:407
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void AddLibraries(EDA_BASE_FRAME *aParent)
void Sync(FOOTPRINT_LIBRARY_ADAPTER *aLibs)
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.
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:655
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition view.cpp:862
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:681
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition view.h:659
Definition kiid.h:46
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:340
void OnKiCadExit()
Definition kiway.cpp:790
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:388
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
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
wxDataViewItem FindItem(const LIB_ID &aLibId)
Returns tree item corresponding to part.
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 ExitPadEditMode()
Definition pad_tool.cpp:814
bool InPadEditMode()
Definition pad_tool.h:58
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:50
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 addConstraintVertical
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 addConstraintPerpendicular
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 addConstraintAngular
static TOOL_ACTION addConstraintArcAngle
static TOOL_ACTION angleSnapModeChanged
Notification event when angle mode changes.
static TOOL_ACTION addConstraintHorizontal
static TOOL_ACTION drawEllipse
static TOOL_ACTION ddImportFootprint
static TOOL_ACTION placeImportedGraphics
static TOOL_ACTION addConstraintCollinear
static TOOL_ACTION drawArc
static TOOL_ACTION graphicsOutlines
Display footprint graphics as outlines.
static TOOL_ACTION addConstraintEqualRadius
static TOOL_ACTION addConstraintTangent
static TOOL_ACTION loadFpFromBoard
static TOOL_ACTION drawCenterDimension
static TOOL_ACTION addConstraintFixedLength
static TOOL_ACTION footprintProperties
static TOOL_ACTION flipBoard
static TOOL_ACTION toggleAutoConstraints
Toggle authoring constraints automatically while drawing.
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 addConstraintSymmetric
static TOOL_ACTION addConstraintFixedPosition
Ground a point, and the cluster holding it.
static TOOL_ACTION mirrorV
static TOOL_ACTION addConstraintPointOnLine
static TOOL_ACTION repairFootprint
static TOOL_ACTION saveFpToBoard
static TOOL_ACTION addConstraintCoincident
static TOOL_ACTION drawLine
static TOOL_ACTION cleanupGraphics
static TOOL_ACTION rotateCw
Rotation of selected objects.
static TOOL_ACTION rotateCcw
static TOOL_ACTION addConstraintParallel
static TOOL_ACTION drawAlignedDimension
static TOOL_ACTION addConstraintFixedRadius
static TOOL_ACTION addConstraintEqualLength
static TOOL_ACTION addConstraintMidpoint
static TOOL_ACTION addConstraintConcentric
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:45
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:141
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:123
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:226
@ PCB_FOOTPRINT_EDITOR_LIB_NICKNAME
Definition project.h:227
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.
RAII class that sets an value at construction and resets it to the original value at destruction.
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.
void ResetTools(TOOL_BASE::RESET_REASON aReason)
Reset all tools (i.e.
A holder to handle a list of undo (or redo) commands.
std::vector< PICKED_ITEMS_LIST * > m_CommandsList
EDA_UNITS GetUserUnits() const
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition utf8.h:67
bool empty() const
Definition utf8.h:105
wxString wx_str() const
Definition utf8.cpp:41
A modified version of the wxInfoBar class that allows us to:
Definition wx_infobar.h:76
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
bool HasCloseButton() const
void AddLink(const wxString &aLinkText, const std::function< void(wxHyperlinkEvent &)> &aFn)
Add a hypertext link to the infobar.
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
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:69
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:422
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:424
#define KICAD_DEFAULT_DRAWFRAME_STYLE
#define FOOTPRINT_EDIT_FRAME_NAME
@ RECURSE
Definition eda_item.h:51
FOOTPRINT_STACKUP
Definition footprint.h:155
@ EXPAND_INNER_LAYERS
The 'normal' stackup handling, where there is a single inner layer (In1) and rule areas using it expa...
Definition footprint.h:160
@ CUSTOM_LAYERS
Stackup handling where the footprint can have any number of copper layers, and objects on those layer...
Definition footprint.h:165
static std::unique_ptr< BOARD > makeFpHolderBoard()
#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:113
@ ID_ON_ZOOM_SELECT
Definition id.h:112
PROJECT & Prj()
Definition kicad.cpp:727
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:785
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:521
#define _HKI(x)
Definition page_info.cpp:40
@ ID_FPEDIT_SAVE_PNG
Definition pcbnew_id.h:82
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)
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:103
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:85
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:84
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
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.