diff --git a/new/make-dir-lib-source-test-data.sh b/new/make-dir-lib-source-test-data.sh index 44e1e6441e..fcd70b22cf 100755 --- a/new/make-dir-lib-source-test-data.sh +++ b/new/make-dir-lib-source-test-data.sh @@ -10,7 +10,7 @@ REVS="rev1 rev5 rev10" REFERENCE=" - (reference U + (reference U? (effects (at 12 13 180)(font (size .7 1))(visible yes)) )" @@ -71,7 +71,7 @@ for C in ${CATEGORIES}; do for P in ${PARTS}; do for R in ${REVS}; do - echo "(part $C/$P (value 22)(footprint SM0805)(model Airplane) + echo "(part $C/$P (value 22)(footprint SM0805)(model Airplane)(datasheet http://favorite.pdf) $REFERENCE $LINE $RECT @@ -86,7 +86,7 @@ for C in ${CATEGORIES}; do )" > $BASEDIR/$C/$P.part.$R done # also make the part without a rev: - echo "(part $C/$P (value 22)(footprint SM0805)(model Airplane) + echo "(part $C/$P (value 22)(footprint SM0805)(model Airplane)(datasheet http://favorite.pdf) $REFERENCE $LINE $RECT diff --git a/new/sch_part.cpp b/new/sch_part.cpp index 6e1fa433c5..fc2954d99b 100644 --- a/new/sch_part.cpp +++ b/new/sch_part.cpp @@ -28,6 +28,7 @@ #include #include #include +#include //#include using namespace SCH; @@ -38,16 +39,21 @@ PART::PART( LIB* aOwner, const STRING& aPartNameAndRev ) : contains( 0 ), partNameAndRev( aPartNameAndRev ), extends( 0 ), - base( 0 ), + base( 0 ) +/* reference( this, wxT( "reference " ) ), value( this, wxT( "value" ) ), footprint( this, wxT( "footprint" ) ), model( this, wxT( "model" ) ), datasheet( this, wxT( "datasheet" ) ) +*/ { // Our goal is to have class LIB only instantiate what is needed, so print here // what it is doing. It is the only class where PART can be instantiated. D(printf("PART::PART(%s)\n", aPartNameAndRev.c_str() );) + + for( int i=REFERENCE; itext = wxT( "U?" ); + break; + + case VALUE: + p = new PROPERTY( this, wxT( "value" ) ); + break; + + case FOOTPRINT: + p = new PROPERTY( this, wxT( "footprint" ) ); + break; + + case DATASHEET: + p = new PROPERTY( this, wxT( "datasheet" ) ); + break; + + case MODEL: + p = new PROPERTY( this, wxT( "model" ) ); + break; + + default: + ; + } + + mandatory[aPropertyId] = p; + } + + return p; } @@ -119,7 +172,7 @@ PART& PART::operator=( const PART& other ) } -void PART::Parse( SWEET_PARSER* aParser, LIB_TABLE* aTable ) throw( IO_ERROR, PARSE_ERROR ) +void PART::Parse( SWEET_PARSER* aParser , LIB_TABLE* aTable ) throw( IO_ERROR, PARSE_ERROR ) { aParser->Parse( this, aTable ); } @@ -151,7 +204,8 @@ PROPERTIES::iterator PART::propertyFind( const wxString& aPropertyName ) } -void PART::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const throw( IO_ERROR ) +void PART::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const + throw( IO_ERROR ) { out->Print( indent, "(part %s", partNameAndRev.c_str() ); @@ -160,12 +214,13 @@ void PART::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const throw( IO_E out->Print( 0, "\n" ); -/* - @todo - for( int i=0; iFormat( out, indent+1, ctl ); } -*/ + for( PROPERTIES::const_iterator it = properties.begin(); it != properties.end(); ++it ) { (*it)->Format( out, indent+1, ctl ); @@ -178,6 +233,14 @@ void PART::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const throw( IO_E InternalToLogical( anchor.y ) ); } + if( keywords.size() ) + { + out->Print( indent+1, "(keywords" ); + for( KEYWORDS::iterator it = keywords.begin(); it != keywords.end(); ++it ) + out->Print( 0, " %s", out->Quotew( *it ).c_str() ); + out->Print( 0, ")\n" ); + } + for( GRAPHICS::const_iterator it = graphics.begin(); it != graphics.end(); ++it ) { (*it)->Format( out, indent+1, ctl ); @@ -187,6 +250,274 @@ void PART::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const throw( IO_E { (*it)->Format( out, indent+1, ctl ); } + + out->Print( indent, ")\n" ); } +//-----< PART objects >------------------------------------------------------ + + +void PROPERTY::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const + throw( IO_ERROR ) +{ + wxASSERT( owner ); // all PROPERTYs should have an owner. + + int i; + for( i = PART::REFERENCE; i < PART::END; ++i ) + { + if( owner->Field( PART::PROP_ID(i) ) == this ) + break; + } + + if( i < PART::END ) // is a field not a property + out->Print( indent, "(%s", TO_UTF8( name ) ); + else + out->Print( indent, "(property %s", out->Quotew( name ).c_str() ); + + if( effects ) + { + out->Print( 0, " %s\n", out->Quotew( text ).c_str() ); + effects->Format( out, indent+1, ctl | CTL_OMIT_NL ); + out->Print( 0, ")\n" ); + } + else + { + out->Print( 0, " %s)\n", out->Quotew( text ).c_str() ); + } +} + + +TEXT_EFFECTS* PROPERTY::EffectsLookup() +{ + if( !effects ) + { + effects = new TEXT_EFFECTS(); + } + + return effects; +} + + +void TEXT_EFFECTS::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const + throw( IO_ERROR ) +{ + if( propName.IsEmpty() ) + out->Print( indent, "(effects " ); + else + out->Print( indent, "(effects %s ", out->Quotew( propName ).c_str() ); + + out->Print( 0, "(at %.6g %.6g", InternalToLogical( pos.x ), InternalToLogical( pos.y ) ); + + if( angle ) + out->Print( 0, " %.6g)", double( angle ) ); + else + out->Print( 0, ")" ); + + font.Format( out, 0, ctl | CTL_OMIT_NL ); + + out->Print( 0, "(visible %s))%s", + isVisible ? "yes" : "no", + ctl & CTL_OMIT_NL ? "" : "\n" ); +} + + +void FONT::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const + throw( IO_ERROR ) +{ + if( name.IsEmpty() ) + out->Print( indent, "(font " ); + else + out->Print( indent, "(font %s ", out->Quotew( name ).c_str() ); + + out->Print( 0, "(size %.6g %.6g)", + InternalToLogical( size.GetHeight() ), + InternalToLogical( size.GetWidth() ) ); + + if( italic ) + out->Print( 0, " italic" ); + + if( bold ) + out->Print( 0, " bold" ); + + out->Print( 0, ")%s", (ctl & CTL_OMIT_NL) ? "" : "\n" ); +} + + +void PIN::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const + throw( IO_ERROR ) +{ + out->Print( indent, "(pin %s %s ", ShowType(), ShowShape() ); + + if( angle ) + out->Print( 0, "(at %.6g %.6g %.6g)", InternalToLogical( pos.x ), InternalToLogical( pos.y ), double(angle) ); + else + out->Print( 0, "(at %.6g %.6g)", InternalToLogical( pos.x ), InternalToLogical( pos.y ) ); + + out->Print( 0, "(length %.6g)", InternalToLogical( length ) ); + + out->Print( 0, "(visible %s)\n", isVisible ? "yes" : "no" ); + + signal.Format( out, "signal", indent+1, 0 ); + padname.Format( out, "padname", indent+1, CTL_OMIT_NL ); + out->Print( 0, ")\n" ); +} + + +void PINTEXT::Format( OUTPUTFORMATTER* out, const char* aElement, int indent, int ctl ) const + throw( IO_ERROR ) +{ + out->Print( indent, "(%s %s ", aElement, out->Quotew( text ).c_str() ); + font.Format( out, 0, CTL_OMIT_NL ); + out->Print( 0, "(visible %s))%s", + isVisible ? "yes" : "no", + ctl & CTL_OMIT_NL ? "" : "\n" ); +} + + +void POLY_LINE::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const + throw( IO_ERROR ) +{ + out->Print( indent, "(%s ", pts.size() == 2 ? "line" : "polyline" ); + formatContents( out, indent, ctl ); +} + + +void POLY_LINE::formatContents( OUTPUTFORMATTER* out, int indent, int ctl ) const + throw( IO_ERROR ) +{ + out->Print( 0, "(line_width %.6g)", lineWidth ); // @todo use logical units? + + if( fillType != PR::T_none ) + out->Print( 0, "(fill %s)", ShowFill( fillType ) ); + + out->Print( 0, "\n" ); + + if( pts.size() ) + { + const int maxLength = 75; + int len = 10; + + len += out->Print( indent+1, "(pts " ); + + for( POINTS::const_iterator it = pts.begin(); it != pts.end(); ++it ) + { + if( len > maxLength ) + { + len = 10; + out->Print( 0, "\n" ); + out->Print( indent+2, "(xy %.6g %.6g)", + InternalToLogical( it->x ), InternalToLogical( it->y ) ); + } + else + out->Print( 0, "(xy %.6g %.6g)", + InternalToLogical( it->x ), InternalToLogical( it->y ) ); + } + + out->Print( 0, ")" ); + } + + out->Print( 0, ")\n" ); +} + + +void BEZIER::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const + throw( IO_ERROR ) +{ + out->Print( indent, "(bezier " ); + formatContents( out, indent, ctl ); // inherited from POLY_LINE +} + + +void RECTANGLE::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const + throw( IO_ERROR ) +{ + // (rectangle (start X Y) (end X Y) (line_width WIDTH) (fill FILL_TYPE)) + + out->Print( indent, "(rectangle (start %.6g %.6g)(end %.6g %.6g)(line_width %.6g)", + InternalToLogical( start.x ), InternalToLogical( start.y ), + InternalToLogical( end.x ), InternalToLogical( end.y ), + lineWidth ); + + if( fillType != PR::T_none ) + out->Print( 0, "(fill %s)", ShowFill( fillType ) ); + + out->Print( 0, ")\n" ); +} + + +void CIRCLE::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const + throw( IO_ERROR ) +{ + /* + (circle (center X Y)(radius LENGTH)(line_width WIDTH)(fill FILL_TYPE)) + */ + + out->Print( indent, "(circle (center %.6g %.6g)(radius %.6g)(line_width %.6g)", + InternalToLogical( center.x ), InternalToLogical( center.y ), + InternalToLogical( radius), + lineWidth ); + + if( fillType != PR::T_none ) + out->Print( 0, "(fill %s)", ShowFill( fillType ) ); + + out->Print( 0, ")\n" ); +} + + +void ARC::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const + throw( IO_ERROR ) +{ + /* + (arc (pos X Y)(radius RADIUS)(start X Y)(end X Y)(line_width WIDTH)(fill FILL_TYPE)) + */ + + out->Print( indent, "(arc (pos %.6g %.6g)(radius %.6g)(start %.6g %.6g)(end %.6g %.6g)(line_width %.6g)", + InternalToLogical( pos.x ), InternalToLogical( pos.y ), + InternalToLogical( radius), + InternalToLogical( start.x ), InternalToLogical( start.y ), + InternalToLogical( end.x ), InternalToLogical( end.y ), + lineWidth ); + + if( fillType != PR::T_none ) + out->Print( 0, "(fill %s)", ShowFill( fillType ) ); + + out->Print( 0, ")\n" ); +} + + +void GR_TEXT::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const + throw( IO_ERROR ) +{ + /* + (text "This is the text that gets drawn." + (at X Y [ANGLE]) + + # Valid horizontal justification values are center, right, and left. Valid + # vertical justification values are center, top, bottom. + (justify HORIZONTAL_JUSTIFY VERTICAL_JUSTIFY) + (font [FONT] (size HEIGHT WIDTH) [italic] [bold]) + (visible YES) + (fill FILL_TYPE) + ) + */ + + out->Print( indent, "(text %s\n", out->Quotew( text ).c_str() ); + + if( angle ) + out->Print( indent+1, "(at %.6g %.6g %.6g)", InternalToLogical( pos.x ), InternalToLogical( pos.y ), double( angle ) ); + else + out->Print( indent+1, "(at %.6g %.6g)", InternalToLogical( pos.x ), InternalToLogical( pos.y ) ); + + out->Print( 0, "(justify %s %s)(visible %s)", + ShowJustify( hjustify ), ShowJustify( vjustify ), + isVisible ? "yes" : "no" ); + + if( fillType != PR::T_none ) + out->Print( 0, "(fill %s)", ShowFill( fillType ) ); + + out->Print( 0, "\n" ); + font.Format( out, indent+1, CTL_OMIT_NL ); + out->Print( 0, ")\n" ); +} + diff --git a/new/sch_part.h b/new/sch_part.h index 021b59953e..ff5336c088 100644 --- a/new/sch_part.h +++ b/new/sch_part.h @@ -29,6 +29,32 @@ #include +#define INTERNAL_PER_LOGICAL 10000 ///< no. internal units per logical unit + + +/** + * Function InternalToLogical + * converts an internal coordinate to a logical coordinate. Logical coordinates + * are defined as the standard distance between pins being equal to one. + * Internal coordinates are currently INTERNAL_PER_LOGICAL times that. + */ +static inline double InternalToLogical( int aCoord ) +{ + return double( aCoord ) / INTERNAL_PER_LOGICAL; +} + + +/** + * Function LogicalToInternal + * converts a logical coordinate to an internal coordinate. Logical coordinates + * are defined as the standard distance between pins being equal to one. + * Internal coordinates are currently INTERNAL_PER_LOGICAL times that. + */ +static inline int LogicalToInternal( double aCoord ) +{ + return int( aCoord * INTERNAL_PER_LOGICAL ); +} + //----------------------- #include @@ -39,6 +65,9 @@ class OUTPUTFORMATTER; +/// Control Bits for Format() functions +#define CTL_OMIT_NL (1<<0) ///< omit new line in Format()s. + namespace SCH { class PART; @@ -81,6 +110,9 @@ public: italic( false ), bold( false ) {} + + void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const + throw( IO_ERROR ); }; @@ -99,6 +131,9 @@ struct TEXT_EFFECTS isVisible( false ), property( 0 ) {} + + void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const + throw( IO_ERROR ); }; @@ -117,7 +152,16 @@ public: virtual ~BASE_GRAPHIC() {} - virtual void Format( OUTPUTFORMATTER* aOutputFormatter, int aNestLevel, int aControlBits ) const + static const char* ShowFill( int aFillType ) + { + return SWEET_LEXER::TokenName( PR::T( aFillType ) ); + } + + /** + * Function Format + * outputs this object to @a aFormatter in s-expression form. + */ + virtual void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const throw( IO_ERROR ) {} }; @@ -134,10 +178,19 @@ protected: int fillType; // T_none, T_filled, or T_transparent POINTS pts; + void formatContents( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const + throw( IO_ERROR ); + public: POLY_LINE( PART* aOwner ) : - BASE_GRAPHIC( aOwner ) - {} + BASE_GRAPHIC( aOwner ), + lineWidth( 1 ), + fillType( PR::T_none ) + { + } + + void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const + throw( IO_ERROR ); }; class BEZIER : public POLY_LINE @@ -148,7 +201,13 @@ class BEZIER : public POLY_LINE public: BEZIER( PART* aOwner ) : POLY_LINE( aOwner ) - {} + { + lineWidth = 1; + fillType = PR::T_none; + } + + void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const + throw( IO_ERROR ); }; class RECTANGLE : public BASE_GRAPHIC @@ -164,8 +223,14 @@ protected: public: RECTANGLE( PART* aOwner ) : - BASE_GRAPHIC( aOwner ) - {} + BASE_GRAPHIC( aOwner ), + lineWidth( 1 ), + fillType( PR::T_none ) + { + } + + void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const + throw( IO_ERROR ); }; @@ -182,8 +247,15 @@ protected: public: CIRCLE( PART* aOwner ) : - BASE_GRAPHIC( aOwner ) - {} + BASE_GRAPHIC( aOwner ), + radius( LogicalToInternal( 0.5 ) ), + lineWidth( 1 ), + fillType( PR::T_none ) + { + } + + void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const + throw( IO_ERROR ); }; @@ -202,8 +274,15 @@ protected: public: ARC( PART* aOwner ) : - BASE_GRAPHIC( aOwner ) - {} + BASE_GRAPHIC( aOwner ), + lineWidth( 1 ), + fillType( PR::T_none ), + radius( LogicalToInternal( 0.5 ) ) + { + } + + void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const + throw( IO_ERROR ); }; @@ -233,6 +312,14 @@ public: vjustify( PR::T_bottom ), isVisible( true ) {} + + static const char* ShowJustify( int aJustify ) + { + return SWEET_LEXER::TokenName( PR::T( aJustify ) ); + } + + void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const + throw( IO_ERROR ); }; @@ -245,14 +332,45 @@ protected: PART* birthplace; ///< at which PART in inheritance chain was this PROPERTY added wxString name; wxString text; - TEXT_EFFECTS effects; + TEXT_EFFECTS* effects; + + void clear() + { + delete effects; + effects = 0; + + name = wxEmptyString; + text = wxEmptyString; + } public: PROPERTY( PART* aOwner, const wxChar* aName = wxT( "" ) ) : BASE_GRAPHIC( aOwner ), birthplace( aOwner ), - name( aName ) + name( aName ), + effects( 0 ) {} + + ~PROPERTY() + { + clear(); + } + + /** + * Function Effects + * returns a pointer to the TEXT_EFFECTS object for this PROPERTY, and optionally + * will lazily allocate one if it did not exist previously. + * @param doAlloc if true, means do an allocation of a new TEXT_EFFECTS if one + * currently does not exist, otherwise return NULL if non-existent. + */ + TEXT_EFFECTS* EffectsLookup(); + TEXT_EFFECTS* Effects() const + { + return effects; + } + + void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const + throw( IO_ERROR ); }; @@ -265,6 +383,9 @@ struct PINTEXT PINTEXT() : isVisible( true ) {} + + void Format( OUTPUTFORMATTER* aFormatter, const char* aElement, int aNestLevel, int aControlBits ) const + throw( IO_ERROR ); }; @@ -284,10 +405,18 @@ public: isVisible( true ) {} -/* - void Format( OUTPUTFORMATTER* aOutputFormatter, int aNestLevel, int aControlBits ) const + const char* ShowType() const + { + return SWEET_LEXER::TokenName( PR::T( connectionType ) ); + } + + const char* ShowShape() const + { + return SWEET_LEXER::TokenName( PR::T( shape ) ); + } + + void Format( OUTPUTFORMATTER* aFormatter, int aNestLevel, int aControlBits ) const throw( IO_ERROR ); -*/ protected: PART* birthplace; ///< at which PART in inheritance chain was this PIN added @@ -340,87 +469,23 @@ class PART friend class LIB; // is the owner of all PARTS, afterall friend class SWEET_PARSER; -protected: // not likely to have C++ descendants, but protected none-the-less. - - /// a protected constructor, only a LIB can instantiate a PART. - PART( LIB* aOwner, const STRING& aPartNameAndRev ); - - /** - * Function destroy - * clears out this object, deleting all graphics, all fields, all properties, - * etc. - */ - void clear(); - - /** - * Function inherit - * is a specialized assignment function that copies a specific subset, enough - * to fulfill the requirements of the Sweet s-expression language. - */ - void inherit( const PART& aBasePart ); - - /** - * Function propertyFind - * searches for aPropertyName and returns a PROPERTIES::iterator which - * is the found item or properties.end() if not found. - */ - PROPERTIES::iterator propertyFind( const wxString& aPropertyName ); - - - POINT anchor; - - //PART( LIB* aOwner ); - - LIB* owner; ///< which LIB am I a part of (pun if you want) - int contains; ///< has bits from Enum PartParts - - STRING partNameAndRev; ///< example "passives/R[/revN..]", immutable. - - LPID* extends; ///< of base part, NULL if none, otherwise I own it. - PART* base; ///< which PART am I extending, if any. no ownership. - - /// encapsulate the old version deletion, take ownership of @a aLPID - void setExtends( LPID* aLPID ); - - /// s-expression text for the part, initially empty, and read in as this part - /// actually becomes cached in RAM. - STRING body; - - // mandatory properties - PROPERTY reference; ///< prefix only, only components have full references - PROPERTY value; - PROPERTY footprint; - PROPERTY model; - PROPERTY datasheet; - - // separate lists for speed: - - /** - * Member properties - * holds the non-mandatory properties. - */ - PROPERTIES properties; - - /** - * Member graphics - * owns : POLY_LINE, RECTANGLE, CIRCLE, ARC, BEZIER, and GR_TEXT objects. - */ - GRAPHICS graphics; - - /** - * Member pins - * owns all the PINs in pins. - */ - PINS pins; - - /// Alternate body forms. - //ALTERNATES alternates; - - KEYWORDS keywords; - - public: + /** + * Enum PROP_ID + * is the set of "mandatory" properties within a PART. These are used by + * class PART as array indices into PART::mandatory[]. + */ + enum PROP_ID + { + REFERENCE, ///< reference prefix, a template for instantiation at COMPONENT level + VALUE, ///< value, e.g. "3.3K" + FOOTPRINT, ///< name of PCB module, e.g. "16DIP300" + DATASHEET, ///< URI of datasheet + MODEL, ///< spice model name + END ///< array sentinel, not a valid index + }; + virtual ~PART(); PART& operator = ( const PART& other ); @@ -457,6 +522,24 @@ public: void PropertyDelete( const wxString& aPropertyName ) throw( IO_ERROR ); + /** + * Function Field + * returns a pointer to one of the mandatory properties, or NULL + * if non-existent. Use FieldLookup() to potentially allocate it. + */ + PROPERTY* Field( PROP_ID aPropertyId ) const + { + wxASSERT( unsigned(aPropertyId) < unsigned(END) ); + return mandatory[aPropertyId]; + } + + /** + * Function FieldLookup + * returns a pointer to one of the mandatory properties, which is lazily + * constructed by this function if need be. + * @param aPropertyId tells which field. + */ + PROPERTY* FieldLookup( PROP_ID aPropertyId ); /* @@ -494,6 +577,89 @@ public: body = aSExpression; } */ + + +protected: // not likely to have C++ descendants, but protected none-the-less. + + /// a protected constructor, only a LIB can instantiate a PART. + PART( LIB* aOwner, const STRING& aPartNameAndRev ); + + /** + * Function destroy + * clears out this object, deleting everything that this PART owns and + * initializing values back to a state as if the object was just constructed + * empty. + */ + void clear(); + + /** + * Function inherit + * is a specialized assignment function that copies a specific subset, enough + * to fulfill the requirements of the Sweet s-expression language. + */ + void inherit( const PART& aBasePart ); + + /** + * Function propertyFind + * searches for aPropertyName and returns a PROPERTIES::iterator which + * is the found item or properties.end() if not found. + */ + PROPERTIES::iterator propertyFind( const wxString& aPropertyName ); + + POINT anchor; + + //PART( LIB* aOwner ); + + LIB* owner; ///< which LIB am I a part of (pun if you want) + int contains; ///< has bits from Enum PartParts + + STRING partNameAndRev; ///< example "passives/R[/revN..]", immutable. + + LPID* extends; ///< of base part, NULL if none, otherwise I own it. + PART* base; ///< which PART am I extending, if any. no ownership. + + /// encapsulate the old version deletion, take ownership of @a aLPID + void setExtends( LPID* aLPID ); + + /// s-expression text for the part, initially empty, and read in as this part + /// actually becomes cached in RAM. + STRING body; + + // mandatory properties + PROPERTY* mandatory[END]; + +/* + PROPERTY value; + PROPERTY footprint; + PROPERTY model; + PROPERTY datasheet; +*/ + + // separate lists for speed: + + /** + * Member properties + * holds the non-mandatory properties. + */ + PROPERTIES properties; + + /** + * Member graphics + * owns : POLY_LINE, RECTANGLE, CIRCLE, ARC, BEZIER, and GR_TEXT objects. + */ + GRAPHICS graphics; + + /** + * Member pins + * owns all the PINs in pins. + */ + PINS pins; + + /// Alternate body forms. + //ALTERNATES alternates; + + KEYWORDS keywords; + }; } // namespace PART diff --git a/new/sch_sweet_parser.cpp b/new/sch_sweet_parser.cpp index 1807fc90b0..c237ab1106 100644 --- a/new/sch_sweet_parser.cpp +++ b/new/sch_sweet_parser.cpp @@ -36,20 +36,9 @@ using namespace PR; #define MAX_INHERITANCE_NESTING 6 ///< max depth of inheritance, no problem going larger -/** - * Function log2int - * converts a logical coordinate to an internal coordinate. Logical coordinates - * are defined as the standard distance between pins being equal to one. - * Internal coordinates are currently INTERNAL_PER_LOGICAL times that. - */ -static inline int log2int( double aCoord ) -{ - return int( aCoord * INTERNAL_PER_LOGICAL ); -} - static inline int internal( const STRING& aCoord ) { - return log2int( strtod( aCoord.c_str(), NULL ) ); + return LogicalToInternal( strtod( aCoord.c_str(), NULL ) ); } @@ -61,15 +50,15 @@ static inline int internal( const STRING& aCoord ) */ enum PartBit { - PARSED, ///< have parsed this part already, otherwise 'body' text must be parsed - EXTENDS, ///< saw "extends" keyword, inheriting from another PART - VALUE, - ANCHOR, - REFERENCE, - FOOTPRINT, - DATASHEET, - MODEL, - KEYWORDS, + parsed, ///< have parsed this part already, otherwise 'body' text must be parsed + extends, ///< saw "extends" keyword, inheriting from another PART + value, + anchor, + reference, + footprint, + datasheet, + model, + keywords, }; @@ -86,7 +75,7 @@ void SWEET_PARSER::parseExtends( PART* me ) PART* base; int offset; - if( contains & PB(EXTENDS) ) + if( contains & PB(extends) ) Duplicate( T_extends ); NeedSYMBOLorNUMBER(); @@ -129,7 +118,7 @@ void SWEET_PARSER::parseExtends( PART* me ) me->inherit( *base ); me->base = base; - contains |= PB(EXTENDS); + contains |= PB(extends); } @@ -175,6 +164,8 @@ void SWEET_PARSER::Parse( PART* me, LIB_TABLE* aTable ) throw( IO_ERROR, PARSE_E { if( tok == T_LEFT ) { + PROPERTY* prop; + tok = NextTok(); // because exceptions are thrown, any 'new' allocation has to be stored @@ -195,13 +186,13 @@ void SWEET_PARSER::Parse( PART* me, LIB_TABLE* aTable ) throw( IO_ERROR, PARSE_E break; case T_anchor: - if( contains & PB(ANCHOR) ) + if( contains & PB(anchor) ) Duplicate( tok ); NeedNUMBER( "anchor x" ); me->anchor.x = internal( CurText() ); NeedNUMBER( "anchor y" ); me->anchor.y = internal( CurText() ); - contains |= PB(ANCHOR); + contains |= PB(anchor); break; case T_line: @@ -247,119 +238,23 @@ void SWEET_PARSER::Parse( PART* me, LIB_TABLE* aTable ) throw( IO_ERROR, PARSE_E parseText( text ); break; - // reference in a PART is incomplete, it is just the prefix of an - // unannotated reference. Only components have full reference designators. - case T_reference: - if( contains & PB(REFERENCE) ) - Duplicate( tok ); - contains |= PB(REFERENCE); - NeedSYMBOLorNUMBER(); - me->reference.text = FromUTF8(); - tok = NextTok(); - if( tok == T_LEFT ) - { - tok = NextTok(); - if( tok != T_effects ) - Expecting( T_effects ); - parseTextEffects( &me->reference.effects ); - NeedRIGHT(); - } - else if( tok != T_RIGHT ) - Expecting( ") | effects" ); - break; - - case T_value: - if( contains & PB(VALUE) ) - Duplicate( tok ); - contains |= PB(VALUE); - NeedSYMBOLorNUMBER(); - me->value.text = FromUTF8(); - tok = NextTok(); - if( tok == T_LEFT ) - { - tok = NextTok(); - if( tok != T_effects ) - Expecting( T_effects ); - parseTextEffects( &me->value.effects ); - NeedRIGHT(); - } - else if( tok != T_RIGHT ) - Expecting( ") | effects" ); - break; - - case T_footprint: - if( contains & PB(FOOTPRINT) ) - Duplicate( tok ); - contains |= PB(FOOTPRINT); - NeedSYMBOLorNUMBER(); - me->footprint.text = FromUTF8(); - tok = NextTok(); - if( tok == T_LEFT ) - { - tok = NextTok(); - if( tok != T_effects ) - Expecting( T_effects ); - parseTextEffects( &me->footprint.effects ); - NeedRIGHT(); - } - else if( tok != T_RIGHT ) - Expecting( ") | effects" ); - break; - - case T_datasheet: - if( contains & PB(MODEL) ) - Duplicate( tok ); - contains |= PB(MODEL); - NeedSYMBOLorNUMBER(); - me->datasheet.text = FromUTF8(); - tok = NextTok(); - if( tok == T_LEFT ) - { - tok = NextTok(); - if( tok != T_effects ) - Expecting( T_effects ); - parseTextEffects( &me->datasheet.effects ); - NeedRIGHT(); - } - else if( tok != T_RIGHT ) - Expecting( ") | effects" ); - break; - - case T_model: - if( contains & PB(MODEL) ) - Duplicate( tok ); - contains |= PB(MODEL); - NeedSYMBOLorNUMBER(); - me->model.text = FromUTF8(); - tok = NextTok(); - if( tok == T_LEFT ) - { - tok = NextTok(); - if( tok != T_effects ) - Expecting( T_effects ); - parseTextEffects( &me->model.effects ); - NeedRIGHT(); - } - else if( tok != T_RIGHT ) - Expecting( ") | effects" ); - break; - case T_property: - PROPERTY* property; - property = new PROPERTY( me ); + prop = new PROPERTY( me ); // @todo check for uniqueness - me->properties.push_back( property ); + me->properties.push_back( prop ); NeedSYMBOLorNUMBER(); - property->name = FromUTF8(); + prop->name = FromUTF8(); + + L_prop: NeedSYMBOLorNUMBER(); - property->text = FromUTF8(); + prop->text = FromUTF8(); tok = NextTok(); if( tok == T_LEFT ) { tok = NextTok(); if( tok != T_effects ) Expecting( T_effects ); - parseTextEffects( &property->effects ); + parseTextEffects( prop->EffectsLookup() ); NeedRIGHT(); } else if( tok != T_RIGHT ) @@ -372,6 +267,43 @@ void SWEET_PARSER::Parse( PART* me, LIB_TABLE* aTable ) throw( IO_ERROR, PARSE_E NeedRIGHT(); break; + // reference in a PART is incomplete, it is just the prefix of an + // unannotated reference. Only components have full reference designators. + case T_reference: + if( contains & PB(reference) ) + Duplicate( tok ); + contains |= PB(reference); + prop = me->FieldLookup( PART::REFERENCE ); + goto L_prop; + + case T_value: + if( contains & PB(value) ) + Duplicate( tok ); + contains |= PB(value); + prop = me->FieldLookup( PART::VALUE ); + goto L_prop; + + case T_footprint: + if( contains & PB(footprint) ) + Duplicate( tok ); + contains |= PB(footprint); + prop = me->FieldLookup( PART::FOOTPRINT ); + goto L_prop; + + case T_datasheet: + if( contains & PB(datasheet) ) + Duplicate( tok ); + contains |= PB(datasheet); + prop = me->FieldLookup( PART::DATASHEET ); + goto L_prop; + + case T_model: + if( contains & PB(model) ) + Duplicate( tok ); + contains |= PB(model); + prop = me->FieldLookup( PART::MODEL ); + goto L_prop; + case T_pin: PIN* pin; pin = new PIN( me ); @@ -404,7 +336,6 @@ void SWEET_PARSER::Parse( PART* me, LIB_TABLE* aTable ) throw( IO_ERROR, PARSE_E case T_route_pin_swap: break; - */ } } @@ -419,7 +350,7 @@ void SWEET_PARSER::Parse( PART* me, LIB_TABLE* aTable ) throw( IO_ERROR, PARSE_E } } - contains |= PB(PARSED); + contains |= PB(parsed); me->contains |= contains; } @@ -804,6 +735,7 @@ void SWEET_PARSER::parsePolyLine( POLY_LINE* me ) if( sawWidth ) Duplicate( tok ); NeedNUMBER( "line_width" ); + // @todo Use logical units? me->lineWidth = strtod( CurText(), NULL ); NeedRIGHT(); sawWidth = true; diff --git a/new/sch_sweet_parser.h b/new/sch_sweet_parser.h index 44584b46f0..1b8485ca76 100644 --- a/new/sch_sweet_parser.h +++ b/new/sch_sweet_parser.h @@ -29,15 +29,6 @@ #include -#define INTERNAL_PER_LOGICAL 10000 ///< no. internal units per logical unit - - -static inline double InternalToLogical( int aCoord ) -{ - return double( aCoord ) / INTERNAL_PER_LOGICAL; -} - - class POINT; namespace SCH { diff --git a/new/test_sch_lib_table.cpp b/new/test_sch_lib_table.cpp index eedbe1218e..c872409e08 100644 --- a/new/test_sch_lib_table.cpp +++ b/new/test_sch_lib_table.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace SCH; @@ -86,7 +87,12 @@ void LIB_TABLE::Test() // find a part LPID lpid( "meparts:tigers/ears" ); - LookupPart( lpid ); + PART* part = LookupPart( lpid ); + + sf.Clear(); + part->Format( &sf, 0, 0 ); + + printf( "%s", sf.GetString().c_str() ); }