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.

449 lines
15 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2018-2021 KiCad Developers, see change_log.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <base_units.h>
  24. #include <pcb_edit_frame.h>
  25. #include <board_design_settings.h>
  26. #include <bitmaps.h>
  27. #include <widgets/wx_grid.h>
  28. #include <wx/treebook.h>
  29. #include <grid_tricks.h>
  30. #include <panel_setup_tracks_and_vias.h>
  31. enum TRACK_VAR_GRID_COLUMNS
  32. {
  33. TR_WIDTH_COL = 0
  34. };
  35. enum VIA_VAR_GRID_COLUMNS
  36. {
  37. VIA_SIZE_COL = 0,
  38. VIA_DRILL_COL
  39. };
  40. enum DIFF_VAR_GRID_COLUMNS
  41. {
  42. DP_WIDTH_COL = 0,
  43. DP_GAP_COL,
  44. DP_VIA_GAP_COL
  45. };
  46. PANEL_SETUP_TRACKS_AND_VIAS::PANEL_SETUP_TRACKS_AND_VIAS( PAGED_DIALOG* aParent,
  47. PCB_EDIT_FRAME* aFrame,
  48. PANEL_SETUP_CONSTRAINTS* aConstraintsPanel ) :
  49. PANEL_SETUP_TRACKS_AND_VIAS_BASE( aParent->GetTreebook() )
  50. {
  51. m_Parent = aParent;
  52. m_Frame = aFrame;
  53. m_Pcb = m_Frame->GetBoard();
  54. m_BrdSettings = &m_Pcb->GetDesignSettings();
  55. m_ConstraintsPanel = aConstraintsPanel;
  56. m_trackWidthsAddButton->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
  57. m_trackWidthsRemoveButton->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
  58. m_viaSizesAddButton->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
  59. m_viaSizesRemoveButton->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
  60. m_diffPairsAddButton->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
  61. m_diffPairsRemoveButton->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
  62. // Membership combobox editors require a bit more room, so increase the row size of
  63. // all our grids for consistency
  64. m_trackWidthsGrid->SetDefaultRowSize( m_trackWidthsGrid->GetDefaultRowSize() + 4 );
  65. m_viaSizesGrid->SetDefaultRowSize( m_viaSizesGrid->GetDefaultRowSize() + 4 );
  66. m_diffPairsGrid->SetDefaultRowSize( m_diffPairsGrid->GetDefaultRowSize() + 4 );
  67. m_trackWidthsGrid->PushEventHandler( new GRID_TRICKS( m_trackWidthsGrid ) );
  68. m_viaSizesGrid->PushEventHandler( new GRID_TRICKS( m_viaSizesGrid ) );
  69. m_diffPairsGrid->PushEventHandler( new GRID_TRICKS( m_diffPairsGrid ) );
  70. m_trackWidthsGrid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
  71. m_viaSizesGrid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
  72. m_diffPairsGrid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
  73. // Ensure width of columns is enough to enter any reasonable value
  74. WX_GRID* grid_list[] = { m_trackWidthsGrid, m_viaSizesGrid, m_diffPairsGrid, nullptr };
  75. int min_linesize = m_trackWidthsGrid->GetTextExtent( "000.000000 mm " ).x;
  76. for( int ii = 0; grid_list[ii]; ii++ )
  77. {
  78. WX_GRID* curr_grid = grid_list[ii];
  79. for( int col = 0; col < curr_grid->GetNumberCols(); col++ )
  80. {
  81. int min_w = curr_grid->GetVisibleWidth( col, true, true, true );
  82. int best_w = std::max( min_linesize, min_w );
  83. curr_grid->SetColMinimalWidth( col, best_w );
  84. curr_grid->SetColSize( col,best_w );
  85. }
  86. }
  87. m_Frame->Bind( UNITS_CHANGED, &PANEL_SETUP_TRACKS_AND_VIAS::onUnitsChanged, this );
  88. }
  89. PANEL_SETUP_TRACKS_AND_VIAS::~PANEL_SETUP_TRACKS_AND_VIAS()
  90. {
  91. // Delete the GRID_TRICKS.
  92. m_trackWidthsGrid->PopEventHandler( true );
  93. m_viaSizesGrid->PopEventHandler( true );
  94. m_diffPairsGrid->PopEventHandler( true );
  95. m_Frame->Unbind( UNITS_CHANGED, &PANEL_SETUP_TRACKS_AND_VIAS::onUnitsChanged, this );
  96. }
  97. void PANEL_SETUP_TRACKS_AND_VIAS::onUnitsChanged( wxCommandEvent& aEvent )
  98. {
  99. BOARD_DESIGN_SETTINGS tempBDS( nullptr, "dummy" );
  100. BOARD_DESIGN_SETTINGS* saveBDS = m_BrdSettings;
  101. m_BrdSettings = &tempBDS; // No, address of stack var does not escape function
  102. TransferDataFromWindow();
  103. TransferDataToWindow();
  104. m_BrdSettings = saveBDS;
  105. aEvent.Skip();
  106. }
  107. bool PANEL_SETUP_TRACKS_AND_VIAS::TransferDataToWindow()
  108. {
  109. m_trackWidthsGrid->ClearRows();
  110. m_viaSizesGrid->ClearRows();
  111. m_diffPairsGrid->ClearRows();
  112. // Skip the first item, which is the current netclass value
  113. for( unsigned ii = 1; ii < m_BrdSettings->m_TrackWidthList.size(); ii++ )
  114. {
  115. AppendTrackWidth( m_BrdSettings->m_TrackWidthList[ii] );
  116. }
  117. // Skip the first item, which is the current netclass value
  118. for( unsigned ii = 1; ii < m_BrdSettings->m_ViasDimensionsList.size(); ii++ )
  119. {
  120. AppendViaSize( m_BrdSettings->m_ViasDimensionsList[ii].m_Diameter,
  121. m_BrdSettings->m_ViasDimensionsList[ii].m_Drill );
  122. }
  123. // Skip the first item, which is the current netclass value
  124. for( unsigned ii = 1; ii < m_BrdSettings->m_DiffPairDimensionsList.size(); ii++ )
  125. {
  126. AppendDiffPairs( m_BrdSettings->m_DiffPairDimensionsList[ii].m_Width,
  127. m_BrdSettings->m_DiffPairDimensionsList[ii].m_Gap,
  128. m_BrdSettings->m_DiffPairDimensionsList[ii].m_ViaGap );
  129. }
  130. return true;
  131. }
  132. bool PANEL_SETUP_TRACKS_AND_VIAS::TransferDataFromWindow()
  133. {
  134. if( !m_trackWidthsGrid->CommitPendingChanges()
  135. || !m_viaSizesGrid->CommitPendingChanges()
  136. || !m_diffPairsGrid->CommitPendingChanges() )
  137. {
  138. return false;
  139. }
  140. wxString msg;
  141. std::vector<int> trackWidths;
  142. std::vector<VIA_DIMENSION> vias;
  143. std::vector<DIFF_PAIR_DIMENSION> diffPairs;
  144. if( !m_trackWidthsGrid->CommitPendingChanges()
  145. || !m_viaSizesGrid->CommitPendingChanges()
  146. || !m_diffPairsGrid->CommitPendingChanges() )
  147. {
  148. return false;
  149. }
  150. // Test ONLY for malformed data. Design rules and constraints are the business of DRC.
  151. for( int row = 0; row < m_trackWidthsGrid->GetNumberRows(); ++row )
  152. {
  153. msg = m_trackWidthsGrid->GetCellValue( row, TR_WIDTH_COL );
  154. if( !msg.IsEmpty() )
  155. trackWidths.push_back( ValueFromString( m_Frame->GetUserUnits(), msg ) );
  156. }
  157. for( int row = 0; row < m_viaSizesGrid->GetNumberRows(); ++row )
  158. {
  159. msg = m_viaSizesGrid->GetCellValue( row, VIA_SIZE_COL );
  160. if( !msg.IsEmpty() )
  161. {
  162. VIA_DIMENSION via_dim;
  163. via_dim.m_Diameter = ValueFromString( m_Frame->GetUserUnits(), msg );
  164. msg = m_viaSizesGrid->GetCellValue( row, VIA_DRILL_COL );
  165. if( !msg.IsEmpty() )
  166. via_dim.m_Drill = ValueFromString( m_Frame->GetUserUnits(), msg );
  167. vias.push_back( via_dim );
  168. }
  169. }
  170. for( int row = 0; row < m_diffPairsGrid->GetNumberRows(); ++row )
  171. {
  172. msg = m_diffPairsGrid->GetCellValue( row, DP_WIDTH_COL );
  173. if( !msg.IsEmpty() )
  174. {
  175. DIFF_PAIR_DIMENSION diffPair_dim;
  176. diffPair_dim.m_Width = ValueFromString( m_Frame->GetUserUnits(), msg );
  177. msg = m_diffPairsGrid->GetCellValue( row, DP_GAP_COL );
  178. diffPair_dim.m_Gap = ValueFromString( m_Frame->GetUserUnits(), msg );
  179. msg = m_diffPairsGrid->GetCellValue( row, DP_VIA_GAP_COL );
  180. if( !msg.IsEmpty() )
  181. diffPair_dim.m_ViaGap = ValueFromString( m_Frame->GetUserUnits(), msg );
  182. diffPairs.push_back( diffPair_dim );
  183. }
  184. }
  185. // Sort lists by increasing value
  186. sort( trackWidths.begin(), trackWidths.end() );
  187. sort( vias.begin(), vias.end() );
  188. sort( diffPairs.begin(), diffPairs.end() );
  189. // These are all stored in project file, not board, so no need for OnModify()
  190. trackWidths.insert( trackWidths.begin(), 0 ); // dummy value for "use netclass"
  191. m_BrdSettings->m_TrackWidthList = trackWidths;
  192. vias.insert( vias.begin(), { 0, 0 } ); // dummy value for "use netclass"
  193. m_BrdSettings->m_ViasDimensionsList = vias;
  194. diffPairs.insert( diffPairs.begin(), { 0, 0, 0 } ); // dummy value for "use netclass"
  195. m_BrdSettings->m_DiffPairDimensionsList = diffPairs;
  196. return true;
  197. }
  198. bool PANEL_SETUP_TRACKS_AND_VIAS::Validate()
  199. {
  200. if( !m_trackWidthsGrid->CommitPendingChanges()
  201. || !m_viaSizesGrid->CommitPendingChanges()
  202. || !m_diffPairsGrid->CommitPendingChanges() )
  203. {
  204. return false;
  205. }
  206. wxString msg;
  207. // Test vias
  208. for( int row = 0; row < m_viaSizesGrid->GetNumberRows(); ++row )
  209. {
  210. wxString viaDia = m_viaSizesGrid->GetCellValue( row, VIA_SIZE_COL );
  211. wxString viaDrill = m_viaSizesGrid->GetCellValue( row, VIA_DRILL_COL );
  212. if( !viaDia.IsEmpty() && viaDrill.IsEmpty() )
  213. {
  214. msg = _( "No via hole size defined." );
  215. m_Parent->SetError( msg, this, m_viaSizesGrid, row, VIA_DRILL_COL );
  216. return false;
  217. }
  218. }
  219. // Test diff pairs
  220. for( int row = 0; row < m_diffPairsGrid->GetNumberRows(); ++row )
  221. {
  222. wxString dpWidth = m_diffPairsGrid->GetCellValue( row, 0 );
  223. wxString dpGap = m_diffPairsGrid->GetCellValue( row, 1 );
  224. if( !dpWidth.IsEmpty() && dpGap.IsEmpty() )
  225. {
  226. msg = _( "No differential pair gap defined." );
  227. m_Parent->SetError( msg, this, m_diffPairsGrid, row, 1 );
  228. return false;
  229. }
  230. }
  231. return true;
  232. }
  233. void PANEL_SETUP_TRACKS_AND_VIAS::AppendTrackWidth( const int aWidth )
  234. {
  235. int i = m_trackWidthsGrid->GetNumberRows();
  236. m_trackWidthsGrid->AppendRows( 1 );
  237. wxString val = StringFromValue( m_Frame->GetUserUnits(), aWidth, true );
  238. m_trackWidthsGrid->SetCellValue( i, TR_WIDTH_COL, val );
  239. }
  240. void PANEL_SETUP_TRACKS_AND_VIAS::AppendViaSize( const int aSize, const int aDrill )
  241. {
  242. int i = m_viaSizesGrid->GetNumberRows();
  243. m_viaSizesGrid->AppendRows( 1 );
  244. wxString val = StringFromValue( m_Frame->GetUserUnits(), aSize, true );
  245. m_viaSizesGrid->SetCellValue( i, VIA_SIZE_COL, val );
  246. if( aDrill > 0 )
  247. {
  248. val = StringFromValue( m_Frame->GetUserUnits(), aDrill, true );
  249. m_viaSizesGrid->SetCellValue( i, VIA_DRILL_COL, val );
  250. }
  251. }
  252. void PANEL_SETUP_TRACKS_AND_VIAS::AppendDiffPairs( const int aWidth, const int aGap,
  253. const int aViaGap )
  254. {
  255. int i = m_diffPairsGrid->GetNumberRows();
  256. m_diffPairsGrid->AppendRows( 1 );
  257. wxString val = StringFromValue( m_Frame->GetUserUnits(), aWidth, true );
  258. m_diffPairsGrid->SetCellValue( i, DP_WIDTH_COL, val );
  259. if( aGap > 0 )
  260. {
  261. val = StringFromValue( m_Frame->GetUserUnits(), aGap, true );
  262. m_diffPairsGrid->SetCellValue( i, DP_GAP_COL, val );
  263. }
  264. if( aViaGap > 0 )
  265. {
  266. val = StringFromValue( m_Frame->GetUserUnits(), aViaGap, true );
  267. m_diffPairsGrid->SetCellValue( i, DP_VIA_GAP_COL, val );
  268. }
  269. }
  270. void PANEL_SETUP_TRACKS_AND_VIAS::OnAddTrackWidthsClick( wxCommandEvent& aEvent )
  271. {
  272. AppendTrackWidth( 0 );
  273. m_trackWidthsGrid->MakeCellVisible( m_trackWidthsGrid->GetNumberRows() - 1, TR_WIDTH_COL );
  274. m_trackWidthsGrid->SetGridCursor( m_trackWidthsGrid->GetNumberRows() - 1, TR_WIDTH_COL );
  275. m_trackWidthsGrid->EnableCellEditControl( true );
  276. m_trackWidthsGrid->ShowCellEditControl();
  277. }
  278. void PANEL_SETUP_TRACKS_AND_VIAS::OnRemoveTrackWidthsClick( wxCommandEvent& event )
  279. {
  280. int curRow = m_trackWidthsGrid->GetGridCursorRow();
  281. if( curRow < 0 || m_trackWidthsGrid->GetNumberRows() <= curRow )
  282. return;
  283. m_trackWidthsGrid->DeleteRows( curRow, 1 );
  284. curRow = std::max( 0, curRow - 1 );
  285. m_trackWidthsGrid->MakeCellVisible( curRow, m_trackWidthsGrid->GetGridCursorCol() );
  286. m_trackWidthsGrid->SetGridCursor( curRow, m_trackWidthsGrid->GetGridCursorCol() );
  287. }
  288. void PANEL_SETUP_TRACKS_AND_VIAS::OnAddViaSizesClick( wxCommandEvent& event )
  289. {
  290. AppendViaSize( 0, 0 );
  291. m_viaSizesGrid->MakeCellVisible( m_viaSizesGrid->GetNumberRows() - 1, VIA_SIZE_COL );
  292. m_viaSizesGrid->SetGridCursor( m_viaSizesGrid->GetNumberRows() - 1, VIA_SIZE_COL );
  293. m_viaSizesGrid->EnableCellEditControl( true );
  294. m_viaSizesGrid->ShowCellEditControl();
  295. }
  296. void PANEL_SETUP_TRACKS_AND_VIAS::OnRemoveViaSizesClick( wxCommandEvent& event )
  297. {
  298. int curRow = m_viaSizesGrid->GetGridCursorRow();
  299. if( curRow < 0 || m_viaSizesGrid->GetNumberRows() <= curRow )
  300. return;
  301. m_viaSizesGrid->DeleteRows( curRow, 1 );
  302. curRow = std::max( 0, curRow - 1 );
  303. m_viaSizesGrid->MakeCellVisible( curRow, m_viaSizesGrid->GetGridCursorCol() );
  304. m_viaSizesGrid->SetGridCursor( curRow, m_viaSizesGrid->GetGridCursorCol() );
  305. }
  306. void PANEL_SETUP_TRACKS_AND_VIAS::OnAddDiffPairsClick( wxCommandEvent& event )
  307. {
  308. AppendDiffPairs( 0, 0, 0 );
  309. m_diffPairsGrid->MakeCellVisible( m_diffPairsGrid->GetNumberRows() - 1, DP_WIDTH_COL );
  310. m_diffPairsGrid->SetGridCursor( m_diffPairsGrid->GetNumberRows() - 1, DP_WIDTH_COL );
  311. m_diffPairsGrid->EnableCellEditControl( true );
  312. m_diffPairsGrid->ShowCellEditControl();
  313. }
  314. void PANEL_SETUP_TRACKS_AND_VIAS::OnRemoveDiffPairsClick( wxCommandEvent& event )
  315. {
  316. int curRow = m_diffPairsGrid->GetGridCursorRow();
  317. if( curRow < 0 || m_diffPairsGrid->GetNumberRows() <= curRow )
  318. return;
  319. m_diffPairsGrid->DeleteRows( curRow, 1 );
  320. curRow = std::max( 0, curRow - 1 );
  321. m_diffPairsGrid->MakeCellVisible( curRow, m_diffPairsGrid->GetGridCursorCol() );
  322. m_diffPairsGrid->SetGridCursor( curRow, m_diffPairsGrid->GetGridCursorCol() );
  323. }
  324. void PANEL_SETUP_TRACKS_AND_VIAS::ImportSettingsFrom( BOARD* aBoard )
  325. {
  326. m_trackWidthsGrid->CommitPendingChanges( true );
  327. m_viaSizesGrid->CommitPendingChanges( true );
  328. m_diffPairsGrid->CommitPendingChanges( true );
  329. // Note: do not change the board, as we need to get the current nets from it for
  330. // netclass memberships. All the netclass definitions and dimension lists are in
  331. // the BOARD_DESIGN_SETTINGS.
  332. BOARD_DESIGN_SETTINGS* savedSettings = m_BrdSettings;
  333. m_BrdSettings = &aBoard->GetDesignSettings();
  334. TransferDataToWindow();
  335. m_BrdSettings = savedSettings;
  336. }