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.

660 lines
25 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright The KiCad Developers, see AUTHORS.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 <widgets/wx_panel.h>
  24. #include <widgets/std_bitmap_button.h>
  25. #include <bitmaps.h>
  26. #include <dialogs/panel_setup_time_domain_parameters.h>
  27. #include <pcb_edit_frame.h>
  28. #include <grid_tricks.h>
  29. #include <layer_ids.h>
  30. #include <pgm_base.h>
  31. #include <widgets/grid_icon_text_helpers.h>
  32. #include <widgets/paged_dialog.h>
  33. #include <wx/wupdlock.h>
  34. PANEL_SETUP_TIME_DOMAIN_PARAMETERS::PANEL_SETUP_TIME_DOMAIN_PARAMETERS(
  35. wxWindow* aParentWindow, PCB_EDIT_FRAME* aFrame, BOARD* aBoard,
  36. std::shared_ptr<TIME_DOMAIN_PARAMETERS> aTimeDomainParameters ) :
  37. PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE( aParentWindow ),
  38. m_timeDomainParameters( std::move( aTimeDomainParameters ) ),
  39. m_frame( aFrame ),
  40. m_board( aFrame->GetBoard() )
  41. {
  42. m_timeDomainParametersPane->SetBorders( true, false, false, false );
  43. m_viaDelayOverridesPane->SetBorders( true, false, false, false );
  44. // Set up units
  45. m_unitsProvider = std::make_unique<UNITS_PROVIDER>( pcbIUScale, m_frame->GetUserUnits() );
  46. m_tracePropagationGrid->SetUnitsProvider( m_unitsProvider.get() );
  47. m_viaPropagationGrid->SetUnitsProvider( m_unitsProvider.get() );
  48. Freeze();
  49. m_splitter->SetMinimumPaneSize( FromDIP( m_splitter->GetMinimumPaneSize() ) );
  50. // Set up the tuning profiles grid
  51. m_tracePropagationGrid->BeginBatch();
  52. m_tracePropagationGrid->SetUseNativeColLabels();
  53. m_tracePropagationGrid->EnsureColLabelsVisible();
  54. m_tracePropagationGrid->PushEventHandler( new GRID_TRICKS( m_tracePropagationGrid ) );
  55. m_tracePropagationGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
  56. m_addDelayProfileButton->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
  57. m_removeDelayProfileButton->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
  58. m_tracePropagationGrid->EndBatch();
  59. m_tracePropagationGrid->Connect(
  60. wxEVT_GRID_CELL_CHANGING,
  61. wxGridEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnDelayProfileGridCellChanging ), nullptr, this );
  62. // Set up the via override grid
  63. m_viaPropagationGrid->BeginBatch();
  64. m_viaPropagationGrid->SetUseNativeColLabels();
  65. m_viaPropagationGrid->EnsureColLabelsVisible();
  66. m_viaPropagationGrid->PushEventHandler( new GRID_TRICKS( m_viaPropagationGrid ) );
  67. m_viaPropagationGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
  68. std::vector<int> viaColIds;
  69. m_viaPropagationGrid->SetAutoEvalColUnits( VIA_GRID_DELAY,
  70. m_unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::TIME ) );
  71. viaColIds.push_back( VIA_GRID_DELAY );
  72. m_viaPropagationGrid->SetAutoEvalCols( viaColIds );
  73. m_viaPropagationGrid->EndBatch();
  74. m_addViaOverrideButton->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
  75. m_removeViaOverrideButton->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
  76. setColumnWidths();
  77. Thaw();
  78. }
  79. PANEL_SETUP_TIME_DOMAIN_PARAMETERS::~PANEL_SETUP_TIME_DOMAIN_PARAMETERS()
  80. {
  81. // Delete the GRID_TRICKS
  82. m_tracePropagationGrid->PopEventHandler( true );
  83. m_viaPropagationGrid->PopEventHandler( true );
  84. m_tracePropagationGrid->Disconnect(
  85. wxEVT_GRID_CELL_CHANGING,
  86. wxGridEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnDelayProfileGridCellChanging ), nullptr, this );
  87. }
  88. bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::TransferDataToWindow()
  89. {
  90. m_tracePropagationGrid->ClearRows();
  91. m_viaPropagationGrid->ClearRows();
  92. const std::vector<DELAY_PROFILE>& delayProfiles = m_timeDomainParameters->GetDelayProfiles();
  93. SyncCopperLayers( m_board->GetCopperLayerCount() );
  94. for( const DELAY_PROFILE& profile : delayProfiles )
  95. {
  96. addProfileRow( profile );
  97. for( const DELAY_PROFILE_VIA_OVERRIDE_ENTRY& viaOverride : profile.m_ViaOverrides )
  98. addViaRow( profile.m_ProfileName, viaOverride );
  99. }
  100. updateViaProfileNamesEditor();
  101. return true;
  102. }
  103. bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::TransferDataFromWindow()
  104. {
  105. if( !Validate() )
  106. return false;
  107. m_timeDomainParameters->ClearDelayProfiles();
  108. for( int i = 0; i < m_tracePropagationGrid->GetNumberRows(); ++i )
  109. {
  110. DELAY_PROFILE profile = getProfileRow( i );
  111. wxString profileName = profile.m_ProfileName;
  112. for( int j = 0; j < m_viaPropagationGrid->GetNumberRows(); ++j )
  113. {
  114. if( m_viaPropagationGrid->GetCellValue( j, VIA_GRID_PROFILE_NAME ) == profileName )
  115. profile.m_ViaOverrides.emplace_back( getViaRow( j ) );
  116. }
  117. m_timeDomainParameters->AddDelayProfile( std::move( profile ) );
  118. }
  119. return true;
  120. }
  121. void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::addProfileRow( const DELAY_PROFILE& aDelayProfile )
  122. {
  123. const int rowId = m_tracePropagationGrid->GetNumberRows();
  124. m_tracePropagationGrid->AppendRows();
  125. m_tracePropagationGrid->SetCellValue( rowId, PROFILE_GRID_PROFILE_NAME, aDelayProfile.m_ProfileName );
  126. m_tracePropagationGrid->SetUnitValue( rowId, PROFILE_GRID_VIA_PROP_DELAY, aDelayProfile.m_ViaPropagationDelay );
  127. for( const auto& [layerId, velocity] : aDelayProfile.m_LayerPropagationDelays )
  128. {
  129. if( !m_copperLayerIdsToColumns.contains( layerId ) )
  130. continue;
  131. int col = m_copperLayerIdsToColumns[layerId];
  132. if( col < m_tracePropagationGrid->GetNumberCols() )
  133. m_tracePropagationGrid->SetUnitValue( rowId, col, velocity );
  134. }
  135. }
  136. DELAY_PROFILE PANEL_SETUP_TIME_DOMAIN_PARAMETERS::getProfileRow( const int aRow )
  137. {
  138. DELAY_PROFILE entry;
  139. entry.m_ProfileName = getProfileNameForProfileGridRow( aRow );
  140. entry.m_ViaPropagationDelay = m_tracePropagationGrid->GetUnitValue( aRow, PROFILE_GRID_VIA_PROP_DELAY );
  141. std::map<PCB_LAYER_ID, int> propDelays;
  142. for( const auto& [layer, col] : m_copperLayerIdsToColumns )
  143. propDelays[layer] = m_tracePropagationGrid->GetUnitValue( aRow, col );
  144. entry.m_LayerPropagationDelays = std::move( propDelays );
  145. return entry;
  146. }
  147. void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::addViaRow( const wxString& aProfileName,
  148. const DELAY_PROFILE_VIA_OVERRIDE_ENTRY& aViaOverrideEntry ) const
  149. {
  150. const int rowId = m_viaPropagationGrid->GetNumberRows();
  151. m_viaPropagationGrid->AppendRows();
  152. m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_PROFILE_NAME, aProfileName );
  153. m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_SIGNAL_LAYER_FROM,
  154. m_board->GetLayerName( aViaOverrideEntry.m_SignalLayerFrom ) );
  155. m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_SIGNAL_LAYER_TO,
  156. m_board->GetLayerName( aViaOverrideEntry.m_SignalLayerTo ) );
  157. m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_VIA_LAYER_FROM,
  158. m_board->GetLayerName( aViaOverrideEntry.m_ViaLayerFrom ) );
  159. m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_VIA_LAYER_TO,
  160. m_board->GetLayerName( aViaOverrideEntry.m_ViaLayerTo ) );
  161. m_viaPropagationGrid->SetUnitValue( rowId, VIA_GRID_DELAY, aViaOverrideEntry.m_Delay );
  162. }
  163. DELAY_PROFILE_VIA_OVERRIDE_ENTRY PANEL_SETUP_TIME_DOMAIN_PARAMETERS::getViaRow( const int aRow )
  164. {
  165. // Get layer info
  166. const wxString signalLayerFrom = m_viaPropagationGrid->GetCellValue( aRow, VIA_GRID_SIGNAL_LAYER_FROM );
  167. const wxString signalLayerTo = m_viaPropagationGrid->GetCellValue( aRow, VIA_GRID_SIGNAL_LAYER_TO );
  168. const wxString viaLayerFrom = m_viaPropagationGrid->GetCellValue( aRow, VIA_GRID_VIA_LAYER_FROM );
  169. const wxString viaLayerTo = m_viaPropagationGrid->GetCellValue( aRow, VIA_GRID_VIA_LAYER_TO );
  170. PCB_LAYER_ID signalLayerIdFrom = m_layerNamesToIDs[signalLayerFrom];
  171. PCB_LAYER_ID signalLayerIdTo = m_layerNamesToIDs[signalLayerTo];
  172. PCB_LAYER_ID viaLayerIdFrom = m_layerNamesToIDs[viaLayerFrom];
  173. PCB_LAYER_ID viaLayerIdTo = m_layerNamesToIDs[viaLayerTo];
  174. // Order layers in stackup order (from F_Cu first)
  175. if( IsCopperLayerLowerThan( signalLayerIdFrom, signalLayerIdTo ) )
  176. std::swap( signalLayerIdFrom, signalLayerIdTo );
  177. if( IsCopperLayerLowerThan( viaLayerIdFrom, viaLayerIdTo ) )
  178. std::swap( viaLayerIdFrom, viaLayerIdTo );
  179. const DELAY_PROFILE_VIA_OVERRIDE_ENTRY entry{ signalLayerIdFrom, signalLayerIdTo, viaLayerIdFrom, viaLayerIdTo,
  180. m_viaPropagationGrid->GetUnitValue( aRow, VIA_GRID_DELAY ) };
  181. return entry;
  182. }
  183. void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::SyncCopperLayers( int aNumCopperLayers )
  184. {
  185. m_prevLayerNamesToIDs = m_layerNamesToIDs;
  186. m_copperLayerIdsToColumns.clear();
  187. m_copperColumnsToLayerId.clear();
  188. m_layerNames.clear();
  189. m_layerNamesToIDs.clear();
  190. int colIdx = PROFILE_GRID_NUM_REQUIRED_COLS;
  191. for( const auto& layer : LSET::AllCuMask( aNumCopperLayers ).CuStack() )
  192. {
  193. wxString layerName = m_board->GetLayerName( layer );
  194. m_layerNames.emplace_back( layerName );
  195. m_layerNamesToIDs[layerName] = layer;
  196. m_copperLayerIdsToColumns[layer] = colIdx;
  197. m_copperColumnsToLayerId[colIdx] = layer;
  198. ++colIdx;
  199. }
  200. updateProfileGridColumns();
  201. updateViaGridColumns();
  202. setColumnWidths();
  203. }
  204. void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::setColumnWidths()
  205. {
  206. const int minValueWidth = m_tracePropagationGrid->GetTextExtent( wxT( "000.00 ps/mm" ) ).x;
  207. const int minNameWidth = m_tracePropagationGrid->GetTextExtent( wxT( "MMMMMMMMMMMM" ) ).x;
  208. for( int i = 0; i < m_tracePropagationGrid->GetNumberCols(); ++i )
  209. {
  210. const int titleSize = m_tracePropagationGrid->GetTextExtent( m_tracePropagationGrid->GetColLabelValue( i ) ).x;
  211. if( i == PROFILE_GRID_PROFILE_NAME )
  212. m_tracePropagationGrid->SetColSize( i, std::max( titleSize, minNameWidth ) );
  213. else
  214. m_tracePropagationGrid->SetColSize( i, std::max( titleSize, minValueWidth ) );
  215. }
  216. for( int i = 0; i < m_viaPropagationGrid->GetNumberCols(); ++i )
  217. {
  218. const int titleSize = GetTextExtent( m_viaPropagationGrid->GetColLabelValue( i ) ).x;
  219. if( i == VIA_GRID_PROFILE_NAME )
  220. m_viaPropagationGrid->SetColSize( i, std::max( titleSize, minNameWidth ) );
  221. else
  222. m_viaPropagationGrid->SetColSize( i, titleSize + 30 );
  223. }
  224. }
  225. void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::updateProfileGridColumns()
  226. {
  227. const int newCopperLayers = static_cast<int>( m_copperLayerIdsToColumns.size() );
  228. const int curCopperLayers = m_tracePropagationGrid->GetNumberCols() - PROFILE_GRID_NUM_REQUIRED_COLS;
  229. if( newCopperLayers < curCopperLayers )
  230. {
  231. // TODO: WARN OF DELETING DATA?
  232. m_tracePropagationGrid->DeleteCols( curCopperLayers - newCopperLayers + PROFILE_GRID_NUM_REQUIRED_COLS,
  233. curCopperLayers - newCopperLayers );
  234. }
  235. else if( newCopperLayers > curCopperLayers )
  236. {
  237. m_tracePropagationGrid->AppendCols( newCopperLayers - curCopperLayers );
  238. }
  239. std::vector<int> copperColIds;
  240. m_tracePropagationGrid->SetAutoEvalColUnits( PROFILE_GRID_VIA_PROP_DELAY,
  241. m_unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::LENGTH_DELAY ) );
  242. copperColIds.push_back( PROFILE_GRID_VIA_PROP_DELAY );
  243. for( const auto& [colIdx, layerId] : m_copperColumnsToLayerId )
  244. {
  245. m_tracePropagationGrid->SetColLabelValue( colIdx, m_board->GetLayerName( layerId ) );
  246. m_tracePropagationGrid->SetAutoEvalColUnits( colIdx,
  247. m_unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::LENGTH_DELAY ) );
  248. copperColIds.push_back( colIdx );
  249. }
  250. m_tracePropagationGrid->SetAutoEvalCols( copperColIds );
  251. m_tracePropagationGrid->EnsureColLabelsVisible();
  252. m_tracePropagationGrid->Refresh();
  253. }
  254. void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::updateViaGridColumns()
  255. {
  256. wxArrayString layerNames;
  257. std::ranges::for_each( m_layerNames,
  258. [&layerNames]( const wxString& aLayerName )
  259. {
  260. layerNames.push_back( aLayerName );
  261. } );
  262. // Save the current data
  263. std::vector<wxString> currentSignalLayersFrom;
  264. std::vector<wxString> currentSignalLayersTo;
  265. std::vector<wxString> currentViaLayersFrom;
  266. std::vector<wxString> currentViaLayersTo;
  267. for( int row = 0; row < m_viaPropagationGrid->GetNumberRows(); ++row )
  268. {
  269. currentSignalLayersFrom.emplace_back( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM ) );
  270. currentSignalLayersTo.emplace_back( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO ) );
  271. currentViaLayersFrom.emplace_back( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_VIA_LAYER_FROM ) );
  272. currentViaLayersTo.emplace_back( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_VIA_LAYER_TO ) );
  273. }
  274. // Reset the via layers lists
  275. wxGridCellAttr* attr = new wxGridCellAttr;
  276. attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
  277. m_viaPropagationGrid->SetColAttr( VIA_GRID_SIGNAL_LAYER_FROM, attr );
  278. attr = new wxGridCellAttr;
  279. attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
  280. m_viaPropagationGrid->SetColAttr( VIA_GRID_SIGNAL_LAYER_TO, attr );
  281. attr = new wxGridCellAttr;
  282. attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
  283. m_viaPropagationGrid->SetColAttr( VIA_GRID_VIA_LAYER_FROM, attr );
  284. attr = new wxGridCellAttr;
  285. attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) );
  286. m_viaPropagationGrid->SetColAttr( VIA_GRID_VIA_LAYER_TO, attr );
  287. // Restore the data, changing or resetting layer names if required
  288. for( int row = 0; row < m_viaPropagationGrid->GetNumberRows(); ++row )
  289. {
  290. const PCB_LAYER_ID lastSignalFromId = m_prevLayerNamesToIDs[currentSignalLayersFrom[row]];
  291. if( m_copperLayerIdsToColumns.contains( lastSignalFromId ) )
  292. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM,
  293. m_board->GetLayerName( lastSignalFromId ) );
  294. else
  295. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM, m_layerNames.front() );
  296. const PCB_LAYER_ID lastSignalToId = m_prevLayerNamesToIDs[currentSignalLayersTo[row]];
  297. if( m_copperLayerIdsToColumns.contains( lastSignalToId ) )
  298. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO,
  299. m_board->GetLayerName( lastSignalToId ) );
  300. else
  301. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO, m_layerNames.back() );
  302. const PCB_LAYER_ID lastViaFromId = m_prevLayerNamesToIDs[currentViaLayersFrom[row]];
  303. if( m_copperLayerIdsToColumns.contains( lastViaFromId ) )
  304. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, m_board->GetLayerName( lastViaFromId ) );
  305. else
  306. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, m_layerNames.front() );
  307. const PCB_LAYER_ID lastViaToId = m_prevLayerNamesToIDs[currentViaLayersTo[row]];
  308. if( m_copperLayerIdsToColumns.contains( lastViaToId ) )
  309. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, m_board->GetLayerName( lastViaToId ) );
  310. else
  311. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, m_layerNames.back() );
  312. }
  313. }
  314. void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnAddDelayProfileClick( wxCommandEvent& event )
  315. {
  316. m_tracePropagationGrid->OnAddRow(
  317. [&]() -> std::pair<int, int>
  318. {
  319. const int row = m_tracePropagationGrid->GetNumberRows();
  320. m_tracePropagationGrid->AppendRows();
  321. m_tracePropagationGrid->SetCellValue( row, PROFILE_GRID_PROFILE_NAME, "" );
  322. for( int i = PROFILE_GRID_VIA_PROP_DELAY; i < m_tracePropagationGrid->GetNumberCols(); ++i )
  323. m_tracePropagationGrid->SetUnitValue( row, i, 0 );
  324. return { row, PROFILE_GRID_PROFILE_NAME };
  325. } );
  326. }
  327. void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnRemoveDelayProfileClick( wxCommandEvent& event )
  328. {
  329. m_tracePropagationGrid->OnDeleteRows(
  330. [&]( int row )
  331. {
  332. wxString profileName = getProfileNameForProfileGridRow( row );
  333. // Delete associated via overrides
  334. for( int viaRow = m_viaPropagationGrid->GetNumberRows() - 1; viaRow >= 0; --viaRow )
  335. {
  336. if( m_viaPropagationGrid->GetCellValue( viaRow, VIA_GRID_PROFILE_NAME ) == profileName )
  337. m_viaPropagationGrid->DeleteRows( viaRow, 1 );
  338. }
  339. // Delete tuning profile
  340. m_tracePropagationGrid->DeleteRows( row, 1 );
  341. updateViaProfileNamesEditor();
  342. } );
  343. }
  344. void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnAddViaOverrideClick( wxCommandEvent& event )
  345. {
  346. m_viaPropagationGrid->OnAddRow(
  347. [&]() -> std::pair<int, int>
  348. {
  349. const int row = m_viaPropagationGrid->GetNumberRows();
  350. // Check we have delay profiles to override
  351. if( m_tracePropagationGrid->GetNumberRows() == 0 )
  352. {
  353. PAGED_DIALOG::GetDialog( this )->SetError( _( "No delay profiles to override" ), this, nullptr );
  354. return { row, -1 };
  355. }
  356. m_viaPropagationGrid->AppendRows();
  357. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_PROFILE_NAME, getProfileNameForProfileGridRow( 0 ) );
  358. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM, m_layerNames.front() );
  359. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO, m_layerNames.back() );
  360. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, m_layerNames.front() );
  361. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, m_layerNames.back() );
  362. m_viaPropagationGrid->SetUnitValue( row, VIA_GRID_DELAY, 0 );
  363. return { row, VIA_GRID_DELAY };
  364. } );
  365. }
  366. void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnRemoveViaOverrideClick( wxCommandEvent& event )
  367. {
  368. m_viaPropagationGrid->OnDeleteRows(
  369. [&]( int row )
  370. {
  371. m_viaPropagationGrid->DeleteRows( row, 1 );
  372. } );
  373. }
  374. void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnDelayProfileGridCellChanging( wxGridEvent& event )
  375. {
  376. if( event.GetCol() == PROFILE_GRID_PROFILE_NAME )
  377. {
  378. if( validateDelayProfileName( event.GetRow(), event.GetString() ) )
  379. {
  380. const wxString oldName = getProfileNameForProfileGridRow( event.GetRow() );
  381. wxString newName = event.GetString();
  382. newName.Trim( true ).Trim( false );
  383. if( !oldName.IsEmpty() )
  384. {
  385. wxWindowUpdateLocker updateLocker( m_viaPropagationGrid );
  386. updateViaProfileNamesEditor( oldName, newName );
  387. // Update changed profile names
  388. for( int row = 0; row < m_viaPropagationGrid->GetNumberRows(); ++row )
  389. {
  390. if( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_PROFILE_NAME ) == oldName )
  391. m_viaPropagationGrid->SetCellValue( row, VIA_GRID_PROFILE_NAME, newName );
  392. }
  393. }
  394. else
  395. {
  396. updateViaProfileNamesEditor( oldName, newName );
  397. }
  398. }
  399. else
  400. {
  401. event.Veto();
  402. }
  403. }
  404. }
  405. void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::updateViaProfileNamesEditor( const wxString& aOldName,
  406. const wxString& aNewName ) const
  407. {
  408. wxArrayString profileNames;
  409. for( int i = 0; i < m_tracePropagationGrid->GetNumberRows(); ++i )
  410. {
  411. wxString profileName = getProfileNameForProfileGridRow( i );
  412. if( profileName == aOldName )
  413. profileName = aNewName;
  414. profileNames.push_back( profileName );
  415. }
  416. std::ranges::sort( profileNames,
  417. []( const wxString& a, const wxString& b )
  418. {
  419. return a.CmpNoCase( b ) < 0;
  420. } );
  421. wxGridCellAttr* attr = new wxGridCellAttr;
  422. attr->SetEditor( new wxGridCellChoiceEditor( profileNames, false ) );
  423. m_viaPropagationGrid->SetColAttr( VIA_GRID_PROFILE_NAME, attr );
  424. }
  425. bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::validateDelayProfileName( int aRow, const wxString& aName, bool focusFirst )
  426. {
  427. wxString tmp = aName;
  428. tmp.Trim( true );
  429. tmp.Trim( false );
  430. if( tmp.IsEmpty() )
  431. {
  432. const wxString msg = _( "Tuning profile must have a name" );
  433. PAGED_DIALOG::GetDialog( this )->SetError( msg, this, m_tracePropagationGrid, aRow, PROFILE_GRID_PROFILE_NAME );
  434. return false;
  435. }
  436. for( int ii = 0; ii < m_tracePropagationGrid->GetNumberRows(); ii++ )
  437. {
  438. if( ii != aRow && getProfileNameForProfileGridRow( ii ).CmpNoCase( tmp ) == 0 )
  439. {
  440. const wxString msg = _( "Tuning profile name already in use" );
  441. PAGED_DIALOG::GetDialog( this )->SetError( msg, this, m_tracePropagationGrid, focusFirst ? aRow : ii,
  442. PROFILE_GRID_PROFILE_NAME );
  443. return false;
  444. }
  445. }
  446. return true;
  447. }
  448. bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::Validate()
  449. {
  450. if( !m_tracePropagationGrid->CommitPendingChanges() || !m_viaPropagationGrid->CommitPendingChanges() )
  451. return false;
  452. // Test delay profile parameters
  453. for( int row = 0; row < m_tracePropagationGrid->GetNumberRows(); row++ )
  454. {
  455. const wxString profileName = getProfileNameForProfileGridRow( row );
  456. if( !validateDelayProfileName( row, profileName, false ) )
  457. return false;
  458. }
  459. // Test via override parameters
  460. if( !validateViaRows() )
  461. return false;
  462. return true;
  463. }
  464. bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::validateViaRows()
  465. {
  466. std::map<wxString, std::set<DELAY_PROFILE_VIA_OVERRIDE_ENTRY>> rowCache;
  467. for( int row = 0; row < m_viaPropagationGrid->GetNumberRows(); row++ )
  468. {
  469. DELAY_PROFILE_VIA_OVERRIDE_ENTRY entry = getViaRow( row );
  470. const wxString profileName = m_viaPropagationGrid->GetCellValue( row, VIA_GRID_PROFILE_NAME );
  471. std::set<DELAY_PROFILE_VIA_OVERRIDE_ENTRY>& viaOverrides = rowCache[profileName];
  472. if( viaOverrides.contains( entry ) )
  473. {
  474. const wxString msg = _( "Via override configuration is duplicated" );
  475. PAGED_DIALOG::GetDialog( this )->SetError( msg, this, m_viaPropagationGrid, row, VIA_GRID_PROFILE_NAME );
  476. return false;
  477. }
  478. else
  479. {
  480. viaOverrides.insert( entry );
  481. }
  482. }
  483. return true;
  484. }
  485. std::vector<wxString> PANEL_SETUP_TIME_DOMAIN_PARAMETERS::GetDelayProfileNames() const
  486. {
  487. std::vector<wxString> profileNames;
  488. for( int i = 0; i < m_tracePropagationGrid->GetNumberRows(); i++ )
  489. {
  490. const wxString profileName = getProfileNameForProfileGridRow( i );
  491. profileNames.emplace_back( profileName );
  492. }
  493. std::ranges::sort( profileNames,
  494. []( const wxString& a, const wxString& b )
  495. {
  496. return a.CmpNoCase( b ) < 0;
  497. } );
  498. return profileNames;
  499. }
  500. void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::ImportSettingsFrom(
  501. const std::shared_ptr<TIME_DOMAIN_PARAMETERS>& aOtherParameters )
  502. {
  503. std::shared_ptr<TIME_DOMAIN_PARAMETERS> savedParameters = m_timeDomainParameters;
  504. m_timeDomainParameters = aOtherParameters;
  505. TransferDataToWindow();
  506. updateViaProfileNamesEditor();
  507. m_viaPropagationGrid->ForceRefresh();
  508. m_timeDomainParameters = std::move( savedParameters );
  509. }
  510. wxString PANEL_SETUP_TIME_DOMAIN_PARAMETERS::getProfileNameForProfileGridRow( const int aRow ) const
  511. {
  512. wxString profileName = m_tracePropagationGrid->GetCellValue( aRow, PROFILE_GRID_PROFILE_NAME );
  513. profileName.Trim( true ).Trim( false );
  514. return profileName;
  515. }