PCB Fields: add saving / reading support to PCB files

Use common text effects parsing with PCB_TEXT
This commit is contained in:
Mike Williams 2023-06-12 10:02:28 -04:00
parent 6d93950dcc
commit 00f6f5011c
4 changed files with 94 additions and 67 deletions

View File

@ -365,7 +365,7 @@ void PCB_PARSER::parseXY( int* aX, int* aY )
} }
std::pair<wxString, wxString> PCB_PARSER::parseProperty() std::pair<wxString, wxString> PCB_PARSER::parseBoardProperty()
{ {
wxString pName; wxString pName;
wxString pValue; wxString pValue;
@ -868,7 +868,7 @@ BOARD* PCB_PARSER::parseBOARD_unchecked()
break; break;
case T_property: case T_property:
properties.insert( parseProperty() ); properties.insert( parseBoardProperty() );
break; break;
case T_net: case T_net:
@ -3041,52 +3041,60 @@ PCB_TEXT* PCB_PARSER::parsePCB_TEXT( BOARD_ITEM* aParent )
text->SetText( value ); text->SetText( value );
NeedLEFT(); NeedLEFT();
token = NextTok();
if( token != T_at ) parsePCB_TEXT_effects( text.get() );
Expecting( T_at );
VECTOR2I pt; return text.release();
}
pt.x = parseBoardUnits( "X coordinate" );
pt.y = parseBoardUnits( "Y coordinate" );
text->SetTextPos( pt );
// If there is no orientation defined, then it is the default value of 0 degrees. void PCB_PARSER::parsePCB_TEXT_effects( PCB_TEXT* aText )
token = NextTok(); {
FOOTPRINT* parentFP = dynamic_cast<FOOTPRINT*>( aText->GetParent() );
if( CurTok() == T_NUMBER ) for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
{
text->SetTextAngle( EDA_ANGLE( parseDouble(), DEGREES_T ) );
NextTok();
}
if( parentFP && CurTok() == T_unlocked )
{
text->SetKeepUpright( false );
NextTok();
}
if( CurTok() != T_RIGHT )
{
Unexpected( CurText() );
}
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{ {
if( token == T_LEFT ) if( token == T_LEFT )
token = NextTok(); token = NextTok();
switch( token ) switch( token )
{ {
case T_at:
{
VECTOR2I pt;
pt.x = parseBoardUnits( "X coordinate" );
pt.y = parseBoardUnits( "Y coordinate" );
aText->SetTextPos( pt );
token = NextTok();
// If there is no orientation defined, then it is the default value of 0 degrees.
if( CurTok() == T_NUMBER )
{
aText->SetTextAngle( EDA_ANGLE( parseDouble(), DEGREES_T ) );
token = NextTok();
}
if( parentFP && CurTok() == T_unlocked )
{
aText->SetKeepUpright( false );
token = NextTok();
}
if( (int) token != DSN_RIGHT )
Expecting( DSN_RIGHT );
}
break;
case T_layer: case T_layer:
text->SetLayer( parseBoardItemLayer() ); aText->SetLayer( parseBoardItemLayer() );
token = NextTok(); token = NextTok();
if( token == T_knockout ) if( token == T_knockout )
{ {
text->SetIsKnockout( true ); aText->SetIsKnockout( true );
token = NextTok(); token = NextTok();
} }
@ -3097,25 +3105,21 @@ PCB_TEXT* PCB_PARSER::parsePCB_TEXT( BOARD_ITEM* aParent )
case T_tstamp: case T_tstamp:
NextTok(); NextTok();
const_cast<KIID&>( text->m_Uuid ) = CurStrToKIID(); const_cast<KIID&>( aText->m_Uuid ) = CurStrToKIID();
NeedRIGHT(); NeedRIGHT();
break; break;
case T_hide: case T_hide:
if( parentFP ) if( parentFP )
text->SetVisible( false ); aText->SetVisible( false );
else else
Expecting( "layer, effects, locked, render_cache or tstamp" ); Expecting( "layer, effects, locked, render_cache or tstamp" );
break; break;
case T_effects: case T_effects: parseEDA_TEXT( static_cast<EDA_TEXT*>( aText ) ); break;
parseEDA_TEXT( static_cast<EDA_TEXT*>( text.get() ) );
break;
case T_render_cache: case T_render_cache: parseRenderCache( static_cast<EDA_TEXT*>( aText ) ); break;
parseRenderCache( static_cast<EDA_TEXT*>( text.get() ) );
break;
default: default:
if( parentFP ) if( parentFP )
@ -3127,11 +3131,9 @@ PCB_TEXT* PCB_PARSER::parsePCB_TEXT( BOARD_ITEM* aParent )
if( parentFP ) if( parentFP )
{ {
text->Rotate( { 0, 0 }, parentFP->GetOrientation() ); aText->Rotate( { 0, 0 }, parentFP->GetOrientation() );
text->Move( parentFP->GetPosition() ); aText->Move( parentFP->GetPosition() );
} }
return text.release();
} }
@ -3806,31 +3808,43 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments
case T_property: case T_property:
{ {
std::pair<wxString, wxString> nameAndValue = parseProperty(); wxString value;
NeedSYMBOL();
wxString pName = FromUTF8();
NeedSYMBOL();
wxString pValue = FromUTF8();
// Skip non-field properties that should be hidden // Skip non-field properties that should be hidden
if( nameAndValue.first == "ki_description" || if( pName == "ki_description" ||
nameAndValue.first == "ki_keywords" || pName == "ki_keywords" ||
nameAndValue.first == "Sheetfile" || pName == "Sheetfile" ||
nameAndValue.first == "Sheetname" ) pName == "Sheetname" )
{ {
NeedRIGHT();
break; break;
} }
if( footprint->HasFieldByName( nameAndValue.first ) ) PCB_FIELD* field = nullptr;
footprint->GetFieldByName( nameAndValue.first )->SetText( nameAndValue.second );
if( footprint->HasFieldByName( pName ) )
{
field = footprint->GetFieldByName( pName );
field->SetText( pValue );
}
else else
{ {
PCB_FIELD* newField = new PCB_FIELD( footprint.get(), footprint->GetFieldCount(), field = new PCB_FIELD( footprint.get(), footprint->GetFieldCount(), pName );
nameAndValue.first );
newField->SetText( nameAndValue.second ); field->SetText( pValue );
newField->SetVisible( false ); field->SetVisible( false );
newField->SetLayer( footprint->GetLayer() == F_Cu ? F_Fab : B_Fab ); field->SetLayer( footprint->GetLayer() == F_Cu ? F_Fab : B_Fab );
newField->StyleFromSettings( m_board->GetDesignSettings() ); field->StyleFromSettings( m_board->GetDesignSettings() );
footprint->AddField( newField ); footprint->AddField( field );
} }
parsePCB_TEXT_effects( field );
} }
break; break;

View File

@ -179,6 +179,7 @@ private:
PCB_SHAPE* parsePCB_SHAPE( BOARD_ITEM* aParent ); PCB_SHAPE* parsePCB_SHAPE( BOARD_ITEM* aParent );
PCB_TEXT* parsePCB_TEXT( BOARD_ITEM* aParent ); PCB_TEXT* parsePCB_TEXT( BOARD_ITEM* aParent );
void parsePCB_TEXT_effects( PCB_TEXT* aText );
PCB_BITMAP* parsePCB_BITMAP( BOARD_ITEM* aParent ); PCB_BITMAP* parsePCB_BITMAP( BOARD_ITEM* aParent );
PCB_TEXTBOX* parsePCB_TEXTBOX( BOARD_ITEM* aParent ); PCB_TEXTBOX* parsePCB_TEXTBOX( BOARD_ITEM* aParent );
PCB_DIMENSION_BASE* parseDIMENSION( BOARD_ITEM* aParent ); PCB_DIMENSION_BASE* parseDIMENSION( BOARD_ITEM* aParent );
@ -245,7 +246,7 @@ private:
void parseXY( int* aX, int* aY ); void parseXY( int* aX, int* aY );
std::pair<wxString, wxString> parseProperty(); std::pair<wxString, wxString> parseBoardProperty();
/** /**
* Parses possible outline points and stores them into \p aPoly. This accepts points * Parses possible outline points and stores them into \p aPoly. This accepts points

View File

@ -366,6 +366,9 @@ void PCB_PLUGIN::Format( const BOARD_ITEM* aItem, int aNestLevel ) const
break; break;
case PCB_FIELD_T: case PCB_FIELD_T:
// Handled in the footprint formatter when properties are formatted
break;
case PCB_TEXT_T: case PCB_TEXT_T:
format( static_cast<const PCB_TEXT*>( aItem ), aNestLevel ); format( static_cast<const PCB_TEXT*>( aItem ), aNestLevel );
break; break;
@ -1121,9 +1124,13 @@ void PCB_PLUGIN::format( const FOOTPRINT* aFootprint, int aNestLevel ) const
for( const PCB_FIELD* field : aFootprint->GetFields() ) for( const PCB_FIELD* field : aFootprint->GetFields() )
{ {
m_out->Print( aNestLevel + 1, "(property %s %s)\n", m_out->Print( aNestLevel + 1, "(property %s %s",
m_out->Quotew( field->GetCanonicalName() ).c_str(), m_out->Quotew( field->GetCanonicalName() ).c_str(),
m_out->Quotew( field->GetText() ).c_str() ); m_out->Quotew( field->GetText() ).c_str() );
format( field, aNestLevel + 1 );
m_out->Print( aNestLevel + 1, ")\n" );
} }
if( !( m_ctl & CTL_OMIT_PATH ) && !aFootprint->GetPath().empty() ) if( !( m_ctl & CTL_OMIT_PATH ) && !aFootprint->GetPath().empty() )
@ -1744,6 +1751,7 @@ void PCB_PLUGIN::format( const PCB_TEXT* aText, int aNestLevel ) const
std::string prefix; std::string prefix;
std::string type; std::string type;
VECTOR2I pos = aText->GetTextPos(); VECTOR2I pos = aText->GetTextPos();
bool isField = dynamic_cast<const PCB_FIELD*>( aText ) != nullptr;
// Always format dimension text as gr_text // Always format dimension text as gr_text
if( dynamic_cast<const PCB_DIMENSION_BASE*>( aText ) ) if( dynamic_cast<const PCB_DIMENSION_BASE*>( aText ) )
@ -1762,12 +1770,14 @@ void PCB_PLUGIN::format( const PCB_TEXT* aText, int aNestLevel ) const
prefix = "gr"; prefix = "gr";
} }
m_out->Print( aNestLevel, "(%s_text%s%s %s (at %s", if( !isField )
prefix.c_str(), {
type.c_str(), m_out->Print( aNestLevel, "(%s_text%s%s %s", prefix.c_str(), type.c_str(),
aText->IsLocked() ? " locked" : "", aText->IsLocked() ? " locked" : "",
m_out->Quotew( aText->GetText() ).c_str(), m_out->Quotew( aText->GetText() ).c_str() );
formatInternalUnits( pos ).c_str() ); }
m_out->Print( 0, " (at %s", formatInternalUnits( pos ).c_str() );
// Due to Pcbnew history, fp_text angle is saved as an absolute on screen angle. // Due to Pcbnew history, fp_text angle is saved as an absolute on screen angle.
if( !aText->GetTextAngle().IsZero() ) if( !aText->GetTextAngle().IsZero() )
@ -1792,7 +1802,8 @@ void PCB_PLUGIN::format( const PCB_TEXT* aText, int aNestLevel ) const
if( aText->GetFont() && aText->GetFont()->IsOutline() ) if( aText->GetFont() && aText->GetFont()->IsOutline() )
formatRenderCache( aText, aNestLevel + 1 ); formatRenderCache( aText, aNestLevel + 1 );
m_out->Print( aNestLevel, ")\n" ); if( !isField )
m_out->Print( aNestLevel, ")\n" );
} }

View File

@ -130,7 +130,8 @@ class PCB_PLUGIN; // forward decl
//#define SEXPR_BOARD_FILE_VERSION 20220914 // Number boxes for custom-shape pads //#define SEXPR_BOARD_FILE_VERSION 20220914 // Number boxes for custom-shape pads
//#define SEXPR_BOARD_FILE_VERSION 20221018 // Via & pad zone-layer-connections //#define SEXPR_BOARD_FILE_VERSION 20221018 // Via & pad zone-layer-connections
//#define SEXPR_BOARD_FILE_VERSION 20230410 // DNP attribute propagated from schematic to attr //#define SEXPR_BOARD_FILE_VERSION 20230410 // DNP attribute propagated from schematic to attr
#define SEXPR_BOARD_FILE_VERSION 20230517 // Teardrop parameters for pads and vias //#define SEXPR_BOARD_FILE_VERSION 20230517 // Teardrop parameters for pads and vias
#define SEXPR_BOARD_FILE_VERSION 20230612 // PCB Fields
#define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag #define BOARD_FILE_HOST_VERSION 20200825 ///< Earlier files than this include the host tag
#define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting #define LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting