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.

642 lines
21 KiB

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