From 00f6f5011c0ac73825489ec11448379b2d074559 Mon Sep 17 00:00:00 2001 From: Mike Williams Date: Mon, 12 Jun 2023 10:02:28 -0400 Subject: [PATCH] PCB Fields: add saving / reading support to PCB files Use common text effects parsing with PCB_TEXT --- pcbnew/plugins/kicad/pcb_parser.cpp | 128 +++++++++++++++------------- pcbnew/plugins/kicad/pcb_parser.h | 3 +- pcbnew/plugins/kicad/pcb_plugin.cpp | 27 ++++-- pcbnew/plugins/kicad/pcb_plugin.h | 3 +- 4 files changed, 94 insertions(+), 67 deletions(-) diff --git a/pcbnew/plugins/kicad/pcb_parser.cpp b/pcbnew/plugins/kicad/pcb_parser.cpp index f884b88005..a6774eafb1 100644 --- a/pcbnew/plugins/kicad/pcb_parser.cpp +++ b/pcbnew/plugins/kicad/pcb_parser.cpp @@ -365,7 +365,7 @@ void PCB_PARSER::parseXY( int* aX, int* aY ) } -std::pair PCB_PARSER::parseProperty() +std::pair PCB_PARSER::parseBoardProperty() { wxString pName; wxString pValue; @@ -868,7 +868,7 @@ BOARD* PCB_PARSER::parseBOARD_unchecked() break; case T_property: - properties.insert( parseProperty() ); + properties.insert( parseBoardProperty() ); break; case T_net: @@ -3041,52 +3041,60 @@ PCB_TEXT* PCB_PARSER::parsePCB_TEXT( BOARD_ITEM* aParent ) text->SetText( value ); NeedLEFT(); - token = NextTok(); - - if( token != T_at ) - Expecting( T_at ); - - VECTOR2I pt; - - 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. - token = NextTok(); + parsePCB_TEXT_effects( text.get() ); - if( CurTok() == T_NUMBER ) - { - text->SetTextAngle( EDA_ANGLE( parseDouble(), DEGREES_T ) ); - NextTok(); - } + return text.release(); +} - if( parentFP && CurTok() == T_unlocked ) - { - text->SetKeepUpright( false ); - NextTok(); - } - if( CurTok() != T_RIGHT ) - { - Unexpected( CurText() ); - } +void PCB_PARSER::parsePCB_TEXT_effects( PCB_TEXT* aText ) +{ + FOOTPRINT* parentFP = dynamic_cast( aText->GetParent() ); - for( token = NextTok(); token != T_RIGHT; token = NextTok() ) + for( T token = NextTok(); token != T_RIGHT; token = NextTok() ) { if( token == T_LEFT ) token = NextTok(); 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: - text->SetLayer( parseBoardItemLayer() ); + aText->SetLayer( parseBoardItemLayer() ); token = NextTok(); if( token == T_knockout ) { - text->SetIsKnockout( true ); + aText->SetIsKnockout( true ); token = NextTok(); } @@ -3097,25 +3105,21 @@ PCB_TEXT* PCB_PARSER::parsePCB_TEXT( BOARD_ITEM* aParent ) case T_tstamp: NextTok(); - const_cast( text->m_Uuid ) = CurStrToKIID(); + const_cast( aText->m_Uuid ) = CurStrToKIID(); NeedRIGHT(); break; case T_hide: if( parentFP ) - text->SetVisible( false ); + aText->SetVisible( false ); else Expecting( "layer, effects, locked, render_cache or tstamp" ); break; - case T_effects: - parseEDA_TEXT( static_cast( text.get() ) ); - break; + case T_effects: parseEDA_TEXT( static_cast( aText ) ); break; - case T_render_cache: - parseRenderCache( static_cast( text.get() ) ); - break; + case T_render_cache: parseRenderCache( static_cast( aText ) ); break; default: if( parentFP ) @@ -3127,11 +3131,9 @@ PCB_TEXT* PCB_PARSER::parsePCB_TEXT( BOARD_ITEM* aParent ) if( parentFP ) { - text->Rotate( { 0, 0 }, parentFP->GetOrientation() ); - text->Move( parentFP->GetPosition() ); + aText->Rotate( { 0, 0 }, parentFP->GetOrientation() ); + aText->Move( parentFP->GetPosition() ); } - - return text.release(); } @@ -3806,31 +3808,43 @@ FOOTPRINT* PCB_PARSER::parseFOOTPRINT_unchecked( wxArrayString* aInitialComments case T_property: { - std::pair nameAndValue = parseProperty(); + wxString value; + + NeedSYMBOL(); + wxString pName = FromUTF8(); + NeedSYMBOL(); + wxString pValue = FromUTF8(); // Skip non-field properties that should be hidden - if( nameAndValue.first == "ki_description" || - nameAndValue.first == "ki_keywords" || - nameAndValue.first == "Sheetfile" || - nameAndValue.first == "Sheetname" ) + if( pName == "ki_description" || + pName == "ki_keywords" || + pName == "Sheetfile" || + pName == "Sheetname" ) { + NeedRIGHT(); break; } - if( footprint->HasFieldByName( nameAndValue.first ) ) - footprint->GetFieldByName( nameAndValue.first )->SetText( nameAndValue.second ); + PCB_FIELD* field = nullptr; + + if( footprint->HasFieldByName( pName ) ) + { + field = footprint->GetFieldByName( pName ); + field->SetText( pValue ); + } else { - PCB_FIELD* newField = new PCB_FIELD( footprint.get(), footprint->GetFieldCount(), - nameAndValue.first ); + field = new PCB_FIELD( footprint.get(), footprint->GetFieldCount(), pName ); - newField->SetText( nameAndValue.second ); - newField->SetVisible( false ); - newField->SetLayer( footprint->GetLayer() == F_Cu ? F_Fab : B_Fab ); - newField->StyleFromSettings( m_board->GetDesignSettings() ); + field->SetText( pValue ); + field->SetVisible( false ); + field->SetLayer( footprint->GetLayer() == F_Cu ? F_Fab : B_Fab ); + field->StyleFromSettings( m_board->GetDesignSettings() ); - footprint->AddField( newField ); + footprint->AddField( field ); } + + parsePCB_TEXT_effects( field ); } break; diff --git a/pcbnew/plugins/kicad/pcb_parser.h b/pcbnew/plugins/kicad/pcb_parser.h index 3f619081d1..f37a4e6b21 100644 --- a/pcbnew/plugins/kicad/pcb_parser.h +++ b/pcbnew/plugins/kicad/pcb_parser.h @@ -179,6 +179,7 @@ private: PCB_SHAPE* parsePCB_SHAPE( 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_TEXTBOX* parsePCB_TEXTBOX( BOARD_ITEM* aParent ); PCB_DIMENSION_BASE* parseDIMENSION( BOARD_ITEM* aParent ); @@ -245,7 +246,7 @@ private: void parseXY( int* aX, int* aY ); - std::pair parseProperty(); + std::pair parseBoardProperty(); /** * Parses possible outline points and stores them into \p aPoly. This accepts points diff --git a/pcbnew/plugins/kicad/pcb_plugin.cpp b/pcbnew/plugins/kicad/pcb_plugin.cpp index 89621d8276..e233ab7037 100644 --- a/pcbnew/plugins/kicad/pcb_plugin.cpp +++ b/pcbnew/plugins/kicad/pcb_plugin.cpp @@ -366,6 +366,9 @@ void PCB_PLUGIN::Format( const BOARD_ITEM* aItem, int aNestLevel ) const break; case PCB_FIELD_T: + // Handled in the footprint formatter when properties are formatted + break; + case PCB_TEXT_T: format( static_cast( aItem ), aNestLevel ); break; @@ -1121,9 +1124,13 @@ void PCB_PLUGIN::format( const FOOTPRINT* aFootprint, int aNestLevel ) const 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->GetText() ).c_str() ); + + format( field, aNestLevel + 1 ); + + m_out->Print( aNestLevel + 1, ")\n" ); } 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 type; VECTOR2I pos = aText->GetTextPos(); + bool isField = dynamic_cast( aText ) != nullptr; // Always format dimension text as gr_text if( dynamic_cast( aText ) ) @@ -1762,12 +1770,14 @@ void PCB_PLUGIN::format( const PCB_TEXT* aText, int aNestLevel ) const prefix = "gr"; } - m_out->Print( aNestLevel, "(%s_text%s%s %s (at %s", - prefix.c_str(), - type.c_str(), - aText->IsLocked() ? " locked" : "", - m_out->Quotew( aText->GetText() ).c_str(), - formatInternalUnits( pos ).c_str() ); + if( !isField ) + { + m_out->Print( aNestLevel, "(%s_text%s%s %s", prefix.c_str(), type.c_str(), + aText->IsLocked() ? " locked" : "", + m_out->Quotew( aText->GetText() ).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. 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() ) formatRenderCache( aText, aNestLevel + 1 ); - m_out->Print( aNestLevel, ")\n" ); + if( !isField ) + m_out->Print( aNestLevel, ")\n" ); } diff --git a/pcbnew/plugins/kicad/pcb_plugin.h b/pcbnew/plugins/kicad/pcb_plugin.h index 65a9f29b5d..95e324c76e 100644 --- a/pcbnew/plugins/kicad/pcb_plugin.h +++ b/pcbnew/plugins/kicad/pcb_plugin.h @@ -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 20221018 // Via & pad zone-layer-connections //#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 LEGACY_ARC_FORMATTING 20210925 ///< These were the last to use old arc formatting