You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1281 lines
42 KiB

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