diff --git a/eeschema/dialogs/dialog_field_properties.cpp b/eeschema/dialogs/dialog_field_properties.cpp index 1a883d84cc..8b386f7383 100644 --- a/eeschema/dialogs/dialog_field_properties.cpp +++ b/eeschema/dialogs/dialog_field_properties.cpp @@ -144,9 +144,16 @@ DIALOG_FIELD_PROPERTIES::DIALOG_FIELD_PROPERTIES( SCH_BASE_FRAME* aParent, const // show text variable cross-references in a human-readable format if( aField->Schematic() ) - m_text = aField->Schematic()->ConvertKIIDsToRefs( aField->GetText() ); + { + const SCH_SHEET_PATH& sheetPath = aField->Schematic()->CurrentSheet(); + wxString variant = aField->Schematic()->GetCurrentVariant(); + + m_text = aField->Schematic()->ConvertKIIDsToRefs( aField->GetText( &sheetPath, variant ) ); + } else + { m_text = aField->GetText(); + } m_font = m_field->GetFont(); m_isItalic = aField->IsItalic(); @@ -581,7 +588,17 @@ void DIALOG_FIELD_PROPERTIES::updateText( SCH_FIELD* aField ) void DIALOG_FIELD_PROPERTIES::UpdateField( SCH_FIELD* aField ) { - aField->SetText( m_text ); + if( aField->Schematic() ) + { + const SCH_SHEET_PATH& sheetPath = aField->Schematic()->CurrentSheet(); + wxString variant = aField->Schematic()->GetCurrentVariant(); + + aField->SetText( m_text, &sheetPath, variant ); + } + else + { + aField->SetText( m_text ); + } updateText( aField ); @@ -605,6 +622,18 @@ void DIALOG_FIELD_PROPERTIES::UpdateField( SCH_COMMIT* aCommit, SCH_FIELD* aFiel { SCH_EDIT_FRAME* editFrame = dynamic_cast( GetParent() ); SCH_ITEM* parent = dynamic_cast( aField->GetParent() ); + bool fieldTextSet = false; + SCH_SHEET_PATH sheetPath; + wxString variantName; + + // convert any text variable cross-references to their UUIDs + m_text = aField->Schematic()->ConvertRefsToKIIDs( m_text ); + + if( aField->Schematic() ) + { + sheetPath = aField->Schematic()->CurrentSheet(); + variantName = aField->Schematic()->GetCurrentVariant(); + } if( parent && parent->Type() == SCH_SYMBOL_T ) { @@ -612,6 +641,10 @@ void DIALOG_FIELD_PROPERTIES::UpdateField( SCH_COMMIT* aCommit, SCH_FIELD* aFiel if( m_fieldId == FIELD_T::REFERENCE ) symbol->SetRef( aSheetPath, m_text ); + else + symbol->SetFieldText( aField->GetName(), m_text, &sheetPath, variantName ); + + fieldTextSet = true; // Set the unit selection in multiple units per package if( m_unitChoice->IsShown() ) @@ -621,6 +654,16 @@ void DIALOG_FIELD_PROPERTIES::UpdateField( SCH_COMMIT* aCommit, SCH_FIELD* aFiel symbol->SetUnit( unit_selection ); } } + else if( parent && parent->Type() == SCH_SHEET_T ) + { + SCH_SHEET* sheet = static_cast( parent ); + + if( !aField->IsMandatory() ) + { + sheet->SetFieldText( aField->GetName(), m_text, &sheetPath, variantName ); + fieldTextSet = true; + } + } else if( parent && parent->Type() == SCH_GLOBAL_LABEL_T ) { if( m_fieldId == FIELD_T::INTERSHEET_REFS ) @@ -648,16 +691,15 @@ void DIALOG_FIELD_PROPERTIES::UpdateField( SCH_COMMIT* aCommit, SCH_FIELD* aFiel if( aField->GetEffectiveVertJustify() != m_verticalJustification ) positioningModified = true; - // convert any text variable cross-references to their UUIDs - m_text = aField->Schematic()->ConvertRefsToKIIDs( m_text ); - // Changing a sheetname need to update the hierarchy navigator bool needUpdateHierNav = false; if( m_fieldId == FIELD_T::SHEET_NAME ) needUpdateHierNav = m_text != aField->GetText(); - aField->SetText( m_text ); + if( !fieldTextSet ) + aField->SetText( m_text ); + updateText( aField ); aField->SetPosition( m_position ); diff --git a/eeschema/dialogs/dialog_sheet_properties.cpp b/eeschema/dialogs/dialog_sheet_properties.cpp index 64f56e9fdf..4c1d8e6b74 100644 --- a/eeschema/dialogs/dialog_sheet_properties.cpp +++ b/eeschema/dialogs/dialog_sheet_properties.cpp @@ -125,6 +125,9 @@ bool DIALOG_SHEET_PROPERTIES::TransferDataToWindow() if( !wxDialog::TransferDataToWindow() ) return false; + SCH_SHEET_PATH instance = m_frame->GetCurrentSheet(); + wxString variantName = m_frame->Schematic().GetCurrentVariant(); + // Push a copy of each field into m_updateFields for( SCH_FIELD& field : m_sheet->GetFields() ) { @@ -140,6 +143,9 @@ bool DIALOG_SHEET_PROPERTIES::TransferDataToWindow() } #endif + if( !field_copy.IsMandatory() ) + field_copy.SetText( m_sheet->GetFieldText( field.GetName(), &instance, variantName ) ); + // change offset to be symbol-relative field_copy.Offset( -m_sheet->GetPosition() ); @@ -167,15 +173,13 @@ bool DIALOG_SHEET_PROPERTIES::TransferDataToWindow() m_borderSwatch->SetSwatchBackground( canvas ); m_backgroundSwatch->SetSwatchBackground( canvas ); - SCH_SHEET_PATH instance = m_frame->GetCurrentSheet(); - instance.push_back( m_sheet ); - - m_pageNumberTextCtrl->ChangeValue( instance.GetPageNumber() ); - - m_cbExcludeFromSim->SetValue( m_sheet->GetExcludedFromSim() ); - m_cbExcludeFromBom->SetValue( m_sheet->GetExcludedFromBOM() ); + m_cbExcludeFromSim->SetValue( m_sheet->GetExcludedFromSim( &instance, variantName ) ); + m_cbExcludeFromBom->SetValue( m_sheet->GetExcludedFromBOM( &instance, variantName ) ); m_cbExcludeFromBoard->SetValue( m_sheet->GetExcludedFromBoard() ); - m_cbDNP->SetValue( m_sheet->GetDNP() ); + m_cbDNP->SetValue( m_sheet->GetDNP( &instance, variantName ) ); + + instance.push_back( m_sheet ); + m_pageNumberTextCtrl->ChangeValue( instance.GetPageNumber() ); return true; } @@ -362,6 +366,9 @@ bool DIALOG_SHEET_PROPERTIES::TransferDataFromWindow() if( positioningChanged( m_fields, m_sheet ) ) m_sheet->SetFieldsAutoplaced( AUTOPLACE_NONE ); + SCH_SHEET_PATH instance = m_frame->GetCurrentSheet(); + wxString variantName = m_frame->Schematic().GetCurrentVariant(); + for( int ii = m_fields->GetNumberRows() - 1; ii >= 0; ii-- ) { SCH_FIELD& field = m_fields->at( ii ); @@ -375,9 +382,31 @@ bool DIALOG_SHEET_PROPERTIES::TransferDataFromWindow() m_fields->erase( m_fields->begin() + ii ); else if( fieldName.IsEmpty() ) field.SetName( _( "untitled" ) ); - } - m_sheet->SetFields( *m_fields ); + SCH_FIELD* existingField = m_sheet->GetField( fieldName ); + SCH_FIELD* tmp; + + if( !existingField ) + { + m_sheet->AddOptionalField( field ); + } + else + { + wxString defaultText = m_sheet->Schematic()->ConvertRefsToKIIDs( existingField->GetText() ); + tmp = const_cast( existingField ); + + *tmp = field; + + if( !variantName.IsEmpty() ) + { + // Restore the default field text for existing fields. + tmp->SetText( defaultText, &instance ); + + tmp->SetText( m_sheet->Schematic()->ConvertRefsToKIIDs( field.GetText() ), + &instance, variantName ); + } + } + } m_sheet->SetBorderWidth( m_borderWidth.GetIntValue() ); @@ -404,12 +433,10 @@ bool DIALOG_SHEET_PROPERTIES::TransferDataFromWindow() m_sheet->SetBorderColor( m_borderSwatch->GetSwatchColor() ); m_sheet->SetBackgroundColor( m_backgroundSwatch->GetSwatchColor() ); - m_sheet->SetExcludedFromSim( m_cbExcludeFromSim->GetValue() ); - m_sheet->SetExcludedFromBOM( m_cbExcludeFromBom->GetValue() ); + m_sheet->SetExcludedFromSim( m_cbExcludeFromSim->GetValue(), &instance, variantName ); + m_sheet->SetExcludedFromBOM( m_cbExcludeFromBom->GetValue(), &instance, variantName ); m_sheet->SetExcludedFromBoard( m_cbExcludeFromBoard->GetValue() ); - m_sheet->SetDNP( m_cbDNP->GetValue() ); - - SCH_SHEET_PATH instance = m_frame->GetCurrentSheet(); + m_sheet->SetDNP( m_cbDNP->GetValue(), &instance, variantName ); instance.push_back( m_sheet ); diff --git a/eeschema/dialogs/dialog_symbol_fields_table.cpp b/eeschema/dialogs/dialog_symbol_fields_table.cpp index 9ba5d2eed8..c6862f1e2f 100644 --- a/eeschema/dialogs/dialog_symbol_fields_table.cpp +++ b/eeschema/dialogs/dialog_symbol_fields_table.cpp @@ -263,6 +263,20 @@ DIALOG_SYMBOL_FIELDS_TABLE::DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent, m_variantListBox->Set( parent->Schematic().GetVariantNamesForUI() ); + if( !m_parent->Schematic().GetCurrentVariant().IsEmpty() ) + { + int toSelect = m_variantListBox->FindString( m_parent->Schematic().GetCurrentVariant() ); + + if( toSelect == wxNOT_FOUND ) + m_variantListBox->SetSelection( 0 ); + else + m_variantListBox->SetSelection( toSelect ); + } + else + { + m_variantListBox->SetSelection( 0 ); + } + if( !ADVANCED_CFG::GetCfg().m_EnableVariantsUI ) m_splitter_left->Unsplit( m_variantsPanel ); @@ -553,7 +567,7 @@ void DIALOG_SYMBOL_FIELDS_TABLE::SetupAllColumnProperties() bool DIALOG_SYMBOL_FIELDS_TABLE::TransferDataToWindow() { - if( !wxDialog::TransferDataFromWindow() ) + if( !wxDialog::TransferDataToWindow() ) return false; TOOL_MANAGER* toolMgr = m_parent->GetToolManager(); @@ -644,11 +658,11 @@ bool DIALOG_SYMBOL_FIELDS_TABLE::TransferDataFromWindow() return true; } - std::set selectedVariantNames; SCH_COMMIT commit( m_parent ); SCH_SHEET_PATH currentSheet = m_parent->GetCurrentSheet(); + wxString currentVariant = m_parent->Schematic().GetCurrentVariant(); - m_dataModel->ApplyData( commit, m_schSettings.m_TemplateFieldNames, selectedVariantNames ); + m_dataModel->ApplyData( commit, m_schSettings.m_TemplateFieldNames, currentVariant ); if( !commit.Empty() ) { @@ -676,7 +690,7 @@ void DIALOG_SYMBOL_FIELDS_TABLE::AddField( const wxString& aFieldName, const wxS return; } - m_dataModel->AddColumn( aFieldName, aLabelValue, addedByUser, getSelectedVariants() ); + m_dataModel->AddColumn( aFieldName, aLabelValue, addedByUser, m_parent->Schematic().GetCurrentVariant() ); wxGridTableMessage msg( m_dataModel, wxGRIDTABLE_NOTIFY_COLS_APPENDED, 1 ); m_grid->ProcessTableMessage( msg ); @@ -1940,7 +1954,7 @@ void DIALOG_SYMBOL_FIELDS_TABLE::doApplyBomPreset( const BOM_PRESET& aPreset ) // Basically, we apply the BOM preset to the data model and then // update our UI to reflect resulting the data model state, not the preset. - m_dataModel->ApplyBomPreset( aPreset, getSelectedVariants() ); + m_dataModel->ApplyBomPreset( aPreset, m_parent->Schematic().GetCurrentVariant() ); // BOM Presets can add, but not remove, columns, so make sure the view controls // grid has all of them before starting @@ -2481,7 +2495,8 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnSchItemsChanged( SCHEMATIC& aSch, std::vector for( SCH_FIELD& field : symbol->GetFields() ) AddField( field.GetCanonicalName(), field.GetName(), true, false, true ); - m_dataModel->UpdateReferences( getSymbolReferences( symbol, allRefs ), getSelectedVariants() ); + m_dataModel->UpdateReferences( getSymbolReferences( symbol, allRefs ), + m_parent->Schematic().GetCurrentVariant() ); } else if( item->Type() == SCH_SHEET_T ) { @@ -2498,7 +2513,7 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnSchItemsChanged( SCHEMATIC& aSch, std::vector AddField( field.GetCanonicalName(), field.GetName(), true, false, true ); } - m_dataModel->UpdateReferences( refs, getSelectedVariants() ); + m_dataModel->UpdateReferences( refs, m_parent->Schematic().GetCurrentVariant() ); } } @@ -2618,99 +2633,99 @@ void DIALOG_SYMBOL_FIELDS_TABLE::onAddVariant( wxCommandEvent& aEvent ) void DIALOG_SYMBOL_FIELDS_TABLE::onDeleteVariant( wxCommandEvent& aEvent ) { - wxArrayInt selections; + int selection = m_variantListBox->GetSelection(); // An empty or default selection cannot be deleted. - if( ( m_variantListBox->GetSelections( selections ) == 0 ) || ( selections[0] == 0 ) ) + if( ( selection == wxNOT_FOUND ) || ( selection == 0 ) ) { wxBell(); return; } - wxArrayString ctrlContents = m_variantListBox->GetStrings(); - - for( int selection : selections ) - { - wxString variantName = m_variantListBox->GetString( selection ); - ctrlContents.Remove( variantName ); - m_parent->Schematic().DeleteVariant( variantName ); - } - - m_variantListBox->Set( ctrlContents ); + wxString variantName = m_variantListBox->GetString( selection ); + m_variantListBox->SetSelection( selection - 1 ); + m_variantListBox->Delete( selection ); + m_parent->Schematic().DeleteVariant( variantName ); } void DIALOG_SYMBOL_FIELDS_TABLE::onRenameVariant( wxCommandEvent& aEvent ) { - wxArrayInt selections; + // wxArrayInt selections; - // Only allow renaming a single selection that is not the default. - if( ( m_variantListBox->GetSelections( selections ) != 1 ) || ( selections[0] == 0 ) ) - { - wxBell(); - return; - } + // // Only allow renaming a single selection that is not the default. + // if( ( m_variantListBox->GetSelections( selections ) != 1 ) || ( selections[0] == 0 ) ) + // { + // wxBell(); + // return; + // } - wxArrayString ctrlContents = m_variantListBox->GetStrings(); - wxString oldVariantName = ctrlContents[selections[0]]; + // wxArrayString ctrlContents = m_variantListBox->GetStrings(); + // wxString oldVariantName = ctrlContents[selections[0]]; - wxTextEntryDialog dlg( this, _( "Add new variant name:" ), _( "New Variant" ), oldVariantName, - wxOK | wxCANCEL | wxCENTER ); + // wxTextEntryDialog dlg( this, _( "Add new variant name:" ), _( "New Variant" ), oldVariantName, + // wxOK | wxCANCEL | wxCENTER ); - if( dlg.ShowModal() == wxID_CANCEL ) - return; + // if( dlg.ShowModal() == wxID_CANCEL ) + // return; - wxString newVariantName = dlg.GetValue(); + // wxString newVariantName = dlg.GetValue(); - if( newVariantName.IsEmpty() || ( newVariantName == oldVariantName ) || ( newVariantName == ctrlContents[0] ) ) - { - wxBell(); - return; - } + // if( newVariantName.IsEmpty() || ( newVariantName == oldVariantName ) || ( newVariantName == ctrlContents[0] ) ) + // { + // wxBell(); + // return; + // } - ctrlContents.Remove( m_variantListBox->GetString( selections[0] ) ); - ctrlContents.Add( newVariantName ); - ctrlContents.Sort( SortVariantNames ); - m_variantListBox->Set( ctrlContents ); + // ctrlContents.Remove( m_variantListBox->GetString( selections[0] ) ); + // ctrlContents.Add( newVariantName ); + // ctrlContents.Sort( SortVariantNames ); + // m_variantListBox->Set( ctrlContents ); } void DIALOG_SYMBOL_FIELDS_TABLE::onVariantSelectionChange( wxCommandEvent& aEvent ) { - std::set selectedVariants = getSelectedVariants(); - - m_dataModel->UpdateReferences( m_symbolsList, selectedVariants ); + wxString currentVariant; + wxString selectedVariant = getSelectedVariant(); if( m_parent ) { - wxString selectedVariant = GetDefaultVariantName(); + currentVariant = m_parent->Schematic().GetCurrentVariant(); - // Selecting more than one variant in the schematic editor doesn't make any sense. Select the first - // variant in the table editor dialog as the variant to show in the schematic editor. - if( selectedVariants.size() >= 1 ) - selectedVariant = *selectedVariants.cbegin(); - - m_parent->SetCurrentVariant( selectedVariant ); + if( currentVariant != selectedVariant ) + m_parent->SetCurrentVariant( selectedVariant ); } -} - -std::set DIALOG_SYMBOL_FIELDS_TABLE::getSelectedVariants() const -{ - std::set retv; - - wxArrayInt selections; - - if( m_variantListBox->GetSelections( selections ) ) + if( currentVariant != selectedVariant ) { - for( int selection : selections ) + if( m_grid->CommitPendingChanges( true ) ) { - if( selection == 0 ) - continue; + m_dataModel->UpdateReferences( m_dataModel->GetReferenceList(), selectedVariant ); + m_dataModel->RebuildRows(); - retv.emplace( m_variantListBox->GetString( selection ) ); + if( m_nbPages->GetSelection() == 1 ) + PreviewRefresh(); + else + m_grid->ForceRefresh(); + + syncBomFmtPresetSelection(); + } + else + { } } +} - return retv; + +wxString DIALOG_SYMBOL_FIELDS_TABLE::getSelectedVariant() const +{ + wxString retv; + + int selection = m_variantListBox->GetSelection(); + + if( ( selection == wxNOT_FOUND ) || ( m_variantListBox->GetString( selection ) == GetDefaultVariantName() ) ) + return retv; + + return m_variantListBox->GetString( selection ); } diff --git a/eeschema/dialogs/dialog_symbol_fields_table.h b/eeschema/dialogs/dialog_symbol_fields_table.h index f7cfa8f0a4..661fe7aa4b 100644 --- a/eeschema/dialogs/dialog_symbol_fields_table.h +++ b/eeschema/dialogs/dialog_symbol_fields_table.h @@ -144,7 +144,7 @@ private: void onRenameVariant( wxCommandEvent& aEvent ) override; void onVariantSelectionChange( wxCommandEvent& aEvent ) override; - std::set getSelectedVariants() const; + wxString getSelectedVariant() const; private: std::map m_bomPresets; diff --git a/eeschema/dialogs/dialog_symbol_fields_table_base.cpp b/eeschema/dialogs/dialog_symbol_fields_table_base.cpp index e4a1bdd3ab..cc38ee240b 100644 --- a/eeschema/dialogs/dialog_symbol_fields_table_base.cpp +++ b/eeschema/dialogs/dialog_symbol_fields_table_base.cpp @@ -138,7 +138,7 @@ DIALOG_SYMBOL_FIELDS_TABLE_BASE::DIALOG_SYMBOL_FIELDS_TABLE_BASE( wxWindow* pare m_staticText9->Wrap( -1 ); bMargins2->Add( m_staticText9, 0, wxTOP|wxBOTTOM|wxLEFT, 2 ); - m_variantListBox = new wxListBox( m_variantsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); + m_variantListBox = new wxListBox( m_variantsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_NEEDED_SB|wxLB_SINGLE ); bMargins2->Add( m_variantListBox, 1, wxEXPAND|wxBOTTOM, 2 ); wxBoxSizer* bSizer14; diff --git a/eeschema/dialogs/dialog_symbol_fields_table_base.fbp b/eeschema/dialogs/dialog_symbol_fields_table_base.fbp index fb11bd973c..61ce81e2c2 100644 --- a/eeschema/dialogs/dialog_symbol_fields_table_base.fbp +++ b/eeschema/dialogs/dialog_symbol_fields_table_base.fbp @@ -1053,7 +1053,7 @@ Resizable 1 - + wxLB_NEEDED_SB|wxLB_SINGLE ; ; forward_declare 0 diff --git a/eeschema/dialogs/dialog_symbol_properties.cpp b/eeschema/dialogs/dialog_symbol_properties.cpp index 479ca95c76..e095a2e9e9 100644 --- a/eeschema/dialogs/dialog_symbol_properties.cpp +++ b/eeschema/dialogs/dialog_symbol_properties.cpp @@ -400,6 +400,10 @@ DIALOG_SYMBOL_PROPERTIES::DIALOG_SYMBOL_PROPERTIES( SCH_EDIT_FRAME* aParent, SCH evt->SetClientData( new VECTOR2I( 0, FDC_VALUE ) ); QueueEvent( evt ); + // Remind user that they are editing the current variant. + if( !aParent->Schematic().GetCurrentVariant().IsEmpty() ) + SetTitle( GetTitle() + wxS( " - " ) + aParent->Schematic().GetCurrentVariant() + _( " Variant" ) ); + finishDialogSettings(); } @@ -434,6 +438,10 @@ bool DIALOG_SYMBOL_PROPERTIES::TransferDataToWindow() if( !wxDialog::TransferDataToWindow() ) return false; + const SCHEMATIC& schematic = GetParent()->Schematic(); + SCH_SHEET_PATH& sheetPath = schematic.CurrentSheet(); + wxString variantName = schematic.GetCurrentVariant(); + std::optional variant = m_symbol->GetVariant( sheetPath, variantName ); std::set defined; // Push a copy of each field into m_updateFields @@ -443,8 +451,8 @@ bool DIALOG_SYMBOL_PROPERTIES::TransferDataToWindow() // change offset to be symbol-relative field.Offset( -m_symbol->GetPosition() ); - - field.SetText( m_symbol->Schematic()->ConvertKIIDsToRefs( field.GetText() ) ); + field.SetText( schematic.ConvertKIIDsToRefs( m_symbol->GetFieldText( field.GetName(), &sheetPath, + variantName ) ) ); defined.insert( field.GetName() ); m_fields->push_back( field ); @@ -452,7 +460,7 @@ bool DIALOG_SYMBOL_PROPERTIES::TransferDataToWindow() // Add in any template fieldnames not yet defined: for( const TEMPLATE_FIELDNAME& templateFieldname : - GetParent()->Schematic().Settings().m_TemplateFieldNames.GetTemplateFieldNames() ) + schematic.Settings().m_TemplateFieldNames.GetTemplateFieldNames() ) { if( defined.count( templateFieldname.m_Name ) <= 0 ) { @@ -471,7 +479,7 @@ bool DIALOG_SYMBOL_PROPERTIES::TransferDataToWindow() { // Ensure symbol unit is the currently selected unit (mandatory in complex hierarchies) // from the current sheet path, because it can be modified by previous calculations - m_symbol->SetUnit( m_symbol->GetUnitSelection( &GetParent()->GetCurrentSheet() ) ); + m_symbol->SetUnit( m_symbol->GetUnitSelection( &sheetPath ) ); for( int ii = 1; ii <= m_symbol->GetUnitCount(); ii++ ) m_unitChoice->Append( m_symbol->GetUnitDisplayName( ii, false ) ); @@ -539,10 +547,10 @@ bool DIALOG_SYMBOL_PROPERTIES::TransferDataToWindow() case SYM_MIRROR_Y: m_mirrorCtrl->SetSelection( 2 ); break; } - m_cbExcludeFromSim->SetValue( m_symbol->GetExcludedFromSim() ); - m_cbExcludeFromBom->SetValue( m_symbol->GetExcludedFromBOM() ); + m_cbExcludeFromSim->SetValue( m_symbol->GetExcludedFromSim( &sheetPath, variantName ) ); + m_cbExcludeFromBom->SetValue( m_symbol->GetExcludedFromBOM( &sheetPath, variantName ) ); m_cbExcludeFromBoard->SetValue( m_symbol->GetExcludedFromBoard() ); - m_cbDNP->SetValue( m_symbol->GetDNP( &GetParent()->GetCurrentSheet() ) ); + m_cbDNP->SetValue( m_symbol->GetDNP( &sheetPath, variantName ) ); if( m_part ) { @@ -694,7 +702,10 @@ bool DIALOG_SYMBOL_PROPERTIES::TransferDataFromWindow() SCH_COMMIT commit( GetParent() ); SCH_SCREEN* currentScreen = GetParent()->GetScreen(); + SCH_SHEET_PATH currentSheet = GetParent()->Schematic().CurrentSheet(); + wxString currentVariant = GetParent()->Schematic().GetCurrentVariant(); bool replaceOnCurrentScreen; + wxCHECK( currentScreen, false ); // This needs to be done before the LIB_ID is changed to prevent stale library symbols in @@ -740,13 +751,9 @@ bool DIALOG_SYMBOL_PROPERTIES::TransferDataFromWindow() // change all field positions from relative to absolute for( SCH_FIELD& field : *m_fields ) - { field.Offset( m_symbol->GetPosition() ); - field.SetText( m_symbol->Schematic()->ConvertRefsToKIIDs( field.GetText() ) ); - } - SCH_FIELDS& fields = m_symbol->GetFields(); - fields.clear(); + int ordinal = 42; // Arbitrarily larger than any mandatory FIELD_T ids. for( SCH_FIELD& field : *m_fields ) { @@ -757,31 +764,40 @@ bool DIALOG_SYMBOL_PROPERTIES::TransferDataFromWindow() else if( fieldName.IsEmpty() ) field.SetName( _( "untitled" ) ); - fields.push_back( field ); - } + // The const version of GetField() is used to prevent a new field from automatically being created. + const SCH_FIELD* existingField = m_symbol->GetField( fieldName ); + SCH_FIELD* tmp; - int ordinal = 42; // Arbitrarily larger than any mandatory FIELD_T ids. + if( !existingField ) + { + tmp = m_symbol->GetField( fieldName ); + *tmp = field; + } + else + { + wxString defaultText = m_symbol->Schematic()->ConvertRefsToKIIDs( existingField->GetText() ); + tmp = const_cast( existingField ); + + *tmp = field; + + if( !currentVariant.IsEmpty() ) + { + // Restore the default field text for existing fields. + tmp->SetText( defaultText, ¤tSheet ); + + tmp->SetText( m_symbol->Schematic()->ConvertRefsToKIIDs( field.GetText() ), + ¤tSheet, currentVariant ); + } + } - for( SCH_FIELD& field : fields ) - { if( !field.IsMandatory() ) field.SetOrdinal( ordinal++ ); } - // Reference has a specific initialization, depending on the current active sheet - // because for a given symbol, in a complex hierarchy, there are more than one - // reference. - m_symbol->SetRef( &GetParent()->GetCurrentSheet(), m_fields->GetField( FIELD_T::REFERENCE )->GetText() ); - - // Similar for Value and Footprint, except that the GUI behavior is that they are kept - // in sync between multiple instances. - m_symbol->SetValueFieldText( m_fields->GetField( FIELD_T::VALUE )->GetText() ); - m_symbol->SetFootprintFieldText( m_fields->GetField( FIELD_T::FOOTPRINT )->GetText() ); - - m_symbol->SetExcludedFromSim( m_cbExcludeFromSim->IsChecked() ); - m_symbol->SetExcludedFromBOM( m_cbExcludeFromBom->IsChecked() ); + m_symbol->SetExcludedFromSim( m_cbExcludeFromSim->IsChecked(), ¤tSheet, currentVariant ); + m_symbol->SetExcludedFromBOM( m_cbExcludeFromBom->IsChecked(), ¤tSheet, currentVariant ); m_symbol->SetExcludedFromBoard( m_cbExcludeFromBoard->IsChecked() ); - m_symbol->SetDNP( m_cbDNP->IsChecked(), &GetParent()->GetCurrentSheet() ); + m_symbol->SetDNP( m_cbDNP->IsChecked(), ¤tSheet, currentVariant ); // Update any assignments if( m_dataModel ) @@ -798,7 +814,7 @@ bool DIALOG_SYMBOL_PROPERTIES::TransferDataFromWindow() // Keep fields other than the reference, include/exclude flags, and alternate pin assignements // in sync in multi-unit parts. - m_symbol->SyncOtherUnits( GetParent()->GetCurrentSheet(), commit, nullptr ); + m_symbol->SyncOtherUnits( currentSheet, commit, nullptr ); if( replaceOnCurrentScreen ) currentScreen->Append( m_symbol ); diff --git a/eeschema/fields_data_model.cpp b/eeschema/fields_data_model.cpp index ef24a02a75..e5a7281013 100644 --- a/eeschema/fields_data_model.cpp +++ b/eeschema/fields_data_model.cpp @@ -30,9 +30,6 @@ #include "fields_data_model.h" -static wxString multipleValues = wxS( "<...>" ); - - /** * Create a unique key for the data store by combining the #KIID_PATH from the * #SCH_SHEET_PATH with the symbol's UUID. @@ -201,7 +198,7 @@ const wxString FIELDS_EDITOR_GRID_DATA_MODEL::ITEM_NUMBER_VARIABLE = wxS( "${ITE void FIELDS_EDITOR_GRID_DATA_MODEL::AddColumn( const wxString& aFieldName, const wxString& aLabel, - bool aAddedByUser, const std::set& aVariantNames ) + bool aAddedByUser, const wxString& aVariantName ) { // Don't add a field twice if( GetFieldNameCol( aFieldName ) != -1 ) @@ -210,13 +207,13 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::AddColumn( const wxString& aFieldName, const m_cols.push_back( { aFieldName, aLabel, aAddedByUser, false, false } ); for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i ) - updateDataStoreSymbolField( m_symbolsList[i], aFieldName, aVariantNames ); + updateDataStoreSymbolField( m_symbolsList[i], aFieldName, aVariantName ); } void FIELDS_EDITOR_GRID_DATA_MODEL::updateDataStoreSymbolField( const SCH_REFERENCE& aSymbolRef, - const wxString& aFieldName, - const std::set& aVariantNames ) + const wxString& aFieldName, + const wxString& aVariantName ) { const SCH_SYMBOL* symbol = aSymbolRef.GetSymbol(); @@ -227,7 +224,7 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::updateDataStoreSymbolField( const SCH_REFERE if( isAttribute( aFieldName ) ) { - m_dataStore[key][aFieldName] = getAttributeValue( *symbol, aFieldName, aVariantNames ); + m_dataStore[key][aFieldName] = getAttributeValue( aSymbolRef, aFieldName, aVariantName ); } else if( const SCH_FIELD* field = symbol->GetField( aFieldName ) ) { @@ -237,24 +234,8 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::updateDataStoreSymbolField( const SCH_REFERE return; } - wxString value = symbol->Schematic()->ConvertKIIDsToRefs( field->GetText() ); - - for( const wxString& variantName : aVariantNames ) - { - std::optional variant = symbol->GetVariant( aSymbolRef.GetSheetPath(), variantName ); - - if( !variant || !variant->m_Fields.contains( aFieldName ) ) - continue; - - if( value.IsEmpty() ) - { - value = variant->m_Fields[aFieldName]; - continue; - } - - if( value != variant->m_Fields[aFieldName] ) - value = multipleValues; - } + wxString value = symbol->Schematic()->ConvertKIIDsToRefs( field->GetText( &aSymbolRef.GetSheetPath(), + aVariantName ) ); m_dataStore[key][aFieldName] = value; } @@ -784,81 +765,52 @@ bool FIELDS_EDITOR_GRID_DATA_MODEL::isAttribute( const wxString& aFieldName ) } -wxString FIELDS_EDITOR_GRID_DATA_MODEL::getAttributeValue( const SCH_SYMBOL& aSymbol, const wxString& aAttributeName, - const std::set& aVariantNames ) +wxString FIELDS_EDITOR_GRID_DATA_MODEL::getAttributeValue( const SCH_REFERENCE& aRef, const wxString& aAttributeName, + const wxString& aVariantName ) { - wxString retv; + if( aAttributeName == wxS( "${DNP}" ) ) + return aRef.GetSymbolDNP( aVariantName ) ? wxS( "1" ) : wxS( "0" ); - auto getAttrString = [&]( const wxString aVariantName = wxEmptyString )->wxString - { - if( aAttributeName == wxS( "${DNP}" ) ) - return aSymbol.GetDNP( nullptr, aVariantName ) ? wxS( "1" ) : wxS( "0" ); + if( aAttributeName == wxS( "${EXCLUDE_FROM_BOARD}" ) ) + return aRef.GetSymbolExcludedFromBoard() ? wxS( "1" ) : wxS( "0" ); - if( aAttributeName == wxS( "${EXCLUDE_FROM_BOARD}" ) ) - return aSymbol.GetExcludedFromBoard() ? wxS( "1" ) : wxS( "0" ); + if( aAttributeName == wxS( "${EXCLUDE_FROM_BOM}" ) ) + return aRef.GetSymbolExcludedFromBOM( aVariantName ) ? wxS( "1" ) : wxS( "0" ); - if( aAttributeName == wxS( "${EXCLUDE_FROM_BOM}" ) ) - return aSymbol.GetExcludedFromBOM( nullptr, aVariantName ) ? wxS( "1" ) : wxS( "0" ); + if( aAttributeName == wxS( "${EXCLUDE_FROM_SIM}" ) ) + return aRef.GetSymbolExcludedFromSim( aVariantName ) ? wxS( "1" ) : wxS( "0" ); - if( aAttributeName == wxS( "${EXCLUDE_FROM_SIM}" ) ) - return aSymbol.GetExcludedFromSim( nullptr, aVariantName ) ? wxS( "1" ) : wxS( "0" ); - - return wxS( "0" ); - }; - - if( aVariantNames.empty() ) - { - retv = getAttrString(); - } - else - { - for( const wxString& variantName : aVariantNames ) - { - if( retv.IsEmpty() ) - { - retv = getAttrString( variantName ); - continue; - } - - if( retv != getAttrString( variantName ) ) - retv = multipleValues; - } - } - - return retv; + return wxS( "0" ); } -bool FIELDS_EDITOR_GRID_DATA_MODEL::setAttributeValue( SCH_SYMBOL& aSymbol, +bool FIELDS_EDITOR_GRID_DATA_MODEL::setAttributeValue( SCH_REFERENCE& aRef, const wxString& aAttributeName, const wxString& aValue, const wxString& aVariantName ) { - if( aValue == multipleValues ) - return false; - bool attrChanged = false; bool newValue = aValue == wxS( "1" ); if( aAttributeName == wxS( "${DNP}" ) ) { - attrChanged = aSymbol.GetDNP( nullptr, aVariantName ) != newValue; - aSymbol.SetDNP( newValue, nullptr, aVariantName ); + attrChanged = aRef.GetSymbolDNP( aVariantName ) != newValue; + aRef.SetSymbolDNP( newValue, aVariantName ); } else if( aAttributeName == wxS( "${EXCLUDE_FROM_BOARD}" ) ) { - attrChanged = aSymbol.GetExcludedFromBoard() != newValue; - aSymbol.SetExcludedFromBoard( newValue ); + attrChanged = aRef.GetSymbolExcludedFromBoard() != newValue; + aRef.SetSymbolExcludedFromBoard( newValue ); } else if( aAttributeName == wxS( "${EXCLUDE_FROM_BOM}" ) ) { - attrChanged = aSymbol.GetExcludedFromBOM( nullptr, aVariantName ) != newValue; - aSymbol.SetExcludedFromBOM( newValue, nullptr, aVariantName ); + attrChanged = aRef.GetSymbolExcludedFromBOM( aVariantName ) != newValue; + aRef.SetSymbolExcludedFromBOM( newValue, aVariantName ); } else if( aAttributeName == wxS( "${EXCLUDE_FROM_SIM}" ) ) { - attrChanged = aSymbol.GetExcludedFromSim( nullptr, aVariantName ) != newValue; - aSymbol.SetExcludedFromSim( newValue, nullptr, aVariantName ); + attrChanged = aRef.GetSymbolExcludedFromSim( aVariantName ) != newValue; + aRef.SetSymbolExcludedFromSim( newValue, aVariantName ); } return attrChanged; @@ -1065,7 +1017,7 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::ExpandAfterSort() void FIELDS_EDITOR_GRID_DATA_MODEL::ApplyData( SCH_COMMIT& aCommit, TEMPLATES& aTemplateFieldnames, - std::set& aVariantNames ) + const wxString& aVariantName ) { bool symbolModified = false; std::unique_ptr symbolCopy; @@ -1089,16 +1041,7 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::ApplyData( SCH_COMMIT& aCommit, TEMPLATES& a // Attributes bypass the field logic, so handle them first if( isAttribute( srcName ) ) { - if( aVariantNames.empty() ) - { - symbolModified |= setAttributeValue( *symbol, srcName, srcValue ); - } - else - { - for( const wxString& name : aVariantNames ) - symbolModified |= setAttributeValue( *symbol, srcName, srcValue, name ); - } - + symbolModified |= setAttributeValue( m_symbolsList[i], srcName, srcValue, aVariantName ); continue; } @@ -1107,10 +1050,6 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::ApplyData( SCH_COMMIT& aCommit, TEMPLATES& a if( IsGeneratedField( srcName ) ) continue; - // Don't change values in the case of multiple variants selected. - if( srcValue == multipleValues ) - continue; - SCH_FIELD* destField = symbol->GetField( srcName ); if( destField && destField->IsPrivate() ) @@ -1148,36 +1087,10 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::ApplyData( SCH_COMMIT& aCommit, TEMPLATES& a if( destField->GetId() == FIELD_T::REFERENCE ) continue; - wxString previousValue = destField->GetText(); + wxString previousValue = destField->GetText( &m_symbolsList[i].GetSheetPath(), aVariantName ); - if( aVariantNames.empty() ) - { - destField->SetText( symbol->Schematic()->ConvertRefsToKIIDs( srcValue ) ); - } - else - { - for( const wxString& variantName : aVariantNames ) - { - std::optional variant = symbol->GetVariant( m_symbolsList[i].GetSheetPath(), - variantName ); - - if( !variant ) - { - SCH_SYMBOL_VARIANT newVariant( variantName ); - - newVariant.m_Fields[srcName] = srcValue; - symbol->AddVariant( m_symbolsList[i].GetSheetPath(), newVariant ); - symbolModified |= true; - } - else if( !variant->m_Fields.contains( srcName ) - || ( variant->m_Fields[srcName] != srcValue ) ) - { - variant->m_Fields[srcName] = srcValue; - symbol->AddVariant( m_symbolsList[i].GetSheetPath(), *variant ); - symbolModified |= true; - } - } - } + destField->SetText( symbol->Schematic()->ConvertRefsToKIIDs( srcValue ), &m_symbolsList[i].GetSheetPath(), + aVariantName ); if( !createField && ( previousValue != srcValue ) ) symbolModified = true; @@ -1241,8 +1154,7 @@ int FIELDS_EDITOR_GRID_DATA_MODEL::GetDataWidth( int aCol ) } -void FIELDS_EDITOR_GRID_DATA_MODEL::ApplyBomPreset( const BOM_PRESET& aPreset, - const std::set& aVariantNames ) +void FIELDS_EDITOR_GRID_DATA_MODEL::ApplyBomPreset( const BOM_PRESET& aPreset, const wxString& aVariantName ) { // Hide and un-group everything by default for( size_t i = 0; i < m_cols.size(); i++ ) @@ -1270,7 +1182,7 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::ApplyBomPreset( const BOM_PRESET& aPreset, // they won't be saved to the symbols anyway if( col == -1 ) { - AddColumn( field.name, field.label, true, aVariantNames ); + AddColumn( field.name, field.label, true, aVariantName ); col = GetFieldNameCol( field.name ); } else @@ -1480,7 +1392,7 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::RemoveReferences( const SCH_REFERENCE_LIST& void FIELDS_EDITOR_GRID_DATA_MODEL::UpdateReferences( const SCH_REFERENCE_LIST& aRefs, - const std::set& aVariantNames ) + const wxString& aVariantName ) { bool refListChanged = false; @@ -1490,7 +1402,7 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::UpdateReferences( const SCH_REFERENCE_LIST& // columns; we must have all fields in the symbol added to the data model at this point, // and some of the data model columns may be variables that are not present in the symbol for( const DATA_MODEL_COL& col : m_cols ) - updateDataStoreSymbolField( ref, col.m_fieldName, aVariantNames ); + updateDataStoreSymbolField( ref, col.m_fieldName, aVariantName ); if( !m_symbolsList.Contains( ref ) ) { @@ -1502,3 +1414,47 @@ void FIELDS_EDITOR_GRID_DATA_MODEL::UpdateReferences( const SCH_REFERENCE_LIST& if( refListChanged ) m_symbolsList.SortBySymbolPtr(); } + + +bool FIELDS_EDITOR_GRID_DATA_MODEL::DeleteRows( size_t aPosition, size_t aNumRows ) +{ + size_t curNumRows = m_rows.size(); + + if( aPosition >= curNumRows ) + { + wxFAIL_MSG( wxString::Format( wxT( "Called FIELDS_EDITOR_GRID_DATA_MODEL::DeleteRows(aPosition=%lu, " + "aNumRows=%lu)\nPosition value is invalid for present table with %lu rows" ), + (unsigned long) aPosition, (unsigned long) aNumRows, + (unsigned long) curNumRows ) ); + + return false; + } + + if( aNumRows > curNumRows - aPosition ) + { + aNumRows = curNumRows - aPosition; + } + + if( aNumRows >= curNumRows ) + { + m_rows.clear(); + m_dataStore.clear(); + } + else + { + const auto first = m_rows.begin() + aPosition; + std::vector dataMapRefs = first->m_Refs; + m_rows.erase( first, first + aNumRows ); + + for( const SCH_REFERENCE& ref : dataMapRefs ) + m_dataStore.erase( ref.GetSheetPath().Path() ); + } + + if( GetView() ) + { + wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aPosition, aNumRows ); + GetView()->ProcessTableMessage( msg ); + } + + return true; +} diff --git a/eeschema/fields_data_model.h b/eeschema/fields_data_model.h index ac4486e49c..301a428a2c 100644 --- a/eeschema/fields_data_model.h +++ b/eeschema/fields_data_model.h @@ -153,7 +153,7 @@ public: static const wxString ITEM_NUMBER_VARIABLE; void AddColumn( const wxString& aFieldName, const wxString& aLabel, bool aAddedByUser, - const std::set& aVariantNames ); + const wxString& aVariantName ); void RemoveColumn( int aCol ); void RenameColumn( int aCol, const wxString& newName ); @@ -267,7 +267,7 @@ public: void CollapseForSort(); void ExpandAfterSort(); - void ApplyData( SCH_COMMIT& aCommit, TEMPLATES& aTemplateFieldnames, std::set& aVariantNames ); + void ApplyData( SCH_COMMIT& aCommit, TEMPLATES& aTemplateFieldnames, const wxString& aVariantName ); bool IsEdited() { return m_edited; } @@ -319,14 +319,18 @@ public: return m_cols[aCol].m_show; } - void ApplyBomPreset( const BOM_PRESET& preset, const std::set& aVariantNames ); + void ApplyBomPreset( const BOM_PRESET& preset, const wxString& aVariantName ); BOM_PRESET GetBomSettings(); wxString Export( const BOM_FMT_PRESET& settings ); void AddReferences( const SCH_REFERENCE_LIST& aRefs ); void RemoveReferences( const SCH_REFERENCE_LIST& aRefs ); void RemoveSymbol( const SCH_SYMBOL& aSymbol ); - void UpdateReferences( const SCH_REFERENCE_LIST& aRefs, const std::set& aVariantNames ); + void UpdateReferences( const SCH_REFERENCE_LIST& aRefs, const wxString& aVariantName ); + + bool DeleteRows( size_t aPosition = 0, size_t aNumRows = 1 ) override; + + const SCH_REFERENCE_LIST& GetReferenceList() const { return m_symbolsList; } private: static bool cmp( const DATA_MODEL_ROW& lhGroup, const DATA_MODEL_ROW& rhGroup, @@ -338,20 +342,20 @@ private: // Helper functions to deal with translating wxGrid values to and from // named field values like ${DNP} bool isAttribute( const wxString& aFieldName ); - wxString getAttributeValue( const SCH_SYMBOL&, const wxString& aAttributeName, - const std::set& aVariantNames ); + wxString getAttributeValue( const SCH_REFERENCE& aRef, const wxString& aAttributeName, + const wxString& aVariantNames ); /** * Set the attribute value. * - * @param aSymbol is the symbol to set the attribute. + * @param aReference is a reference to the symbol to set the attribute. * @param aAttributeName is the name of the symbol attribute. * @param aValue is the value to set the attribute. * @param aVariantName is an optional variant name to set the variant attribute. * @retval true if the symbol attribute value has changed. * @retval false if the symbol attribute has **not** changed. */ - bool setAttributeValue( SCH_SYMBOL& aSymbol, const wxString& aAttributeName, const wxString& aValue, + bool setAttributeValue( SCH_REFERENCE& aRef, const wxString& aAttributeName, const wxString& aValue, const wxString& aVariantName = wxEmptyString ); /* Helper function to get the resolved field value. @@ -363,7 +367,7 @@ private: void Sort(); void updateDataStoreSymbolField( const SCH_REFERENCE& aSymbolRef, const wxString& aFieldName, - const std::set& aVariantNames ); + const wxString& aVariantName ); protected: /** diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp index 0ca136d61c..6148e29e0d 100644 --- a/eeschema/files-io.cpp +++ b/eeschema/files-io.cpp @@ -693,6 +693,9 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() ) screen->MigrateSimModels(); + + Schematic().LoadVariants(); + UpdateVariantSelectionCtrl( Schematic().GetVariantNamesForUI() ); } // After the schematic is successfully loaded, we load the drawing sheet. diff --git a/eeschema/lib_symbol.h b/eeschema/lib_symbol.h index 644491d7a1..e43f034d89 100644 --- a/eeschema/lib_symbol.h +++ b/eeschema/lib_symbol.h @@ -356,7 +356,8 @@ public: return GetReferenceField().GetText(); } - const wxString GetValue( bool aResolve, const SCH_SHEET_PATH* aPath, bool aAllowExtraText ) const override + const wxString GetValue( bool aResolve, const SCH_SHEET_PATH* aPath, bool aAllowExtraText, + const wxString& aVariantName = wxEmptyString ) const override { return GetValueField().GetText(); } diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp index d9a95942bf..ba313c3e0a 100644 --- a/eeschema/sch_edit_frame.cpp +++ b/eeschema/sch_edit_frame.cpp @@ -472,6 +472,9 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : wxPoint canvas_pos = GetCanvas()->GetScreenPosition(); hierarchy_pane.FloatingPosition( canvas_pos.x + 10, canvas_pos.y + 10 ); + if( ADVANCED_CFG::GetCfg().m_EnableVariantsUI ) + Bind( wxEVT_CHOICE, &SCH_EDIT_FRAME::onVariantSelected, this ); + Bind( EDA_EVT_CLOSE_DIALOG_BOOK_REPORTER, &SCH_EDIT_FRAME::onCloseSymbolDiffDialog, this ); Bind( EDA_EVT_CLOSE_ERC_DIALOG, &SCH_EDIT_FRAME::onCloseErcDialog, this ); Bind( EDA_EVT_CLOSE_DIALOG_SYMBOL_FIELDS_TABLE, &SCH_EDIT_FRAME::onCloseSymbolFieldsTableDialog, this ); @@ -3041,7 +3044,7 @@ void SCH_EDIT_FRAME::RemoveVariant() wxString variantName = dlg.GetStringSelection(); - if( variantName.IsEmpty() || ( m_currentVariantCtrl->FindString( variantName ) != wxNOT_FOUND ) ) + if( variantName.IsEmpty() ) return; Schematic().DeleteVariant( variantName ); @@ -3067,6 +3070,8 @@ void SCH_EDIT_FRAME::RemoveVariant() SetCurrentVariant( wxEmptyString ); } } + + GetCanvas()->Refresh(); } diff --git a/eeschema/sch_field.cpp b/eeschema/sch_field.cpp index 322635636b..04a0e251f6 100644 --- a/eeschema/sch_field.cpp +++ b/eeschema/sch_field.cpp @@ -188,17 +188,64 @@ wxString SCH_FIELD::GetShownName() const } -wxString SCH_FIELD::GetShownText( const SCH_SHEET_PATH* aPath, bool aAllowExtraText, int aDepth ) const +wxString SCH_FIELD::GetShownText( const SCH_SHEET_PATH* aPath, bool aAllowExtraText, int aDepth, + const wxString& aVariantName ) const { // Use local depth counter so each text element starts fresh int depth = 0; - wxString variantName; + std::function libSymbolResolver = [&]( wxString* token ) -> bool + { + LIB_SYMBOL* symbol = static_cast( m_parent ); + return symbol->ResolveTextVar( token, depth + 1 ); + }; - if( SCHEMATIC* schematic = Schematic() ) - variantName = schematic->GetCurrentVariant(); + std::function symbolResolver = [&]( wxString* token ) -> bool + { + SCH_SYMBOL* symbol = static_cast( m_parent ); + return symbol->ResolveTextVar( aPath, token, depth + 1 ); + }; - wxString text = getUnescapedText( aPath, variantName ); + std::function schematicResolver = [&]( wxString* token ) -> bool + { + if( !aPath ) + return false; + + if( SCHEMATIC* schematic = Schematic() ) + return schematic->ResolveTextVar( aPath, token, depth + 1 ); + + return false; + }; + + std::function sheetResolver = [&]( wxString* token ) -> bool + { + if( !aPath ) + return false; + + SCH_SHEET* sheet = static_cast( m_parent ); + + SCHEMATIC* schematic = Schematic(); + SCH_SHEET_PATH path = *aPath; + path.push_back( sheet ); + + bool retval = sheet->ResolveTextVar( &path, token, depth + 1 ); + + if( schematic ) + retval |= schematic->ResolveTextVar( &path, token, depth + 1 ); + + return retval; + }; + + std::function labelResolver = [&]( wxString* token ) -> bool + { + if( !aPath ) + return false; + + SCH_LABEL_BASE* label = static_cast( m_parent ); + return label->ResolveTextVar( aPath, token, depth + 1 ); + }; + + wxString text = getUnescapedText( aPath, aVariantName ); if( IsNameShown() && aAllowExtraText ) text = GetShownName() << wxS( ": " ) << text; @@ -222,10 +269,13 @@ wxString SCH_FIELD::GetShownText( bool aAllowExtraText, int aDepth ) const if( SCHEMATIC* schematic = Schematic() ) { const SCH_SHEET_PATH& currentSheet = schematic->CurrentSheet(); + wxString variantName = schematic->GetCurrentVariant(); + wxLogTrace( traceSchFieldRendering, - "GetShownText (no path arg): field=%s, current sheet path='%s', size=%zu, empty=%d", GetName(), - currentSheet.Path().AsString(), currentSheet.size(), currentSheet.empty() ? 1 : 0 ); - return GetShownText( ¤tSheet, aAllowExtraText, aDepth ); + "GetShownText (no path arg): field=%s, current sheet path='%s', variant='%s', size=%zu, empty=%d", + GetName(), currentSheet.Path().AsString(), variantName, currentSheet.size(), + currentSheet.empty() ? 1 : 0 ); + return GetShownText( ¤tSheet, aAllowExtraText, aDepth, variantName ); } else return GetShownText( nullptr, aAllowExtraText, aDepth ); @@ -1035,6 +1085,77 @@ void SCH_FIELD::SetText( const wxString& aText ) } +void SCH_FIELD::SetText( const wxString& aText, const SCH_SHEET_PATH* aPath, const wxString& aVariantName ) +{ + wxCHECK( aPath && m_parent, /* void */ ); + + // Don't allow modification of text value of generated fields. + if( m_isGeneratedField ) + return; + + wxString tmp = aText; + + if( IsMandatory() ) + tmp = aText.Strip( wxString::both ) ; + + switch( m_parent->Type() ) + { + case SCH_SYMBOL_T: + { + SCH_SYMBOL* symbol = static_cast( m_parent ); + wxCHECK( symbol, /* void */ ); + symbol->SetFieldText( GetName(), aText, aPath, aVariantName ); + break; + } + + case SCH_SHEET_T: + { + SCH_SHEET* sheet = static_cast( m_parent ); + wxCHECK( sheet, /* void */ ); + sheet->SetFieldText( GetName(), aText, aPath, aVariantName ); + break; + } + + default: + SCH_FIELD::SetText( aText ); + break; + } +} + + +wxString SCH_FIELD::GetText( const SCH_SHEET_PATH* aPath, const wxString& aVariantName ) const +{ + wxString retv; + + wxCHECK( aPath && m_parent, retv ); + + switch( m_parent->Type() ) + { + case SCH_SYMBOL_T: + { + SCH_SYMBOL* symbol = static_cast( m_parent ); + wxCHECK( symbol, retv ); + retv = symbol->GetFieldText( GetName(), aPath, aVariantName ); + break; + } + + case SCH_SHEET_T: + { + SCH_SHEET* sheet = static_cast( m_parent ); + wxCHECK( sheet, retv ); + retv = sheet->GetFieldText( GetName(), aPath, aVariantName ); + break; + } + + default: + retv = GetText(); + break; + } + + return retv; +} + + wxString SCH_FIELD::GetName( bool aUseDefaultName ) const { if( m_parent && m_parent->IsType( labelTypes ) ) @@ -1160,7 +1281,7 @@ void SCH_FIELD::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& wxString text; if( Schematic() ) - text = GetShownText( &Schematic()->CurrentSheet(), true ); + text = GetShownText( &Schematic()->CurrentSheet(), true, 0, Schematic()->GetCurrentVariant() ); else text = GetShownText( true ); diff --git a/eeschema/sch_field.h b/eeschema/sch_field.h index 955a43ac26..7d70552536 100644 --- a/eeschema/sch_field.h +++ b/eeschema/sch_field.h @@ -113,6 +113,12 @@ public: void SetText( const wxString& aText ) override; + void SetText( const wxString& aText, const SCH_SHEET_PATH* aPath, const wxString& aVariantName = wxEmptyString ); + + virtual const wxString& GetText() const override { return EDA_TEXT::GetText(); } + + wxString GetText( const SCH_SHEET_PATH* aPath, const wxString& aVariantName = wxEmptyString ) const; + FIELD_T GetId() const { return m_id; } int GetOrdinal() const @@ -131,7 +137,8 @@ public: * with the ${} stripped. */ wxString GetShownName() const; - wxString GetShownText( const SCH_SHEET_PATH* aPath, bool aAllowExtraText, int aDepth = 0 ) const; + wxString GetShownText( const SCH_SHEET_PATH* aPath, bool aAllowExtraText, int aDepth = 0, + const wxString& aVariantName = wxEmptyString ) const; wxString GetShownText( bool aAllowExtraText, int aDepth = 0 ) const override; diff --git a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr_parser.cpp b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr_parser.cpp index 359ad8b5d0..509004cee7 100644 --- a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr_parser.cpp +++ b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr_parser.cpp @@ -3377,12 +3377,35 @@ SCH_SYMBOL* SCH_IO_KICAD_SEXPR_PARSER::parseSchematicSymbol() case T_field: { - NeedSYMBOL(); - wxString fieldName = FromUTF8(); - NeedRIGHT(); - NeedSYMBOL(); - wxString fieldValue = FromUTF8(); - NeedRIGHT(); + wxString fieldName; + wxString fieldValue; + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_name: + NeedSYMBOL(); + fieldName = FromUTF8(); + NeedRIGHT(); + break; + + case T_value: + NeedSYMBOL(); + fieldValue = FromUTF8(); + NeedRIGHT(); + break; + + default: + Expecting( "name or value" ); + } + } + variant.m_Fields[fieldName] = fieldValue; break; } @@ -3394,7 +3417,6 @@ SCH_SYMBOL* SCH_IO_KICAD_SEXPR_PARSER::parseSchematicSymbol() instance.m_Variants[variant.m_Name] = variant; } - NeedRIGHT(); break; } @@ -3806,12 +3828,35 @@ SCH_SHEET* SCH_IO_KICAD_SEXPR_PARSER::parseSheet() case T_field: { - NeedSYMBOL(); - wxString fieldName = FromUTF8(); - NeedRIGHT(); - NeedSYMBOL(); - wxString fieldValue = FromUTF8(); - NeedRIGHT(); + wxString fieldName; + wxString fieldValue; + + for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + { + if( token != T_LEFT ) + Expecting( T_LEFT ); + + token = NextTok(); + + switch( token ) + { + case T_name: + NeedSYMBOL(); + fieldName = FromUTF8(); + NeedRIGHT(); + break; + + case T_value: + NeedSYMBOL(); + fieldValue = FromUTF8(); + NeedRIGHT(); + break; + + default: + Expecting( "name or value" ); + } + } + variant.m_Fields[fieldName] = fieldValue; break; } @@ -3823,7 +3868,6 @@ SCH_SHEET* SCH_IO_KICAD_SEXPR_PARSER::parseSheet() instance.m_Variants[variant.m_Name] = variant; } - NeedRIGHT(); break; } diff --git a/eeschema/sch_painter.cpp b/eeschema/sch_painter.cpp index 81d211ed60..51a16dc69c 100644 --- a/eeschema/sch_painter.cpp +++ b/eeschema/sch_painter.cpp @@ -2660,19 +2660,25 @@ void SCH_PAINTER::draw( const SCH_SYMBOL* aSymbol, int aLayer ) std::optional optSheetPath; + wxString variantName; + if( m_schematic ) { optSheetPath = m_schematic->CurrentSheet(); + variantName = m_schematic->GetCurrentVariant(); wxLogTrace( traceSchPainter, - "SCH_PAINTER::draw symbol %s: Current sheet path='%s', size=%zu, empty=%d", - aSymbol->m_Uuid.AsString(), - optSheetPath->Path().AsString(), - optSheetPath->size(), - optSheetPath->empty() ? 1 : 0 ); + "SCH_PAINTER::draw symbol %s: Current sheet path='%s', variant='%s', size=%zu, empty=%d", + aSymbol->m_Uuid.AsString(), + variantName.IsEmpty() ? GetDefaultVariantName() : variantName, + optSheetPath->Path().AsString(), + optSheetPath->size(), + optSheetPath->empty() ? 1 : 0 ); } - bool DNP = aSymbol->GetDNP( nullptr ); - bool markExclusion = eeconfig()->m_Appearance.mark_sim_exclusions && aSymbol->GetExcludedFromSim( nullptr ); + SCH_SHEET_PATH* sheetPath = optSheetPath ? &optSheetPath.value() : nullptr; + bool DNP = aSymbol->GetDNP( sheetPath, variantName ); + bool markExclusion = eeconfig()->m_Appearance.mark_sim_exclusions && aSymbol->GetExcludedFromSim( sheetPath, + variantName ); if( m_schSettings.IsPrinting() && drawingShadows ) return; @@ -3260,8 +3266,10 @@ void SCH_PAINTER::draw( const SCH_DIRECTIVE_LABEL* aLabel, int aLayer, bool aDim void SCH_PAINTER::draw( const SCH_SHEET* aSheet, int aLayer ) { + SCH_SHEET_PATH currentPath = aSheet->Schematic()->CurrentSheet(); + wxString currentVariant = aSheet->Schematic()->GetCurrentVariant(); bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS; - bool DNP = aSheet->GetDNP(); + bool DNP = aSheet->GetDNP( ¤tPath, currentVariant ); bool markExclusion = eeconfig()->m_Appearance.mark_sim_exclusions && aSheet->GetExcludedFromSim(); diff --git a/eeschema/sch_reference_list.cpp b/eeschema/sch_reference_list.cpp index 1aa94004b4..be8cf8befc 100644 --- a/eeschema/sch_reference_list.cpp +++ b/eeschema/sch_reference_list.cpp @@ -935,6 +935,38 @@ wxString SCH_REFERENCE_LIST::Shorthand( std::vector aList, } +bool SCH_REFERENCE::GetSymbolDNP( const wxString& aVariant ) const +{ + wxCHECK( m_rootSymbol, false ); + + return m_rootSymbol->GetDNP( &m_sheetPath, aVariant ); +} + + +bool SCH_REFERENCE::GetSymbolExcludedFromBOM( const wxString& aVariant ) const +{ + wxCHECK( m_rootSymbol, false ); + + return m_rootSymbol->GetExcludedFromBOM( &m_sheetPath, aVariant ); +} + + +bool SCH_REFERENCE::GetSymbolExcludedFromSim( const wxString& aVariant ) const +{ + wxCHECK( m_rootSymbol, false ); + + return m_rootSymbol->GetExcludedFromSim( &m_sheetPath, aVariant ); +} + + +bool SCH_REFERENCE::GetSymbolExcludedFromBoard() const +{ + wxCHECK( m_rootSymbol, false ); + + return m_rootSymbol->GetExcludedFromBoard(); +} + + wxString SCH_REFERENCE::formatRefStr( int aNumber ) const { // To avoid a risk of duplicate, for power symbols the ref number is 0nnn instead of nnn. @@ -946,6 +978,38 @@ wxString SCH_REFERENCE::formatRefStr( int aNumber ) const } +void SCH_REFERENCE::SetSymbolDNP( bool aEnable, const wxString& aVariant ) +{ + wxCHECK( m_rootSymbol, /* void */ ); + + m_rootSymbol->SetDNP( aEnable, &m_sheetPath, aVariant ); +} + + +void SCH_REFERENCE::SetSymbolExcludedFromBOM( bool aEnable, const wxString& aVariant ) +{ + wxCHECK( m_rootSymbol, /* void */ ); + + m_rootSymbol->SetExcludedFromBOM( aEnable, &m_sheetPath, aVariant ); +} + + +void SCH_REFERENCE::SetSymbolExcludedFromSim( bool aEnable, const wxString& aVariant ) +{ + wxCHECK( m_rootSymbol, /* void */ ); + + m_rootSymbol->SetExcludedFromSim( aEnable, &m_sheetPath, aVariant ); +} + + +void SCH_REFERENCE::SetSymbolExcludedFromBoard( bool aEnable ) +{ + wxCHECK( m_rootSymbol, /* void */ ); + + m_rootSymbol->SetExcludedFromBoard( aEnable ); +} + + #if defined( DEBUG ) void SCH_REFERENCE_LIST::Show( const char* aPrefix ) { diff --git a/eeschema/sch_reference_list.h b/eeschema/sch_reference_list.h index 34fec21639..6b280de876 100644 --- a/eeschema/sch_reference_list.h +++ b/eeschema/sch_reference_list.h @@ -231,6 +231,16 @@ public: m_numRefStr = formatRefStr( aNum ); } + bool GetSymbolDNP( const wxString& aVariant = wxEmptyString ) const; + bool GetSymbolExcludedFromBOM( const wxString& aVariant = wxEmptyString ) const; + bool GetSymbolExcludedFromSim( const wxString& aVariant = wxEmptyString ) const; + bool GetSymbolExcludedFromBoard() const; + + void SetSymbolDNP( bool aEnable, const wxString& aVariant = wxEmptyString ); + void SetSymbolExcludedFromBOM( bool aEnable, const wxString& aVariant = wxEmptyString ); + void SetSymbolExcludedFromSim( bool aEnable, const wxString& aVariant = wxEmptyString ); + void SetSymbolExcludedFromBoard( bool aEnable ); + private: wxString formatRefStr( int aNumber ) const; diff --git a/eeschema/sch_sheet.cpp b/eeschema/sch_sheet.cpp index 6e77474309..4ca4edc9f1 100644 --- a/eeschema/sch_sheet.cpp +++ b/eeschema/sch_sheet.cpp @@ -392,6 +392,18 @@ const SCH_FIELD* SCH_SHEET::GetField( FIELD_T aFieldType ) const } +SCH_FIELD* SCH_SHEET::GetField( const wxString& aFieldName ) +{ + return FindField( m_fields, aFieldName ); +} + + +const SCH_FIELD* SCH_SHEET::GetField( const wxString& aFieldName ) const +{ + return FindField( m_fields, aFieldName ); +} + + int SCH_SHEET::GetNextFieldOrdinal() const { return NextFieldOrdinal( m_fields ); @@ -407,6 +419,114 @@ void SCH_SHEET::SetFields( const std::vector& aFields ) } +void SCH_SHEET::AddOptionalField( const SCH_FIELD& aField ) +{ + SCH_FIELD* field = GetField( aField.GetId() ); + + if( ( aField.GetId() == FIELD_T::SHEET_FILENAME ) || ( aField.GetId() == FIELD_T::SHEET_NAME ) ) + return; + + if( field ) + *field = aField; + else + m_fields.emplace_back( aField ); +} + + +void SCH_SHEET::SetFieldText( const wxString& aFieldName, const wxString& aFieldText, const SCH_SHEET_PATH* aPath, + const wxString& aVariantName ) +{ + wxCHECK( !aFieldName.IsEmpty(), /* void */ ); + + SCH_FIELD* field = GetField( aFieldName ); + + wxCHECK( field, /* void */ ); + + switch( field->GetId() ) + { + case FIELD_T::SHEET_FILENAME: + { + // File names are stored using unix separators. + wxString tmp = aFieldText; + tmp.Replace( wxT( "\\" ), wxT( "/" ) ); + GetField( FIELD_T::SHEET_FILENAME )->SetText( tmp ); + break; + } + + case FIELD_T::SHEET_NAME: + field->SetText( aFieldText ); + break; + + default: + if( aFieldText != field->GetText( aPath ) ) // Do not set the variant unless it's different than the default. + { + if( aVariantName.IsEmpty() ) + { + field->SetText( aFieldText ); + } + else + { + SCH_SHEET_INSTANCE* instance = getInstance( *aPath ); + + wxCHECK( instance, /* void */ ); + + if( instance->m_Variants.contains( aVariantName ) ) + { + instance->m_Variants[aVariantName].m_Fields[aFieldName] = aFieldText; + } + else + { + SCH_SHEET_VARIANT newVariant( aVariantName ); + + newVariant.InitializeAttributes( *this ); + newVariant.m_Fields[aFieldName] = aFieldText; + instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) ); + } + } + } + + break; + } +} + + +wxString SCH_SHEET::GetFieldText( const wxString& aFieldName, const SCH_SHEET_PATH* aPath, + const wxString& aVariantName ) const +{ + wxCHECK( !aFieldName.IsEmpty(), wxEmptyString ); + + const SCH_FIELD* field = GetField( aFieldName ); + + wxCHECK( field, wxEmptyString ); + + switch( field->GetId() ) + { + case FIELD_T::REFERENCE: + case FIELD_T::FOOTPRINT: + return field->GetText(); + break; + + default: + if( aVariantName.IsEmpty() ) + { + return field->GetText(); + } + else + { + const SCH_SHEET_INSTANCE* instance = getInstance( *aPath ); + + if( instance->m_Variants.contains( aVariantName ) + && instance->m_Variants.at( aVariantName ).m_Fields.contains( aFieldName ) ) + return instance->m_Variants.at( aVariantName ).m_Fields.at( aFieldName ); + } + + break; + } + + return field->GetText(); +} + + void SCH_SHEET::AddPin( SCH_SHEET_PIN* aSheetPin ) { wxASSERT( aSheetPin != nullptr ); @@ -1313,7 +1433,16 @@ void SCH_SHEET::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& for( SCH_FIELD& field : m_fields ) field.Plot( aPlotter, aBackground, aPlotOpts, aUnit, aBodyStyle, aOffset, aDimmed ); - if( GetDNP() ) + SCH_SHEET_PATH instance; + wxString variantName; + + if( Schematic() ) + { + instance = Schematic()->CurrentSheet(); + variantName = Schematic()->GetCurrentVariant(); + } + + if( GetDNP( &instance, variantName) ) { COLOR_SETTINGS* colors = ::GetColorSettings( DEFAULT_THEME ); BOX2I bbox = GetBodyBoundingBox(); @@ -1466,6 +1595,30 @@ bool SCH_SHEET::getInstance( SCH_SHEET_INSTANCE& aInstance, const KIID_PATH& aSh } +SCH_SHEET_INSTANCE* SCH_SHEET::getInstance( const KIID_PATH& aSheetPath ) +{ + for( SCH_SHEET_INSTANCE& instance : m_instances ) + { + if( instance.m_Path == aSheetPath ) + return &instance; + } + + return nullptr; +} + + +const SCH_SHEET_INSTANCE* SCH_SHEET::getInstance( const KIID_PATH& aSheetPath ) const +{ + for( const SCH_SHEET_INSTANCE& instance : m_instances ) + { + if( instance.m_Path == aSheetPath ) + return &instance; + } + + return nullptr; +} + + bool SCH_SHEET::HasRootInstance() const { for( const SCH_SHEET_INSTANCE& instance : m_instances ) @@ -1674,39 +1827,233 @@ double SCH_SHEET::Similarity( const SCH_ITEM& aOther ) const } +void SCH_SHEET::AddVariant( const SCH_SHEET_PATH& aInstance, const SCH_SHEET_VARIANT& aVariant ) +{ + SCH_SHEET_INSTANCE* instance = getInstance( aInstance ); + + // The instance path must already exist. + if( !instance ) + return; + + instance->m_Variants.insert( std::make_pair( aVariant.m_Name, aVariant ) ); +} + + +void SCH_SHEET::DeleteVariant( const SCH_SHEET_PATH& aInstance, const wxString& aVariantName ) +{ + SCH_SHEET_INSTANCE instance; + + // The instance path must already exist. + if( !getInstance( instance, aInstance.Path() ) || !instance.m_Variants.contains( aVariantName ) ) + return; + + instance.m_Variants.erase( aVariantName ); +} + + +void SCH_SHEET::SetDNP( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) +{ + if( !aInstance || aVariantName.IsEmpty() ) + { + m_DNP = aEnable; + return; + } + + SCH_SHEET_INSTANCE* instance = getInstance( *aInstance ); + + wxCHECK_MSG( instance, /* void */, + wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ), + aInstance->PathHumanReadable() ) ); + + if( aVariantName.IsEmpty() ) + { + m_DNP = aEnable; + } + else + { + if( instance->m_Variants.contains( aVariantName ) && ( aEnable != instance->m_Variants[aVariantName].m_DNP ) ) + { + instance->m_Variants[aVariantName].m_DNP = aEnable; + } + else + { + SCH_SHEET_VARIANT variant( aVariantName ); + + variant.InitializeAttributes( *this ); + variant.m_DNP = aEnable; + AddVariant( *aInstance, variant ); + } + } +} + + +bool SCH_SHEET::GetDNP( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const +{ + if( !aInstance || aVariantName.IsEmpty() ) + return m_DNP; + + SCH_SHEET_INSTANCE instance; + + if( !getInstance( instance, aInstance->Path() ) ) + return m_DNP; + + if( aVariantName.IsEmpty() ) + return m_DNP; + else if( instance.m_Variants.contains( aVariantName ) ) + return instance.m_Variants[aVariantName].m_DNP; + + // If the variant has not been defined, return the default DNP setting. + return m_DNP; +} + + bool SCH_SHEET::GetDNPProp() const { - return GetDNP( nullptr, Schematic()->GetCurrentVariant() ); + return GetDNP( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() ); } void SCH_SHEET::SetDNPProp( bool aEnable ) { - SetDNP( aEnable, nullptr, Schematic()->GetCurrentVariant() ); + SetDNP( aEnable, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() ); +} + + +void SCH_SHEET::SetExcludedFromSim( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) +{ + if( !aInstance || aVariantName.IsEmpty() ) + { + m_excludedFromSim = aEnable; + return; + } + + SCH_SHEET_INSTANCE* instance = getInstance( *aInstance ); + + wxCHECK_MSG( instance, /* void */, + wxString::Format( wxS( "Cannot get m_excludedFromSim attribute for invalid sheet path '%s'." ), + aInstance->PathHumanReadable() ) ); + + if( aVariantName.IsEmpty() ) + { + m_excludedFromSim = aEnable; + } + else + { + if( instance->m_Variants.contains( aVariantName ) + && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromSim ) ) + { + instance->m_Variants[aVariantName].m_ExcludedFromSim = aEnable; + } + else + { + SCH_SHEET_VARIANT variant( aVariantName ); + + variant.InitializeAttributes( *this ); + variant.m_ExcludedFromSim = aEnable; + AddVariant( *aInstance, variant ); + } + } +} + + +bool SCH_SHEET::GetExcludedFromSim( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const +{ + if( !aInstance || aVariantName.IsEmpty() ) + return m_excludedFromSim; + + SCH_SHEET_INSTANCE instance; + + if( !getInstance( instance, aInstance->Path() ) ) + return m_excludedFromSim; + + if( aVariantName.IsEmpty() ) + return m_excludedFromSim; + else if( instance.m_Variants.contains( aVariantName ) ) + return instance.m_Variants[aVariantName].m_ExcludedFromSim; + + // If the variant has not been defined, return the default DNP setting. + return m_excludedFromSim; } bool SCH_SHEET::GetExcludedFromSimProp() const { - return GetExcludedFromSim( nullptr, Schematic()->GetCurrentVariant() ); + return GetExcludedFromSim( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() ); } void SCH_SHEET::SetExcludedFromSimProp( bool aEnable ) { - SetExcludedFromSim( aEnable, nullptr, Schematic()->GetCurrentVariant() ); + SetExcludedFromSim( aEnable, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() ); +} + + +void SCH_SHEET::SetExcludedFromBOM( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) +{ + if( !aInstance || aVariantName.IsEmpty() ) + { + m_excludedFromBOM = aEnable; + return; + } + + SCH_SHEET_INSTANCE* instance = getInstance( *aInstance ); + + wxCHECK_MSG( instance, /* void */, + wxString::Format( wxS( "Cannot get m_excludedFromBOM attribute for invalid sheet path '%s'." ), + aInstance->PathHumanReadable() ) ); + + if( aVariantName.IsEmpty() ) + { + m_excludedFromBOM = aEnable; + } + else + { + if( instance->m_Variants.contains( aVariantName ) + && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromBOM ) ) + { + instance->m_Variants[aVariantName].m_ExcludedFromBOM = aEnable; + } + else + { + SCH_SHEET_VARIANT variant( aVariantName ); + + variant.InitializeAttributes( *this ); + variant.m_ExcludedFromBOM = aEnable; + AddVariant( *aInstance, variant ); + } + } +} + + +bool SCH_SHEET::GetExcludedFromBOM( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const +{ + if( !aInstance || aVariantName.IsEmpty() ) + return m_excludedFromBOM; + + SCH_SHEET_INSTANCE instance; + + if( !getInstance( instance, aInstance->Path() ) ) + return m_excludedFromBOM; + + if( aVariantName.IsEmpty() ) + return m_excludedFromBOM; + else if( instance.m_Variants.contains( aVariantName ) ) + return instance.m_Variants[aVariantName].m_ExcludedFromBOM; + + // If the variant has not been defined, return the default DNP setting. + return m_excludedFromBOM; } bool SCH_SHEET::GetExcludedFromBOMProp() const { - return GetExcludedFromBOM( nullptr, Schematic()->GetCurrentVariant() ); + return GetExcludedFromBOM( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() ); } void SCH_SHEET::SetExcludedFromBOMProp( bool aEnable ) { - SetExcludedFromBOM( aEnable, nullptr, Schematic()->GetCurrentVariant() ); + SetExcludedFromBOM( aEnable, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() ); } diff --git a/eeschema/sch_sheet.h b/eeschema/sch_sheet.h index 97a64ae638..71b229e1a9 100644 --- a/eeschema/sch_sheet.h +++ b/eeschema/sch_sheet.h @@ -95,6 +95,16 @@ public: SCH_FIELD* GetField( FIELD_T aFieldType ); const SCH_FIELD* GetField( FIELD_T aFieldNdx ) const; + /** + * Return a field in this sheet. + * + * @param aFieldName is the canonical name of the field. + * + * @return Both non-const and const versions return nullptr if the field is not found. + */ + SCH_FIELD* GetField( const wxString& aFieldName ); + const SCH_FIELD* GetField( const wxString& aFieldName ) const; + /** * Return the next ordinal for a user field for this sheet */ @@ -107,6 +117,24 @@ public: */ void SetFields( const std::vector& aFields ); + /** + * Add an optional @aField to the list of fields. + * + * If @aField already exists in the field list, it replaces the existing field. If @aField does not exist, + * it is added to the field list. + * + * @note This has no affect if @aField is the sheet file name or sheet name fields. + * + * @param aField is the field to add. + */ + void AddOptionalField( const SCH_FIELD& aField ); + + void SetFieldText( const wxString& aFieldName, const wxString& aFieldText, const SCH_SHEET_PATH* aPath = nullptr, + const wxString& aVariantName = wxEmptyString ); + + wxString GetFieldText( const wxString& aFieldName, const SCH_SHEET_PATH* aPath = nullptr, + const wxString& aVariantName = wxEmptyString ) const; + wxString GetShownName( bool aAllowExtraText ) const { return GetField( FIELD_T::SHEET_NAME )->GetShownText( aAllowExtraText ); @@ -409,16 +437,9 @@ public: * Set or clear the exclude from simulation flag. */ void SetExcludedFromSim( bool aExcludeFromSim, const SCH_SHEET_PATH* aInstance = nullptr, - const wxString& aVariantName = wxEmptyString ) override - { - m_excludedFromSim = aExcludeFromSim; - } - + const wxString& aVariantName = wxEmptyString ) override; bool GetExcludedFromSim( const SCH_SHEET_PATH* aInstance = nullptr, - const wxString& aVariantName = wxEmptyString ) const override - { - return m_excludedFromSim; - } + const wxString& aVariantName = wxEmptyString ) const override; bool GetExcludedFromSimProp() const; void SetExcludedFromSimProp( bool aEnable ); @@ -427,16 +448,9 @@ public: * Set or clear the exclude from schematic bill of materials flag. */ void SetExcludedFromBOM( bool aExcludeFromBOM, const SCH_SHEET_PATH* aInstance = nullptr, - const wxString& aVariantName = wxEmptyString ) override - { - m_excludedFromBOM = aExcludeFromBOM; - } - + const wxString& aVariantName = wxEmptyString ) override; bool GetExcludedFromBOM( const SCH_SHEET_PATH* aInstance = nullptr, - const wxString& aVariantName = wxEmptyString ) const override - { - return m_excludedFromBOM; - } + const wxString& aVariantName = wxEmptyString ) const override; bool GetExcludedFromBOMProp() const; void SetExcludedFromBOMProp( bool aEnable ); @@ -451,9 +465,9 @@ public: * Set or clear the 'Do Not Populate' flags */ bool GetDNP( const SCH_SHEET_PATH* aInstance = nullptr, - const wxString& aVariantName = wxEmptyString ) const override { return m_DNP; } + const wxString& aVariantName = wxEmptyString ) const override; void SetDNP( bool aDNP, const SCH_SHEET_PATH* aInstance = nullptr, - const wxString& aVariantName = wxEmptyString ) override { m_DNP = aDNP; } + const wxString& aVariantName = wxEmptyString ) override; bool GetDNPProp() const; void SetDNPProp( bool aEnable ); @@ -509,6 +523,9 @@ public: void AddInstance( const SCH_SHEET_INSTANCE& aInstance ); + void AddVariant( const SCH_SHEET_PATH& aInstance, const SCH_SHEET_VARIANT& aVariant ); + void DeleteVariant( const SCH_SHEET_PATH& aInstance, const wxString& aVariantName ); + /** * Check if the instance data of this sheet has any changes compared to \a aOther. * @@ -581,6 +598,12 @@ protected: bool getInstance( SCH_SHEET_INSTANCE& aInstance, const KIID_PATH& aSheetPath, bool aTestFromEnd = false ) const; + SCH_SHEET_INSTANCE* getInstance( const KIID_PATH& aPath ); + const SCH_SHEET_INSTANCE* getInstance( const KIID_PATH& aPath ) const; + + SCH_SHEET_INSTANCE* getInstance( const SCH_SHEET_PATH& aPath ) { return getInstance( aPath.Path() ); } + const SCH_SHEET_INSTANCE* getInstance( const SCH_SHEET_PATH& aPath ) const { return getInstance( aPath.Path() ); } + /** * Renumber the sheet pins in the sheet. * diff --git a/eeschema/sch_sheet_path.cpp b/eeschema/sch_sheet_path.cpp index 2489b6f993..c3a91c5990 100644 --- a/eeschema/sch_sheet_path.cpp +++ b/eeschema/sch_sheet_path.cpp @@ -103,6 +103,14 @@ void SCH_SYMBOL_VARIANT::InitializeAttributes( const SCH_SYMBOL& aSymbol ) } +void SCH_SHEET_VARIANT::InitializeAttributes( const SCH_SHEET& aSheet ) +{ + m_DNP = aSheet.GetDNP(); + m_ExcludedFromBOM = aSheet.GetExcludedFromBOM(); + m_ExcludedFromSim = aSheet.GetExcludedFromSim(); +} + + namespace std { size_t hash::operator()( const SCH_SHEET_PATH& path ) const diff --git a/eeschema/sch_sheet_path.h b/eeschema/sch_sheet_path.h index b073639fb9..01718b454c 100644 --- a/eeschema/sch_sheet_path.h +++ b/eeschema/sch_sheet_path.h @@ -129,13 +129,13 @@ struct SCH_SYMBOL_INSTANCE class SCH_SHEET_VARIANT : public VARIANT { public: - SCH_SHEET_VARIANT() : - VARIANT() + SCH_SHEET_VARIANT( const wxString& aName = wxEmptyString ) : + VARIANT( aName ) {} virtual ~SCH_SHEET_VARIANT() = default; - void InitializeAttributes( const SCH_SHEET& aSymbol ); + void InitializeAttributes( const SCH_SHEET& aSheet ); }; diff --git a/eeschema/sch_symbol.cpp b/eeschema/sch_symbol.cpp index 6941a5cce5..0c134a06f2 100644 --- a/eeschema/sch_symbol.cpp +++ b/eeschema/sch_symbol.cpp @@ -713,6 +713,100 @@ void SCH_SYMBOL::SetRef( const SCH_SHEET_PATH* sheet, const wxString& ref ) } +void SCH_SYMBOL::SetFieldText( const wxString& aFieldName, const wxString& aFieldText, const SCH_SHEET_PATH* aPath, + const wxString& aVariantName ) +{ + wxCHECK( !aFieldName.IsEmpty(), /* void */ ); + + SCH_FIELD* field = GetField( aFieldName ); + + wxCHECK( field, /* void */ ); + + switch( field->GetId() ) + { + case FIELD_T::REFERENCE: + wxCHECK( aPath, /* void */ ); + SetRef( aPath, aFieldText ); + break; + + case FIELD_T::FOOTPRINT: + SetFootprintFieldText( aFieldText ); + break; + + default: + if( aFieldText != field->GetText( aPath ) ) // Do not set the variant unless it's different than the default. + { + if( aVariantName.IsEmpty() ) + { + field->SetText( aFieldText ); + } + else + { + SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath ); + + wxCHECK( instance, /* void */ ); + + if( instance->m_Variants.contains( aVariantName ) ) + { + instance->m_Variants[aVariantName].m_Fields[aFieldName] = aFieldText; + } + else + { + SCH_SYMBOL_VARIANT newVariant( aVariantName ); + + newVariant.InitializeAttributes( *this ); + newVariant.m_Fields[aFieldName] = aFieldText; + instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) ); + } + } + } + + break; + } +} + + +wxString SCH_SYMBOL::GetFieldText( const wxString& aFieldName, const SCH_SHEET_PATH* aPath, + const wxString& aVariantName ) const +{ + wxCHECK( !aFieldName.IsEmpty(), wxEmptyString ); + + const SCH_FIELD* field = GetField( aFieldName ); + + wxCHECK( field, wxEmptyString ); + + switch( field->GetId() ) + { + case FIELD_T::REFERENCE: + wxCHECK( aPath, field->GetText() ); + return GetRef( aPath, false ); + break; + + case FIELD_T::FOOTPRINT: + return GetFootprintFieldText( false, nullptr, false ); + break; + + default: + if( aVariantName.IsEmpty() ) + { + return field->GetText(); + } + else + { + const SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath ); + + if( instance->m_Variants.contains( aVariantName ) + && instance->m_Variants.at( aVariantName ).m_Fields.contains( aFieldName ) ) + return instance->m_Variants.at( aVariantName ).m_Fields.at( aFieldName ); + } + + break; + } + + return field->GetText(); +} + + bool SCH_SYMBOL::IsAnnotated( const SCH_SHEET_PATH* aSheet ) const { KIID_PATH path = aSheet->Path(); @@ -800,30 +894,27 @@ void SCH_SYMBOL::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelect void SCH_SYMBOL::SetDNP( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) { - if( !aInstance ) + if( !aInstance || aVariantName.IsEmpty() ) { m_DNP = aEnable; return; } - SCH_SYMBOL_INSTANCE instance; + SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance ); - wxCHECK_MSG( GetInstance( instance, aInstance->Path() ), /* void */, + wxCHECK_MSG( instance, /* void */, wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ), aInstance->PathHumanReadable() ) ); if( aVariantName.IsEmpty() ) { - instance.m_DNP = aEnable; - - // @todo: remove this when/if we allow per symbol instance DNP setting. m_DNP = aEnable; } else { - if( instance.m_Variants.contains( aVariantName ) ) + if( instance->m_Variants.contains( aVariantName ) && ( aEnable != instance->m_Variants[aVariantName].m_DNP ) ) { - instance.m_Variants[aVariantName].m_DNP = aEnable; + instance->m_Variants[aVariantName].m_DNP = aEnable; } else { @@ -839,66 +930,47 @@ void SCH_SYMBOL::SetDNP( bool aEnable, const SCH_SHEET_PATH* aInstance, const wx bool SCH_SYMBOL::GetDNP( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const { - if( !aInstance ) + if( !aInstance || aVariantName.IsEmpty() ) return m_DNP; SCH_SYMBOL_INSTANCE instance; - wxCHECK_MSG( GetInstance( instance, aInstance->Path() ), m_DNP, - wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ), - aInstance->PathHumanReadable() ) ); - - if( aVariantName.IsEmpty() ) - { + if( !GetInstance( instance, aInstance->Path() ) ) return m_DNP; - // @todo: uncomment this when/if we allow per symbol instance DNP setting. - // return instance.m_DNP; - } - else - { - wxCHECK_MSG( instance.m_Variants.contains( aVariantName ), false, - wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s' for variant '%s'." ), - aInstance->PathHumanReadable(), aVariantName ) ); - + if( aVariantName.IsEmpty() ) + return m_DNP; + else if( instance.m_Variants.contains( aVariantName ) ) return instance.m_Variants[aVariantName].m_DNP; - } -} - -void SCH_SYMBOL::SetDNP( bool aEnable, const SCH_SHEET_PATH& aInstance, const std::vector& aVariantNames ) -{ - for( const wxString& variantName : aVariantNames ) - SetDNP( aEnable, &aInstance, variantName ); + return m_DNP; } void SCH_SYMBOL::SetExcludedFromBOM( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) { - if( !aInstance ) + if( !aInstance || aVariantName.IsEmpty() ) { m_excludedFromBOM = aEnable; return; } - SCH_SYMBOL_INSTANCE instance; + SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance ); - wxCHECK_MSG( GetInstance( instance, aInstance->Path() ), /* void */, + wxCHECK_MSG( instance, /* void */, wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ), aInstance->PathHumanReadable() ) ); if( aVariantName.IsEmpty() ) { - instance.m_ExcludedFromBOM = aEnable; - - // @todo: remove this when/if we allow per symbol instance exclude from BOM setting. m_excludedFromBOM = aEnable; } else { - if( instance.m_Variants.contains( aVariantName ) ) + if( instance->m_Variants.contains( aVariantName ) + && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromBOM ) ) { - instance.m_Variants[aVariantName].m_ExcludedFromBOM = aEnable; + instance->m_Variants[aVariantName].m_ExcludedFromBOM = aEnable; } else { @@ -914,66 +986,48 @@ void SCH_SYMBOL::SetExcludedFromBOM( bool aEnable, const SCH_SHEET_PATH* aInstan bool SCH_SYMBOL::GetExcludedFromBOM( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const { - if( !aInstance ) + if( !aInstance || aVariantName.IsEmpty() ) return m_excludedFromBOM; SCH_SYMBOL_INSTANCE instance; - wxCHECK_MSG( GetInstance( instance, aInstance->Path() ), m_excludedFromBOM, - wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ), - aInstance->PathHumanReadable() ) ); + if( !GetInstance( instance, aInstance->Path() ) ) + return m_excludedFromBOM; if( aVariantName.IsEmpty() ) - { return m_excludedFromBOM; - // @todo: uncomment this when/if we allow per symbol instance exclude from BOM setting. - // return instance.m_ExcludedFromBOM; - } - else - { - wxCHECK_MSG( instance.m_Variants.contains( aVariantName ), false, - wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s' variant '%s'." ), - aInstance->PathHumanReadable(), aVariantName ) ); - + else if( instance.m_Variants.contains( aVariantName ) ) return instance.m_Variants[aVariantName].m_ExcludedFromBOM; - } -} - -void SCH_SYMBOL::SetExcludedFromBOM( bool aEnable, const SCH_SHEET_PATH& aInstance, - const std::vector& aVariantNames ) -{ - for( const wxString& variantName : aVariantNames ) - SetExcludedFromBOM( aEnable, &aInstance, variantName ); + // If the variant has not been defined yet, return the default exclude from BOM setting. + return m_excludedFromBOM; } void SCH_SYMBOL::SetExcludedFromSim( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) { - if( !aInstance ) + if( !aInstance || aVariantName.IsEmpty() ) { m_excludedFromSim = aEnable; return; } - SCH_SYMBOL_INSTANCE instance; + SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance ); - wxCHECK_MSG( GetInstance( instance, aInstance->Path() ), /* void */, + wxCHECK_MSG( instance, /* void */, wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ), aInstance->PathHumanReadable() ) ); if( aVariantName.IsEmpty() ) { - instance.m_ExcludedFromSim = aEnable; - - // @todo: remove this when/if we allow per symbol instance exclude from simulation setting. m_excludedFromSim = aEnable; } else { - if( instance.m_Variants.contains( aVariantName ) ) + if( instance->m_Variants.contains( aVariantName ) + && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromSim ) ) { - instance.m_Variants[aVariantName].m_ExcludedFromSim = aEnable; + instance->m_Variants[aVariantName].m_ExcludedFromSim = aEnable; } else { @@ -989,37 +1043,21 @@ void SCH_SYMBOL::SetExcludedFromSim( bool aEnable, const SCH_SHEET_PATH* aInstan bool SCH_SYMBOL::GetExcludedFromSim( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const { - if( !aInstance ) + if( !aInstance || aVariantName.IsEmpty() ) return m_excludedFromSim; SCH_SYMBOL_INSTANCE instance; - wxCHECK_MSG( GetInstance( instance, aInstance->Path() ), m_excludedFromSim, - wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ), - aInstance->PathHumanReadable() ) ); + if( !GetInstance( instance, aInstance->Path() ) ) + return m_excludedFromSim; if( aVariantName.IsEmpty() ) - { return m_excludedFromSim; - // @todo: uncooment this when/if we allow per symbol instance exclude from simulation setting. - // return instance.m_ExcludedFromSim; - } - else - { - wxCHECK_MSG( instance.m_Variants.contains( aVariantName ), false, - wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s' variant '%s'." ), - aInstance->PathHumanReadable(), aVariantName ) ); - + else if ( instance.m_Variants.contains( aVariantName ) ) return instance.m_Variants[aVariantName].m_ExcludedFromSim; - } -} - -void SCH_SYMBOL::SetExcludedFromSim( bool aEnable, const SCH_SHEET_PATH& aInstance, - const std::vector& aVariantNames ) -{ - for( const wxString& variantName : aVariantNames ) - SetExcludedFromSim( aEnable, &aInstance, variantName ); + // If variant is not defined yet, return default exclude from simulation setting. + return m_excludedFromSim; } @@ -1030,18 +1068,48 @@ void SCH_SYMBOL::SetUnitSelection( int aUnitSelection ) } -const wxString SCH_SYMBOL::GetValue( bool aResolve, const SCH_SHEET_PATH* aPath, bool aAllowExtraText ) const +const wxString SCH_SYMBOL::GetValue( bool aResolve, const SCH_SHEET_PATH* aInstance, + bool aAllowExtraText, const wxString& aVariantName ) const { - if( aResolve ) - return GetField( FIELD_T::VALUE )->GetShownText( aPath, aAllowExtraText ); + if( aVariantName.IsEmpty() ) + { + if( aResolve ) + return GetField( FIELD_T::VALUE )->GetShownText( aInstance, aAllowExtraText ); - return GetField( FIELD_T::VALUE )->GetText(); + return GetField( FIELD_T::VALUE )->GetText(); + } + + std::optional variant = GetVariant( *aInstance, aVariantName ); + + if( variant && variant->m_Fields.contains( GetField( FIELD_T::VALUE )->GetName() ) ) + return variant->m_Fields[GetField( FIELD_T::VALUE )->GetName()]; + + return wxEmptyString; } -void SCH_SYMBOL::SetValueFieldText( const wxString& aValue ) +void SCH_SYMBOL::SetValueFieldText( const wxString& aValue, const SCH_SHEET_PATH* aInstance, + const wxString& aVariantName ) { - GetField( FIELD_T::VALUE )->SetText( aValue ); + if( !aInstance || aVariantName.IsEmpty() ) + { + GetField( FIELD_T::VALUE )->SetText( aValue ); + return; + } + + std::optional variant = GetVariant( *aInstance, aVariantName ); + + if( variant ) + { + variant->m_Fields[GetField( FIELD_T::VALUE )->GetName()] = aValue; + } + else + { + SCH_SYMBOL_VARIANT newVariant( aVariantName ); + + newVariant.m_Fields[GetField( FIELD_T::VALUE )->GetName()] = aValue; + AddVariant( *aInstance, newVariant ); + } } @@ -2982,11 +3050,12 @@ void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& } } - if( m_DNP ) - PlotDNP( aPlotter ); - + wxString variant = Schematic()->GetCurrentVariant(); SCH_SHEET_PATH* sheet = &Schematic()->CurrentSheet(); + if( GetDNP( sheet, variant ) ) + PlotDNP( aPlotter ); + // Plot attributes to a hypertext menu if( aPlotOpts.m_PDFPropertyPopups ) { @@ -2994,7 +3063,7 @@ void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& for( const SCH_FIELD& field : GetFields() ) { - wxString text_field = field.GetShownText( sheet, false ); + wxString text_field = field.GetShownText( sheet, false, 0, variant ); if( text_field.IsEmpty() ) continue; @@ -3322,13 +3391,13 @@ std::optional SCH_SYMBOL::GetVariant( const SCH_SHEET_PATH& void SCH_SYMBOL::AddVariant( const SCH_SHEET_PATH& aInstance, const SCH_SYMBOL_VARIANT& aVariant ) { - SCH_SYMBOL_INSTANCE instance; + SCH_SYMBOL_INSTANCE* instance = getInstance( aInstance ); // The instance path must already exist. - if( !GetInstance( instance, aInstance.Path() ) ) + if( !instance ) return; - instance.m_Variants.emplace( std::make_pair( aVariant.m_Name, aVariant ) ); + instance->m_Variants.insert( std::make_pair( aVariant.m_Name, aVariant ) ); } @@ -3450,6 +3519,30 @@ void SCH_SYMBOL::BuildLocalPowerIconShape( std::vector& aShapeList, c } +SCH_SYMBOL_INSTANCE* SCH_SYMBOL::getInstance( const KIID_PATH& aSheetPath ) +{ + for( SCH_SYMBOL_INSTANCE& instance : m_instanceReferences ) + { + if( instance.m_Path == aSheetPath ) + return &instance; + } + + return nullptr; +} + + +const SCH_SYMBOL_INSTANCE* SCH_SYMBOL::getInstance( const KIID_PATH& aSheetPath ) const +{ + for( const SCH_SYMBOL_INSTANCE& instance : m_instanceReferences ) + { + if( instance.m_Path == aSheetPath ) + return &instance; + } + + return nullptr; +} + + static struct SCH_SYMBOL_DESC { SCH_SYMBOL_DESC() diff --git a/eeschema/sch_symbol.h b/eeschema/sch_symbol.h index b2c563cd36..e6c25e09c8 100644 --- a/eeschema/sch_symbol.h +++ b/eeschema/sch_symbol.h @@ -476,9 +476,10 @@ public: * @return the value for the instance on the given sheet. */ const wxString GetValue( bool aResolve, const SCH_SHEET_PATH* aPath, - bool aAllowExtraText ) const override; + bool aAllowExtraText, const wxString& aVariantName = wxEmptyString ) const override; - void SetValueFieldText( const wxString& aValue ); + void SetValueFieldText( const wxString& aValue, const SCH_SHEET_PATH* aInstance = nullptr, + const wxString& aVariantName = wxEmptyString ); const wxString GetFootprintFieldText( bool aResolve, const SCH_SHEET_PATH* aPath, bool aAllowExtraText ) const; @@ -496,12 +497,12 @@ public: wxString GetValueProp() const { - return GetValue( false, &Schematic()->CurrentSheet(), false ); + return GetValue( false, &Schematic()->CurrentSheet(), false, Schematic()->GetCurrentVariant() ); } - void SetValueProp( const wxString& aRef ) + void SetValueProp( const wxString& aValue ) { - SetValueFieldText( aRef ); + SetValueFieldText( aValue, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() ); } int GetUnitProp() const @@ -509,6 +510,12 @@ public: return GetUnitSelection( &Schematic()->CurrentSheet() ); } + void SetFieldText( const wxString& aFieldName, const wxString& aFieldText, const SCH_SHEET_PATH* aPath = nullptr, + const wxString& aVariantName = wxEmptyString ); + + wxString GetFieldText( const wxString& aFieldName, const SCH_SHEET_PATH* aPath = nullptr, + const wxString& aVariantName = wxEmptyString ) const; + void SetUnitProp( int aUnit ) { SetUnitSelection( &Schematic()->CurrentSheet(), aUnit ); @@ -678,44 +685,40 @@ public: const wxString& aVariantName = wxEmptyString ) override; virtual bool GetDNP( const SCH_SHEET_PATH* aInstance = nullptr, const wxString& aVariantName = wxEmptyString ) const override; - void SetDNP( bool aEnable, const SCH_SHEET_PATH& aInstance, const std::vector& aVariantNames ); - bool GetDNPProp() const { return GetDNP( nullptr, Schematic()->GetCurrentVariant() ); } + bool GetDNPProp() const { return GetDNP( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() ); } - void SetDNPProp( bool aEnable ) { SetDNP( aEnable, nullptr, Schematic()->GetCurrentVariant() ); } + void SetDNPProp( bool aEnable ) { SetDNP( aEnable, &Schematic()->CurrentSheet(), + Schematic()->GetCurrentVariant() ); } void SetExcludedFromBOM( bool aEnable, const SCH_SHEET_PATH* aInstance = nullptr, const wxString& aVariantName = wxEmptyString ) override; bool GetExcludedFromBOM( const SCH_SHEET_PATH* aInstance = nullptr, const wxString& aVariantName = wxEmptyString ) const override; - void SetExcludedFromBOM( bool aEnable, const SCH_SHEET_PATH& aInstance, - const std::vector& aVariantNames ); bool GetExcludedFromBOMProp() const { - return GetExcludedFromBOM( nullptr, Schematic()->GetCurrentVariant() ); + return GetExcludedFromBOM( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() ); } void SetExcludedFromBOMProp( bool aEnable ) { - SetExcludedFromBOM( aEnable, nullptr, Schematic()->GetCurrentVariant() ); + SetExcludedFromBOM( aEnable, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() ); } void SetExcludedFromSim( bool aEnable, const SCH_SHEET_PATH* aInstance = nullptr, const wxString& aVariantName = wxEmptyString ) override; bool GetExcludedFromSim( const SCH_SHEET_PATH* aInstance = nullptr, const wxString& aVariantName = wxEmptyString ) const override; - void SetExcludedFromSim( bool aEnable, const SCH_SHEET_PATH& aInstance, - const std::vector& aVariantNames ); bool GetExcludedFromSimProp() const { - return GetExcludedFromSim( nullptr, Schematic()->GetCurrentVariant() ); + return GetExcludedFromSim( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() ); } void SetExcludedFromSimProp( bool aEnable ) { - SetExcludedFromSim( aEnable, nullptr, Schematic()->GetCurrentVariant() ); + SetExcludedFromSim( aEnable, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() ); } /** @@ -912,6 +915,12 @@ private: void Init( const VECTOR2I& pos = VECTOR2I( 0, 0 ) ); + SCH_SYMBOL_INSTANCE* getInstance( const KIID_PATH& aPath ); + const SCH_SYMBOL_INSTANCE* getInstance( const KIID_PATH& aPath ) const; + + SCH_SYMBOL_INSTANCE* getInstance( const SCH_SHEET_PATH& aPath ) { return getInstance( aPath.Path() ); } + const SCH_SYMBOL_INSTANCE* getInstance( const SCH_SHEET_PATH& aPath ) const { return getInstance( aPath.Path() ); } + private: VECTOR2I m_pos; LIB_ID m_lib_id; ///< Name and library the symbol was loaded from, i.e. 74xx:74LS00. diff --git a/eeschema/schematic.cpp b/eeschema/schematic.cpp index 3f8d345857..32071e4eed 100644 --- a/eeschema/schematic.cpp +++ b/eeschema/schematic.cpp @@ -468,6 +468,11 @@ bool SCHEMATIC::ResolveTextVar( const SCH_SHEET_PATH* aSheetPath, wxString* toke *token = m_project->GetProjectName(); return true; } + else if( token->IsSameAs( wxT( "VARIANTNAME" ) ) ) + { + *token = m_currentVariant; + return true; + } // aSheetPath->LastScreen() can be null during schematic loading if( aSheetPath->LastScreen() && aSheetPath->LastScreen()->GetTitleBlock().TextVarResolver( token, m_project ) ) @@ -2112,6 +2117,17 @@ void SCHEMATIC::DeleteVariant( const wxString& aVariantName ) } +void SCHEMATIC::LoadVariants() +{ + if( m_rootSheet->GetScreen() ) + { + SCH_SCREENS screens( m_rootSheet ); + std::set variantNames = screens.GetVariantNames(); + m_variantNames.insert( variantNames.begin(), variantNames.end() ); + } +} + + void SCHEMATIC::SaveToHistory( const wxString& aProjectPath, std::vector& aFiles ) { wxString projPath = m_project->GetProjectPath(); diff --git a/eeschema/schematic.h b/eeschema/schematic.h index 7aca82e8cb..869aa24eba 100644 --- a/eeschema/schematic.h +++ b/eeschema/schematic.h @@ -460,6 +460,14 @@ public: void AddVariant( const wxString& aVariantName ) { m_variantNames.emplace( aVariantName ); } + /** + * This is a throw away method for variant testing. + * + * Once the schematic loading is properly fixed due to SetRoot() method breakage, this method should + * be removed. + */ + void LoadVariants(); + /** * True if a SCHEMATIC exists, false if not */ diff --git a/eeschema/symbol.h b/eeschema/symbol.h index 0754a0dfa7..36c2a012e8 100644 --- a/eeschema/symbol.h +++ b/eeschema/symbol.h @@ -143,7 +143,7 @@ public: bool aIncludeUnit = false ) const = 0; virtual const wxString GetValue( bool aResolve, const SCH_SHEET_PATH* aPath, - bool aAllowExtraText ) const = 0; + bool aAllowExtraText, const wxString& aVaraintName = wxEmptyString ) const = 0; virtual void GetFields( std::vector& aVector, bool aVisibleOnly ) const = 0; @@ -190,7 +190,7 @@ public: * Set or clear the exclude from schematic bill of materials flag. */ virtual void SetExcludedFromBOM( bool aExcludeFromBOM, const SCH_SHEET_PATH* aInstance = nullptr, - const wxString& aVariantName = wxEmptyString ) override + const wxString& aVariantName = wxEmptyString ) override { m_excludedFromBOM = aExcludeFromBOM; } diff --git a/eeschema/toolbars_sch_editor.cpp b/eeschema/toolbars_sch_editor.cpp index d79643cb07..39cf9d230f 100644 --- a/eeschema/toolbars_sch_editor.cpp +++ b/eeschema/toolbars_sch_editor.cpp @@ -320,6 +320,8 @@ void SCH_EDIT_FRAME::onVariantSelected( wxCommandEvent& aEvent ) selectedVariant = m_currentVariantCtrl->GetString( selection ); Schematic().SetCurrentVariant( selectedVariant ); + UpdateProperties(); + HardRedraw(); } @@ -328,7 +330,9 @@ void SCH_EDIT_FRAME::SetCurrentVariant( const wxString& aVariantName ) if( !m_currentVariantCtrl ) return; - int newSelection = m_currentVariantCtrl->FindString( aVariantName ); + wxString name = aVariantName.IsEmpty() ? GetDefaultVariantName() : aVariantName; + + int newSelection = m_currentVariantCtrl->FindString( name ); if( newSelection == wxNOT_FOUND ) return; @@ -340,7 +344,7 @@ void SCH_EDIT_FRAME::SetCurrentVariant( const wxString& aVariantName ) if( currentSelection != wxNOT_FOUND ) selectedString = m_currentVariantCtrl->GetString( currentSelection ); - if( selectedString != aVariantName ) + if( selectedString != name ) { m_currentVariantCtrl->SetSelection( newSelection ); Schematic().SetCurrentVariant( aVariantName ); diff --git a/qa/data/eeschema/variant_test/variant_test.kicad_pro b/qa/data/eeschema/variant_test/variant_test.kicad_pro new file mode 100644 index 0000000000..bfae7e8a30 --- /dev/null +++ b/qa/data/eeschema/variant_test/variant_test.kicad_pro @@ -0,0 +1,410 @@ +{ + "board": { + "3dviewports": [], + "ipc2581": { + "dist": "", + "distpn": "", + "internal_id": "", + "mfg": "", + "mpn": "" + }, + "layer_pairs": [], + "layer_presets": [], + "viewports": [] + }, + "boards": [], + "cvpcb": { + "equivalence_files": [] + }, + "erc": { + "erc_exclusions": [], + "meta": { + "version": 0 + }, + "pin_map": [ + [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2 + ], + [ + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 2 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2 + ], + [ + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 2 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2 + ], + [ + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2 + ], + [ + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2 + ], + [ + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 2 + ], + [ + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2 + ], + [ + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2 + ], + [ + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2 + ] + ], + "rule_severities": { + "bus_definition_conflict": "error", + "bus_entry_needed": "error", + "bus_to_bus_conflict": "error", + "bus_to_net_conflict": "error", + "different_unit_footprint": "error", + "different_unit_net": "error", + "duplicate_reference": "error", + "duplicate_sheet_names": "error", + "endpoint_off_grid": "warning", + "extra_units": "error", + "footprint_filter": "ignore", + "footprint_link_issues": "warning", + "four_way_junction": "ignore", + "global_label_dangling": "warning", + "hier_label_mismatch": "error", + "label_dangling": "error", + "label_multiple_wires": "warning", + "lib_symbol_issues": "warning", + "lib_symbol_mismatch": "warning", + "missing_bidi_pin": "warning", + "missing_input_pin": "warning", + "missing_power_pin": "error", + "missing_unit": "warning", + "multiple_net_names": "warning", + "net_not_bus_member": "warning", + "no_connect_connected": "warning", + "no_connect_dangling": "warning", + "pin_not_connected": "error", + "pin_not_driven": "error", + "pin_to_pin": "warning", + "power_pin_not_driven": "error", + "same_local_global_label": "warning", + "similar_label_and_power": "warning", + "similar_labels": "warning", + "similar_power": "warning", + "simulation_model_issue": "ignore", + "single_global_label": "ignore", + "unannotated": "error", + "unconnected_wire_endpoint": "warning", + "undefined_netclass": "error", + "unit_value_mismatch": "error", + "unresolved_variable": "error", + "wire_dangling": "error" + } + }, + "libraries": { + "pinned_footprint_libs": [], + "pinned_symbol_libs": [] + }, + "meta": { + "filename": "variant_test.kicad_pro", + "version": 3 + }, + "net_settings": { + "classes": [ + { + "bus_width": 12, + "clearance": 0.2, + "diff_pair_gap": 0.25, + "diff_pair_via_gap": 0.25, + "diff_pair_width": 0.2, + "line_style": 0, + "microvia_diameter": 0.3, + "microvia_drill": 0.1, + "name": "Default", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "priority": 2147483647, + "schematic_color": "rgba(0, 0, 0, 0.000)", + "track_width": 0.2, + "via_diameter": 0.6, + "via_drill": 0.3, + "wire_width": 6 + } + ], + "meta": { + "version": 4 + }, + "net_colors": null, + "netclass_assignments": null, + "netclass_patterns": [] + }, + "pcbnew": { + "last_paths": { + "gencad": "", + "idf": "", + "netlist": "", + "plot": "", + "pos_files": "", + "specctra_dsn": "", + "step": "", + "svg": "", + "vrml": "" + }, + "page_layout_descr_file": "" + }, + "schematic": { + "annotate_start_num": 0, + "bom_export_filename": "${PROJECTNAME}.csv", + "bom_fmt_presets": [], + "bom_fmt_settings": { + "field_delimiter": ",", + "keep_line_breaks": false, + "keep_tabs": false, + "name": "CSV", + "ref_delimiter": ",", + "ref_range_delimiter": "", + "string_delimiter": "\"" + }, + "bom_presets": [], + "bom_settings": { + "exclude_dnp": false, + "fields_ordered": [ + { + "group_by": false, + "label": "Reference", + "name": "Reference", + "show": true + }, + { + "group_by": false, + "label": "Qty", + "name": "${QUANTITY}", + "show": true + }, + { + "group_by": true, + "label": "Value", + "name": "Value", + "show": true + }, + { + "group_by": true, + "label": "DNP", + "name": "${DNP}", + "show": true + }, + { + "group_by": true, + "label": "Exclude from BOM", + "name": "${EXCLUDE_FROM_BOM}", + "show": true + }, + { + "group_by": true, + "label": "Exclude from Board", + "name": "${EXCLUDE_FROM_BOARD}", + "show": true + }, + { + "group_by": true, + "label": "Footprint", + "name": "Footprint", + "show": true + }, + { + "group_by": false, + "label": "Datasheet", + "name": "Datasheet", + "show": true + } + ], + "filter_string": "", + "group_symbols": true, + "include_excluded_from_bom": true, + "name": "Default Editing", + "sort_asc": true, + "sort_field": "Reference" + }, + "connection_grid_size": 50.0, + "drawing": { + "dashed_lines_dash_length_ratio": 12.0, + "dashed_lines_gap_length_ratio": 3.0, + "default_line_thickness": 6.0, + "default_text_size": 50.0, + "field_names": [], + "intersheets_ref_own_page": false, + "intersheets_ref_prefix": "", + "intersheets_ref_short": false, + "intersheets_ref_show": false, + "intersheets_ref_suffix": "", + "junction_size_choice": 3, + "label_size_ratio": 0.375, + "operating_point_overlay_i_precision": 3, + "operating_point_overlay_i_range": "~A", + "operating_point_overlay_v_precision": 3, + "operating_point_overlay_v_range": "~V", + "overbar_offset_ratio": 1.23, + "pin_symbol_size": 25.0, + "text_offset_ratio": 0.15 + }, + "legacy_lib_dir": "", + "legacy_lib_list": [], + "meta": { + "version": 1 + }, + "net_format_name": "", + "page_layout_descr_file": "", + "plot_directory": "", + "space_save_all_events": true, + "spice_current_sheet_as_root": false, + "spice_external_command": "spice \"%I\"", + "spice_model_current_sheet_as_root": true, + "spice_save_all_currents": false, + "spice_save_all_dissipations": false, + "spice_save_all_voltages": false, + "subpart_first_id": 65, + "subpart_id_separator": 0 + }, + "sheets": [ + [ + "054bba16-8cdf-4a21-a2a2-bd9ba5ee743f", + "Root" + ] + ], + "text_variables": {} +} diff --git a/qa/data/eeschema/variant_test/variant_test.kicad_sch b/qa/data/eeschema/variant_test/variant_test.kicad_sch new file mode 100644 index 0000000000..d9a2ab5b36 --- /dev/null +++ b/qa/data/eeschema/variant_test/variant_test.kicad_sch @@ -0,0 +1,209 @@ +(kicad_sch + (version 20250114) + (generator "eeschema") + (generator_version "9.0") + (uuid "054bba16-8cdf-4a21-a2a2-bd9ba5ee743f") + (paper "A4") + (lib_symbols + (symbol "Device:R" + (pin_numbers + (hide yes) + ) + (pin_names + (offset 0) + ) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (property "Reference" "R" + (at 2.032 0 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Value" "R" + (at 0 0 90) + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (property "Footprint" "" + (at -1.778 0 90) + (effects + (font + (size 1.27 1.27) + ) + (hide yes) + ) + ) + (property "Datasheet" "~" + (at 0 0 0) + (effects + (font + (size 1.27 1.27) + ) + (hide yes) + ) + ) + (property "Description" "Resistor" + (at 0 0 0) + (effects + (font + (size 1.27 1.27) + ) + (hide yes) + ) + ) + (property "ki_keywords" "R res resistor" + (at 0 0 0) + (effects + (font + (size 1.27 1.27) + ) + (hide yes) + ) + ) + (property "ki_fp_filters" "R_*" + (at 0 0 0) + (effects + (font + (size 1.27 1.27) + ) + (hide yes) + ) + ) + (symbol "R_0_1" + (rectangle + (start -1.016 -2.54) + (end 1.016 2.54) + (stroke + (width 0.254) + (type default) + ) + (fill + (type none) + ) + ) + ) + (symbol "R_1_1" + (pin passive line + (at 0 3.81 270) + (length 1.27) + (name "~" + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (number "1" + (effects + (font + (size 1.27 1.27) + ) + ) + ) + ) + (pin passive line + (at 0 -3.81 90) + (length 1.27) + (name "~" + (effects + (font + (size 1.27 1.27) + ) + ) + ) + (number "2" + (effects + (font + (size 1.27 1.27) + ) + ) + ) + ) + ) + (embedded_fonts no) + ) + ) + (symbol + (lib_id "Device:R") + (at 110.49 88.9 0) + (unit 1) + (exclude_from_sim no) + (in_bom yes) + (on_board yes) + (dnp no) + (fields_autoplaced yes) + (uuid "c3f93c62-4b18-4940-a587-6e1147c4fd43") + (property "Reference" "R1" + (at 113.03 87.6299 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Value" "1K" + (at 113.03 90.1699 0) + (effects + (font + (size 1.27 1.27) + ) + (justify left) + ) + ) + (property "Footprint" "" + (at 108.712 88.9 90) + (effects + (font + (size 1.27 1.27) + ) + (hide yes) + ) + ) + (property "Datasheet" "~" + (at 110.49 88.9 0) + (effects + (font + (size 1.27 1.27) + ) + (hide yes) + ) + ) + (property "Description" "Resistor" + (at 110.49 88.9 0) + (effects + (font + (size 1.27 1.27) + ) + (hide yes) + ) + ) + (pin "1" + (uuid "1e787b7c-7f54-4b81-9254-825bd71b3511") + ) + (pin "2" + (uuid "07fa4c47-5960-4d30-8bfd-93c1e8ac9e63") + ) + (instances + (project "" + (path "/054bba16-8cdf-4a21-a2a2-bd9ba5ee743f" + (reference "R1") + (unit 1) + ) + ) + ) + ) + (sheet_instances + (path "/" + (page "1") + ) + ) + (embedded_fonts no) +) diff --git a/qa/tests/eeschema/test_sch_symbol.cpp b/qa/tests/eeschema/test_sch_symbol.cpp index 49b8102bbb..a7778ff373 100644 --- a/qa/tests/eeschema/test_sch_symbol.cpp +++ b/qa/tests/eeschema/test_sch_symbol.cpp @@ -27,17 +27,36 @@ */ #include +#include "eeschema_test_utils.h" // Code under test #include - #include +#include -class TEST_SCH_SYMBOL_FIXTURE + +class TEST_SCH_SYMBOL_FIXTURE : public KI_TEST::SCHEMATIC_TEST_FIXTURE { public: - TEST_SCH_SYMBOL_FIXTURE() + SCH_SYMBOL* GetFirstSymbol() { + if( !m_schematic ) + return nullptr; + + SCH_SCREEN* screen = m_schematic->RootScreen(); + + if( !screen ) + return nullptr; + + for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) ) + { + SCH_SYMBOL* symbol = static_cast( item ); + + if( symbol ) + return symbol; + } + + return nullptr; } ///< #SCH_SYMBOL object with no extra data set. @@ -77,4 +96,50 @@ BOOST_AUTO_TEST_CASE( Orientation ) } +/** + * Test symbol variant handling. + */ +BOOST_AUTO_TEST_CASE( SchSymbolVariantTest ) +{ + wxFileName fn; + fn.SetPath( KI_TEST::GetEeschemaTestDataDir() ); + fn.AppendDir( wxS( "variant_test" ) ); + fn.SetName( wxS( "variant_test" ) ); + fn.SetExt( FILEEXT::KiCadSchematicFileExtension ); + + LoadSchematic( fn.GetFullPath() ); + + SCH_SYMBOL* symbol = GetFirstSymbol(); + BOOST_CHECK( symbol ); + + // Test for an empty (non-existant) variant. + wxString variantName = wxS( "Variant1" ); + std::optional variant = symbol->GetVariant( m_schematic->Hierarchy()[0], variantName ); + BOOST_CHECK( !variant ); + + // Test DNP property variant. + BOOST_CHECK( !symbol->GetDNP() ); + symbol->SetDNP( true, &m_schematic->Hierarchy()[0], variantName ); + BOOST_CHECK( symbol->GetDNP( &m_schematic->Hierarchy()[0], variantName ) ); + + // Test exclude from BOM property variant. + BOOST_CHECK( !symbol->GetExcludedFromBOM() ); + symbol->SetExcludedFromBOM( true, &m_schematic->Hierarchy()[0], variantName ); + BOOST_CHECK( symbol->GetExcludedFromBOM( &m_schematic->Hierarchy()[0], variantName ) ); + + // Test exclude from simulation property variant. + BOOST_CHECK( !symbol->GetExcludedFromSim() ); + symbol->SetExcludedFromSim( true, &m_schematic->Hierarchy()[0], variantName ); + BOOST_CHECK( symbol->GetExcludedFromSim( &m_schematic->Hierarchy()[0], variantName ) ); + + // Test a value field variant change. + BOOST_CHECK( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0], + false, 0 ) == wxS( "1K" ) ); + symbol->GetField( FIELD_T::VALUE )->SetText( wxS( "10K" ), &m_schematic->Hierarchy()[0], variantName ); + BOOST_CHECK( symbol->GetField( FIELD_T::VALUE )->GetShownText( &m_schematic->Hierarchy()[0], + false, 0, variantName ) == wxS( "10K" ) ); + // BOOST_CHECK( symbol->GetFieldText( FIELD_T::VALUE, &m_schematic->Hierarchy()[0], variantName ) == wxS( "10K" ) ); +} + + BOOST_AUTO_TEST_SUITE_END()