PCB: convert footprints to use PCB_FIELDs for fields from schematics

This commit is contained in:
Mike Williams 2023-05-24 08:39:25 -04:00
parent 968785382e
commit a859b25d2c
20 changed files with 623 additions and 325 deletions

View File

@ -77,7 +77,7 @@ DIALOG_FOOTPRINT_PROPERTIES::DIALOG_FOOTPRINT_PROPERTIES( PCB_EDIT_FRAME* aParen
m_posX.SetCoordType( ORIGIN_TRANSFORMS::ABS_X_COORD );
m_posY.SetCoordType( ORIGIN_TRANSFORMS::ABS_Y_COORD );
m_texts = new FP_TEXT_GRID_TABLE( m_frame );
m_fields = new FP_TEXT_GRID_TABLE( m_frame );
m_delayedErrorMessage = wxEmptyString;
m_delayedFocusGrid = nullptr;
@ -93,7 +93,7 @@ DIALOG_FOOTPRINT_PROPERTIES::DIALOG_FOOTPRINT_PROPERTIES( PCB_EDIT_FRAME* aParen
// Give a bit more room for combobox editors
m_itemsGrid->SetDefaultRowSize( m_itemsGrid->GetDefaultRowSize() + 4 );
m_itemsGrid->SetTable( m_texts );
m_itemsGrid->SetTable( m_fields );
m_itemsGrid->PushEventHandler( new GRID_TRICKS( m_itemsGrid ) );
// Show/hide text item columns according to the user's preference
@ -177,7 +177,7 @@ DIALOG_FOOTPRINT_PROPERTIES::~DIALOG_FOOTPRINT_PROPERTIES()
cfg->m_FootprintTextShownColumns = m_itemsGrid->GetShownColumnsAsString();
// Prevents crash bug in wxGrid's d'tor
m_itemsGrid->DestroyTable( m_texts );
m_itemsGrid->DestroyTable( m_fields );
// Delete the GRID_TRICKS.
m_itemsGrid->PopEventHandler( true );
@ -244,18 +244,13 @@ bool DIALOG_FOOTPRINT_PROPERTIES::TransferDataToWindow()
if( !m_3dPanel->TransferDataToWindow() )
return false;
// Footprint Texts
m_texts->push_back( m_footprint->Reference() );
m_texts->push_back( m_footprint->Value() );
for( BOARD_ITEM* item : m_footprint->GraphicalItems() )
{
if( PCB_TEXT* textItem = dynamic_cast<PCB_TEXT*>( item ) )
m_texts->push_back( *textItem );
}
// Footprint Fields
for( PCB_FIELD* field : m_footprint->GetFields() )
m_fields->push_back( field );
// notify the grid
wxGridTableMessage tmsg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_texts->GetNumberRows() );
wxGridTableMessage tmsg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
m_fields->GetNumberRows() );
m_itemsGrid->ProcessTableMessage( tmsg );
// Footprint Properties
@ -328,7 +323,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES::TransferDataToWindow()
m_itemsGrid->SetColSize( col, col_size );
}
m_itemsGrid->SetRowLabelSize( m_itemsGrid->GetVisibleWidth( -1, false, true, true ) );
m_itemsGrid->SetRowLabelSize( 0 );
Layout();
adjustGridColumns();
@ -346,24 +341,19 @@ bool DIALOG_FOOTPRINT_PROPERTIES::Validate()
return false;
// Validate texts.
for( size_t i = 0; i < m_texts->size(); ++i )
for( size_t i = 0; i < m_fields->size(); ++i )
{
PCB_TEXT& text = m_texts->at( i );
PCB_FIELD* field = m_fields->at( i );
if( i >= 2 )
// Check for missing field names.
if( field->GetName( false ).IsEmpty() )
{
if( text.GetText().IsEmpty() )
{
if( m_NoteBook->GetSelection() != 0 )
m_NoteBook->SetSelection( 0 );
m_delayedFocusGrid = m_itemsGrid;
m_delayedErrorMessage = wxString::Format( _( "Fields must have a name." ) );
m_delayedFocusColumn = FPT_NAME;
m_delayedFocusRow = i;
m_delayedFocusGrid = m_itemsGrid;
m_delayedErrorMessage = _( "Text items must have some content." );
m_delayedFocusColumn = FPT_TEXT;
m_delayedFocusRow = i;
return false;
}
return false;
}
int minSize = pcbIUScale.MilsToIU( TEXT_MIN_SIZE_MILS );
@ -426,9 +416,9 @@ bool DIALOG_FOOTPRINT_PROPERTIES::Validate()
}
// Test for acceptable values for thickness and size and clamp if fails
int maxPenWidth = Clamp_Text_PenSize( text.GetTextThickness(), text.GetTextSize() );
int maxPenWidth = Clamp_Text_PenSize( field->GetTextThickness(), field->GetTextSize() );
if( text.GetTextThickness() > maxPenWidth )
if( field->GetTextThickness() > maxPenWidth )
{
wxString clamped = m_frame->StringFromValue( maxPenWidth, true );
@ -470,30 +460,24 @@ bool DIALOG_FOOTPRINT_PROPERTIES::TransferDataFromWindow()
BOARD_COMMIT commit( m_frame );
commit.Modify( m_footprint );
// copy reference and value
m_footprint->Reference() = m_texts->at( 0 );
m_footprint->Value() = m_texts->at( 1 );
// Update fields
size_t i = 0;
size_t i = 2;
for( BOARD_ITEM* item : m_footprint->GraphicalItems() )
for( PCB_FIELD* field : m_footprint->GetFields() )
{
if( PCB_TEXT* textItem = dynamic_cast<PCB_TEXT*>( item ) )
{
// copy grid table entries till we run out, then delete any remaining texts
if( i < m_texts->size() )
*textItem = m_texts->at( i++ );
else
textItem->DeleteStructure();
}
// copy grid table entries till we run out, then delete any remaining texts
if( i < m_fields->size() )
field = m_fields->at( i++ );
else
field->DeleteStructure();
}
// if there are still grid table entries, create new texts for them
while( i < m_texts->size() )
while( i < m_fields->size() )
{
PCB_TEXT* newText = new PCB_TEXT( m_texts->at( i++ ) );
m_footprint->Add( newText, ADD_MODE::APPEND );
view->Add( newText );
PCB_FIELD* newField = m_fields->at( i++ );
m_footprint->Add( newField, ADD_MODE::APPEND );
view->Add( newField );
}
// Initialize masks clearances
@ -583,30 +567,21 @@ void DIALOG_FOOTPRINT_PROPERTIES::OnAddField( wxCommandEvent& )
if( !m_itemsGrid->CommitPendingChanges() )
return;
const BOARD_DESIGN_SETTINGS& dsnSettings = m_frame->GetDesignSettings();
PCB_TEXT textItem( m_footprint, PCB_TEXT::TEXT_is_DIVERS );
PCB_FIELD* newField = new PCB_FIELD( m_footprint, m_fields->size() );
// Set active layer if legal; otherwise copy layer from previous text item
if( LSET::AllTechMask().test( m_frame->GetActiveLayer() ) )
textItem.SetLayer( m_frame->GetActiveLayer() );
else
textItem.SetLayer( m_texts->at( m_texts->size() - 1 ).GetLayer() );
newField->SetLayer( m_footprint->GetLayer() == F_Cu ? F_Fab : B_Fab );
newField->SetVisible( false );
newField->StyleFromSettings( m_frame->GetDesignSettings() );
textItem.SetTextSize( dsnSettings.GetTextSize( textItem.GetLayer() ) );
textItem.SetTextThickness( dsnSettings.GetTextThickness( textItem.GetLayer() ) );
textItem.SetItalic( dsnSettings.GetTextItalic( textItem.GetLayer() ) );
textItem.SetKeepUpright( dsnSettings.GetTextUpright( textItem.GetLayer() ) );
textItem.SetMirrored( IsBackLayer( textItem.GetLayer() ) );
m_texts->push_back( textItem );
m_fields->push_back( newField );
// notify the grid
wxGridTableMessage msg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
m_itemsGrid->ProcessTableMessage( msg );
m_itemsGrid->SetFocus();
m_itemsGrid->MakeCellVisible( m_texts->size() - 1, 0 );
m_itemsGrid->SetGridCursor( m_texts->size() - 1, 0 );
m_itemsGrid->MakeCellVisible( m_fields->size() - 1, 0 );
m_itemsGrid->SetGridCursor( m_fields->size() - 1, 0 );
m_itemsGrid->EnableCellEditControl( true );
m_itemsGrid->ShowCellEditControl();
@ -628,22 +603,26 @@ void DIALOG_FOOTPRINT_PROPERTIES::OnDeleteField( wxCommandEvent& )
for( int row : selectedRows )
{
if( row < 2 )
if( row < MANDATORY_FIELDS )
{
DisplayError( nullptr, _( "Reference and value are mandatory." ) );
DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
MANDATORY_FIELDS ) );
return;
}
}
m_itemsGrid->CommitPendingChanges( true /* quiet mode */ );
m_itemsGrid->ClearSelection();
// Reverse sort so deleting a row doesn't change the indexes of the other rows.
selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
for( int row : selectedRows )
{
m_texts->erase( m_texts->begin() + row );
m_fields->erase( m_fields->begin() + row );
// notify the grid
wxGridTableMessage msg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
m_itemsGrid->ProcessTableMessage( msg );
if( m_itemsGrid->GetNumberRows() > 0 )
@ -662,11 +641,16 @@ void DIALOG_FOOTPRINT_PROPERTIES::adjustGridColumns()
itemsWidth -= m_itemsGrid->GetRowLabelSize();
for( int i = 1; i < m_itemsGrid->GetNumberCols(); i++ )
itemsWidth -= m_itemsGrid->GetColSize( i );
for( int i = 0; i < m_itemsGrid->GetNumberCols(); i++ )
{
if( i == 1 )
continue;
m_itemsGrid->SetColSize( 0, std::max( itemsWidth,
m_itemsGrid->GetVisibleWidth( 0, true, false ) ) );
itemsWidth -= m_itemsGrid->GetColSize( i );
}
m_itemsGrid->SetColSize(
1, std::max( itemsWidth, m_itemsGrid->GetVisibleWidth( 0, true, false ) ) );
// Update the width of the 3D panel
m_3dPanel->AdjustGridColumnWidths();
@ -710,7 +694,10 @@ void DIALOG_FOOTPRINT_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& )
if( !m_initialFocus || grid == m_itemsGrid )
{
grid->SetGridCursor( row, col );
grid->EnableCellEditControl( true );
if( !( col == 0 && row < MANDATORY_FIELDS ) )
grid->EnableCellEditControl( true );
grid->ShowCellEditControl();
if( grid == m_itemsGrid && row == 0 && col == 0 )

View File

@ -82,7 +82,7 @@ private:
static int m_page; // remember the last open page during session
FP_TEXT_GRID_TABLE* m_texts;
FP_TEXT_GRID_TABLE* m_fields;
UNIT_BINDER m_posX;
UNIT_BINDER m_posY;
UNIT_BINDER m_orientation;

View File

@ -142,7 +142,7 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR(
m_3dPanel = new PANEL_FP_PROPERTIES_3D_MODEL( m_frame, m_footprint, this, m_NoteBook );
m_NoteBook->AddPage( m_3dPanel, _("3D Models"), false );
m_texts = new FP_TEXT_GRID_TABLE( m_frame );
m_fields = new FP_TEXT_GRID_TABLE( m_frame );
m_privateLayers = new PRIVATE_LAYERS_GRID_TABLE( m_frame );
m_delayedErrorMessage = wxEmptyString;
@ -161,7 +161,7 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR(
m_itemsGrid->SetDefaultRowSize( m_itemsGrid->GetDefaultRowSize() + 4 );
m_privateLayersGrid->SetDefaultRowSize( m_privateLayersGrid->GetDefaultRowSize() + 4 );
m_itemsGrid->SetTable( m_texts );
m_itemsGrid->SetTable( m_fields );
m_privateLayersGrid->SetTable( m_privateLayers );
m_itemsGrid->PushEventHandler( new GRID_TRICKS( m_itemsGrid ) );
@ -232,7 +232,7 @@ DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::~DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR()
cfg->m_FootprintTextShownColumns = m_itemsGrid->GetShownColumnsAsString();
// Prevents crash bug in wxGrid's d'tor
m_itemsGrid->DestroyTable( m_texts );
m_itemsGrid->DestroyTable( m_fields );
m_privateLayersGrid->DestroyTable( m_privateLayers );
// Delete the GRID_TRICKS.
@ -267,18 +267,13 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataToWindow()
if( !m_3dPanel->TransferDataToWindow() )
return false;
// Footprint Texts
m_texts->push_back( m_footprint->Reference() );
m_texts->push_back( m_footprint->Value() );
for( BOARD_ITEM* item : m_footprint->GraphicalItems() )
{
if( PCB_TEXT* textItem = dynamic_cast<PCB_TEXT*>( item) )
m_texts->push_back( *textItem );
}
// Footprint Fields
for( PCB_FIELD* field : m_footprint->GetFields() )
m_fields->push_back( field );
// Notify the grid
wxGridTableMessage tmsg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_texts->GetNumberRows() );
wxGridTableMessage tmsg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
m_fields->GetNumberRows() );
m_itemsGrid->ProcessTableMessage( tmsg );
if( m_footprint->GetAttributes() & FP_THROUGH_HOLE )
@ -352,7 +347,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataToWindow()
m_itemsGrid->SetColSize( col, col_size );
}
m_itemsGrid->SetRowLabelSize( m_itemsGrid->GetVisibleWidth( -1, true, true, true ) );
m_itemsGrid->SetRowLabelSize( 0 );
Layout();
adjustGridColumns();
@ -401,19 +396,17 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::Validate()
return false;
}
// Check for empty texts.
for( size_t i = 2; i < m_texts->size(); ++i )
// Check for valid field text properties
for( size_t i = 0; i < m_fields->size(); ++i )
{
PCB_TEXT& text = m_texts->at( i );
PCB_FIELD* field = m_fields->at( i );
if( text.GetText().IsEmpty() )
// Check for missing field names.
if( field->GetName( false ).IsEmpty() )
{
if( m_NoteBook->GetSelection() != 0 )
m_NoteBook->SetSelection( 0 );
m_delayedErrorMessage = _( "Text items must have some content." );
m_delayedFocusGrid = m_itemsGrid;
m_delayedFocusColumn = FPT_TEXT;
m_delayedErrorMessage = wxString::Format( _( "Fields must have a name." ) );
m_delayedFocusColumn = FPT_NAME;
m_delayedFocusRow = i;
return false;
@ -422,7 +415,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::Validate()
int minSize = pcbIUScale.MilsToIU( TEXT_MIN_SIZE_MILS );
int maxSize = pcbIUScale.MilsToIU( TEXT_MAX_SIZE_MILS );
if( text.GetTextWidth() < minSize || text.GetTextWidth() > maxSize )
if( field->GetTextWidth() < minSize || field->GetTextWidth() > maxSize )
{
m_delayedFocusGrid = m_itemsGrid;
m_delayedErrorMessage = wxString::Format( _( "The text width must be between %s and %s." ),
@ -434,7 +427,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::Validate()
return false;
}
if( text.GetTextHeight() < minSize || text.GetTextHeight() > maxSize )
if( field->GetTextHeight() < minSize || field->GetTextHeight() > maxSize )
{
m_delayedFocusGrid = m_itemsGrid;
m_delayedErrorMessage = wxString::Format( _( "The text height must be between %s and %s." ),
@ -447,9 +440,9 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::Validate()
}
// Test for acceptable values for thickness and size and clamp if fails
int maxPenWidth = Clamp_Text_PenSize( text.GetTextThickness(), text.GetTextSize() );
int maxPenWidth = Clamp_Text_PenSize( field->GetTextThickness(), field->GetTextSize() );
if( text.GetTextThickness() > maxPenWidth )
if( field->GetTextThickness() > maxPenWidth )
{
m_itemsGrid->SetCellValue( i, FPT_THICKNESS,
m_frame->StringFromValue( maxPenWidth, true ) );
@ -502,44 +495,37 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataFromWindow()
m_footprint->SetDescription( m_DocCtrl->GetValue() );
m_footprint->SetKeywords( m_KeywordCtrl->GetValue() );
// copy reference and value
m_footprint->Reference() = m_texts->at( 0 );
m_footprint->Value() = m_texts->at( 1 );
// Update fields
size_t i = 2;
std::vector<PCB_TEXT*> items_to_remove;
size_t i = 0;
for( BOARD_ITEM* item : m_footprint->GraphicalItems() )
for( PCB_FIELD* field : m_footprint->GetFields() )
{
PCB_TEXT* textItem = dynamic_cast<PCB_TEXT*>( item );
if( textItem )
{
// copy grid table entries till we run out, then delete any remaining texts
if( i < m_texts->size() )
*textItem = m_texts->at( i++ );
else // store this item to remove and delete it later,
// after the graphic list is explored:
items_to_remove.push_back( textItem );
}
// copy grid table entries till we run out, then delete any remaining texts
if( i < m_fields->size() )
field = m_fields->at( i++ );
else
items_to_remove.push_back( field );
}
// Remove text items:
PCB_SELECTION_TOOL* selTool = m_frame->GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
for( PCB_TEXT* item: items_to_remove )
for( PCB_TEXT* item : items_to_remove )
{
selTool->RemoveItemFromSel( item );
view->Remove( item );
item->DeleteStructure();
}
// if there are still grid table entries, create new texts for them
while( i < m_texts->size() )
while( i < m_fields->size() )
{
PCB_TEXT* newText = new PCB_TEXT( m_texts->at( i++ ) );
m_footprint->Add( newText, ADD_MODE::APPEND );
view->Add( newText );
PCB_FIELD* field = m_fields->at( i++ );
m_footprint->AddField( field );
view->Add( field );
}
LSET privateLayers;
@ -636,27 +622,27 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnAddField( wxCommandEvent& event )
return;
const BOARD_DESIGN_SETTINGS& dsnSettings = m_frame->GetDesignSettings();
PCB_TEXT textItem( m_footprint );
PCB_FIELD* newField = new PCB_FIELD( m_footprint, m_fields->size() );
// Set active layer if legal; otherwise copy layer from previous text item
if( LSET::AllTechMask().test( m_frame->GetActiveLayer() ) )
textItem.SetLayer( m_frame->GetActiveLayer() );
newField->SetLayer( m_frame->GetActiveLayer() );
else
textItem.SetLayer( m_texts->at( m_texts->size() - 1 ).GetLayer() );
newField->SetLayer( m_fields->at( m_fields->size() - 1 )->GetLayer() );
textItem.SetTextSize( dsnSettings.GetTextSize( textItem.GetLayer() ) );
textItem.SetTextThickness( dsnSettings.GetTextThickness( textItem.GetLayer() ) );
textItem.SetItalic( dsnSettings.GetTextItalic( textItem.GetLayer() ) );
newField->SetTextSize( dsnSettings.GetTextSize( newField->GetLayer() ) );
newField->SetTextThickness( dsnSettings.GetTextThickness( newField->GetLayer() ) );
newField->SetItalic( dsnSettings.GetTextItalic( newField->GetLayer() ) );
m_texts->push_back( textItem );
m_fields->push_back( newField );
// notify the grid
wxGridTableMessage msg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
m_itemsGrid->ProcessTableMessage( msg );
m_itemsGrid->SetFocus();
m_itemsGrid->MakeCellVisible( m_texts->size() - 1, 0 );
m_itemsGrid->SetGridCursor( m_texts->size() - 1, 0 );
m_itemsGrid->MakeCellVisible( m_fields->size() - 1, 0 );
m_itemsGrid->SetGridCursor( m_fields->size() - 1, 0 );
m_itemsGrid->EnableCellEditControl( true );
m_itemsGrid->ShowCellEditControl();
@ -678,22 +664,26 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnDeleteField( wxCommandEvent& event
for( int row : selectedRows )
{
if( row < 2 )
if( row < MANDATORY_FIELDS )
{
DisplayError( nullptr, _( "Reference and value are mandatory." ) );
DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
MANDATORY_FIELDS ) );
return;
}
}
m_itemsGrid->CommitPendingChanges( true /* quiet mode */ );
m_itemsGrid->ClearSelection();
// Reverse sort so deleting a row doesn't change the indexes of the other rows.
selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
for( int row : selectedRows )
{
m_texts->erase( m_texts->begin() + row );
m_fields->erase( m_fields->begin() + row );
// notify the grid
wxGridTableMessage msg( m_texts, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
m_itemsGrid->ProcessTableMessage( msg );
if( m_itemsGrid->GetNumberRows() > 0 )
@ -800,11 +790,16 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::adjustGridColumns()
itemsWidth -= m_itemsGrid->GetRowLabelSize();
for( int i = 1; i < m_itemsGrid->GetNumberCols(); i++ )
itemsWidth -= m_itemsGrid->GetColSize( i );
for( int i = 0; i < m_itemsGrid->GetNumberCols(); i++ )
{
if( i == 1 )
continue;
m_itemsGrid->SetColSize( 0, std::max( itemsWidth,
m_itemsGrid->GetVisibleWidth( 0, true, false ) ) );
itemsWidth -= m_itemsGrid->GetColSize( i );
}
m_itemsGrid->SetColSize(
1, std::max( itemsWidth, m_itemsGrid->GetVisibleWidth( 0, true, false ) ) );
// Update the width private layers grid
m_privateLayersGrid->SetColSize( 0, std::max( m_privateLayersGrid->GetClientSize().x,
@ -860,7 +855,9 @@ void DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::OnUpdateUI( wxUpdateUIEvent& event )
m_delayedFocusGrid->MakeCellVisible( m_delayedFocusRow, m_delayedFocusColumn );
m_delayedFocusGrid->SetGridCursor( m_delayedFocusRow, m_delayedFocusColumn );
m_delayedFocusGrid->EnableCellEditControl( true );
if( !( m_delayedFocusColumn == 0 && m_delayedFocusRow < MANDATORY_FIELDS ) )
m_delayedFocusGrid->EnableCellEditControl( true );
m_delayedFocusGrid->ShowCellEditControl();
m_delayedFocusGrid = nullptr;

View File

@ -102,7 +102,7 @@ private:
static NOTEBOOK_PAGES m_page; // remember the last open page during session
FP_TEXT_GRID_TABLE* m_texts;
FP_TEXT_GRID_TABLE* m_fields;
PRIVATE_LAYERS_GRID_TABLE* m_privateLayers;
UNIT_BINDER m_netClearance;

View File

@ -41,6 +41,7 @@
#include <pcb_dimension.h>
#include <pcb_bitmap.h>
#include <pcb_textbox.h>
#include <pcb_field.h>
#include <footprint.h>
#include <zone.h>
#include <view/view.h>
@ -76,9 +77,31 @@ FOOTPRINT::FOOTPRINT( BOARD* parent ) :
m_zoneConnection = ZONE_CONNECTION::INHERITED;
m_fileFormatVersionAtLoad = 0;
// These are special and mandatory text fields
m_reference = new PCB_TEXT( this, PCB_TEXT::TEXT_is_REFERENCE );
m_value = new PCB_TEXT( this, PCB_TEXT::TEXT_is_VALUE );
// These are the mandatory fields for the editor to work
for( int i = 0; i < MANDATORY_FIELDS; i++ )
{
PCB_FIELD* field = AddField( new PCB_FIELD( this, i ) );
// Style according to the board settings if we have them
if( parent )
ApplyDefaultFieldSettings( *parent );
switch( i )
{
case REFERENCE_FIELD:
field->SetLayer( F_SilkS );
field->SetVisible( true );
break;
case VALUE_FIELD:
field->SetLayer( F_Fab );
field->SetVisible( true );
break;
default:
field->SetLayer( F_Fab );
field->SetVisible( false );
break;
}
}
m_3D_Drawings.clear();
}
@ -115,14 +138,13 @@ FOOTPRINT::FOOTPRINT( const FOOTPRINT& aFootprint ) :
std::map<BOARD_ITEM*, BOARD_ITEM*> ptrMap;
// Copy reference and value.
m_reference = new PCB_TEXT( *aFootprint.m_reference );
m_reference->SetParent( this );
ptrMap[ aFootprint.m_reference ] = m_reference;
m_value = new PCB_TEXT( *aFootprint.m_value );
m_value->SetParent( this );
ptrMap[ aFootprint.m_value ] = m_value;
// Copy fields
for( PCB_FIELD* field : aFootprint.Fields() )
{
PCB_FIELD* newField = static_cast<PCB_FIELD*>( field->Clone() );
ptrMap[field] = newField;
Add( newField, ADD_MODE::APPEND ); // Append to ensure indexes are identical
}
// Copy pads
for( PAD* pad : aFootprint.Pads() )
@ -180,7 +202,6 @@ FOOTPRINT::FOOTPRINT( const FOOTPRINT& aFootprint ) :
m_3D_Drawings = aFootprint.m_3D_Drawings;
m_doc = aFootprint.m_doc;
m_keywords = aFootprint.m_keywords;
m_fields = aFootprint.m_fields;
m_privateLayers = aFootprint.m_privateLayers;
m_arflag = 0;
@ -207,10 +228,13 @@ FOOTPRINT::~FOOTPRINT()
}
// Clean up the owned elements
delete m_reference;
delete m_value;
delete m_initial_comments;
for( PCB_FIELD* f : m_fields )
delete f;
m_fields.clear();
for( PAD* p : m_pads )
delete p;
@ -236,13 +260,115 @@ FOOTPRINT::~FOOTPRINT()
}
PCB_FIELD* FOOTPRINT::GetField( MANDATORY_FIELD_T aFieldType )
{
return m_fields[aFieldType];
}
const PCB_FIELD* FOOTPRINT::GetField( MANDATORY_FIELD_T aFieldType ) const
{
return m_fields[aFieldType];
}
PCB_FIELD* FOOTPRINT::GetFieldById( int aFieldId )
{
for( size_t ii = 0; ii < m_fields.size(); ++ii )
{
if( m_fields[ii]->GetId() == aFieldId )
return m_fields[ii];
}
return nullptr;
}
bool FOOTPRINT::HasFieldByName( const wxString& aFieldName ) const
{
for( size_t ii = 0; ii < m_fields.size(); ++ii )
{
if( m_fields[ii]->GetCanonicalName() == aFieldName )
return true;
}
return false;
}
PCB_FIELD* FOOTPRINT::GetFieldByName( const wxString& aFieldName )
{
for( size_t ii = 0; ii < m_fields.size(); ++ii )
{
if( m_fields[ii]->GetName() == aFieldName )
return m_fields[ii];
}
return nullptr;
}
wxString FOOTPRINT::GetFieldText( const wxString& aFieldName ) const
{
for( const PCB_FIELD* field : m_fields )
{
if( aFieldName == field->GetName() || aFieldName == field->GetCanonicalName() )
return field->GetText();
}
return wxEmptyString;
}
void FOOTPRINT::GetFields( std::vector<PCB_FIELD*>& aVector, bool aVisibleOnly )
{
for( PCB_FIELD* field : m_fields )
{
if( aVisibleOnly )
{
if( !field->IsVisible() || field->GetText().IsEmpty() )
continue;
}
aVector.push_back( field );
}
}
PCB_FIELD* FOOTPRINT::AddField( PCB_FIELD* aField )
{
int newNdx = m_fields.size();
m_fields.push_back( aField );
return m_fields[newNdx];
}
void FOOTPRINT::RemoveField( const wxString& aFieldName )
{
for( unsigned i = MANDATORY_FIELDS; i < m_fields.size(); ++i )
{
if( aFieldName == m_fields[i]->GetName( false ) )
{
m_fields.erase( m_fields.begin() + i );
return;
}
}
}
void FOOTPRINT::ApplyDefaultFieldSettings( BOARD& board )
{
for( PCB_FIELD* f : m_fields )
f->StyleFromSettings( board.GetDesignSettings() );
}
bool FOOTPRINT::FixUuids()
{
// replace null UUIDs if any by a valid uuid
std::vector< BOARD_ITEM* > item_list;
item_list.push_back( m_reference );
item_list.push_back( m_value );
for( PCB_FIELD* field : m_fields )
item_list.push_back( field );
for( PAD* pad : m_pads )
item_list.push_back( pad );
@ -303,12 +429,11 @@ FOOTPRINT& FOOTPRINT::operator=( FOOTPRINT&& aOther )
m_zoneConnection = aOther.m_zoneConnection;
m_netTiePadGroups = aOther.m_netTiePadGroups;
// Move reference and value
m_reference = aOther.m_reference;
m_reference->SetParent( this );
m_value = aOther.m_value;
m_value->SetParent( this );
// Move the fields
m_fields.clear();
for( PCB_FIELD* field : aOther.Fields() )
Add( field );
// Move the pads
m_pads.clear();
@ -354,17 +479,15 @@ FOOTPRINT& FOOTPRINT::operator=( FOOTPRINT&& aOther )
m_3D_Drawings = aOther.m_3D_Drawings;
m_doc = aOther.m_doc;
m_keywords = aOther.m_keywords;
m_fields = aOther.m_fields;
m_privateLayers = aOther.m_privateLayers;
m_initial_comments = aOther.m_initial_comments;
// Clear the other item's containers since this is a move
aOther.Fields().clear();
aOther.Pads().clear();
aOther.Zones().clear();
aOther.GraphicalItems().clear();
aOther.m_value = nullptr;
aOther.m_reference = nullptr;
aOther.m_initial_comments = nullptr;
return *this;
@ -400,14 +523,18 @@ FOOTPRINT& FOOTPRINT::operator=( const FOOTPRINT& aOther )
m_zoneConnection = aOther.m_zoneConnection;
m_netTiePadGroups = aOther.m_netTiePadGroups;
// Copy reference and value
*m_reference = *aOther.m_reference;
m_reference->SetParent( this );
*m_value = *aOther.m_value;
m_value->SetParent( this );
std::map<BOARD_ITEM*, BOARD_ITEM*> ptrMap;
// Copy fields
m_fields.clear();
for( PCB_FIELD* field : aOther.GetFields() )
{
PCB_FIELD* newField = new PCB_FIELD( *field );
ptrMap[field] = newField;
Add( newField );
}
// Copy pads
m_pads.clear();
@ -462,7 +589,6 @@ FOOTPRINT& FOOTPRINT::operator=( const FOOTPRINT& aOther )
m_3D_Drawings = aOther.m_3D_Drawings;
m_doc = aOther.m_doc;
m_keywords = aOther.m_keywords;
m_fields = aOther.m_fields;
m_privateLayers = aOther.m_privateLayers;
m_initial_comments = aOther.m_initial_comments ?
@ -498,12 +624,12 @@ bool FOOTPRINT::ResolveTextVar( wxString* token, int aDepth ) const
if( token->IsSameAs( wxT( "REFERENCE" ) ) )
{
*token = m_reference->GetShownText( false, aDepth + 1 );
*token = Reference().GetShownText( false, aDepth + 1 );
return true;
}
else if( token->IsSameAs( wxT( "VALUE" ) ) )
{
*token = m_value->GetShownText( false, aDepth + 1 );
*token = Value().GetShownText( false, aDepth + 1 );
return true;
}
else if( token->IsSameAs( wxT( "LAYER" ) ) )
@ -543,9 +669,9 @@ bool FOOTPRINT::ResolveTextVar( wxString* token, int aDepth ) const
}
}
}
else if( m_fields.count( *token ) )
else if( HasFieldByName( *token ) )
{
*token = m_fields.at( *token );
*token = GetFieldText( *token );
return true;
}
@ -570,8 +696,22 @@ void FOOTPRINT::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode, bool aSkipConnectiv
switch( aBoardItem->Type() )
{
case PCB_TEXT_T:
// Only user text can be added this way.
wxASSERT( static_cast<PCB_TEXT*>( aBoardItem )->GetType() == PCB_TEXT::TEXT_is_DIVERS );
if( dynamic_cast<PCB_FIELD*>( aBoardItem ) != nullptr )
{
if( aMode == ADD_MODE::APPEND )
m_fields.push_back( static_cast<PCB_FIELD*>( aBoardItem ) );
else
m_fields.push_front( static_cast<PCB_FIELD*>( aBoardItem ) );
break;
}
else
{
// Only user text can be added this way.
wxASSERT( static_cast<PCB_TEXT*>( aBoardItem )->GetType() == PCB_TEXT::TEXT_is_DIVERS );
}
KI_FALLTHROUGH;
case PCB_DIM_ALIGNED_T:
@ -633,6 +773,14 @@ void FOOTPRINT::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aMode )
// Only user text can be removed this way.
wxCHECK_RET( static_cast<PCB_TEXT*>( aBoardItem )->GetType() == PCB_TEXT::TEXT_is_DIVERS,
wxT( "Please report this bug: Invalid remove operation on required text" ) );
for( auto it = m_fields.begin(); it != m_fields.end(); ++it )
{
if( *it == aBoardItem )
{
m_fields.erase( it );
break;
}
}
KI_FALLTHROUGH;
case PCB_DIM_ALIGNED_T:
@ -890,28 +1038,28 @@ const BOX2I FOOTPRINT::GetBoundingBox( bool aIncludeText, bool aIncludeInvisible
// not being present in the current PCB stackup. Values, references, and all
// footprint text can also be turned off via the GAL meta-layers, so the 2nd and
// 3rd "&&" conditionals handle that.
valueLayerIsVisible = board->IsLayerVisible( m_value->GetLayer() )
valueLayerIsVisible = board->IsLayerVisible( Value().GetLayer() )
&& board->IsElementVisible( LAYER_MOD_VALUES )
&& board->IsElementVisible( LAYER_MOD_TEXT );
refLayerIsVisible = board->IsLayerVisible( m_reference->GetLayer() )
refLayerIsVisible = board->IsLayerVisible( Reference().GetLayer() )
&& board->IsElementVisible( LAYER_MOD_REFERENCES )
&& board->IsElementVisible( LAYER_MOD_TEXT );
}
if( ( m_value->IsVisible() && valueLayerIsVisible )
if( ( Value().IsVisible() && valueLayerIsVisible )
|| aIncludeInvisibleText
|| noDrawItems )
{
bbox.Merge( m_value->GetBoundingBox() );
bbox.Merge( Value().GetBoundingBox() );
}
if( ( m_reference->IsVisible() && refLayerIsVisible )
if( ( Reference().IsVisible() && refLayerIsVisible )
|| aIncludeInvisibleText
|| noDrawItems )
{
bbox.Merge( m_reference->GetBoundingBox() );
bbox.Merge( Reference().GetBoundingBox() );
}
}
@ -1025,8 +1173,8 @@ void FOOTPRINT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_I
wxString msg, msg2;
// Don't use GetShownText(); we want to see the variable references here
aList.emplace_back( UnescapeString( m_reference->GetText() ),
UnescapeString( m_value->GetText() ) );
aList.emplace_back( UnescapeString( Reference().GetText() ),
UnescapeString( Value().GetText() ) );
if( aFrame->IsType( FRAME_FOOTPRINT_VIEWER )
|| aFrame->IsType( FRAME_FOOTPRINT_VIEWER_MODAL )
@ -1112,6 +1260,12 @@ bool FOOTPRINT::IsOnLayer( PCB_LAYER_ID aLayer, bool aIncludeCourtyards ) const
return false;
}
for( PCB_FIELD* field : m_fields )
{
if( !field->IsOnLayer( aLayer ) )
return false;
}
for( BOARD_ITEM* item : m_drawings )
{
if( !item->IsOnLayer( aLayer ) )
@ -1161,6 +1315,12 @@ bool FOOTPRINT::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) co
return true;
}
for( PCB_FIELD* field : m_fields )
{
if( field->HitTest( arect, false, 0 ) )
return true;
}
for( ZONE* zone : m_zones )
{
if( zone->HitTest( arect, false, 0 ) )
@ -1319,10 +1479,10 @@ INSPECT_RESULT FOOTPRINT::Visit( INSPECTOR inspector, void* testData,
break;
case PCB_TEXT_T:
if( inspector( m_reference, testData ) == INSPECT_RESULT::QUIT )
if( inspector( &Reference(), testData ) == INSPECT_RESULT::QUIT )
return INSPECT_RESULT::QUIT;
if( inspector( m_value, testData ) == INSPECT_RESULT::QUIT )
if( inspector( &Value(), testData ) == INSPECT_RESULT::QUIT )
return INSPECT_RESULT::QUIT;
// Intentionally fall through since m_Drawings can hold PCB_TEXT_T also
@ -1393,6 +1553,9 @@ void FOOTPRINT::RunOnChildren( const std::function<void ( BOARD_ITEM*)>& aFuncti
{
try
{
for( PCB_FIELD* field : m_fields )
aFunction( static_cast<PCB_FIELD*>( field ) );
for( PAD* pad : m_pads )
aFunction( static_cast<BOARD_ITEM*>( pad ) );
@ -1404,9 +1567,6 @@ void FOOTPRINT::RunOnChildren( const std::function<void ( BOARD_ITEM*)>& aFuncti
for( BOARD_ITEM* drawing : m_drawings )
aFunction( static_cast<BOARD_ITEM*>( drawing ) );
aFunction( static_cast<BOARD_ITEM*>( m_reference ) );
aFunction( static_cast<BOARD_ITEM*>( m_value ) );
}
catch( std::bad_function_call& )
{
@ -1567,8 +1727,8 @@ void FOOTPRINT::Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle )
SetPosition( newpos );
SetOrientation( newOrientation );
m_reference->KeepUpright( orientation, newOrientation );
m_value->KeepUpright( orientation, newOrientation );
for( PCB_FIELD* field : m_fields )
field->KeepUpright( orientation, newOrientation );
for( BOARD_ITEM* item : m_drawings )
{
@ -1619,6 +1779,10 @@ void FOOTPRINT::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
newOrientation.Normalize180();
m_orient = ANGLE_0;
// Mirror fields to other side of board.
for( PCB_FIELD* field : m_fields )
field->Flip( m_pos, false );
// Mirror pads to other side of board.
for( PAD* pad : m_pads )
pad->Flip( m_pos, false );
@ -1630,10 +1794,6 @@ void FOOTPRINT::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
for( ZONE* zone : m_zones )
zone->Flip( m_pos, false );
// Mirror reference and value.
m_reference->Flip( m_pos, false );
m_value->Flip( m_pos, false );
// Reverse mirror footprint graphics and texts.
for( BOARD_ITEM* item : m_drawings )
item->Flip( m_pos, false );
@ -1659,8 +1819,8 @@ void FOOTPRINT::SetPosition( const VECTOR2I& aPos )
m_pos += delta;
m_reference->EDA_TEXT::Offset( delta );
m_value->EDA_TEXT::Offset( delta );
for( PCB_FIELD* field : m_fields )
field->EDA_TEXT::Offset( delta );
for( PAD* pad : m_pads )
pad->SetPosition( pad->GetPosition() + delta );
@ -1695,9 +1855,9 @@ void FOOTPRINT::MoveAnchorPosition( const VECTOR2I& aMoveVector )
VECTOR2I moveVector = aMoveVector;
RotatePoint( moveVector, -GetOrientation() );
// Update of the reference and value.
m_reference->Move( moveVector );
m_value->Move( moveVector );
// Update field local coordinates
for( PCB_FIELD* field : m_fields )
field->Move( moveVector );
// Update the pad local coordinates.
for( PAD* pad : m_pads )
@ -1732,16 +1892,15 @@ void FOOTPRINT::SetOrientation( const EDA_ANGLE& aNewAngle )
m_orient = aNewAngle;
m_orient.Normalize180();
for( PCB_FIELD* field : m_fields )
field->Rotate( GetPosition(), angleChange );
for( PAD* pad : m_pads )
pad->Rotate( GetPosition(), angleChange );
for( ZONE* zone : m_zones )
zone->Rotate( GetPosition(), angleChange );
// Update of the reference and value.
m_reference->Rotate( GetPosition(), angleChange );
m_value->Rotate( GetPosition(), angleChange );
for( BOARD_ITEM* item : m_drawings )
item->Rotate( GetPosition(), angleChange );
@ -2436,11 +2595,11 @@ void FOOTPRINT::CheckNetTies( const std::function<void( const BOARD_ITEM* aItem,
copperItems.push_back( zone );
}
if( m_reference->IsOnCopperLayer() )
copperItems.push_back( m_reference );
if( m_value->IsOnCopperLayer() )
copperItems.push_back( m_value );
for( PCB_FIELD* field : m_fields )
{
if( field->IsOnCopperLayer() )
copperItems.push_back( field );
}
for( PCB_LAYER_ID layer : { F_Cu, In1_Cu, B_Cu } )
{
@ -2719,7 +2878,7 @@ void FOOTPRINT::TransformFPShapesToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_I
bool aIncludeText, bool aIncludeShapes,
bool aIncludePrivateItems ) const
{
std::vector<PCB_TEXT*> texts; // List of PCB_TEXTs to convert
std::vector<const PCB_TEXT*> texts; // List of PCB_TEXTs to convert
for( BOARD_ITEM* item : GraphicalItems() )
{
@ -2753,11 +2912,11 @@ void FOOTPRINT::TransformFPShapesToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_I
if( aIncludeText )
{
if( Reference().GetLayer() == aLayer && Reference().IsVisible() )
texts.push_back( &Reference() );
if( Value().GetLayer() == aLayer && Value().IsVisible() )
texts.push_back( &Value() );
for( const PCB_FIELD* field : m_fields )
{
if( field->GetLayer() == aLayer && field->IsVisible() )
texts.push_back( field );
}
}
for( const PCB_TEXT* text : texts )

View File

@ -27,6 +27,8 @@
#include <deque>
#include <template_fieldnames.h>
#include <board_item_container.h>
#include <board_item.h>
#include <collectors.h>
@ -38,6 +40,7 @@
#include <convert_shape_list_to_polygon.h>
#include <pcb_item_containers.h>
#include <pcb_text.h>
#include <pcb_field.h>
#include <functional>
#include <math/vector3.h>
@ -169,6 +172,9 @@ public:
const BOX2I GetBoundingBox() const override;
const BOX2I GetBoundingBox( bool aIncludeText, bool aIncludeInvisibleText ) const;
PCB_FIELDS& Fields() { return m_fields; }
const PCB_FIELDS& Fields() const { return m_fields; }
PADS& Pads() { return m_pads; }
const PADS& Pads() const { return m_pads; }
@ -518,19 +524,13 @@ public:
/**
* @return reference designator text.
*/
const wxString& GetReference() const
{
return m_reference->GetText();
}
const wxString& GetReference() const { return Reference().GetText(); }
/**
* @param aReference A reference to a wxString object containing the reference designator
* text.
*/
void SetReference( const wxString& aReference )
{
m_reference->SetText( aReference );
}
void SetReference( const wxString& aReference ) { Reference().SetText( aReference ); }
// Property system doesn't like const references
wxString GetReferenceAsString() const
@ -546,18 +546,12 @@ public:
/**
* @return the value text.
*/
const wxString& GetValue() const
{
return m_value->GetText();
}
const wxString& GetValue() const { return Value().GetText(); }
/**
* @param aValue A reference to a wxString object containing the value text.
*/
void SetValue( const wxString& aValue )
{
m_value->SetText( aValue );
}
void SetValue( const wxString& aValue ) { Value().SetText( aValue ); }
// Property system doesn't like const references
wxString GetValueAsString() const
@ -566,21 +560,105 @@ public:
}
/// read/write accessors:
PCB_TEXT& Value() { return *m_value; }
PCB_TEXT& Reference() { return *m_reference; }
PCB_FIELD& Value() { return *GetField( VALUE_FIELD ); }
PCB_FIELD& Reference() { return *GetField( REFERENCE_FIELD ); }
/// The const versions to keep the compiler happy.
PCB_TEXT& Value() const { return *m_value; }
PCB_TEXT& Reference() const { return *m_reference; }
const PCB_FIELD& Value() const { return *GetField( VALUE_FIELD ); }
const PCB_FIELD& Reference() const { return *GetField( REFERENCE_FIELD ); }
const std::map<wxString, wxString>& GetFields() const { return m_fields; }
void SetFields( const std::map<wxString, wxString>& aFields ) { m_fields = aFields; }
const wxString& GetField( const wxString& aKey) { return m_fields[ aKey ]; }
bool HasField( const wxString& aKey)
{
return m_fields.find( aKey ) != m_fields.end();
}
void SetField( const wxString& aKey, const wxString& aVal ) { m_fields[ aKey ] = aVal; }
//-----<Fields>-----------------------------------------------------------
/**
* Return a mandatory field in this symbol.
*
* @note If you need to fetch a user field, use GetFieldById.
*
* @param aFieldType is one of the mandatory field types (REFERENCE_FIELD, VALUE_FIELD, etc.).
* @return is the field at \a aFieldType or NULL if the field does not exist.
*/
PCB_FIELD* GetField( MANDATORY_FIELD_T aFieldType );
const PCB_FIELD* GetField( MANDATORY_FIELD_T aFieldNdx ) const;
/**
* Return a field in this symbol.
*
* @param aFieldId is the id of the field requested. Note that this id ONLY SOMETIMES equates
* to the field's position in the vector.
* @return is the field at \a aFieldType or NULL if the field does not exist.
*/
PCB_FIELD* GetFieldById( int aFieldId );
/**
* Return a field in this symbol.
*
* @param aFieldName is the name of the field
*
* @return is the field with \a aFieldName or NULL if the field does not exist.
*/
PCB_FIELD* GetFieldByName( const wxString& aFieldName );
bool HasFieldByName( const wxString& aFieldName ) const;
/**
* Search for a field named \a aFieldName and returns text associated with this field.
*
* @param aFieldName is the name of the field
*/
wxString GetFieldText( const wxString& aFieldName ) const;
/**
* Populate a std::vector with PCB_TEXTs.
*
* @param aVector is the vector to populate.
* @param aVisibleOnly is used to add only the fields that are visible and contain text.
*/
void GetFields( std::vector<PCB_FIELD*>& aVector, bool aVisibleOnly );
/**
* Return a vector of fields from the symbol
*/
PCB_FIELDS GetFields() { return m_fields; }
const PCB_FIELDS& GetFields() const { return m_fields; }
/**
* Add a field to the symbol.
*
* @param aField is the field to add to this symbol.
*
* @return the newly inserted field.
*/
PCB_FIELD* AddField( PCB_FIELD* aField );
/**
* Remove a user field from the footprint.
* @param aFieldName is the user fieldName to remove. Attempts to remove a mandatory
* field or a non-existant field are silently ignored.
*/
void RemoveField( const wxString& aFieldName );
void RemoveField( PCB_FIELD* aField ) { RemoveField( aField->GetName() ); }
/**
* Set multiple schematic fields.
*
* @param aFields are the fields to set in this symbol.
*/
void SetFields( PCB_FIELDS aFields ) { m_fields = aFields; }
/**
* Return the number of fields in this symbol.
*/
int GetFieldCount() const { return (int) m_fields.size(); }
/**
* @brief Apply default board settings to the footprint field text properties.
*
* This is needed because the board settings are not available when the footprint is
* being created in the footprint library cache, and we want these fields to have
* the correct default text properties.
*/
void ApplyDefaultFieldSettings( BOARD& board );
bool IsBoardOnly() const { return m_attributes & FP_BOARD_ONLY; }
void SetBoardOnly( bool aIsBoardOnly = true )
@ -836,6 +914,7 @@ protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
private:
PCB_FIELDS m_fields;
DRAWINGS m_drawings; // BOARD_ITEMs for drawings on the board, owned by pointer.
PADS m_pads; // PAD items, owned by pointer
ZONES m_zones; // PCB_ZONE items, owned by pointer
@ -843,8 +922,6 @@ private:
EDA_ANGLE m_orient; // Orientation
VECTOR2I m_pos; // Position of footprint on the board in internal units.
PCB_TEXT* m_reference; // Component reference designator value (U34, R18..)
PCB_TEXT* m_value; // Component value (74LS00, 22K..)
LIB_ID m_fpid; // The #LIB_ID of the FOOTPRINT.
int m_attributes; // Flag bits (see FOOTPRINT_ATTR_T)
int m_fpStatus; // For autoplace: flags (LOCKED, FIELDS_AUTOPLACED)
@ -888,7 +965,6 @@ private:
LSET m_privateLayers; // Layers visible only in the footprint editor
std::vector<FP_3DMODEL> m_3D_Drawings; // 3D models.
std::map<wxString, wxString> m_fields;
wxArrayString* m_initial_comments; // s-expression comments in the footprint,
// lazily allocated only if needed for speed

View File

@ -1293,7 +1293,7 @@ FOOTPRINT* PCB_BASE_FRAME::CreateNewFootprint( const wxString& aFootprintName, b
footprint->SetAttributes( footprintTranslated );
PCB_LAYER_ID txt_layer;
VECTOR2I default_pos;
VECTOR2I default_pos;
BOARD_DESIGN_SETTINGS& settings = GetDesignSettings();
footprint->Reference().SetText( settings.m_DefaultFPTextItems[0].m_Text );

View File

@ -98,7 +98,8 @@ wxString FP_TEXT_GRID_TABLE::GetColLabelValue( int aCol )
{
switch( aCol )
{
case FPT_TEXT: return _( "Text Items" );
case FPT_NAME: return _( "Name" );
case FPT_VALUE: return _( "Value" );
case FPT_SHOWN: return _( "Show" );
case FPT_WIDTH: return _( "Width" );
case FPT_HEIGHT: return _( "Height" );
@ -115,22 +116,12 @@ wxString FP_TEXT_GRID_TABLE::GetColLabelValue( int aCol )
}
wxString FP_TEXT_GRID_TABLE::GetRowLabelValue( int aRow )
{
switch( aRow )
{
case 0: return _( "Reference designator" );
case 1: return _( "Value" );
default: return wxEmptyString;
}
}
bool FP_TEXT_GRID_TABLE::CanGetValueAs( int aRow, int aCol, const wxString& aTypeName )
{
switch( aCol )
{
case FPT_TEXT:
case FPT_NAME:
case FPT_VALUE:
case FPT_WIDTH:
case FPT_HEIGHT:
case FPT_THICKNESS:
@ -165,7 +156,16 @@ wxGridCellAttr* FP_TEXT_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr:
{
switch( aCol )
{
case FPT_TEXT:
case FPT_NAME:
if( aRow < 2 )
{
m_readOnlyAttr->IncRef();
return m_readOnlyAttr;
}
return nullptr;
case FPT_VALUE:
case FPT_WIDTH:
case FPT_HEIGHT:
case FPT_THICKNESS:
@ -198,7 +198,7 @@ wxGridCellAttr* FP_TEXT_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr:
wxString FP_TEXT_GRID_TABLE::GetValue( int aRow, int aCol )
{
wxGrid* grid = GetView();
const PCB_TEXT& text = this->at( (size_t) aRow );
const PCB_FIELD* field = this->at( (size_t) aRow );
if( grid->GetGridCursorRow() == aRow && grid->GetGridCursorCol() == aCol
&& grid->IsCellEditControlShown() )
@ -211,32 +211,35 @@ wxString FP_TEXT_GRID_TABLE::GetValue( int aRow, int aCol )
switch( aCol )
{
case FPT_TEXT:
return text.GetText();
case FPT_NAME:
return field->GetName();
case FPT_VALUE:
return field->GetText();
case FPT_WIDTH:
return m_frame->StringFromValue( text.GetTextWidth(), true );
return m_frame->StringFromValue( field->GetTextWidth(), true );
case FPT_HEIGHT:
return m_frame->StringFromValue( text.GetTextHeight(), true );
return m_frame->StringFromValue( field->GetTextHeight(), true );
case FPT_THICKNESS:
return m_frame->StringFromValue( text.GetTextThickness(), true );
return m_frame->StringFromValue( field->GetTextThickness(), true );
case FPT_LAYER:
return text.GetLayerName();
return field->GetLayerName();
case FPT_ORIENTATION:
{
EDA_ANGLE angle = text.GetTextAngle() - text.GetParentFootprint()->GetOrientation();
EDA_ANGLE angle = field->GetTextAngle() - field->GetParentFootprint()->GetOrientation();
return m_frame->StringFromValue( angle, true );
}
case FPT_XOFFSET:
return m_frame->StringFromValue( text.GetFPRelativePosition().x, true );
return m_frame->StringFromValue( field->GetFPRelativePosition().x, true );
case FPT_YOFFSET:
return m_frame->StringFromValue( text.GetFPRelativePosition().y, true );
return m_frame->StringFromValue( field->GetFPRelativePosition().y, true );
default:
// we can't assert here because wxWidgets sometimes calls this without checking
@ -248,14 +251,14 @@ wxString FP_TEXT_GRID_TABLE::GetValue( int aRow, int aCol )
bool FP_TEXT_GRID_TABLE::GetValueAsBool( int aRow, int aCol )
{
PCB_TEXT& text = this->at( (size_t) aRow );
PCB_FIELD* field = this->at( (size_t) aRow );
switch( aCol )
{
case FPT_SHOWN: return text.IsVisible();
case FPT_ITALIC: return text.IsItalic();
case FPT_UPRIGHT: return text.IsKeepUpright();
case FPT_KNOCKOUT: return text.IsKnockout();
case FPT_SHOWN: return field->IsVisible();
case FPT_ITALIC: return field->IsItalic();
case FPT_UPRIGHT: return field->IsKeepUpright();
case FPT_KNOCKOUT: return field->IsKnockout();
default:
wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
@ -266,11 +269,11 @@ bool FP_TEXT_GRID_TABLE::GetValueAsBool( int aRow, int aCol )
long FP_TEXT_GRID_TABLE::GetValueAsLong( int aRow, int aCol )
{
PCB_TEXT& text = this->at( (size_t) aRow );
PCB_FIELD* field = this->at( (size_t) aRow );
switch( aCol )
{
case FPT_LAYER: return text.GetLayer();
case FPT_LAYER: return field->GetLayer();
default:
wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a long value" ), aCol ) );
@ -281,7 +284,7 @@ long FP_TEXT_GRID_TABLE::GetValueAsLong( int aRow, int aCol )
void FP_TEXT_GRID_TABLE::SetValue( int aRow, int aCol, const wxString &aValue )
{
PCB_TEXT& text = this->at( (size_t) aRow );
PCB_FIELD* field = this->at( (size_t) aRow );
VECTOR2I pos;
wxString value = aValue;
@ -308,37 +311,41 @@ void FP_TEXT_GRID_TABLE::SetValue( int aRow, int aCol, const wxString &aValue )
switch( aCol )
{
case FPT_TEXT:
text.SetText( value );
case FPT_NAME:
field->SetName( value );
break;
case FPT_VALUE:
field->SetText( value );
break;
case FPT_WIDTH:
text.SetTextWidth( m_frame->ValueFromString( value ) );
field->SetTextWidth( m_frame->ValueFromString( value ) );
break;
case FPT_HEIGHT:
text.SetTextHeight( m_frame->ValueFromString( value ) );
field->SetTextHeight( m_frame->ValueFromString( value ) );
break;
case FPT_THICKNESS:
text.SetTextThickness( m_frame->ValueFromString( value ) );
field->SetTextThickness( m_frame->ValueFromString( value ) );
break;
case FPT_ORIENTATION:
text.SetTextAngle( m_frame->AngleValueFromString( value )
+ text.GetParentFootprint()->GetOrientation() );
field->SetTextAngle( m_frame->AngleValueFromString( value )
+ field->GetParentFootprint()->GetOrientation() );
break;
case FPT_XOFFSET:
case FPT_YOFFSET:
pos = text.GetFPRelativePosition();
pos = field->GetFPRelativePosition();
if( aCol == FPT_XOFFSET )
pos.x = m_frame->ValueFromString( value );
else
pos.y = m_frame->ValueFromString( value );
text.SetFPRelativePosition( pos );
field->SetFPRelativePosition( pos );
break;
default:
@ -352,24 +359,24 @@ void FP_TEXT_GRID_TABLE::SetValue( int aRow, int aCol, const wxString &aValue )
void FP_TEXT_GRID_TABLE::SetValueAsBool( int aRow, int aCol, bool aValue )
{
PCB_TEXT& text = this->at( (size_t) aRow );
PCB_FIELD* field = this->at( (size_t) aRow );
switch( aCol )
{
case FPT_SHOWN:
text.SetVisible( aValue );
field->SetVisible( aValue );
break;
case FPT_ITALIC:
text.SetItalic( aValue );
field->SetItalic( aValue );
break;
case FPT_UPRIGHT:
text.SetKeepUpright( aValue );
field->SetKeepUpright( aValue );
break;
case FPT_KNOCKOUT:
text.SetIsKnockout( aValue );
field->SetIsKnockout( aValue );
break;
default:
@ -381,13 +388,13 @@ void FP_TEXT_GRID_TABLE::SetValueAsBool( int aRow, int aCol, bool aValue )
void FP_TEXT_GRID_TABLE::SetValueAsLong( int aRow, int aCol, long aValue )
{
PCB_TEXT& text = this->at( (size_t) aRow );
PCB_FIELD* field = this->at( (size_t) aRow );
switch( aCol )
{
case FPT_LAYER:
text.SetLayer( ToLAYER_ID( (int) aValue ) );
text.SetMirrored( IsBackLayer( text.GetLayer() ) );
field->SetLayer( ToLAYER_ID( (int) aValue ) );
field->SetMirrored( IsBackLayer( field->GetLayer() ) );
break;
default:

View File

@ -26,14 +26,15 @@
#include <wx/grid.h>
#include <grid_tricks.h>
#include <pcb_text.h>
#include <pcb_field.h>
class PCB_BASE_FRAME;
enum FP_TEXT_COL_ORDER
{
FPT_TEXT,
FPT_NAME,
FPT_VALUE,
FPT_SHOWN,
FPT_WIDTH,
FPT_HEIGHT,
@ -50,7 +51,7 @@ enum FP_TEXT_COL_ORDER
};
class FP_TEXT_GRID_TABLE : public wxGridTableBase, public std::vector<PCB_TEXT>
class FP_TEXT_GRID_TABLE : public wxGridTableBase, public std::vector<PCB_FIELD*>
{
public:
FP_TEXT_GRID_TABLE( PCB_BASE_FRAME* aFrame );
@ -60,7 +61,6 @@ public:
int GetNumberCols() override { return FPT_COUNT; }
wxString GetColLabelValue( int aCol ) override;
wxString GetRowLabelValue( int aRow ) override;
bool IsEmptyCell( int row, int col ) override
{

View File

@ -349,11 +349,16 @@ FOOTPRINT* PCB_BASE_FRAME::loadFootprint( const LIB_ID& aFootprintId )
{
}
// If the footprint is found, clear all net info to be sure there are no broken links to
// any netinfo list (should be not needed, but it can be edited from the footprint editor )
if( footprint )
{
// If the footprint is found, clear all net info to be sure there are no broken links to
// any netinfo list (should be not needed, but it can be edited from the footprint editor )
footprint->ClearAllNets();
if( m_pcb )
footprint->ApplyDefaultFieldSettings( *m_pcb );
}
return footprint;
}

View File

@ -31,6 +31,7 @@
#include <base_units.h>
#include <board.h>
#include <board_design_settings.h>
#include <netinfo.h>
#include <footprint.h>
#include <pad.h>
@ -343,7 +344,11 @@ bool BOARD_NETLIST_UPDATER::updateFootprintParameters( FOOTPRINT* aPcbFootprint,
m_reporter->Report( msg, RPT_SEVERITY_ACTION );
}
if( aPcbFootprint->GetFields() != aNetlistComponent->GetFields() )
std::map<wxString, wxString> fpFieldsAsMap;
for( PCB_FIELD* field : aPcbFootprint->GetFields() )
fpFieldsAsMap[field->GetName()] = field->GetText();
if( fpFieldsAsMap != aNetlistComponent->GetFields() )
{
if( m_isDryRun )
{
@ -354,7 +359,24 @@ bool BOARD_NETLIST_UPDATER::updateFootprintParameters( FOOTPRINT* aPcbFootprint,
msg.Printf( _( "Updated %s fields." ), aPcbFootprint->GetReference() );
changed = true;
aPcbFootprint->SetFields( aNetlistComponent->GetFields() );
for( auto pair : aNetlistComponent->GetFields() )
{
if( aPcbFootprint->HasFieldByName( pair.first ) )
aPcbFootprint->GetFieldByName( pair.first )->SetText( pair.second );
else
{
PCB_FIELD* newField = new PCB_FIELD(
aPcbFootprint, aPcbFootprint->GetFieldCount(), pair.first );
newField->SetText( pair.second );
newField->SetVisible( false );
newField->SetLayer( aPcbFootprint->GetLayer() == F_Cu ? F_Fab : B_Fab );
newField->StyleFromSettings( m_frame->GetDesignSettings() );
aPcbFootprint->AddField( newField );
}
}
}
m_reporter->Report( msg, RPT_SEVERITY_ACTION );

View File

@ -52,7 +52,6 @@ void COMPONENT::SetFootprint( FOOTPRINT* aFootprint )
aFootprint->SetValue( m_value );
aFootprint->SetFPID( m_fpid );
aFootprint->SetPath( path );
aFootprint->SetFields( m_properties );
}

View File

@ -993,8 +993,10 @@ static void getFieldFunc( LIBEVAL::CONTEXT* aCtx, void* self )
{
FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
if( fp->HasField( arg->AsString() ) )
return fp->GetField( arg->AsString() );
PCB_FIELD* field = fp->GetFieldByName( arg->AsString() );
if( field )
return field->GetText();
}
return "";

View File

@ -23,6 +23,8 @@
*/
#include <pcb_field.h>
#include <footprint.h>
#include <board_design_settings.h>
PCB_FIELD::PCB_FIELD( FOOTPRINT* aParent, int aFieldId, const wxString& aName ) :
PCB_TEXT( aParent, TEXT_TYPE( aFieldId ) )
@ -39,6 +41,17 @@ PCB_FIELD::PCB_FIELD( const PCB_TEXT& aText, int aFieldId, const wxString& aName
SetId( aFieldId );
}
void PCB_FIELD::StyleFromSettings( const BOARD_DESIGN_SETTINGS& settings )
{
SetTextSize( settings.GetTextSize( GetLayer() ) );
SetTextThickness( settings.GetTextThickness( GetLayer() ) );
SetItalic( settings.GetTextItalic( GetLayer() ) );
SetKeepUpright( settings.GetTextUpright( GetLayer() ) );
SetMirrored( IsBackLayer( GetLayer() ) );
}
wxString PCB_FIELD::GetName( bool aUseDefaultName ) const
{
if( m_parent && m_parent->Type() == PCB_FOOTPRINT_T )

View File

@ -28,6 +28,8 @@
#include <pcb_text.h>
#include <template_fieldnames.h>
class BOARD_DESIGN_SETTINGS;
class PCB_FIELD : public PCB_TEXT
{
public:
@ -44,6 +46,8 @@ public:
*/
PCB_FIELD* CloneField() const { return (PCB_FIELD*) Clone(); }
void StyleFromSettings( const BOARD_DESIGN_SETTINGS& settings );
/**
* Return the field name (not translated)..
*

View File

@ -95,8 +95,10 @@ void PlotInteractiveLayer( BOARD* aBoard, PLOTTER* aPlotter, const PCB_PLOT_PARA
_( "Value" ),
fp->Value().GetShownText( false ) ) );
for( const auto& [name, value] : fp->GetFields() )
properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), name, value ) );
for( int i = VALUE_FIELD; i < fp->GetFieldCount(); i++ )
properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
fp->GetFields().at( i )->GetName(),
fp->GetFields().at( i )->GetText() ) );
properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
_( "Footprint" ),

View File

@ -3707,8 +3707,6 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>( m_board );
std::map<wxString, wxString> properties;
footprint->SetInitialComments( aInitialComments );
token = NextTok();
@ -3813,7 +3811,33 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
break;
case T_property:
properties.insert( parseProperty() );
{
std::pair<wxString, wxString> nameAndValue = parseProperty();
// Skip non-field properties that should be hidden
if( nameAndValue.first == "ki_description" ||
nameAndValue.first == "ki_keywords" ||
nameAndValue.first == "Sheetfile" ||
nameAndValue.first == "Sheetname" )
{
break;
}
if( footprint->HasFieldByName( nameAndValue.first ) )
footprint->GetFieldByName( nameAndValue.first )->SetText( nameAndValue.second );
else
{
PCB_FIELD* newField = new PCB_FIELD( footprint.get(), footprint->GetFieldCount(),
nameAndValue.first );
newField->SetText( nameAndValue.second );
newField->SetVisible( false );
newField->SetLayer( footprint->GetLayer() == F_Cu ? F_Fab : B_Fab );
newField->StyleFromSettings( m_board->GetDesignSettings() );
footprint->AddField( newField );
}
}
break;
case T_path:
@ -3950,13 +3974,13 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
switch( text->GetType() )
{
case PCB_TEXT::TEXT_is_REFERENCE:
footprint->Reference() = *text;
footprint->Reference() = PCB_FIELD( *text, REFERENCE_FIELD );
const_cast<KIID&>( footprint->Reference().m_Uuid ) = text->m_Uuid;
delete text;
break;
case PCB_TEXT::TEXT_is_VALUE:
footprint->Value() = *text;
footprint->Value() = PCB_FIELD( *text, VALUE_FIELD );
const_cast<KIID&>( footprint->Value().m_Uuid ) = text->m_Uuid;
delete text;
break;
@ -4067,7 +4091,6 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
footprint->SetAttributes( attributes );
footprint->SetFPID( fpid );
footprint->SetFields( properties );
return footprint.release();
}

View File

@ -1118,13 +1118,11 @@ void PCB_PLUGIN::format( const FOOTPRINT* aFootprint, int aNestLevel ) const
m_out->Quotew( aFootprint->GetKeywords() ).c_str() );
}
const std::map<wxString, wxString>& props = aFootprint->GetFields();
for( const std::pair<const wxString, wxString>& prop : props )
for( const PCB_FIELD* field : aFootprint->GetFields() )
{
m_out->Print( aNestLevel+1, "(property %s %s)\n",
m_out->Quotew( prop.first ).c_str(),
m_out->Quotew( prop.second ).c_str() );
m_out->Print( aNestLevel + 1, "(property %s %s)\n",
m_out->Quotew( field->GetCanonicalName() ).c_str(),
m_out->Quotew( field->GetText() ).c_str() );
}
if( !( m_ctl & CTL_OMIT_PATH ) && !aFootprint->GetPath().empty() )

View File

@ -1124,6 +1124,9 @@ int BOARD_EDITOR_CONTROL::PlaceFootprint( const TOOL_EVENT& aEvent )
fp->SetOrientation( ANGLE_0 );
fp->SetPosition( cursorPos );
// Fill this in since it won't be synced from a symbol
fp->GetField( FOOTPRINT_FIELD )->SetText( UnescapeString( fp->GetFPIDAsString() ) );
commit.Add( fp );
m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, fp );

View File

@ -94,6 +94,7 @@ PRIVATE
eeschema_kiface_objects
common
pcbcommon
3d-viewer
scripting
kimath
qa_utils