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.

632 lines
21 KiB

14 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2015 Dick Hollenbeck, dick@softplc.com
  6. * Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
  7. * Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU 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, you may find one here:
  21. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. * or you may search the http://www.gnu.org website for the version 2 license,
  23. * or you may write to the Free Software Foundation, Inc.,
  24. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. #include <confirm.h>
  27. #include <dialogs/dialog_text_entry.h>
  28. #include <3d_viewer/eda_3d_viewer_frame.h>
  29. #include <validators.h>
  30. #include <board_design_settings.h>
  31. #include <board_commit.h>
  32. #include <bitmaps.h>
  33. #include <widgets/grid_text_button_helpers.h>
  34. #include <widgets/wx_grid.h>
  35. #include <widgets/text_ctrl_eval.h>
  36. #include <footprint.h>
  37. #include <footprint_edit_frame.h>
  38. #include <footprint_editor_settings.h>
  39. #include <dialog_footprint_properties_fp_editor.h>
  40. #include <panel_fp_properties_3d_model.h>
  41. #include "3d_rendering/opengl/3d_model.h"
  42. #include "filename_resolver.h"
  43. #include <pgm_base.h>
  44. #include "dialogs/panel_preview_3d_model.h"
  45. #include "dialogs/3d_cache_dialogs.h"
  46. #include <settings/settings_manager.h>
  47. #include <tool/tool_manager.h>
  48. #include <tools/pcb_selection_tool.h>
  49. #include <fp_lib_table.h>
  50. // Remember the last open page during session.
  51. NOTEBOOK_PAGES DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::m_page = NOTEBOOK_PAGES::PAGE_GENERAL;
  52. DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR(
  53. FOOTPRINT_EDIT_FRAME* aParent,
  54. FOOTPRINT* aFootprint ) :
  55. DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR_BASE( aParent ),
  56. m_frame( aParent ),
  57. m_footprint( aFootprint ),
  58. m_netClearance( aParent, m_NetClearanceLabel, m_NetClearanceCtrl, m_NetClearanceUnits ),
  59. m_solderMask( aParent, m_SolderMaskMarginLabel, m_SolderMaskMarginCtrl,
  60. m_SolderMaskMarginUnits ),
  61. m_solderPaste( aParent, m_SolderPasteMarginLabel, m_SolderPasteMarginCtrl,
  62. m_SolderPasteMarginUnits ),
  63. m_solderPasteRatio( aParent, m_PasteMarginRatioLabel, m_PasteMarginRatioCtrl,
  64. m_PasteMarginRatioUnits )
  65. {
  66. // Create the 3D models page
  67. m_3dPanel = new PANEL_FP_PROPERTIES_3D_MODEL( m_frame, m_footprint, this, m_NoteBook );
  68. m_NoteBook->AddPage( m_3dPanel, _("3D Models"), false );
  69. m_texts = new FP_TEXT_GRID_TABLE( m_frame );
  70. m_delayedErrorMessage = wxEmptyString;
  71. m_delayedFocusCtrl = nullptr;
  72. m_delayedFocusGrid = nullptr;
  73. m_delayedFocusRow = -1;
  74. m_delayedFocusColumn = -1;
  75. m_delayedFocusPage = NOTEBOOK_PAGES::PAGE_UNKNOWN;
  76. // Give an icon
  77. wxIcon icon;
  78. icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_modedit ) );
  79. SetIcon( icon );
  80. // Give a bit more room for combobox editors
  81. m_itemsGrid->SetDefaultRowSize( m_itemsGrid->GetDefaultRowSize() + 4 );
  82. m_itemsGrid->SetTable( m_texts );
  83. m_itemsGrid->PushEventHandler( new GRID_TRICKS( m_itemsGrid ) );
  84. m_itemsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
  85. // Show/hide columns according to the user's preference
  86. m_itemsGrid->ShowHideColumns( m_frame->GetSettings()->m_FootprintTextShownColumns );
  87. m_FootprintNameCtrl->SetValidator( FOOTPRINT_NAME_VALIDATOR() );
  88. // Set font sizes
  89. wxFont infoFont = KIUI::GetInfoFont( this );
  90. #if __WXMAC__
  91. m_allow90Label->SetFont( infoFont );
  92. m_allow180Label->SetFont( infoFont );
  93. #endif
  94. infoFont.SetStyle( wxFONTSTYLE_ITALIC );
  95. m_staticTextInfoValNeg->SetFont( infoFont );
  96. m_staticTextInfoValPos->SetFont( infoFont );
  97. m_staticTextInfoCopper->SetFont( infoFont );
  98. m_staticTextInfoPaste->SetFont( infoFont );
  99. if( static_cast<int>( m_page ) >= 0 )
  100. m_NoteBook->SetSelection( (unsigned) m_page );
  101. if( m_page == NOTEBOOK_PAGES::PAGE_GENERAL )
  102. {
  103. m_delayedFocusGrid = m_itemsGrid;
  104. m_delayedFocusRow = 0;
  105. m_delayedFocusColumn = 0;
  106. m_delayedFocusPage = NOTEBOOK_PAGES::PAGE_GENERAL;
  107. }
  108. else if( m_page == NOTEBOOK_PAGES::PAGE_CLEARANCES )
  109. {
  110. SetInitialFocus( m_NetClearanceCtrl );
  111. }
  112. m_solderPaste.SetNegativeZero();
  113. m_solderPasteRatio.SetUnits( EDA_UNITS::PERCENT );
  114. m_solderPasteRatio.SetNegativeZero();
  115. m_sdbSizerStdButtonsOK->SetDefault();
  116. // Configure button logos
  117. m_bpAdd->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
  118. m_bpDelete->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
  119. // wxFormBuilder doesn't include this event...
  120. m_itemsGrid->Connect( wxEVT_GRID_CELL_CHANGING,
  121. wxGridEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnGridCellChanging ),
  122. nullptr, this );
  123. finishDialogSettings();
  124. }
  125. DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::~DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR()
  126. {
  127. m_frame->GetSettings()->m_FootprintTextShownColumns =
  128. m_itemsGrid->GetShownColumns().ToStdString();
  129. // Prevents crash bug in wxGrid's d'tor
  130. m_itemsGrid->DestroyTable( m_texts );
  131. m_itemsGrid->Disconnect( wxEVT_GRID_CELL_CHANGING,
  132. wxGridEventHandler( DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnGridCellChanging ),
  133. nullptr, this );
  134. // Delete the GRID_TRICKS.
  135. m_itemsGrid->PopEventHandler( true );
  136. m_page = static_cast<NOTEBOOK_PAGES>( m_NoteBook->GetSelection() );
  137. // the GL canvas on the 3D models page has to be visible before it is destroyed
  138. m_NoteBook->SetSelection( static_cast<int>( NOTEBOOK_PAGES::PAGE_3D_MODELS ) );
  139. }
  140. bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataToWindow()
  141. {
  142. LIB_ID fpID = m_footprint->GetFPID();
  143. wxString footprintName = fpID.GetLibItemName();
  144. m_FootprintNameCtrl->ChangeValue( footprintName );
  145. m_DocCtrl->SetValue( m_footprint->GetDescription() );
  146. m_KeywordCtrl->SetValue( m_footprint->GetKeywords() );
  147. if( !wxDialog::TransferDataToWindow() )
  148. return false;
  149. if( !m_PanelGeneral->TransferDataToWindow() )
  150. return false;
  151. // Add the models to the panel
  152. if( !m_3dPanel->TransferDataToWindow() )
  153. return false;
  154. // Footprint Texts
  155. m_texts->push_back( m_footprint->Reference() );
  156. m_texts->push_back( m_footprint->Value() );
  157. for( auto item : m_footprint->GraphicalItems() )
  158. {
  159. auto textItem = dyn_cast<FP_TEXT*>( item );
  160. if( textItem )
  161. m_texts->push_back( *textItem );
  162. }
  163. // Notify the grid
  164. wxGridTableMessage tmsg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_texts->GetNumberRows() );
  165. m_itemsGrid->ProcessTableMessage( tmsg );
  166. // Footprint Properties
  167. m_CostRot90Ctrl->SetValue( m_footprint->GetPlacementCost90() );
  168. m_CostRot180Ctrl->SetValue( m_footprint->GetPlacementCost180() );
  169. if( m_footprint->GetAttributes() & FP_THROUGH_HOLE )
  170. m_componentType->SetSelection( 0 );
  171. else if( m_footprint->GetAttributes() & FP_SMD )
  172. m_componentType->SetSelection( 1 );
  173. else
  174. m_componentType->SetSelection( 2 );
  175. m_boardOnly->SetValue( m_footprint->GetAttributes() & FP_BOARD_ONLY );
  176. m_excludeFromPosFiles->SetValue( m_footprint->GetAttributes() & FP_EXCLUDE_FROM_POS_FILES );
  177. m_excludeFromBOM->SetValue( m_footprint->GetAttributes() & FP_EXCLUDE_FROM_BOM );
  178. // Local Clearances
  179. m_netClearance.SetValue( m_footprint->GetLocalClearance() );
  180. m_solderMask.SetValue( m_footprint->GetLocalSolderMaskMargin() );
  181. m_solderPaste.SetValue( m_footprint->GetLocalSolderPasteMargin() );
  182. m_solderPasteRatio.SetDoubleValue( m_footprint->GetLocalSolderPasteMarginRatio() * 100.0 );
  183. switch( m_footprint->GetZoneConnection() )
  184. {
  185. default:
  186. case ZONE_CONNECTION::INHERITED: m_ZoneConnectionChoice->SetSelection( 0 ); break;
  187. case ZONE_CONNECTION::FULL: m_ZoneConnectionChoice->SetSelection( 1 ); break;
  188. case ZONE_CONNECTION::THERMAL: m_ZoneConnectionChoice->SetSelection( 2 ); break;
  189. case ZONE_CONNECTION::NONE: m_ZoneConnectionChoice->SetSelection( 3 ); break;
  190. }
  191. // Items grid
  192. for( int col = 0; col < m_itemsGrid->GetNumberCols(); col++ )
  193. {
  194. // Adjust min size to the column label size
  195. m_itemsGrid->SetColMinimalWidth( col, m_itemsGrid->GetVisibleWidth( col, true, false,
  196. false ) );
  197. // Adjust the column size.
  198. int col_size = m_itemsGrid->GetVisibleWidth( col, true, true, false );
  199. if( col == FPT_LAYER ) // This one's a drop-down. Check all possible values.
  200. {
  201. BOARD* board = m_footprint->GetBoard();
  202. for( PCB_LAYER_ID layer : board->GetEnabledLayers().Seq() )
  203. col_size = std::max( col_size, GetTextExtent( board->GetLayerName( layer ) ).x );
  204. // And the swatch:
  205. col_size += 20;
  206. }
  207. if( m_itemsGrid->IsColShown( col ) )
  208. m_itemsGrid->SetColSize( col, col_size );
  209. }
  210. m_itemsGrid->SetRowLabelSize( m_itemsGrid->GetVisibleWidth( -1, true, true, true ) );
  211. Layout();
  212. adjustGridColumns( m_itemsGrid->GetRect().GetWidth() );
  213. return true;
  214. }
  215. bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::checkFootprintName( const wxString& aFootprintName )
  216. {
  217. if( aFootprintName.IsEmpty() )
  218. {
  219. m_delayedErrorMessage = _( "Footprint must have a name." );
  220. return false;
  221. }
  222. else if( !FOOTPRINT::IsLibNameValid( aFootprintName ) )
  223. {
  224. m_delayedErrorMessage.Printf( _( "Footprint name may not contain '%s'." ),
  225. FOOTPRINT::StringLibNameInvalidChars( true ) );
  226. return false;
  227. }
  228. return true;
  229. }
  230. bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::Validate()
  231. {
  232. if( !m_itemsGrid->CommitPendingChanges() )
  233. return false;
  234. if( !DIALOG_SHIM::Validate() )
  235. return false;
  236. // First, test for invalid chars in footprint name
  237. wxString footprintName = m_FootprintNameCtrl->GetValue();
  238. if( !checkFootprintName( footprintName ) )
  239. {
  240. if( m_NoteBook->GetSelection() != 0 )
  241. m_NoteBook->SetSelection( 0 );
  242. m_delayedFocusCtrl = m_FootprintNameCtrl;
  243. m_delayedFocusPage = NOTEBOOK_PAGES::PAGE_GENERAL;
  244. return false;
  245. }
  246. // Check for empty texts.
  247. for( size_t i = 2; i < m_texts->size(); ++i )
  248. {
  249. FP_TEXT& text = m_texts->at( i );
  250. if( text.GetText().IsEmpty() )
  251. {
  252. if( m_NoteBook->GetSelection() != 0 )
  253. m_NoteBook->SetSelection( 0 );
  254. m_delayedErrorMessage = _( "Text items must have some content." );
  255. m_delayedFocusGrid = m_itemsGrid;
  256. m_delayedFocusColumn = FPT_TEXT;
  257. m_delayedFocusRow = i;
  258. return false;
  259. }
  260. }
  261. if( !m_netClearance.Validate( 0, INT_MAX ) )
  262. return false;
  263. return true;
  264. }
  265. bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataFromWindow()
  266. {
  267. if( !Validate() )
  268. return false;
  269. if( !DIALOG_SHIM::TransferDataFromWindow() )
  270. return false;
  271. if( !m_itemsGrid->CommitPendingChanges() )
  272. return false;
  273. // This only commits the editor, model updating is done below so it is inside
  274. // the commit
  275. if( !m_3dPanel->TransferDataFromWindow() )
  276. return false;
  277. auto view = m_frame->GetCanvas()->GetView();
  278. BOARD_COMMIT commit( m_frame );
  279. commit.Modify( m_footprint );
  280. LIB_ID fpID = m_footprint->GetFPID();
  281. fpID.SetLibItemName( m_FootprintNameCtrl->GetValue() );
  282. m_footprint->SetFPID( fpID );
  283. m_footprint->SetDescription( m_DocCtrl->GetValue() );
  284. m_footprint->SetKeywords( m_KeywordCtrl->GetValue() );
  285. // copy reference and value
  286. m_footprint->Reference() = m_texts->at( 0 );
  287. m_footprint->Value() = m_texts->at( 1 );
  288. size_t i = 2;
  289. std::vector<FP_TEXT*> items_to_remove;
  290. for( BOARD_ITEM* item : m_footprint->GraphicalItems() )
  291. {
  292. FP_TEXT* textItem = dynamic_cast<FP_TEXT*>( item );
  293. if( textItem )
  294. {
  295. // copy grid table entries till we run out, then delete any remaining texts
  296. if( i < m_texts->size() )
  297. *textItem = m_texts->at( i++ );
  298. else // store this item to remove and delete it later,
  299. // after the graphic list is explored:
  300. items_to_remove.push_back( textItem );
  301. }
  302. }
  303. // Remove text items:
  304. PCB_SELECTION_TOOL* selTool = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
  305. for( FP_TEXT* item: items_to_remove )
  306. {
  307. selTool->RemoveItemFromSel( item );
  308. view->Remove( item );
  309. item->DeleteStructure();
  310. }
  311. // if there are still grid table entries, create new texts for them
  312. while( i < m_texts->size() )
  313. {
  314. FP_TEXT* newText = new FP_TEXT( m_texts->at( i++ ) );
  315. m_footprint->Add( newText, ADD_MODE::APPEND );
  316. view->Add( newText );
  317. }
  318. int attributes = 0;
  319. switch( m_componentType->GetSelection() )
  320. {
  321. case 0: attributes |= FP_THROUGH_HOLE; break;
  322. case 1: attributes |= FP_SMD; break;
  323. default: break;
  324. }
  325. if( m_boardOnly->GetValue() )
  326. attributes |= FP_BOARD_ONLY;
  327. if( m_excludeFromPosFiles->GetValue() )
  328. attributes |= FP_EXCLUDE_FROM_POS_FILES;
  329. if( m_excludeFromBOM->GetValue() )
  330. attributes |= FP_EXCLUDE_FROM_BOM;
  331. m_footprint->SetAttributes( attributes );
  332. m_footprint->SetPlacementCost90( m_CostRot90Ctrl->GetValue() );
  333. m_footprint->SetPlacementCost180( m_CostRot180Ctrl->GetValue() );
  334. // Initialize masks clearances
  335. m_footprint->SetLocalClearance( m_netClearance.GetValue() );
  336. m_footprint->SetLocalSolderMaskMargin( m_solderMask.GetValue() );
  337. m_footprint->SetLocalSolderPasteMargin( m_solderPaste.GetValue() );
  338. m_footprint->SetLocalSolderPasteMarginRatio( m_solderPasteRatio.GetDoubleValue() / 100.0 );
  339. switch( m_ZoneConnectionChoice->GetSelection() )
  340. {
  341. default:
  342. case 0: m_footprint->SetZoneConnection( ZONE_CONNECTION::INHERITED ); break;
  343. case 1: m_footprint->SetZoneConnection( ZONE_CONNECTION::FULL ); break;
  344. case 2: m_footprint->SetZoneConnection( ZONE_CONNECTION::THERMAL ); break;
  345. case 3: m_footprint->SetZoneConnection( ZONE_CONNECTION::NONE ); break;
  346. }
  347. // Copy the models from the panel to the footprint
  348. std::vector<FP_3DMODEL>& panelList = m_3dPanel->GetModelList();
  349. std::list<FP_3DMODEL>* fpList = &m_footprint->Models();
  350. fpList->clear();
  351. fpList->insert( fpList->end(), panelList.begin(), panelList.end() );
  352. commit.Push( _( "Modify footprint properties" ) );
  353. return true;
  354. }
  355. static bool footprintIsFromBoard( FOOTPRINT* aFootprint )
  356. {
  357. return aFootprint->GetLink() != niluuid;
  358. }
  359. void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnGridCellChanging( wxGridEvent& event )
  360. {
  361. // Currently: nothing to do
  362. }
  363. void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnFootprintNameText( wxCommandEvent& event )
  364. {
  365. if( !footprintIsFromBoard( m_footprint ) )
  366. {
  367. // Currently: nothing to do
  368. }
  369. }
  370. void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnAddField( wxCommandEvent& event )
  371. {
  372. if( !m_itemsGrid->CommitPendingChanges() )
  373. return;
  374. const BOARD_DESIGN_SETTINGS& dsnSettings = m_frame->GetDesignSettings();
  375. FP_TEXT textItem( m_footprint );
  376. // Set active layer if legal; otherwise copy layer from previous text item
  377. if( LSET::AllTechMask().test( m_frame->GetActiveLayer() ) )
  378. textItem.SetLayer( m_frame->GetActiveLayer() );
  379. else
  380. textItem.SetLayer( m_texts->at( m_texts->size() - 1 ).GetLayer() );
  381. textItem.SetTextSize( dsnSettings.GetTextSize( textItem.GetLayer() ) );
  382. textItem.SetTextThickness( dsnSettings.GetTextThickness( textItem.GetLayer() ) );
  383. textItem.SetItalic( dsnSettings.GetTextItalic( textItem.GetLayer() ) );
  384. m_texts->push_back( textItem );
  385. // notify the grid
  386. wxGridTableMessage msg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
  387. m_itemsGrid->ProcessTableMessage( msg );
  388. m_itemsGrid->SetFocus();
  389. m_itemsGrid->MakeCellVisible( m_texts->size() - 1, 0 );
  390. m_itemsGrid->SetGridCursor( m_texts->size() - 1, 0 );
  391. m_itemsGrid->EnableCellEditControl( true );
  392. m_itemsGrid->ShowCellEditControl();
  393. }
  394. void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnDeleteField( wxCommandEvent& event )
  395. {
  396. if( !m_itemsGrid->CommitPendingChanges() )
  397. return;
  398. wxArrayInt selectedRows = m_itemsGrid->GetSelectedRows();
  399. if( selectedRows.empty() && m_itemsGrid->GetGridCursorRow() >= 0 )
  400. selectedRows.push_back( m_itemsGrid->GetGridCursorRow() );
  401. if( selectedRows.empty() )
  402. return;
  403. for( int row : selectedRows )
  404. {
  405. if( row < 2 )
  406. {
  407. DisplayError( nullptr, _( "Reference and value are mandatory." ) );
  408. return;
  409. }
  410. }
  411. // Reverse sort so deleting a row doesn't change the indexes of the other rows.
  412. selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
  413. for( int row : selectedRows )
  414. {
  415. m_texts->erase( m_texts->begin() + row );
  416. // notify the grid
  417. wxGridTableMessage msg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
  418. m_itemsGrid->ProcessTableMessage( msg );
  419. if( m_itemsGrid->GetNumberRows() > 0 )
  420. {
  421. m_itemsGrid->MakeCellVisible( std::max( 0, row-1 ), m_itemsGrid->GetGridCursorCol() );
  422. m_itemsGrid->SetGridCursor( std::max( 0, row-1 ), m_itemsGrid->GetGridCursorCol() );
  423. }
  424. }
  425. }
  426. void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::adjustGridColumns( int aWidth )
  427. {
  428. // Account for scroll bars
  429. int itemsWidth = aWidth - ( m_itemsGrid->GetSize().x - m_itemsGrid->GetClientSize().x );
  430. itemsWidth -= m_itemsGrid->GetRowLabelSize();
  431. for( int i = 1; i < m_itemsGrid->GetNumberCols(); i++ )
  432. itemsWidth -= m_itemsGrid->GetColSize( i );
  433. if( itemsWidth > 0 )
  434. {
  435. m_itemsGrid->SetColSize( 0, std::max( itemsWidth,
  436. m_itemsGrid->GetVisibleWidth( 0, true, false, false ) ) );
  437. }
  438. // Update the width of the 3D panel
  439. m_3dPanel->AdjustGridColumnWidths( aWidth );
  440. }
  441. void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnUpdateUI( wxUpdateUIEvent& event )
  442. {
  443. if( !m_itemsGrid->IsCellEditControlShown() )
  444. adjustGridColumns( m_itemsGrid->GetRect().GetWidth() );
  445. // Handle a delayed focus. The delay allows us to:
  446. // a) change focus when the error was triggered from within a killFocus handler
  447. // b) show the correct notebook page in the background before the error dialog comes up
  448. // when triggered from an OK or a notebook page change
  449. if( static_cast<int>( m_delayedFocusPage ) >= 0 )
  450. {
  451. if( m_NoteBook->GetSelection() != static_cast<int>( m_delayedFocusPage ) )
  452. m_NoteBook->ChangeSelection( static_cast<int>( m_delayedFocusPage ) );
  453. m_delayedFocusPage = NOTEBOOK_PAGES::PAGE_UNKNOWN;
  454. }
  455. if( !m_delayedErrorMessage.IsEmpty() )
  456. {
  457. // We will re-enter this routine when the error dialog is displayed, so make
  458. // sure we don't keep putting up more dialogs.
  459. wxString msg = m_delayedErrorMessage;
  460. m_delayedErrorMessage = wxEmptyString;
  461. // Do not use DisplayErrorMessage(); it screws up window order on Mac
  462. DisplayError( nullptr, msg );
  463. }
  464. if( m_delayedFocusCtrl )
  465. {
  466. m_delayedFocusCtrl->SetFocus();
  467. if( auto textEntry = dynamic_cast<wxTextEntry*>( m_delayedFocusCtrl ) )
  468. textEntry->SelectAll();
  469. m_delayedFocusCtrl = nullptr;
  470. }
  471. else if( m_delayedFocusGrid )
  472. {
  473. m_delayedFocusGrid->SetFocus();
  474. m_delayedFocusGrid->MakeCellVisible( m_delayedFocusRow, m_delayedFocusColumn );
  475. m_delayedFocusGrid->SetGridCursor( m_delayedFocusRow, m_delayedFocusColumn );
  476. m_delayedFocusGrid->EnableCellEditControl( true );
  477. m_delayedFocusGrid->ShowCellEditControl();
  478. m_delayedFocusGrid = nullptr;
  479. m_delayedFocusRow = -1;
  480. m_delayedFocusColumn = -1;
  481. }
  482. }
  483. void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnGridSize( wxSizeEvent& event )
  484. {
  485. adjustGridColumns( event.GetSize().GetX() );
  486. event.Skip();
  487. }