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 <dick@softplc.com>
6  * Copyright (C) 2015-2016 Wayne Stambaugh <stambaughw@gmail.com>
7  * Copyright (C) 1992-2021 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 along
20  * with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "tools/convert_tool.h"
24 #include "tools/drawing_tool.h"
25 #include "tools/edit_tool.h"
26 #include "tools/footprint_editor_control.h"
27 #include "tools/pad_tool.h"
28 #include "tools/pcb_actions.h"
29 #include "tools/pcb_control.h"
30 #include "tools/pcb_picker_tool.h"
31 #include "tools/placement_tool.h"
32 #include "tools/pcb_point_editor.h"
33 #include "tools/pcb_selection_tool.h"
34 #include <python/scripting/pcb_scripting_tool.h>
35 #include <3d_viewer/eda_3d_viewer_frame.h>
36 #include <bitmaps.h>
37 #include <board.h>
38 #include <footprint.h>
39 #include <confirm.h>
40 #include <dialogs/panel_fp_editor_color_settings.h>
41 #include <dialogs/panel_fp_editor_defaults.h>
42 #include <dialogs/panel_display_options.h>
43 #include <dialogs/panel_edit_options.h>
44 #include <footprint_edit_frame.h>
45 #include <footprint_editor_settings.h>
46 #include <footprint_info_impl.h>
47 #include <footprint_tree_pane.h>
48 #include <fp_lib_table.h>
49 #include <plugins/kicad/pcb_plugin.h>
50 #include <kiface_base.h>
51 #include <kiplatform/app.h>
52 #include <kiway.h>
53 #include <macros.h>
54 #include <panel_hotkeys_editor.h>
55 #include <pcb_draw_panel_gal.h>
56 #include <pcb_edit_frame.h>
57 #include <pcbnew.h>
58 #include <pcbnew_id.h>
59 #include <pgm_base.h>
60 #include <project.h>
61 #include <settings/settings_manager.h>
62 #include <tool/action_toolbar.h>
63 #include <tool/common_control.h>
64 #include <tool/common_tools.h>
65 #include <tool/selection.h>
66 #include <tool/tool_dispatcher.h>
67 #include <tool/tool_manager.h>
68 #include <tool/zoom_tool.h>
69 #include <tools/pcb_editor_conditions.h>
70 #include <tools/pcb_viewer_tools.h>
71 #include <tools/group_tool.h>
72 #include <tools/position_relative_tool.h>
73 #include <widgets/appearance_controls.h>
74 #include <widgets/infobar.h>
75 #include <widgets/lib_tree.h>
76 #include <widgets/paged_dialog.h>
77 #include <widgets/panel_selection_filter.h>
78 #include <widgets/wx_progress_reporters.h>
79 #include <wildcards_and_files_ext.h>
80 #include <wx/filedlg.h>
81 #include <wx/treebook.h>
82 #include <widgets/wx_aui_utils.h>
83 
BEGIN_EVENT_TABLE(FOOTPRINT_EDIT_FRAME,PCB_BASE_FRAME)84 BEGIN_EVENT_TABLE( FOOTPRINT_EDIT_FRAME, PCB_BASE_FRAME )
85     EVT_MENU( wxID_CLOSE, FOOTPRINT_EDIT_FRAME::CloseFootprintEditor )
86     EVT_MENU( wxID_EXIT, FOOTPRINT_EDIT_FRAME::OnExitKiCad )
87 
88     EVT_SIZE( FOOTPRINT_EDIT_FRAME::OnSize )
89 
90     EVT_CHOICE( ID_ON_ZOOM_SELECT, FOOTPRINT_EDIT_FRAME::OnSelectZoom )
91     EVT_CHOICE( ID_ON_GRID_SELECT, FOOTPRINT_EDIT_FRAME::OnSelectGrid )
92 
93     EVT_TOOL( ID_FPEDIT_SAVE_PNG, FOOTPRINT_EDIT_FRAME::OnSaveFootprintAsPng )
94 
95     EVT_TOOL( ID_LOAD_FOOTPRINT_FROM_BOARD, FOOTPRINT_EDIT_FRAME::LoadFootprintFromBoard )
96     EVT_TOOL( ID_ADD_FOOTPRINT_TO_BOARD, FOOTPRINT_EDIT_FRAME::SaveFootprintToBoard )
97 
98     // Horizontal toolbar
99     EVT_MENU( ID_GRID_SETTINGS, FOOTPRINT_EDIT_FRAME::OnGridSettings )
100     EVT_COMBOBOX( ID_TOOLBARH_PCB_SELECT_LAYER, FOOTPRINT_EDIT_FRAME::SelectLayer )
101 
102     // UI update events.
103     EVT_UPDATE_UI( ID_LOAD_FOOTPRINT_FROM_BOARD,
104                    FOOTPRINT_EDIT_FRAME::OnUpdateLoadFootprintFromBoard )
105     EVT_UPDATE_UI( ID_ADD_FOOTPRINT_TO_BOARD,
106                    FOOTPRINT_EDIT_FRAME::OnUpdateSaveFootprintToBoard )
107     EVT_UPDATE_UI( ID_TOOLBARH_PCB_SELECT_LAYER, FOOTPRINT_EDIT_FRAME::OnUpdateLayerSelectBox )
108 END_EVENT_TABLE()
109 
110 
111 FOOTPRINT_EDIT_FRAME::FOOTPRINT_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
112     PCB_BASE_EDIT_FRAME( aKiway, aParent, FRAME_FOOTPRINT_EDITOR, wxEmptyString,
113                          wxDefaultPosition, wxDefaultSize,
114                          KICAD_DEFAULT_DRAWFRAME_STYLE, GetFootprintEditorFrameName() ),
115     m_show_layer_manager_tools( true )
116 {
117     m_showBorderAndTitleBlock = false;   // true to show the frame references
118     m_aboutTitle = _( "KiCad Footprint Editor" );
119     m_selLayerBox = nullptr;
120     m_editorSettings = nullptr;
121 
122     // Give an icon
123     wxIcon icon;
124     wxIconBundle icon_bundle;
125 
126     icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit ) );
127     icon_bundle.AddIcon( icon );
128     icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit_32 ) );
129     icon_bundle.AddIcon( icon );
130     icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit_16 ) );
131     icon_bundle.AddIcon( icon );
132 
133     SetIcons( icon_bundle );
134 
135     // Create GAL canvas
136     m_canvasType = loadCanvasTypeSetting();
137 
138     PCB_DRAW_PANEL_GAL* drawPanel = new PCB_DRAW_PANEL_GAL( this, -1, wxPoint( 0, 0 ), m_frameSize,
139                                                             GetGalDisplayOptions(), m_canvasType );
140     SetCanvas( drawPanel );
141     SetBoard( new BOARD() );
142 
143     // This board will only be used to hold a footprint for editing
144     GetBoard()->SetBoardUse( BOARD_USE::FPHOLDER );
145 
146     // In Footprint Editor, the default net clearance is not known (it depends on the actual
147     // board).  So we do not show the default clearance, by setting it to 0.  The footprint or
148     // pad specific clearance will be shown.
149     GetBoard()->GetDesignSettings().GetDefault()->SetClearance( 0 );
150 
151     // Don't show the default board solder mask clearance in the footprint editor.  Only the
152     // footprint or pad clearance setting should be shown if it is not 0.
153     GetBoard()->GetDesignSettings().m_SolderMaskMargin = 0;
154 
155     // restore the last footprint from the project, if any
156     restoreLastFootprint();
157 
158     // Ensure all layers and items are visible:
159     // In footprint editor, some layers have no meaning or cannot be used, but we show all of
160     // them, at least to be able to edit a bad layer
161     GetBoard()->SetVisibleAlls();
162 
163     // However the "no net" mark on pads is useless, because there are no nets in footprint
164     // editor: make it non visible.
165     GetBoard()->SetElementVisibility( LAYER_NO_CONNECTS, false );
166 
167     GetGalDisplayOptions().m_axesEnabled = true;
168 
169     // In Footprint Editor, set the default paper size to A4 for plot/print
170     SetPageSettings( PAGE_INFO( PAGE_INFO::A4 ) );
171     SetScreen( new PCB_SCREEN( GetPageSettings().GetSizeIU() ) );
172 
173     // Create the manager and dispatcher & route draw panel events to the dispatcher
174     setupTools();
175     setupUIConditions();
176 
177     initLibraryTree();
178     m_treePane = new FOOTPRINT_TREE_PANE( this );
179 
180     ReCreateMenuBar();
181     ReCreateHToolbar();
182     ReCreateVToolbar();
183     ReCreateOptToolbar();
184 
185     m_selectionFilterPanel = new PANEL_SELECTION_FILTER( this );
186     m_appearancePanel = new APPEARANCE_CONTROLS( this, GetCanvas(), true );
187 
188     // LoadSettings() *after* creating m_LayersManager, because LoadSettings() initialize
189     // parameters in m_LayersManager
190     // NOTE: KifaceSettings() will return PCBNEW_SETTINGS if we started from pcbnew
191     LoadSettings( GetSettings() );
192 
193     // Must be set after calling LoadSettings() to be sure these parameters are not dependent
194     // on what is read in stored settings.  Enable one internal layer, because footprints
195     // support keepout areas that can be on internal layers only (therefore on the first internal
196     // layer).  This is needed to handle these keepout in internal layers only.
197     GetBoard()->SetCopperLayerCount( 3 );
198     GetBoard()->SetEnabledLayers( GetBoard()->GetEnabledLayers().set( In1_Cu ) );
199     GetBoard()->SetVisibleLayers( GetBoard()->GetEnabledLayers() );
200     GetBoard()->SetLayerName( In1_Cu, _( "Inner layers" ) );
201 
202     SetActiveLayer( F_SilkS );
203 
204     m_auimgr.SetManagedWindow( this );
205 
206     CreateInfoBar();
207 
208     unsigned int auiFlags = wxAUI_MGR_DEFAULT;
209 #if !defined( _WIN32 )
210     // Windows cannot redraw the UI fast enough during a live resize and may lead to all kinds
211     // of graphical glitches
212     auiFlags |= wxAUI_MGR_LIVE_RESIZE;
213 #endif
214     m_auimgr.SetFlags( auiFlags );
215 
216     // Rows; layers 4 - 6
217     m_auimgr.AddPane( m_mainToolBar, EDA_PANE().HToolbar().Name( "MainToolbar" )
218                       .Top().Layer( 6 ) );
219     m_auimgr.AddPane( m_messagePanel, EDA_PANE().Messages().Name( "MsgPanel" )
220                       .Bottom().Layer( 6 ) );
221 
222     // Columns; layers 1 - 3
223     m_auimgr.AddPane( m_optionsToolBar, EDA_PANE().VToolbar().Name( "OptToolbar" )
224                       .Left().Layer( 3 ) );
225     m_auimgr.AddPane( m_treePane, EDA_PANE().Palette().Name( "Footprints" )
226                       .Left().Layer(2)
227                       .Caption( _( "Libraries" ) )
228                       .MinSize( 250, 400 ).Resizable() );
229 
230     m_auimgr.AddPane( m_drawToolBar, EDA_PANE().VToolbar().Name( "ToolsToolbar" )
231                       .Right().Layer(2) );
232 
233     m_auimgr.AddPane( m_appearancePanel, EDA_PANE().Name( "LayersManager" )
234                       .Right().Layer( 3 )
235                       .Caption( _( "Appearance" ) ).PaneBorder( false )
236                       .MinSize( 180, -1 ).BestSize( 180, -1 ) );
237     m_auimgr.AddPane( m_selectionFilterPanel, EDA_PANE().Palette().Name( "SelectionFilter" )
238                       .Right().Layer( 3 ).Position( 2 )
239                       .Caption( _( "Selection Filter" ) ).PaneBorder( false )
240                       .MinSize( 160, -1 ).BestSize( m_selectionFilterPanel->GetBestSize() ) );
241 
242     // Center
243     m_auimgr.AddPane( GetCanvas(), EDA_PANE().Canvas().Name( "DrawFrame" )
244                       .Center() );
245 
246     m_auimgr.GetPane( "LayersManager" ).Show( m_show_layer_manager_tools );
247     m_auimgr.GetPane( "SelectionFilter" ).Show( m_show_layer_manager_tools );
248 
249     // The selection filter doesn't need to grow in the vertical direction when docked
250     m_auimgr.GetPane( "SelectionFilter" ).dock_proportion = 0;
251 
252     ActivateGalCanvas();
253 
254     FinishAUIInitialization();
255 
256     if( m_editorSettings->m_LibWidth > 0 )
257     {
258         wxAuiPaneInfo& treePane = m_auimgr.GetPane( "Footprints" );
259 
260         // wxAUI hack: force width by setting MinSize() and then Fixed()
261         // thanks to ZenJu http://trac.wxwidgets.org/ticket/13180
262         treePane.MinSize( m_editorSettings->m_LibWidth, -1 );
263         treePane.Fixed();
264         m_auimgr.Update();
265 
266         // now make it resizable again
267         treePane.Resizable();
268         m_auimgr.Update();
269 
270         // Note: DO NOT call m_auimgr.Update() anywhere after this; it will nuke the size
271         // back to minimum.
272         treePane.MinSize( 250, -1 );
273     }
274 
275     // Apply saved visibility stuff at the end
276     FOOTPRINT_EDITOR_SETTINGS* cfg = GetSettings();
277     m_appearancePanel->SetUserLayerPresets( cfg->m_LayerPresets );
278     m_appearancePanel->ApplyLayerPreset( cfg->m_ActiveLayerPreset );
279 
280     if( cfg->m_AuiPanels.right_panel_width > 0 )
281     {
282         wxAuiPaneInfo& layersManager = m_auimgr.GetPane( "LayersManager" );
283         SetAuiPaneSize( m_auimgr, layersManager, cfg->m_AuiPanels.right_panel_width, -1 );
284     }
285 
286     m_appearancePanel->SetTabIndex( cfg->m_AuiPanels.appearance_panel_tab );
287 
288     GetToolManager()->RunAction( ACTIONS::zoomFitScreen, false );
289     UpdateTitle();
290     setupUnits( GetSettings() );
291 
292     resolveCanvasType();
293 
294     // Default shutdown reason until a file is loaded
295     KIPLATFORM::APP::SetShutdownBlockReason( this, _( "Footprint changes are unsaved" ) );
296 
297     // Catch unhandled accelerator command characters that were no handled by the library tree
298     // panel.
299     Bind( wxEVT_CHAR, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
300     Bind( wxEVT_CHAR_HOOK, &TOOL_DISPATCHER::DispatchWxEvent, m_toolDispatcher );
301 
302     // Ensure the window is on top
303     Raise();
304     Show( true );
305 
306     // Register a call to update the toolbar sizes. It can't be done immediately because
307     // it seems to require some sizes calculated that aren't yet (at least on GTK).
308     CallAfter( [&]()
309                {
310                    // Ensure the controls on the toolbars all are correctly sized
311                     UpdateToolbarControlSizes();
312                } );
313 }
314 
315 
~FOOTPRINT_EDIT_FRAME()316 FOOTPRINT_EDIT_FRAME::~FOOTPRINT_EDIT_FRAME()
317 {
318     // Shutdown all running tools
319     if( m_toolManager )
320         m_toolManager->ShutdownAllTools();
321 
322     // save the footprint in the PROJECT
323     retainLastFootprint();
324 
325     delete m_selectionFilterPanel;
326     delete m_appearancePanel;
327 }
328 
329 
IsContentModified() const330 bool FOOTPRINT_EDIT_FRAME::IsContentModified() const
331 {
332     return GetScreen() && GetScreen()->IsContentModified() && GetBoard() && GetBoard()->GetFirstFootprint();
333 }
334 
335 
GetCurrentSelection()336 SELECTION& FOOTPRINT_EDIT_FRAME::GetCurrentSelection()
337 {
338     return m_toolManager->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
339 }
340 
341 
SwitchCanvas(EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType)342 void FOOTPRINT_EDIT_FRAME::SwitchCanvas( EDA_DRAW_PANEL_GAL::GAL_TYPE aCanvasType )
343 {
344     // switches currently used canvas (Cairo / OpenGL).
345     PCB_BASE_FRAME::SwitchCanvas( aCanvasType );
346 
347     GetCanvas()->GetGAL()->SetAxesEnabled( true );
348 
349     // The base class method *does not reinit* the layers manager. We must update the layer
350     // widget to match board visibility states, both layers and render columns, and and some
351     // settings dependent on the canvas.
352     UpdateUserInterface();
353 }
354 
355 
HardRedraw()356 void FOOTPRINT_EDIT_FRAME::HardRedraw()
357 {
358     SyncLibraryTree( true );
359     GetCanvas()->ForceRefresh();
360 }
361 
362 
ToggleSearchTree()363 void FOOTPRINT_EDIT_FRAME::ToggleSearchTree()
364 {
365     wxAuiPaneInfo& treePane = m_auimgr.GetPane( m_treePane );
366     treePane.Show( !IsSearchTreeShown() );
367     m_auimgr.Update();
368 }
369 
370 
ToggleLayersManager()371 void FOOTPRINT_EDIT_FRAME::ToggleLayersManager()
372 {
373     FOOTPRINT_EDITOR_SETTINGS* settings = GetSettings();
374     wxAuiPaneInfo&             layersManager = m_auimgr.GetPane( "LayersManager" );
375     wxAuiPaneInfo&             selectionFilter = m_auimgr.GetPane( "SelectionFilter" );
376 
377     // show auxiliary Vertical layers and visibility manager toolbar
378     m_show_layer_manager_tools = !m_show_layer_manager_tools;
379     layersManager.Show( m_show_layer_manager_tools );
380     selectionFilter.Show( m_show_layer_manager_tools );
381 
382     if( m_show_layer_manager_tools )
383     {
384         SetAuiPaneSize( m_auimgr, layersManager, settings->m_AuiPanels.right_panel_width, -1 );
385     }
386     else
387     {
388         settings->m_AuiPanels.right_panel_width = m_appearancePanel->GetSize().x;
389         m_auimgr.Update();
390     }
391 }
392 
393 
IsSearchTreeShown() const394 bool FOOTPRINT_EDIT_FRAME::IsSearchTreeShown() const
395 {
396     return const_cast<wxAuiManager&>( m_auimgr ).GetPane( m_treePane ).IsShown();
397 }
398 
399 
GetModel() const400 BOARD_ITEM_CONTAINER* FOOTPRINT_EDIT_FRAME::GetModel() const
401 {
402     return GetBoard()->GetFirstFootprint();
403 }
404 
405 
GetTreeFPID() const406 LIB_ID FOOTPRINT_EDIT_FRAME::GetTreeFPID() const
407 {
408     return m_treePane->GetLibTree()->GetSelectedLibId();
409 }
410 
411 
GetCurrentTreeNode() const412 LIB_TREE_NODE* FOOTPRINT_EDIT_FRAME::GetCurrentTreeNode() const
413 {
414     return m_treePane->GetLibTree()->GetCurrentTreeNode();
415 }
416 
417 
GetTargetFPID() const418 LIB_ID FOOTPRINT_EDIT_FRAME::GetTargetFPID() const
419 {
420     LIB_ID id;
421 
422     if( IsSearchTreeShown() )
423         id = GetTreeFPID();
424 
425     if( id.GetLibNickname().empty() )
426         id = GetLoadedFPID();
427 
428     return id;
429 }
430 
431 
GetLoadedFPID() const432 LIB_ID FOOTPRINT_EDIT_FRAME::GetLoadedFPID() const
433 {
434     FOOTPRINT* footprint = GetBoard()->GetFirstFootprint();
435 
436     if( footprint )
437         return LIB_ID( footprint->GetFPID().GetLibNickname(), m_footprintNameWhenLoaded );
438     else
439         return LIB_ID();
440 }
441 
442 
ClearModify()443 void FOOTPRINT_EDIT_FRAME::ClearModify()
444 {
445     if( GetBoard()->GetFirstFootprint() )
446         m_footprintNameWhenLoaded = GetBoard()->GetFirstFootprint()->GetFPID().GetLibItemName();
447 
448     GetScreen()->SetContentModified( false );
449 }
450 
451 
IsCurrentFPFromBoard() const452 bool FOOTPRINT_EDIT_FRAME::IsCurrentFPFromBoard() const
453 {
454     FOOTPRINT* footprint = GetBoard()->GetFirstFootprint();
455 
456     return ( footprint && footprint->GetLink() != niluuid );
457 }
458 
459 
retainLastFootprint()460 void FOOTPRINT_EDIT_FRAME::retainLastFootprint()
461 {
462     LIB_ID id = GetLoadedFPID();
463 
464     if( id.IsValid() )
465     {
466         Prj().SetRString( PROJECT::PCB_FOOTPRINT_EDITOR_LIB_NICKNAME, id.GetLibNickname() );
467         Prj().SetRString( PROJECT::PCB_FOOTPRINT_EDITOR_FP_NAME, id.GetLibItemName() );
468     }
469 }
470 
471 
restoreLastFootprint()472 void FOOTPRINT_EDIT_FRAME::restoreLastFootprint()
473 {
474     const wxString& footprintName = Prj().GetRString( PROJECT::PCB_FOOTPRINT_EDITOR_FP_NAME );
475     const wxString& libNickname =  Prj().GetRString( PROJECT::PCB_FOOTPRINT_EDITOR_LIB_NICKNAME );
476 
477     if( libNickname.Length() && footprintName.Length() )
478     {
479         LIB_ID id;
480         id.SetLibNickname( libNickname );
481         id.SetLibItemName( footprintName );
482 
483         FOOTPRINT* footprint = loadFootprint( id );
484 
485         if( footprint )
486             AddFootprintToBoard( footprint );
487     }
488 }
489 
490 
AddFootprintToBoard(FOOTPRINT * aFootprint)491 void FOOTPRINT_EDIT_FRAME::AddFootprintToBoard( FOOTPRINT* aFootprint )
492 {
493     m_revertModule.reset( (FOOTPRINT*) aFootprint->Clone() );
494 
495     m_footprintNameWhenLoaded = aFootprint->GetFPID().GetLibItemName();
496 
497     PCB_BASE_EDIT_FRAME::AddFootprintToBoard( aFootprint );
498     // Ensure item UUIDs are valide
499     // ("old" footprints can have null uuids that create issues in fp editor)
500     aFootprint->FixUuids();
501 
502     if( IsCurrentFPFromBoard() )
503     {
504         wxString msg;
505         msg.Printf( _( "Editing %s from board.  Saving will update the board only." ),
506                     aFootprint->GetReference() );
507 
508         GetInfoBar()->RemoveAllButtons();
509         GetInfoBar()->AddCloseButton();
510         GetInfoBar()->ShowMessage( msg, wxICON_INFORMATION );
511     }
512 
513     UpdateMsgPanel();
514 }
515 
516 
GetFootprintEditorFrameName()517 const wxChar* FOOTPRINT_EDIT_FRAME::GetFootprintEditorFrameName()
518 {
519     return FOOTPRINT_EDIT_FRAME_NAME;
520 }
521 
522 
GetDesignSettings() const523 BOARD_DESIGN_SETTINGS& FOOTPRINT_EDIT_FRAME::GetDesignSettings() const
524 {
525     return GetBoard()->GetDesignSettings();
526 }
527 
528 
GetPlotSettings() const529 const PCB_PLOT_PARAMS& FOOTPRINT_EDIT_FRAME::GetPlotSettings() const
530 {
531     wxFAIL_MSG( "Plotting not supported in Footprint Editor" );
532 
533     return PCB_BASE_FRAME::GetPlotSettings();
534 }
535 
536 
SetPlotSettings(const PCB_PLOT_PARAMS & aSettings)537 void FOOTPRINT_EDIT_FRAME::SetPlotSettings( const PCB_PLOT_PARAMS& aSettings )
538 {
539     wxFAIL_MSG( "Plotting not supported in Footprint Editor" );
540 }
541 
542 
GetSettings()543 FOOTPRINT_EDITOR_SETTINGS* FOOTPRINT_EDIT_FRAME::GetSettings()
544 {
545     if( !m_editorSettings )
546         m_editorSettings = Pgm().GetSettingsManager().GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>();
547 
548     return m_editorSettings;
549 }
550 
551 
config() const552 APP_SETTINGS_BASE* FOOTPRINT_EDIT_FRAME::config() const
553 {
554     return m_editorSettings ? m_editorSettings
555                             : Pgm().GetSettingsManager().GetAppSettings<FOOTPRINT_EDITOR_SETTINGS>();
556 }
557 
558 
LoadSettings(APP_SETTINGS_BASE * aCfg)559 void FOOTPRINT_EDIT_FRAME::LoadSettings( APP_SETTINGS_BASE* aCfg )
560 {
561     // aCfg will be the PCBNEW_SETTINGS
562     FOOTPRINT_EDITOR_SETTINGS* cfg = GetSettings();
563 
564     PCB_BASE_FRAME::LoadSettings( cfg );
565 
566     GetDesignSettings() = cfg->m_DesignSettings;
567 
568     m_displayOptions = cfg->m_Display;
569     m_show_layer_manager_tools = cfg->m_AuiPanels.show_layer_manager;
570 
571     GetToolManager()->GetTool<PCB_SELECTION_TOOL>()->GetFilter() = cfg->m_SelectionFilter;
572     m_selectionFilterPanel->SetCheckboxesFromFilter( cfg->m_SelectionFilter );
573 }
574 
575 
SaveSettings(APP_SETTINGS_BASE * aCfg)576 void FOOTPRINT_EDIT_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg )
577 {
578     GetGalDisplayOptions().m_axesEnabled = true;
579 
580     // aCfg will be the PCBNEW_SETTINGS
581     FOOTPRINT_EDITOR_SETTINGS* cfg = GetSettings();
582 
583     PCB_BASE_FRAME::SaveSettings( cfg );
584 
585     cfg->m_DesignSettings    = GetDesignSettings();
586     cfg->m_Display           = m_displayOptions;
587     cfg->m_LibWidth          = m_treePane->GetSize().x;
588     cfg->m_SelectionFilter   = GetToolManager()->GetTool<PCB_SELECTION_TOOL>()->GetFilter();
589     cfg->m_LayerPresets      = m_appearancePanel->GetUserLayerPresets();
590     cfg->m_ActiveLayerPreset = m_appearancePanel->GetActiveLayerPreset();
591 
592     cfg->m_AuiPanels.show_layer_manager   = m_show_layer_manager_tools;
593     cfg->m_AuiPanels.right_panel_width    = m_appearancePanel->GetSize().x;
594     cfg->m_AuiPanels.appearance_panel_tab = m_appearancePanel->GetTabIndex();
595 
596     GetSettingsManager()->SaveColorSettings( GetColorSettings(), "board" );
597 }
598 
599 
GetColorSettings() const600 COLOR_SETTINGS* FOOTPRINT_EDIT_FRAME::GetColorSettings() const
601 {
602     wxString currentTheme = GetFootprintEditorSettings()->m_ColorTheme;
603     return Pgm().GetSettingsManager().GetColorSettings( currentTheme );
604 }
605 
606 
GetMagneticItemsSettings()607 MAGNETIC_SETTINGS* FOOTPRINT_EDIT_FRAME::GetMagneticItemsSettings()
608 {
609     // Get the actual frame settings for magnetic items
610     FOOTPRINT_EDITOR_SETTINGS* cfg = GetSettings();
611     wxCHECK( cfg, nullptr );
612     return &cfg->m_MagneticItems;
613 }
614 
615 
GetDocumentExtents(bool aIncludeAllVisible) const616 const BOX2I FOOTPRINT_EDIT_FRAME::GetDocumentExtents( bool aIncludeAllVisible ) const
617 {
618     FOOTPRINT* footprint = GetBoard()->GetFirstFootprint();
619 
620     if( footprint )
621     {
622         bool hasGraphicalItem = footprint->Pads().size() || footprint->Zones().size();
623 
624         if( !hasGraphicalItem )
625         {
626             for( const BOARD_ITEM* item : footprint->GraphicalItems() )
627             {
628                 if( item->Type() == PCB_FP_TEXT_T )
629                     continue;
630 
631                 hasGraphicalItem = true;
632                 break;
633             }
634         }
635 
636         if( hasGraphicalItem )
637         {
638             return footprint->GetBoundingBox( false, false );
639         }
640         else
641         {
642             BOX2I newFootprintBB( { 0, 0 }, { 0, 0 } );
643             newFootprintBB.Inflate( Millimeter2iu( 12 ) );
644             return newFootprintBB;
645         }
646     }
647 
648     return GetBoardBoundingBox( false );
649 }
650 
651 
canCloseWindow(wxCloseEvent & aEvent)652 bool FOOTPRINT_EDIT_FRAME::canCloseWindow( wxCloseEvent& aEvent )
653 {
654     if( IsContentModified() )
655     {
656         // Shutdown blocks must be determined and vetoed as early as possible
657         if( KIPLATFORM::APP::SupportsShutdownBlockReason() &&
658             aEvent.GetId() == wxEVT_QUERY_END_SESSION )
659         {
660             aEvent.Veto();
661             return false;
662         }
663 
664         wxString footprintName = GetBoard()->GetFirstFootprint()->GetFPID().GetLibItemName();
665         wxString msg = _( "Save changes to '%s' before closing?" );
666 
667         if( !HandleUnsavedChanges( this, wxString::Format( msg, footprintName ),
668                                    [&]() -> bool
669                                    {
670                                        return SaveFootprint( GetBoard()->GetFirstFootprint() );
671                                    } ) )
672         {
673             aEvent.Veto();
674             return false;
675         }
676     }
677 
678     return PCB_BASE_EDIT_FRAME::canCloseWindow( aEvent );
679 }
680 
681 
doCloseWindow()682 void FOOTPRINT_EDIT_FRAME::doCloseWindow()
683 {
684     // No more vetos
685     GetCanvas()->SetEventDispatcher( nullptr );
686     GetCanvas()->StopDrawing();
687 
688     // Do not show the layer manager during closing to avoid flicker
689     // on some platforms (Windows) that generate useless redraw of items in
690     // the Layer Manager
691     m_auimgr.GetPane( "LayersManager" ).Show( false );
692     m_auimgr.GetPane( "SelectionFilter" ).Show( false );
693 
694     Clear_Pcb( false );
695 
696     SETTINGS_MANAGER* mgr = GetSettingsManager();
697 
698     if( mgr->IsProjectOpen() && wxFileName::IsDirWritable( Prj().GetProjectPath() ) )
699     {
700         GFootprintList.WriteCacheToFile( Prj().GetProjectPath() + "fp-info-cache" );
701     }
702 
703     mgr->FlushAndRelease( GetSettings() );
704 }
705 
706 
OnExitKiCad(wxCommandEvent & event)707 void FOOTPRINT_EDIT_FRAME::OnExitKiCad( wxCommandEvent& event )
708 {
709     Kiway().OnKiCadExit();
710 }
711 
712 
CloseFootprintEditor(wxCommandEvent & Event)713 void FOOTPRINT_EDIT_FRAME::CloseFootprintEditor( wxCommandEvent& Event )
714 {
715     Close();
716 }
717 
718 
OnUpdateLoadFootprintFromBoard(wxUpdateUIEvent & aEvent)719 void FOOTPRINT_EDIT_FRAME::OnUpdateLoadFootprintFromBoard( wxUpdateUIEvent& aEvent )
720 {
721     PCB_EDIT_FRAME* frame = (PCB_EDIT_FRAME*) Kiway().Player( FRAME_PCB_EDITOR, false );
722 
723     aEvent.Enable( frame && frame->GetBoard()->GetFirstFootprint() != nullptr );
724 }
725 
726 
OnUpdateSaveFootprintToBoard(wxUpdateUIEvent & aEvent)727 void FOOTPRINT_EDIT_FRAME::OnUpdateSaveFootprintToBoard( wxUpdateUIEvent& aEvent )
728 {
729     PCB_EDIT_FRAME* frame = (PCB_EDIT_FRAME*) Kiway().Player( FRAME_PCB_EDITOR, false );
730 
731     FOOTPRINT* editorFootprint = GetBoard()->GetFirstFootprint();
732     bool       canInsert = frame && editorFootprint && editorFootprint->GetLink() == niluuid;
733 
734     // If the source was deleted, the footprint can inserted but not updated in the board.
735     if( frame && editorFootprint && editorFootprint->GetLink() != niluuid )
736     {
737         BOARD*  mainpcb = frame->GetBoard();
738         canInsert = true;
739 
740         // search if the source footprint was not deleted:
741         for( FOOTPRINT* candidate : mainpcb->Footprints() )
742         {
743             if( editorFootprint->GetLink() == candidate->m_Uuid )
744             {
745                 canInsert = false;
746                 break;
747             }
748         }
749     }
750 
751     aEvent.Enable( canInsert );
752 }
753 
754 
ShowChangedLanguage()755 void FOOTPRINT_EDIT_FRAME::ShowChangedLanguage()
756 {
757     // call my base class
758     PCB_BASE_EDIT_FRAME::ShowChangedLanguage();
759 
760     // We have 2 panes to update.
761     // For some obscure reason, the AUI manager hides the first modified pane.
762     // So force show panes
763     wxAuiPaneInfo& tree_pane_info = m_auimgr.GetPane( m_treePane );
764     bool tree_shown = tree_pane_info.IsShown();
765     tree_pane_info.Caption( _( "Libraries" ) );
766 
767     wxAuiPaneInfo& lm_pane_info = m_auimgr.GetPane( m_appearancePanel );
768     bool lm_shown = lm_pane_info.IsShown();
769     lm_pane_info.Caption( _( "Appearance" ) );
770 
771     // update the layer manager
772     m_appearancePanel->OnBoardChanged();
773     UpdateUserInterface();
774 
775     // Now restore the visibility:
776     lm_pane_info.Show( lm_shown );
777     tree_pane_info.Show( tree_shown );
778     m_auimgr.Update();
779 }
780 
781 
OnModify()782 void FOOTPRINT_EDIT_FRAME::OnModify()
783 {
784     PCB_BASE_FRAME::OnModify();
785     Update3DView( true, true );
786     m_treePane->GetLibTree()->RefreshLibTree();
787 
788     if( !GetTitle().StartsWith( "*" ) )
789         UpdateTitle();
790 }
791 
792 
UpdateTitle()793 void FOOTPRINT_EDIT_FRAME::UpdateTitle()
794 {
795     wxString   title;
796     LIB_ID     fpid = GetLoadedFPID();
797     FOOTPRINT* footprint = GetBoard()->GetFirstFootprint();
798     bool       writable = true;
799 
800     if( IsCurrentFPFromBoard() )
801     {
802         if( IsContentModified() )
803             title = wxT( "*" );
804 
805         title += footprint->GetReference();
806         title += wxS( " " ) + wxString::Format( _( "[from %s]" ),
807                                                 Prj().GetProjectName() + "." + PcbFileExtension );
808     }
809     else if( fpid.IsValid() )
810     {
811         try
812         {
813             writable = Prj().PcbFootprintLibs()->IsFootprintLibWritable( fpid.GetLibNickname() );
814         }
815         catch( const IO_ERROR& )
816         {
817             // best efforts...
818         }
819 
820         // Note: don't used GetLoadedFPID(); footprint name may have been edited
821         if( IsContentModified() )
822             title = wxT( "*" );
823 
824         title += FROM_UTF8( footprint->GetFPID().Format().c_str() );
825 
826         if( !writable )
827             title += wxS( " " ) + _( "[Read Only]" );
828     }
829     else if( !fpid.GetLibItemName().empty() )
830     {
831         // Note: don't used GetLoadedFPID(); footprint name may have been edited
832         if( IsContentModified() )
833             title = wxT( "*" );
834 
835         title += FROM_UTF8( footprint->GetFPID().GetLibItemName().c_str() );
836         title += wxS( " " ) + _( "[Unsaved]" );
837     }
838     else
839     {
840         title = _( "[no footprint loaded]" );
841     }
842 
843     title += wxT( " \u2014 " ) + _( "Footprint Editor" );
844 
845     SetTitle( title );
846 }
847 
848 
UpdateUserInterface()849 void FOOTPRINT_EDIT_FRAME::UpdateUserInterface()
850 {
851     m_appearancePanel->OnBoardChanged();
852 }
853 
854 
UpdateView()855 void FOOTPRINT_EDIT_FRAME::UpdateView()
856 {
857     GetCanvas()->UpdateColors();
858     GetCanvas()->DisplayBoard( GetBoard() );
859     m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD );
860     UpdateTitle();
861 }
862 
863 
initLibraryTree()864 void FOOTPRINT_EDIT_FRAME::initLibraryTree()
865 {
866     FP_LIB_TABLE*   fpTable = Prj().PcbFootprintLibs();
867 
868     WX_PROGRESS_REPORTER progressReporter( this, _( "Loading Footprint Libraries" ), 2 );
869 
870     if( GFootprintList.GetCount() == 0 )
871         GFootprintList.ReadCacheFromFile( Prj().GetProjectPath() + "fp-info-cache" );
872 
873     GFootprintList.ReadFootprintFiles( fpTable, nullptr, &progressReporter );
874     progressReporter.Show( false );
875 
876     if( GFootprintList.GetErrorCount() )
877         GFootprintList.DisplayErrors( this );
878 
879     m_adapter = FP_TREE_SYNCHRONIZING_ADAPTER::Create( this, fpTable );
880     auto adapter = static_cast<FP_TREE_SYNCHRONIZING_ADAPTER*>( m_adapter.get() );
881 
882     adapter->AddLibraries();
883 }
884 
885 
SyncLibraryTree(bool aProgress)886 void FOOTPRINT_EDIT_FRAME::SyncLibraryTree( bool aProgress )
887 {
888     FP_LIB_TABLE* fpTable = Prj().PcbFootprintLibs();
889     auto          adapter = static_cast<FP_TREE_SYNCHRONIZING_ADAPTER*>( m_adapter.get() );
890     LIB_ID        target = GetTargetFPID();
891     bool          targetSelected = ( target == m_treePane->GetLibTree()->GetSelectedLibId() );
892 
893     // Sync FOOTPRINT_INFO list to the libraries on disk
894     if( aProgress )
895     {
896         WX_PROGRESS_REPORTER progressReporter( this, _( "Updating Footprint Libraries" ), 2 );
897         GFootprintList.ReadFootprintFiles( fpTable, nullptr, &progressReporter );
898         progressReporter.Show( false );
899     }
900     else
901     {
902         GFootprintList.ReadFootprintFiles( fpTable, nullptr, nullptr );
903     }
904 
905     // Sync the LIB_TREE to the FOOTPRINT_INFO list
906     adapter->Sync();
907 
908     m_treePane->GetLibTree()->Unselect();
909     m_treePane->GetLibTree()->Regenerate( true );
910 
911     if( target.IsValid() )
912     {
913         if( adapter->FindItem( target ) )
914         {
915             if( targetSelected )
916                 m_treePane->GetLibTree()->SelectLibId( target );
917             else
918                 m_treePane->GetLibTree()->CenterLibId( target );
919         }
920         else
921         {
922             // Try to focus on parent
923             target.SetLibItemName( wxEmptyString );
924             m_treePane->GetLibTree()->CenterLibId( target );
925         }
926     }
927 }
928 
929 
RegenerateLibraryTree()930 void FOOTPRINT_EDIT_FRAME::RegenerateLibraryTree()
931 {
932     LIB_ID target = GetTargetFPID();
933 
934     m_treePane->GetLibTree()->Regenerate( true );
935 
936     if( target.IsValid() )
937         m_treePane->GetLibTree()->CenterLibId( target );
938 }
939 
940 
RefreshLibraryTree()941 void FOOTPRINT_EDIT_FRAME::RefreshLibraryTree()
942 {
943     m_treePane->GetLibTree()->RefreshLibTree();
944 }
945 
946 
FocusOnLibID(const LIB_ID & aLibID)947 void FOOTPRINT_EDIT_FRAME::FocusOnLibID( const LIB_ID& aLibID )
948 {
949     m_treePane->GetLibTree()->SelectLibId( aLibID );
950 }
951 
952 
OnDisplayOptionsChanged()953 void FOOTPRINT_EDIT_FRAME::OnDisplayOptionsChanged()
954 {
955     m_appearancePanel->UpdateDisplayOptions();
956 }
957 
958 
InstallPreferences(PAGED_DIALOG * aParent,PANEL_HOTKEYS_EDITOR * aHotkeysPanel)959 void FOOTPRINT_EDIT_FRAME::InstallPreferences( PAGED_DIALOG* aParent,
960                                                PANEL_HOTKEYS_EDITOR* aHotkeysPanel )
961 {
962     wxTreebook* book = aParent->GetTreebook();
963 
964     book->AddPage( new wxPanel( book ), _( "Footprint Editor" ) );
965     book->AddSubPage( new PANEL_DISPLAY_OPTIONS( this, aParent ), _( "Display Options" ) );
966     book->AddSubPage( new PANEL_EDIT_OPTIONS( this, aParent ), _( "Editing Options" ) );
967     book->AddSubPage( new PANEL_FP_EDITOR_COLOR_SETTINGS( this, book ), _( "Colors" ) );
968     book->AddSubPage( new PANEL_FP_EDITOR_DEFAULTS( this, aParent ), _( "Default Values" ) );
969 
970     aHotkeysPanel->AddHotKeys( GetToolManager() );
971 }
972 
973 
setupTools()974 void FOOTPRINT_EDIT_FRAME::setupTools()
975 {
976     // Create the manager and dispatcher & route draw panel events to the dispatcher
977     m_toolManager = new TOOL_MANAGER;
978     m_toolManager->SetEnvironment( GetBoard(), GetCanvas()->GetView(),
979                                    GetCanvas()->GetViewControls(), config(), this );
980     m_actions = new PCB_ACTIONS();
981     m_toolDispatcher = new TOOL_DISPATCHER( m_toolManager );
982 
983     GetCanvas()->SetEventDispatcher( m_toolDispatcher );
984 
985     m_toolManager->RegisterTool( new COMMON_CONTROL );
986     m_toolManager->RegisterTool( new COMMON_TOOLS );
987     m_toolManager->RegisterTool( new PCB_SELECTION_TOOL );
988     m_toolManager->RegisterTool( new ZOOM_TOOL );
989     m_toolManager->RegisterTool( new EDIT_TOOL );
990     m_toolManager->RegisterTool( new PAD_TOOL );
991     m_toolManager->RegisterTool( new DRAWING_TOOL );
992     m_toolManager->RegisterTool( new PCB_POINT_EDITOR );
993     m_toolManager->RegisterTool( new PCB_CONTROL );            // copy/paste
994     m_toolManager->RegisterTool( new FOOTPRINT_EDITOR_CONTROL );
995     m_toolManager->RegisterTool( new ALIGN_DISTRIBUTE_TOOL );
996     m_toolManager->RegisterTool( new PCB_PICKER_TOOL );
997     m_toolManager->RegisterTool( new POSITION_RELATIVE_TOOL );
998     m_toolManager->RegisterTool( new PCB_VIEWER_TOOLS );
999     m_toolManager->RegisterTool( new GROUP_TOOL );
1000     m_toolManager->RegisterTool( new CONVERT_TOOL );
1001     m_toolManager->RegisterTool( new SCRIPTING_TOOL );
1002 
1003     m_toolManager->GetTool<PCB_SELECTION_TOOL>()->SetIsFootprintEditor( true );
1004     m_toolManager->GetTool<EDIT_TOOL>()->SetIsFootprintEditor( true );
1005     m_toolManager->GetTool<PAD_TOOL>()->SetIsFootprintEditor( true );
1006     m_toolManager->GetTool<DRAWING_TOOL>()->SetIsFootprintEditor( true );
1007     m_toolManager->GetTool<PCB_POINT_EDITOR>()->SetIsFootprintEditor( true );
1008     m_toolManager->GetTool<PCB_CONTROL>()->SetIsFootprintEditor( true );
1009     m_toolManager->GetTool<PCB_PICKER_TOOL>()->SetIsFootprintEditor( true );
1010     m_toolManager->GetTool<POSITION_RELATIVE_TOOL>()->SetIsFootprintEditor( true );
1011     m_toolManager->GetTool<GROUP_TOOL>()->SetIsFootprintEditor( true );
1012     m_toolManager->GetTool<SCRIPTING_TOOL>()->SetIsFootprintEditor( true );
1013 
1014     m_toolManager->GetTool<PCB_VIEWER_TOOLS>()->SetFootprintFrame( true );
1015     m_toolManager->InitTools();
1016 
1017     m_toolManager->InvokeTool( "pcbnew.InteractiveSelection" );
1018 }
1019 
1020 
setupUIConditions()1021 void FOOTPRINT_EDIT_FRAME::setupUIConditions()
1022 {
1023     PCB_BASE_EDIT_FRAME::setupUIConditions();
1024 
1025     ACTION_MANAGER*       mgr = m_toolManager->GetActionManager();
1026     PCB_EDITOR_CONDITIONS cond( this );
1027 
1028     wxASSERT( mgr );
1029 
1030 #define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
1031 #define CHECK( x )  ACTION_CONDITIONS().Check( x )
1032 
1033     auto haveFootprintCond =
1034             [this]( const SELECTION& )
1035             {
1036                 return GetBoard()->GetFirstFootprint() != nullptr;
1037             };
1038 
1039     auto footprintTargettedCond =
1040             [this]( const SELECTION& )
1041             {
1042                 return !GetTargetFPID().GetLibItemName().empty();
1043             };
1044 
1045     mgr->SetConditions( ACTIONS::saveAs,                 ENABLE( footprintTargettedCond ) );
1046     mgr->SetConditions( ACTIONS::revert,                 ENABLE( cond.ContentModified() ) );
1047     mgr->SetConditions( ACTIONS::save,                   ENABLE( SELECTION_CONDITIONS::ShowAlways ) );
1048 
1049     mgr->SetConditions( ACTIONS::undo,                   ENABLE( cond.UndoAvailable() ) );
1050     mgr->SetConditions( ACTIONS::redo,                   ENABLE( cond.RedoAvailable() ) );
1051 
1052     mgr->SetConditions( ACTIONS::toggleGrid,             CHECK( cond.GridVisible() ) );
1053     mgr->SetConditions( ACTIONS::toggleCursorStyle,      CHECK( cond.FullscreenCursor() ) );
1054     mgr->SetConditions( ACTIONS::millimetersUnits,       CHECK( cond.Units( EDA_UNITS::MILLIMETRES ) ) );
1055     mgr->SetConditions( ACTIONS::inchesUnits,            CHECK( cond.Units( EDA_UNITS::INCHES ) ) );
1056     mgr->SetConditions( ACTIONS::milsUnits,              CHECK( cond.Units( EDA_UNITS::MILS ) ) );
1057 
1058     mgr->SetConditions( ACTIONS::cut,                    ENABLE( cond.HasItems() ) );
1059     mgr->SetConditions( ACTIONS::copy,                   ENABLE( cond.HasItems() ) );
1060     mgr->SetConditions( ACTIONS::paste,                  ENABLE( SELECTION_CONDITIONS::Idle && cond.NoActiveTool() ) );
1061     mgr->SetConditions( ACTIONS::pasteSpecial,           ENABLE( SELECTION_CONDITIONS::Idle && cond.NoActiveTool() ) );
1062     mgr->SetConditions( ACTIONS::doDelete,               ENABLE( cond.HasItems() ) );
1063     mgr->SetConditions( ACTIONS::duplicate,              ENABLE( cond.HasItems() ) );
1064     mgr->SetConditions( ACTIONS::selectAll,              ENABLE( cond.HasItems() ) );
1065 
1066     auto haveAtLeastOneGroupCond =
1067             []( const SELECTION& aSel )
1068             {
1069                 for( EDA_ITEM* item : aSel )
1070                 {
1071                     if( item->Type() == PCB_GROUP_T )
1072                         return true;
1073                 }
1074 
1075                 return false;
1076             };
1077 
1078     mgr->SetConditions( PCB_ACTIONS::rotateCw,           ENABLE( cond.HasItems() ) );
1079     mgr->SetConditions( PCB_ACTIONS::rotateCcw,          ENABLE( cond.HasItems() ) );
1080     mgr->SetConditions( PCB_ACTIONS::mirror,             ENABLE( cond.HasItems() ) );
1081     mgr->SetConditions( PCB_ACTIONS::group,              ENABLE( SELECTION_CONDITIONS::MoreThan( 1 ) ) );
1082     mgr->SetConditions( PCB_ACTIONS::ungroup,            ENABLE( haveAtLeastOneGroupCond ) );
1083 
1084     mgr->SetConditions( PCB_ACTIONS::padDisplayMode,     CHECK( !cond.PadFillDisplay() ) );
1085     mgr->SetConditions( PCB_ACTIONS::textOutlines,       CHECK( !cond.TextFillDisplay() ) );
1086     mgr->SetConditions( PCB_ACTIONS::graphicsOutlines,   CHECK( !cond.GraphicsFillDisplay() ) );
1087 
1088     mgr->SetConditions( ACTIONS::zoomTool,               CHECK( cond.CurrentTool( ACTIONS::zoomTool ) ) );
1089     mgr->SetConditions( ACTIONS::selectionTool,          CHECK( cond.CurrentTool( ACTIONS::selectionTool ) ) );
1090 
1091     mgr->SetConditions( PCB_ACTIONS::checkFootprint,     ENABLE( cond.HasItems() ) );
1092     mgr->SetConditions( PCB_ACTIONS::repairFootprint,    ENABLE( cond.HasItems() ) );
1093 
1094 
1095     auto highContrastCond =
1096             [this]( const SELECTION& )
1097             {
1098                 return GetDisplayOptions().m_ContrastModeDisplay != HIGH_CONTRAST_MODE::NORMAL;
1099             };
1100 
1101     auto boardFlippedCond =
1102             [this]( const SELECTION& )
1103             {
1104                 return GetCanvas()->GetView()->IsMirroredX();
1105             };
1106 
1107     auto footprintTreeCond =
1108             [this](const SELECTION& )
1109             {
1110                 return IsSearchTreeShown();
1111             };
1112 
1113     auto layerManagerCond =
1114             [this]( const SELECTION& )
1115             {
1116                 return m_auimgr.GetPane( "LayersManager" ).IsShown();
1117             };
1118 
1119     mgr->SetConditions( ACTIONS::highContrastMode,          CHECK( highContrastCond ) );
1120     mgr->SetConditions( PCB_ACTIONS::flipBoard,             CHECK( boardFlippedCond ) );
1121     mgr->SetConditions( PCB_ACTIONS::showFootprintTree,     CHECK( footprintTreeCond ) );
1122     mgr->SetConditions( PCB_ACTIONS::showLayersManager,     CHECK( layerManagerCond ) );
1123 
1124     mgr->SetConditions( ACTIONS::print,                     ENABLE( haveFootprintCond ) );
1125     mgr->SetConditions( PCB_ACTIONS::exportFootprint,       ENABLE( haveFootprintCond ) );
1126     mgr->SetConditions( PCB_ACTIONS::footprintProperties,   ENABLE( haveFootprintCond ) );
1127     mgr->SetConditions( PCB_ACTIONS::cleanupGraphics,       ENABLE( haveFootprintCond ) );
1128     mgr->SetConditions( PCB_ACTIONS::placeImportedGraphics, ENABLE( haveFootprintCond ) );
1129 
1130 
1131 // Only enable a tool if the part is edtable
1132 #define CURRENT_EDIT_TOOL( action ) mgr->SetConditions( action, \
1133                                     ACTION_CONDITIONS().Enable( haveFootprintCond ).Check( cond.CurrentTool( action ) ) )
1134 
1135     CURRENT_EDIT_TOOL( ACTIONS::deleteTool );
1136     CURRENT_EDIT_TOOL( ACTIONS::measureTool );
1137     CURRENT_EDIT_TOOL( PCB_ACTIONS::placePad );
1138     CURRENT_EDIT_TOOL( PCB_ACTIONS::drawLine );
1139     CURRENT_EDIT_TOOL( PCB_ACTIONS::drawRectangle );
1140     CURRENT_EDIT_TOOL( PCB_ACTIONS::drawCircle );
1141     CURRENT_EDIT_TOOL( PCB_ACTIONS::drawArc );
1142     CURRENT_EDIT_TOOL( PCB_ACTIONS::drawPolygon );
1143     CURRENT_EDIT_TOOL( PCB_ACTIONS::drawRuleArea );
1144     CURRENT_EDIT_TOOL( PCB_ACTIONS::placeText );
1145     CURRENT_EDIT_TOOL( PCB_ACTIONS::setAnchor );
1146     CURRENT_EDIT_TOOL( PCB_ACTIONS::gridSetOrigin );
1147 
1148 #undef CURRENT_EDIT_TOOL
1149 #undef ENABLE
1150 #undef CHECK
1151 }
1152 
1153 
ActivateGalCanvas()1154 void FOOTPRINT_EDIT_FRAME::ActivateGalCanvas()
1155 {
1156     PCB_BASE_EDIT_FRAME::ActivateGalCanvas();
1157 
1158     // Be sure the axis are enabled
1159     GetCanvas()->GetGAL()->SetAxesEnabled( true );
1160 
1161     UpdateView();
1162 
1163     // Ensure the m_Layers settings are using the canvas type:
1164     UpdateUserInterface();
1165 }
1166 
1167 
CommonSettingsChanged(bool aEnvVarsChanged,bool aTextVarsChanged)1168 void FOOTPRINT_EDIT_FRAME::CommonSettingsChanged( bool aEnvVarsChanged, bool aTextVarsChanged )
1169 {
1170     PCB_BASE_EDIT_FRAME::CommonSettingsChanged( aEnvVarsChanged, aTextVarsChanged );
1171 
1172     GetCanvas()->GetView()->UpdateAllLayersColor();
1173     GetCanvas()->ForceRefresh();
1174 
1175     UpdateUserInterface();
1176 
1177     if( aEnvVarsChanged )
1178         SyncLibraryTree( true );
1179 
1180     Layout();
1181     SendSizeEvent();
1182 }
1183 
1184 
OnSaveFootprintAsPng(wxCommandEvent & event)1185 void FOOTPRINT_EDIT_FRAME::OnSaveFootprintAsPng( wxCommandEvent& event )
1186 {
1187     wxString   fullFileName;
1188 
1189     LIB_ID id = GetLoadedFPID();
1190 
1191     if( id.empty() )
1192     {
1193         wxMessageBox( _( "No footprint selected." ) );
1194         return;
1195     }
1196 
1197     wxFileName fn( id.GetLibItemName() );
1198     fn.SetExt( "png" );
1199 
1200     wxString projectPath = wxPathOnly( Prj().GetProjectFullName() );
1201 
1202     wxFileDialog dlg( this, _( "Footprint Image File Name" ), projectPath,
1203                       fn.GetFullName(), PngFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1204 
1205     if( dlg.ShowModal() == wxID_CANCEL || dlg.GetPath().IsEmpty() )
1206         return;
1207 
1208     // calling wxYield is mandatory under Linux, after closing the file selector dialog
1209     // to refresh the screen before creating the PNG or JPEG image from screen
1210     wxYield();
1211     SaveCanvasImageToFile( this, dlg.GetPath() );
1212 }
1213