/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright The KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include PANEL_SETUP_TIME_DOMAIN_PARAMETERS::PANEL_SETUP_TIME_DOMAIN_PARAMETERS( wxWindow* aParentWindow, PCB_EDIT_FRAME* aFrame, BOARD* aBoard, std::shared_ptr aTimeDomainParameters ) : PANEL_SETUP_TIME_DOMAIN_PARAMETERS_BASE( aParentWindow ), m_timeDomainParameters( std::move( aTimeDomainParameters ) ), m_frame( aFrame ), m_board( aFrame->GetBoard() ) { m_timeDomainParametersPane->SetBorders( true, false, false, false ); // Set up units m_unitsProvider = std::make_unique( pcbIUScale, m_frame->GetUserUnits() ); m_tracePropagationGrid->SetUnitsProvider( m_unitsProvider.get() ); m_viaPropagationGrid->SetUnitsProvider( m_unitsProvider.get() ); Freeze(); m_splitter->SetMinimumPaneSize( FromDIP( m_splitter->GetMinimumPaneSize() ) ); // Set up the tuning profiles grid m_tracePropagationGrid->BeginBatch(); m_tracePropagationGrid->SetUseNativeColLabels(); m_tracePropagationGrid->EnsureColLabelsVisible(); m_tracePropagationGrid->PushEventHandler( new GRID_TRICKS( m_tracePropagationGrid ) ); m_tracePropagationGrid->SetSelectionMode( wxGrid::wxGridSelectRows ); m_addDelayProfileButton->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) ); m_removeDelayProfileButton->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) ); m_tracePropagationGrid->EndBatch(); m_tracePropagationGrid->Connect( wxEVT_GRID_CELL_CHANGING, wxGridEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnDelayProfileGridCellChanging ), nullptr, this ); // Set up the via override grid m_viaPropagationGrid->BeginBatch(); m_viaPropagationGrid->SetUseNativeColLabels(); m_viaPropagationGrid->EnsureColLabelsVisible(); m_viaPropagationGrid->PushEventHandler( new GRID_TRICKS( m_viaPropagationGrid ) ); m_viaPropagationGrid->SetSelectionMode( wxGrid::wxGridSelectRows ); std::vector viaColIds; m_viaPropagationGrid->SetAutoEvalColUnits( VIA_GRID_DELAY, m_unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::TIME ) ); viaColIds.push_back( VIA_GRID_DELAY ); m_viaPropagationGrid->SetAutoEvalCols( viaColIds ); m_viaPropagationGrid->EndBatch(); m_addViaOverrideButton->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) ); m_removeViaOverrideButton->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) ); setColumnWidths(); Thaw(); } PANEL_SETUP_TIME_DOMAIN_PARAMETERS::~PANEL_SETUP_TIME_DOMAIN_PARAMETERS() { // Delete the GRID_TRICKS m_tracePropagationGrid->PopEventHandler( true ); m_viaPropagationGrid->PopEventHandler( true ); m_tracePropagationGrid->Disconnect( wxEVT_GRID_CELL_CHANGING, wxGridEventHandler( PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnDelayProfileGridCellChanging ), nullptr, this ); } bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::TransferDataToWindow() { m_tracePropagationGrid->ClearRows(); m_viaPropagationGrid->ClearRows(); const std::vector& delayProfiles = m_timeDomainParameters->GetDelayProfiles(); SyncCopperLayers( m_board->GetCopperLayerCount() ); for( const DELAY_PROFILE& profile : delayProfiles ) { addProfileRow( profile ); for( const DELAY_PROFILE_VIA_OVERRIDE_ENTRY& viaOverride : profile.m_ViaOverrides ) addViaRow( profile.m_ProfileName, viaOverride ); } updateViaProfileNamesEditor(); return true; } bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::TransferDataFromWindow() { if( !Validate() ) return false; m_timeDomainParameters->ClearDelayProfiles(); for( int i = 0; i < m_tracePropagationGrid->GetNumberRows(); ++i ) { DELAY_PROFILE profile = getProfileRow( i ); wxString profileName = profile.m_ProfileName; for( int j = 0; j < m_viaPropagationGrid->GetNumberRows(); ++j ) { if( m_viaPropagationGrid->GetCellValue( j, VIA_GRID_PROFILE_NAME ) == profileName ) profile.m_ViaOverrides.emplace_back( getViaRow( j ) ); } m_timeDomainParameters->AddDelayProfile( std::move( profile ) ); } return true; } void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::addProfileRow( const DELAY_PROFILE& aDelayProfile ) { const int rowId = m_tracePropagationGrid->GetNumberRows(); m_tracePropagationGrid->AppendRows(); m_tracePropagationGrid->SetCellValue( rowId, PROFILE_GRID_PROFILE_NAME, aDelayProfile.m_ProfileName ); m_tracePropagationGrid->SetUnitValue( rowId, PROFILE_GRID_VIA_PROP_DELAY, aDelayProfile.m_ViaPropagationDelay ); for( const auto& [layerId, velocity] : aDelayProfile.m_LayerPropagationDelays ) { if( !m_copperLayerIdsToColumns.contains( layerId ) ) continue; int col = m_copperLayerIdsToColumns[layerId]; if( col < m_tracePropagationGrid->GetNumberCols() ) m_tracePropagationGrid->SetUnitValue( rowId, col, velocity ); } } DELAY_PROFILE PANEL_SETUP_TIME_DOMAIN_PARAMETERS::getProfileRow( const int aRow ) { DELAY_PROFILE entry; entry.m_ProfileName = getProfileNameForProfileGridRow( aRow ); entry.m_ViaPropagationDelay = m_tracePropagationGrid->GetUnitValue( aRow, PROFILE_GRID_VIA_PROP_DELAY ); std::map propDelays; for( const auto& [layer, col] : m_copperLayerIdsToColumns ) propDelays[layer] = m_tracePropagationGrid->GetUnitValue( aRow, col ); entry.m_LayerPropagationDelays = std::move( propDelays ); return entry; } void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::addViaRow( const wxString& aProfileName, const DELAY_PROFILE_VIA_OVERRIDE_ENTRY& aViaOverrideEntry ) const { const int rowId = m_viaPropagationGrid->GetNumberRows(); m_viaPropagationGrid->AppendRows(); m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_PROFILE_NAME, aProfileName ); m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_SIGNAL_LAYER_FROM, m_board->GetLayerName( aViaOverrideEntry.m_SignalLayerFrom ) ); m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_SIGNAL_LAYER_TO, m_board->GetLayerName( aViaOverrideEntry.m_SignalLayerTo ) ); m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_VIA_LAYER_FROM, m_board->GetLayerName( aViaOverrideEntry.m_ViaLayerFrom ) ); m_viaPropagationGrid->SetCellValue( rowId, VIA_GRID_VIA_LAYER_TO, m_board->GetLayerName( aViaOverrideEntry.m_ViaLayerTo ) ); m_viaPropagationGrid->SetUnitValue( rowId, VIA_GRID_DELAY, aViaOverrideEntry.m_Delay ); } DELAY_PROFILE_VIA_OVERRIDE_ENTRY PANEL_SETUP_TIME_DOMAIN_PARAMETERS::getViaRow( const int aRow ) { // Get layer info const wxString signalLayerFrom = m_viaPropagationGrid->GetCellValue( aRow, VIA_GRID_SIGNAL_LAYER_FROM ); const wxString signalLayerTo = m_viaPropagationGrid->GetCellValue( aRow, VIA_GRID_SIGNAL_LAYER_TO ); const wxString viaLayerFrom = m_viaPropagationGrid->GetCellValue( aRow, VIA_GRID_VIA_LAYER_FROM ); const wxString viaLayerTo = m_viaPropagationGrid->GetCellValue( aRow, VIA_GRID_VIA_LAYER_TO ); PCB_LAYER_ID signalLayerIdFrom = m_layerNamesToIDs[signalLayerFrom]; PCB_LAYER_ID signalLayerIdTo = m_layerNamesToIDs[signalLayerTo]; PCB_LAYER_ID viaLayerIdFrom = m_layerNamesToIDs[viaLayerFrom]; PCB_LAYER_ID viaLayerIdTo = m_layerNamesToIDs[viaLayerTo]; // Order layers in stackup order (from F_Cu first) if( IsCopperLayerLowerThan( signalLayerIdFrom, signalLayerIdTo ) ) std::swap( signalLayerIdFrom, signalLayerIdTo ); if( IsCopperLayerLowerThan( viaLayerIdFrom, viaLayerIdTo ) ) std::swap( viaLayerIdFrom, viaLayerIdTo ); const DELAY_PROFILE_VIA_OVERRIDE_ENTRY entry{ signalLayerIdFrom, signalLayerIdTo, viaLayerIdFrom, viaLayerIdTo, m_viaPropagationGrid->GetUnitValue( aRow, VIA_GRID_DELAY ) }; return entry; } void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::SyncCopperLayers( int aNumCopperLayers ) { m_prevLayerNamesToIDs = m_layerNamesToIDs; m_copperLayerIdsToColumns.clear(); m_copperColumnsToLayerId.clear(); m_layerNames.clear(); m_layerNamesToIDs.clear(); int colIdx = PROFILE_GRID_NUM_REQUIRED_COLS; for( const auto& layer : LSET::AllCuMask( aNumCopperLayers ).CuStack() ) { wxString layerName = m_board->GetLayerName( layer ); m_layerNames.emplace_back( layerName ); m_layerNamesToIDs[layerName] = layer; m_copperLayerIdsToColumns[layer] = colIdx; m_copperColumnsToLayerId[colIdx] = layer; ++colIdx; } updateProfileGridColumns(); updateViaGridColumns(); setColumnWidths(); } void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::setColumnWidths() { const int minValueWidth = m_tracePropagationGrid->GetTextExtent( wxT( "000.00 ps/mm" ) ).x; const int minNameWidth = m_tracePropagationGrid->GetTextExtent( wxT( "MMMMMMMMMMMM" ) ).x; for( int i = 0; i < m_tracePropagationGrid->GetNumberCols(); ++i ) { const int titleSize = m_tracePropagationGrid->GetTextExtent( m_tracePropagationGrid->GetColLabelValue( i ) ).x; if( i == PROFILE_GRID_PROFILE_NAME ) m_tracePropagationGrid->SetColSize( i, std::max( titleSize, minNameWidth ) ); else m_tracePropagationGrid->SetColSize( i, std::max( titleSize, minValueWidth ) ); } for( int i = 0; i < m_viaPropagationGrid->GetNumberCols(); ++i ) { const int titleSize = GetTextExtent( m_viaPropagationGrid->GetColLabelValue( i ) ).x; if( i == VIA_GRID_PROFILE_NAME ) m_viaPropagationGrid->SetColSize( i, std::max( titleSize, minNameWidth ) ); else m_viaPropagationGrid->SetColSize( i, titleSize + 30 ); } } void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::updateProfileGridColumns() { const int newCopperLayers = static_cast( m_copperLayerIdsToColumns.size() ); const int curCopperLayers = m_tracePropagationGrid->GetNumberCols() - PROFILE_GRID_NUM_REQUIRED_COLS; if( newCopperLayers < curCopperLayers ) { // TODO: WARN OF DELETING DATA? m_tracePropagationGrid->DeleteCols( curCopperLayers - newCopperLayers + PROFILE_GRID_NUM_REQUIRED_COLS, curCopperLayers - newCopperLayers ); } else if( newCopperLayers > curCopperLayers ) { m_tracePropagationGrid->AppendCols( newCopperLayers - curCopperLayers ); } std::vector copperColIds; m_tracePropagationGrid->SetAutoEvalColUnits( PROFILE_GRID_VIA_PROP_DELAY, m_unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::LENGTH_DELAY ) ); copperColIds.push_back( PROFILE_GRID_VIA_PROP_DELAY ); for( const auto& [colIdx, layerId] : m_copperColumnsToLayerId ) { m_tracePropagationGrid->SetColLabelValue( colIdx, m_board->GetLayerName( layerId ) ); m_tracePropagationGrid->SetAutoEvalColUnits( colIdx, m_unitsProvider->GetUnitsFromType( EDA_DATA_TYPE::LENGTH_DELAY ) ); copperColIds.push_back( colIdx ); } m_tracePropagationGrid->SetAutoEvalCols( copperColIds ); m_tracePropagationGrid->EnsureColLabelsVisible(); m_tracePropagationGrid->Refresh(); } void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::updateViaGridColumns() { wxArrayString layerNames; std::ranges::for_each( m_layerNames, [&layerNames]( const wxString& aLayerName ) { layerNames.push_back( aLayerName ); } ); // Save the current data std::vector currentSignalLayersFrom; std::vector currentSignalLayersTo; std::vector currentViaLayersFrom; std::vector currentViaLayersTo; for( int row = 0; row < m_viaPropagationGrid->GetNumberRows(); ++row ) { currentSignalLayersFrom.emplace_back( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM ) ); currentSignalLayersTo.emplace_back( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO ) ); currentViaLayersFrom.emplace_back( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_VIA_LAYER_FROM ) ); currentViaLayersTo.emplace_back( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_VIA_LAYER_TO ) ); } // Reset the via layers lists wxGridCellAttr* attr = new wxGridCellAttr; attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) ); m_viaPropagationGrid->SetColAttr( VIA_GRID_SIGNAL_LAYER_FROM, attr ); attr = new wxGridCellAttr; attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) ); m_viaPropagationGrid->SetColAttr( VIA_GRID_SIGNAL_LAYER_TO, attr ); attr = new wxGridCellAttr; attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) ); m_viaPropagationGrid->SetColAttr( VIA_GRID_VIA_LAYER_FROM, attr ); attr = new wxGridCellAttr; attr->SetEditor( new wxGridCellChoiceEditor( layerNames, false ) ); m_viaPropagationGrid->SetColAttr( VIA_GRID_VIA_LAYER_TO, attr ); // Restore the data, changing or resetting layer names if required for( int row = 0; row < m_viaPropagationGrid->GetNumberRows(); ++row ) { const PCB_LAYER_ID lastSignalFromId = m_prevLayerNamesToIDs[currentSignalLayersFrom[row]]; if( m_copperLayerIdsToColumns.contains( lastSignalFromId ) ) m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM, m_board->GetLayerName( lastSignalFromId ) ); else m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM, m_layerNames.front() ); const PCB_LAYER_ID lastSignalToId = m_prevLayerNamesToIDs[currentSignalLayersTo[row]]; if( m_copperLayerIdsToColumns.contains( lastSignalToId ) ) m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO, m_board->GetLayerName( lastSignalToId ) ); else m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO, m_layerNames.back() ); const PCB_LAYER_ID lastViaFromId = m_prevLayerNamesToIDs[currentViaLayersFrom[row]]; if( m_copperLayerIdsToColumns.contains( lastViaFromId ) ) m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, m_board->GetLayerName( lastViaFromId ) ); else m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, m_layerNames.front() ); const PCB_LAYER_ID lastViaToId = m_prevLayerNamesToIDs[currentViaLayersTo[row]]; if( m_copperLayerIdsToColumns.contains( lastViaToId ) ) m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, m_board->GetLayerName( lastViaToId ) ); else m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, m_layerNames.back() ); } } void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnAddDelayProfileClick( wxCommandEvent& event ) { m_tracePropagationGrid->OnAddRow( [&]() -> std::pair { const int row = m_tracePropagationGrid->GetNumberRows(); m_tracePropagationGrid->AppendRows(); m_tracePropagationGrid->SetCellValue( row, PROFILE_GRID_PROFILE_NAME, "" ); for( int i = PROFILE_GRID_VIA_PROP_DELAY; i < m_tracePropagationGrid->GetNumberCols(); ++i ) m_tracePropagationGrid->SetUnitValue( row, i, 0 ); return { row, PROFILE_GRID_PROFILE_NAME }; } ); } void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnRemoveDelayProfileClick( wxCommandEvent& event ) { m_tracePropagationGrid->OnDeleteRows( [&]( int row ) { wxString profileName = getProfileNameForProfileGridRow( row ); // Delete associated via overrides for( int viaRow = m_viaPropagationGrid->GetNumberRows() - 1; viaRow >= 0; --viaRow ) { if( m_viaPropagationGrid->GetCellValue( viaRow, VIA_GRID_PROFILE_NAME ) == profileName ) m_viaPropagationGrid->DeleteRows( viaRow, 1 ); } // Delete tuning profile m_tracePropagationGrid->DeleteRows( row, 1 ); updateViaProfileNamesEditor(); } ); } void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnAddViaOverrideClick( wxCommandEvent& event ) { m_viaPropagationGrid->OnAddRow( [&]() -> std::pair { const int row = m_viaPropagationGrid->GetNumberRows(); // Check we have delay profiles to override if( m_tracePropagationGrid->GetNumberRows() == 0 ) { PAGED_DIALOG::GetDialog( this )->SetError( _( "No delay profiles to override" ), this, nullptr ); return { row, -1 }; } m_viaPropagationGrid->AppendRows(); m_viaPropagationGrid->SetCellValue( row, VIA_GRID_PROFILE_NAME, getProfileNameForProfileGridRow( 0 ) ); m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_FROM, m_layerNames.front() ); m_viaPropagationGrid->SetCellValue( row, VIA_GRID_SIGNAL_LAYER_TO, m_layerNames.back() ); m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_FROM, m_layerNames.front() ); m_viaPropagationGrid->SetCellValue( row, VIA_GRID_VIA_LAYER_TO, m_layerNames.back() ); m_viaPropagationGrid->SetUnitValue( row, VIA_GRID_DELAY, 0 ); return { row, VIA_GRID_DELAY }; } ); } void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnRemoveViaOverrideClick( wxCommandEvent& event ) { m_viaPropagationGrid->OnDeleteRows( [&]( int row ) { m_viaPropagationGrid->DeleteRows( row, 1 ); } ); } void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::OnDelayProfileGridCellChanging( wxGridEvent& event ) { if( event.GetCol() == PROFILE_GRID_PROFILE_NAME ) { if( validateDelayProfileName( event.GetRow(), event.GetString() ) ) { const wxString oldName = getProfileNameForProfileGridRow( event.GetRow() ); wxString newName = event.GetString(); newName.Trim( true ).Trim( false ); if( !oldName.IsEmpty() ) { wxWindowUpdateLocker updateLocker( m_viaPropagationGrid ); updateViaProfileNamesEditor( oldName, newName ); // Update changed profile names for( int row = 0; row < m_viaPropagationGrid->GetNumberRows(); ++row ) { if( m_viaPropagationGrid->GetCellValue( row, VIA_GRID_PROFILE_NAME ) == oldName ) m_viaPropagationGrid->SetCellValue( row, VIA_GRID_PROFILE_NAME, newName ); } } else { updateViaProfileNamesEditor( oldName, newName ); } } else { event.Veto(); } } } void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::updateViaProfileNamesEditor( const wxString& aOldName, const wxString& aNewName ) const { wxArrayString profileNames; for( int i = 0; i < m_tracePropagationGrid->GetNumberRows(); ++i ) { wxString profileName = getProfileNameForProfileGridRow( i ); if( profileName == aOldName ) profileName = aNewName; profileNames.push_back( profileName ); } std::ranges::sort( profileNames, []( const wxString& a, const wxString& b ) { return a.CmpNoCase( b ) < 0; } ); wxGridCellAttr* attr = new wxGridCellAttr; attr->SetEditor( new wxGridCellChoiceEditor( profileNames, false ) ); m_viaPropagationGrid->SetColAttr( VIA_GRID_PROFILE_NAME, attr ); } bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::validateDelayProfileName( int aRow, const wxString& aName, bool focusFirst ) { wxString tmp = aName; tmp.Trim( true ); tmp.Trim( false ); if( tmp.IsEmpty() ) { const wxString msg = _( "Tuning profile must have a name" ); PAGED_DIALOG::GetDialog( this )->SetError( msg, this, m_tracePropagationGrid, aRow, PROFILE_GRID_PROFILE_NAME ); return false; } for( int ii = 0; ii < m_tracePropagationGrid->GetNumberRows(); ii++ ) { if( ii != aRow && getProfileNameForProfileGridRow( ii ).CmpNoCase( tmp ) == 0 ) { const wxString msg = _( "Tuning profile name already in use" ); PAGED_DIALOG::GetDialog( this )->SetError( msg, this, m_tracePropagationGrid, focusFirst ? aRow : ii, PROFILE_GRID_PROFILE_NAME ); return false; } } return true; } bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::Validate() { if( !m_tracePropagationGrid->CommitPendingChanges() || !m_viaPropagationGrid->CommitPendingChanges() ) return false; // Test delay profile parameters for( int row = 0; row < m_tracePropagationGrid->GetNumberRows(); row++ ) { const wxString profileName = getProfileNameForProfileGridRow( row ); if( !validateDelayProfileName( row, profileName, false ) ) return false; } // Test via override parameters if( !validateViaRows() ) return false; return true; } bool PANEL_SETUP_TIME_DOMAIN_PARAMETERS::validateViaRows() { std::map> rowCache; for( int row = 0; row < m_viaPropagationGrid->GetNumberRows(); row++ ) { DELAY_PROFILE_VIA_OVERRIDE_ENTRY entry = getViaRow( row ); const wxString profileName = m_viaPropagationGrid->GetCellValue( row, VIA_GRID_PROFILE_NAME ); std::set& viaOverrides = rowCache[profileName]; if( viaOverrides.contains( entry ) ) { const wxString msg = _( "Via override configuration is duplicated" ); PAGED_DIALOG::GetDialog( this )->SetError( msg, this, m_viaPropagationGrid, row, VIA_GRID_PROFILE_NAME ); return false; } else { viaOverrides.insert( entry ); } } return true; } std::vector PANEL_SETUP_TIME_DOMAIN_PARAMETERS::GetDelayProfileNames() const { std::vector profileNames; for( int i = 0; i < m_tracePropagationGrid->GetNumberRows(); i++ ) { const wxString profileName = getProfileNameForProfileGridRow( i ); profileNames.emplace_back( profileName ); } std::ranges::sort( profileNames, []( const wxString& a, const wxString& b ) { return a.CmpNoCase( b ) < 0; } ); return profileNames; } void PANEL_SETUP_TIME_DOMAIN_PARAMETERS::ImportSettingsFrom( const std::shared_ptr& aOtherParameters ) { std::shared_ptr savedParameters = m_timeDomainParameters; m_timeDomainParameters = aOtherParameters; TransferDataToWindow(); updateViaProfileNamesEditor(); m_viaPropagationGrid->ForceRefresh(); m_timeDomainParameters = std::move( savedParameters ); } wxString PANEL_SETUP_TIME_DOMAIN_PARAMETERS::getProfileNameForProfileGridRow( const int aRow ) const { wxString profileName = m_tracePropagationGrid->GetCellValue( aRow, PROFILE_GRID_PROFILE_NAME ); profileName.Trim( true ).Trim( false ); return profileName; }