You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

675 lines
17 KiB

15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
14 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2011 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  5. * Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <wx/wx.h> // _()
  25. #include <sch_part.h>
  26. #include <sch_sweet_parser.h>
  27. #include <sch_lpid.h>
  28. #include <sch_lib_table.h>
  29. #include <macros.h>
  30. /**
  31. * Function formatAt
  32. * outputs a formatted "(at X Y [ANGLE])" s-expression
  33. */
  34. static void formatAt( OUTPUTFORMATTER* out, const SCH::POINT& aPos, ANGLE aAngle, int indent=0 )
  35. throw( IO_ERROR )
  36. {
  37. // if( aPos.x || aPos.y || aAngle )
  38. {
  39. out->Print( indent, aAngle!=0.0 ? "(at %.6g %.6g %.6g)" : "(at %.6g %.6g)",
  40. InternalToLogical( aPos.x ), InternalToLogical( aPos.y ),
  41. double( aAngle ) );
  42. }
  43. }
  44. static void formatStroke( OUTPUTFORMATTER* out, STROKE aStroke, int indent=0 )
  45. throw( IO_ERROR )
  46. {
  47. if( aStroke == STROKE_DEFAULT )
  48. out->Print( indent, "(stroke %.6g)", InternalToWidth( aStroke ) );
  49. }
  50. using namespace SCH;
  51. PART::PART( LIB* aOwner, const STRING& aPartNameAndRev ) :
  52. owner( aOwner ),
  53. contains( 0 ),
  54. partNameAndRev( aPartNameAndRev ),
  55. extends( 0 ),
  56. base( 0 )
  57. {
  58. // Our goal is to have class LIB only instantiate what is needed, so print here
  59. // what it is doing. It is the only class where PART can be instantiated.
  60. D(printf("PART::PART(%s)\n", aPartNameAndRev.c_str() );)
  61. for( int i=REFERENCE; i<END; ++i )
  62. mandatory[i] = 0;
  63. }
  64. void PART::clear()
  65. {
  66. if( extends )
  67. {
  68. delete extends;
  69. extends = 0;
  70. }
  71. // clear the mandatory fields
  72. for( int ndx = REFERENCE; ndx < END; ++ndx )
  73. {
  74. delete mandatory[ndx];
  75. mandatory[ndx] = 0;
  76. }
  77. // delete properties I own, since their container will not destroy them:
  78. for( PROPERTIES::iterator it = properties.begin(); it != properties.end(); ++it )
  79. delete *it;
  80. properties.clear();
  81. // delete graphics I own, since their container will not destroy them:
  82. for( GRAPHICS::iterator it = graphics.begin(); it != graphics.end(); ++it )
  83. delete *it;
  84. graphics.clear();
  85. // delete PINs I own, since their container will not destroy them.
  86. for( PINS::iterator it = pins.begin(); it != pins.end(); ++it )
  87. delete *it;
  88. pins.clear();
  89. alternates.clear();
  90. keywords.clear();
  91. pin_merges.clear();
  92. contains = 0;
  93. }
  94. PROPERTY* PART::FieldLookup( PROP_ID aPropertyId )
  95. {
  96. wxASSERT( unsigned(aPropertyId) < unsigned(END) );
  97. PROPERTY* p = mandatory[aPropertyId];
  98. if( !p )
  99. {
  100. switch( aPropertyId )
  101. {
  102. case REFERENCE:
  103. p = new PROPERTY( this, wxT( "reference" ) );
  104. p->text = wxT( "U?" );
  105. break;
  106. case VALUE:
  107. p = new PROPERTY( this, wxT( "value" ) );
  108. break;
  109. case FOOTPRINT:
  110. p = new PROPERTY( this, wxT( "footprint" ) );
  111. break;
  112. case DATASHEET:
  113. p = new PROPERTY( this, wxT( "datasheet" ) );
  114. break;
  115. case MODEL:
  116. p = new PROPERTY( this, wxT( "model" ) );
  117. break;
  118. default:
  119. ;
  120. }
  121. mandatory[aPropertyId] = p;
  122. }
  123. return p;
  124. }
  125. PROPERTY& PROPERTY::operator = ( const PROPERTY& r )
  126. {
  127. *(BASE_GRAPHIC*) this = (BASE_GRAPHIC&) r;
  128. name = r.name;
  129. text = r.text;
  130. delete effects;
  131. if( r.effects )
  132. effects = new TEXT_EFFECTS( *r.effects );
  133. else
  134. effects = 0;
  135. return *this;
  136. }
  137. PINS::iterator PART::pinFindByPad( const wxString& aPad )
  138. {
  139. PINS::iterator it;
  140. for( it = pins.begin(); it != pins.end(); ++it )
  141. {
  142. if( (*it)->pad.text == aPad )
  143. break;
  144. }
  145. return it;
  146. }
  147. void PART::PinsFindBySignal( PIN_LIST* aResults, const wxString& aSignal )
  148. {
  149. for( PINS::const_iterator it = pins.begin(); it != pins.end(); ++it )
  150. {
  151. if( (*it)->signal.text == aSignal )
  152. {
  153. aResults->push_back( *it );
  154. }
  155. }
  156. }
  157. bool PART::PinDelete( const wxString& aPad )
  158. {
  159. PINS::iterator it = pinFindByPad( aPad );
  160. if( it != pins.end() )
  161. {
  162. delete *it;
  163. pins.erase( it );
  164. return true;
  165. }
  166. // there is only one reason this can fail: not found:
  167. return false;
  168. }
  169. PART::~PART()
  170. {
  171. clear();
  172. }
  173. void PART::setExtends( LPID* aLPID )
  174. {
  175. delete extends;
  176. extends = aLPID;
  177. }
  178. void PART::inherit( const PART& r )
  179. {
  180. // Inherit can be called at any time, even from an interactive text
  181. // editor, so cannot assume 'this' object is new. Clear it.
  182. clear();
  183. // copy anything inherited, such as drawables, properties, pins, etc. here
  184. contains = r.contains;
  185. base = &r;
  186. anchor = r.anchor;
  187. for( int i=REFERENCE; i<END; ++i )
  188. {
  189. if( r.mandatory[i] )
  190. mandatory[i] = (PROPERTY*) r.mandatory[i]->Clone( this );
  191. }
  192. for( PROPERTIES::const_iterator it = r.properties.begin(); it != r.properties.end(); ++it )
  193. properties.push_back( (PROPERTY*) (*it)->Clone( this ) );
  194. for( GRAPHICS::const_iterator it = r.graphics.begin(); it != r.graphics.end(); ++it )
  195. graphics.push_back( (*it)->Clone( this ) );
  196. for( PINS::const_iterator it = r.pins.begin(); it != r.pins.end(); ++it )
  197. pins.push_back( (PIN*) (*it)->Clone( this ) );
  198. /* not sure about this concept yet:
  199. for( PART_REFS::const_iterator it = r.alternates.begin(); it != r.alternates.end(); ++it )
  200. alternates.push_back( *it );
  201. */
  202. for( KEYWORDS::const_iterator it = r.keywords.begin(); it != r.keywords.end(); ++it )
  203. keywords.insert( *it );
  204. for( MERGE_SETS::const_iterator it = r.pin_merges.begin(); it != r.pin_merges.end(); ++it )
  205. {
  206. pin_merges[ *it->first ] = * new MERGE_SET( *it->second );
  207. }
  208. }
  209. PART& PART::operator=( const PART& r )
  210. {
  211. // maintain in concert with inherit(), which is a partial assignment operator.
  212. inherit( r );
  213. owner = r.owner;
  214. partNameAndRev = r.partNameAndRev;
  215. body = r.body;
  216. base = r.base;
  217. setExtends( r.extends ? new LPID( *r.extends ) : 0 );
  218. return *this;
  219. }
  220. void PART::Parse( SWEET_PARSER* aParser , LIB_TABLE* aTable ) throw( IO_ERROR, PARSE_ERROR )
  221. {
  222. aParser->Parse( this, aTable );
  223. }
  224. bool PART::PropDelete( const wxString& aPropertyName )
  225. {
  226. PROPERTIES::iterator it = propertyFind( aPropertyName );
  227. if( it != properties.end() )
  228. {
  229. delete *it;
  230. properties.erase( it );
  231. return true;
  232. }
  233. return false;
  234. }
  235. PROPERTIES::iterator PART::propertyFind( const wxString& aPropertyName )
  236. {
  237. PROPERTIES::iterator it;
  238. for( it = properties.begin(); it!=properties.end(); ++it )
  239. if( (*it)->name == aPropertyName )
  240. break;
  241. return it;
  242. }
  243. void PART::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const
  244. throw( IO_ERROR )
  245. {
  246. out->Print( indent, "(part %s", partNameAndRev.c_str() );
  247. if( extends )
  248. out->Print( 0, " inherits %s", extends->Format().c_str() );
  249. out->Print( 0, "\n" );
  250. for( int i = REFERENCE; i < END; ++i )
  251. {
  252. PROPERTY* prop = Field( PROP_ID( i ) );
  253. if( prop )
  254. prop->Format( out, indent+1, ctl );
  255. }
  256. for( PROPERTIES::const_iterator it = properties.begin(); it != properties.end(); ++it )
  257. {
  258. (*it)->Format( out, indent+1, ctl );
  259. }
  260. if( anchor.x || anchor.y )
  261. {
  262. out->Print( indent+1, "(anchor (at %.6g %.6g))\n",
  263. InternalToLogical( anchor.x ),
  264. InternalToLogical( anchor.y ) );
  265. }
  266. if( keywords.size() )
  267. {
  268. out->Print( indent+1, "(keywords" );
  269. for( KEYWORDS::iterator it = keywords.begin(); it != keywords.end(); ++it )
  270. out->Print( 0, " %s", out->Quotew( *it ).c_str() );
  271. out->Print( 0, ")\n" );
  272. }
  273. for( GRAPHICS::const_iterator it = graphics.begin(); it != graphics.end(); ++it )
  274. {
  275. (*it)->Format( out, indent+1, ctl );
  276. }
  277. for( PINS::const_iterator it = pins.begin(); it != pins.end(); ++it )
  278. {
  279. (*it)->Format( out, indent+1, ctl );
  280. }
  281. if( alternates.size() )
  282. {
  283. out->Print( indent+1, "(alternates" );
  284. for( PART_REFS::const_iterator it = alternates.begin(); it!=alternates.end(); ++it )
  285. out->Print( 0, " %s", out->Quotes( it->Format() ).c_str() );
  286. out->Print( 0, ")\n" );
  287. }
  288. for( MERGE_SETS::const_iterator mit = pin_merges.begin(); mit != pin_merges.end(); ++mit )
  289. {
  290. out->Print( indent+1, "(pin_merge %s (pads", out->Quotew( mit->first ).c_str() );
  291. const MERGE_SET& mset = *mit->second;
  292. for( MERGE_SET::const_iterator pit = mset.begin(); pit != mset.end(); ++pit )
  293. {
  294. out->Print( 0, " %s", out->Quotew( *pit ).c_str() );
  295. }
  296. out->Print( 0, "))\n" );
  297. }
  298. out->Print( indent, ")\n" );
  299. }
  300. //-----< PART objects >------------------------------------------------------
  301. void PROPERTY::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const
  302. throw( IO_ERROR )
  303. {
  304. wxASSERT( owner ); // all PROPERTYs should have an owner.
  305. int i;
  306. for( i = PART::REFERENCE; i < PART::END; ++i )
  307. {
  308. if( owner->Field( PART::PROP_ID(i) ) == this )
  309. break;
  310. }
  311. if( i < PART::END ) // is a field not a property
  312. out->Print( indent, "(%s", TO_UTF8( name ) );
  313. else
  314. out->Print( indent, "(property %s", out->Quotew( name ).c_str() );
  315. if( effects )
  316. {
  317. out->Print( 0, " %s\n", out->Quotew( text ).c_str() );
  318. effects->Format( out, indent+1, ctl | CTL_OMIT_NL );
  319. out->Print( 0, ")\n" );
  320. }
  321. else
  322. {
  323. out->Print( 0, " %s)\n", out->Quotew( text ).c_str() );
  324. }
  325. }
  326. TEXT_EFFECTS* PROPERTY::EffectsLookup()
  327. {
  328. if( !effects )
  329. {
  330. effects = new TEXT_EFFECTS();
  331. }
  332. return effects;
  333. }
  334. void TEXT_EFFECTS::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const
  335. throw( IO_ERROR )
  336. {
  337. if( propName.IsEmpty() )
  338. out->Print( indent, "(effects " );
  339. else
  340. out->Print( indent, "(effects %s ", out->Quotew( propName ).c_str() );
  341. formatAt( out, pos, angle );
  342. font.Format( out, 0, ctl | CTL_OMIT_NL );
  343. out->Print( 0, "(visible %s))%s",
  344. isVisible ? "yes" : "no",
  345. ctl & CTL_OMIT_NL ? "" : "\n" );
  346. }
  347. void FONT::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const
  348. throw( IO_ERROR )
  349. {
  350. if( italic || bold || !name.IsEmpty() || size.height != FONTZ_DEFAULT || size.width != FONTZ_DEFAULT )
  351. {
  352. if( name.IsEmpty() )
  353. out->Print( indent, "(font " );
  354. else
  355. out->Print( indent, "(font %s ", out->Quotew( name ).c_str() );
  356. out->Print( 0, "(size %.6g %.6g)",
  357. InternalToFontz( size.height ),
  358. InternalToFontz( size.width ) );
  359. if( italic )
  360. out->Print( 0, " italic" );
  361. if( bold )
  362. out->Print( 0, " bold" );
  363. out->Print( 0, ")%s", (ctl & CTL_OMIT_NL) ? "" : "\n" );
  364. }
  365. }
  366. void PIN::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const
  367. throw( IO_ERROR )
  368. {
  369. bool hasSignal = !signal.text.IsEmpty();
  370. bool hasPad = !pad.text.IsEmpty();
  371. out->Print( indent, "(pin" );
  372. if( connectionType != PIN_CONN_DEFAULT )
  373. out->Print( 0, " %s", ShowType() );
  374. if( shape != PIN_SHAPE_DEFAULT )
  375. out->Print( 0, " %s", ShowShape() );
  376. out->Print( 0, " " );
  377. if( pos.x || pos.y || angle )
  378. formatAt( out, pos, angle );
  379. if( length != PIN_LEN_DEFAULT )
  380. out->Print( 0, "(length %.6g)", InternalToLogical( length ) );
  381. if( !isVisible )
  382. out->Print( 0, "(visible %s)", isVisible ? "yes" : "no" );
  383. if( hasSignal )
  384. signal.Format( out, "signal", 0, CTL_OMIT_NL );
  385. if( hasPad )
  386. pad.Format( out, "pad", 0, CTL_OMIT_NL );
  387. out->Print( 0, ")\n" );
  388. }
  389. PIN::~PIN()
  390. {
  391. }
  392. void PINTEXT::Format( OUTPUTFORMATTER* out, const char* aElement, int indent, int ctl ) const
  393. throw( IO_ERROR )
  394. {
  395. out->Print( indent, "(%s %s", aElement, out->Quotew( text ).c_str() );
  396. font.Format( out, 0, CTL_OMIT_NL );
  397. if( !isVisible )
  398. out->Print( 0, " (visible %s)", isVisible ? "yes" : "no" );
  399. out->Print( 0, ")%s", ctl & CTL_OMIT_NL ? "" : "\n" );
  400. }
  401. void POLY_LINE::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const
  402. throw( IO_ERROR )
  403. {
  404. out->Print( indent, "(%s ", pts.size() == 2 ? "line" : "polyline" );
  405. formatContents( out, indent, ctl );
  406. }
  407. void POLY_LINE::formatContents( OUTPUTFORMATTER* out, int indent, int ctl ) const
  408. throw( IO_ERROR )
  409. {
  410. formatStroke( out, stroke );
  411. if( fillType != PR::T_none )
  412. out->Print( 0, "(fill %s)", ShowFill( fillType ) );
  413. out->Print( 0, "\n" );
  414. if( pts.size() )
  415. {
  416. const int maxLength = 75;
  417. int len = 10;
  418. len += out->Print( indent+1, "(pts " );
  419. for( POINTS::const_iterator it = pts.begin(); it != pts.end(); ++it )
  420. {
  421. if( len > maxLength )
  422. {
  423. len = 10;
  424. out->Print( 0, "\n" );
  425. out->Print( indent+2, "(xy %.6g %.6g)",
  426. InternalToLogical( it->x ), InternalToLogical( it->y ) );
  427. }
  428. else
  429. out->Print( 0, "(xy %.6g %.6g)",
  430. InternalToLogical( it->x ), InternalToLogical( it->y ) );
  431. }
  432. out->Print( 0, ")" );
  433. }
  434. out->Print( 0, ")\n" );
  435. }
  436. void BEZIER::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const
  437. throw( IO_ERROR )
  438. {
  439. out->Print( indent, "(bezier " );
  440. formatContents( out, indent, ctl ); // inherited from POLY_LINE
  441. }
  442. void RECTANGLE::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const
  443. throw( IO_ERROR )
  444. {
  445. // (rectangle (start X Y) (end X Y) [(stroke WIDTH)] (fill FILL_TYPE))
  446. out->Print( indent, "(rectangle (start %.6g %.6g)(end %.6g %.6g)",
  447. InternalToLogical( start.x ), InternalToLogical( start.y ),
  448. InternalToLogical( end.x ), InternalToLogical( end.y )
  449. );
  450. formatStroke( out, stroke );
  451. if( fillType != PR::T_none )
  452. out->Print( 0, "(fill %s)", ShowFill( fillType ) );
  453. out->Print( 0, ")\n" );
  454. }
  455. void CIRCLE::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const
  456. throw( IO_ERROR )
  457. {
  458. /*
  459. (circle (center X Y)(radius LENGTH) [(stroke WIDTH)] (fill FILL_TYPE))
  460. */
  461. out->Print( indent, "(circle (center %.6g %.6g)(radius %.6g)",
  462. InternalToLogical( center.x ), InternalToLogical( center.y ),
  463. InternalToLogical( radius) );
  464. formatStroke( out, stroke );
  465. if( fillType != PR::T_none )
  466. out->Print( 0, "(fill %s)", ShowFill( fillType ) );
  467. out->Print( 0, ")\n" );
  468. }
  469. void ARC::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const
  470. throw( IO_ERROR )
  471. {
  472. /*
  473. (arc (pos X Y)(radius RADIUS)(start X Y)(end X Y) [(stroke WIDTH)] (fill FILL_TYPE))
  474. */
  475. out->Print( indent, "(arc (pos %.6g %.6g)(radius %.6g)(start %.6g %.6g)(end %.6g %.6g)",
  476. InternalToLogical( pos.x ), InternalToLogical( pos.y ),
  477. InternalToLogical( radius),
  478. InternalToLogical( start.x ), InternalToLogical( start.y ),
  479. InternalToLogical( end.x ), InternalToLogical( end.y )
  480. );
  481. formatStroke( out, stroke );
  482. if( fillType != PR::T_none )
  483. out->Print( 0, "(fill %s)", ShowFill( fillType ) );
  484. out->Print( 0, ")\n" );
  485. }
  486. void GR_TEXT::Format( OUTPUTFORMATTER* out, int indent, int ctl ) const
  487. throw( IO_ERROR )
  488. {
  489. /*
  490. (text "This is the text that gets drawn."
  491. (at X Y [ANGLE])(justify HORIZONTAL_JUSTIFY VERTICAL_JUSTIFY)(visible YES)(fill FILL_TYPE)
  492. (font [FONT] (size HEIGHT WIDTH) [italic] [bold])
  493. )
  494. */
  495. out->Print( indent, "(text %s\n", out->Quotew( text ).c_str() );
  496. formatAt( out, pos, angle, indent+1 );
  497. if( hjustify != PR::T_left || vjustify != PR::T_bottom )
  498. out->Print( 0, "(justify %s %s)",
  499. ShowJustify( hjustify ), ShowJustify( vjustify ) );
  500. if( !isVisible )
  501. out->Print( 0, "(visible %s)", isVisible ? "yes" : "no" );
  502. if( fillType != PR::T_filled )
  503. out->Print( 0, "(fill %s)", ShowFill( fillType ) );
  504. font.Format( out, 0, CTL_OMIT_NL );
  505. out->Print( 0, ")\n" );
  506. }