KiCad PCB EDA Suite
page_layout_reader.cpp
Go to the documentation of this file.
1 
7 /*
8  * This program source code file is part of KiCad, a free EDA CAD application.
9  *
10  * Copyright (C) 1992-2013 Jean-Pierre Charras <jp.charras at wanadoo.fr>.
11  * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
12  *
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, you may find one here:
26  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
27  * or you may search the http://www.gnu.org website for the version 2 license,
28  * or you may write to the Free Software Foundation, Inc.,
29  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
30  */
31 
32 #include <fctsys.h>
33 #include <base_struct.h>
34 #include <worksheet.h>
36 #include <worksheet_dataitem.h>
37 #include <page_layout_reader_lexer.h>
38 
39 #include <wx/file.h>
40 #include <wx/mstream.h>
41 
42 
43 using namespace TB_READER_T;
44 
50 class PAGE_LAYOUT_READER_PARSER : public PAGE_LAYOUT_READER_LEXER
51 {
52 public:
53  PAGE_LAYOUT_READER_PARSER( const char* aLine, const wxString& aSource );
54  void Parse( WORKSHEET_LAYOUT* aLayout );
55 
56 private:
57 
65  int parseInt( int aMin, int aMax );
66 
72  double parseDouble();
73 
74  void parseSetup( WORKSHEET_LAYOUT* aLayout );
75 
79  void parseGraphic( WORKSHEET_DATAITEM * aItem );
80 
84  void parseText( WORKSHEET_DATAITEM_TEXT * aItem );
85 
90  void parsePolygon( WORKSHEET_DATAITEM_POLYPOLYGON * aItem );
91 
95  void parsePolyOutline( WORKSHEET_DATAITEM_POLYPOLYGON * aItem );
96 
97 
101  void parseBitmap( WORKSHEET_DATAITEM_BITMAP * aItem );
102 
103  void parseCoordinate( POINT_COORD& aCoord);
104  void readOption( WORKSHEET_DATAITEM * aItem );
105  void readPngdata( WORKSHEET_DATAITEM_BITMAP * aItem );
106 };
107 
108 // PCB_PLOT_PARAMS_PARSER
109 
110 PAGE_LAYOUT_READER_PARSER::PAGE_LAYOUT_READER_PARSER( const char* aLine, const wxString& aSource ) :
111  PAGE_LAYOUT_READER_LEXER( aLine, aSource )
112 {
113 }
114 
115 
117 {
118  T token;
119  WORKSHEET_DATAITEM * item;
120 
121  LOCALE_IO toggle;
122 
123  while( ( token = NextTok() ) != T_RIGHT )
124  {
125  if( token == T_EOF)
126  break;
127 
128  if( token == T_LEFT )
129  token = NextTok();
130 
131  if( token == T_page_layout )
132  continue;
133 
134  switch( token )
135  {
136  case T_setup: // Defines default values for graphic items
137  parseSetup( aLayout );
138  break;
139 
140  case T_line:
142  parseGraphic( item );
143  aLayout->Append( item );
144  break;
145 
146  case T_rect:
148  parseGraphic( item );
149  aLayout->Append( item );
150  break;
151 
152  case T_polygon:
153  item = new WORKSHEET_DATAITEM_POLYPOLYGON();
155  aLayout->Append( item );
156  break;
157 
158  case T_bitmap:
159  item = new WORKSHEET_DATAITEM_BITMAP( NULL );
161  aLayout->Append( item );
162  break;
163 
164  case T_tbtext:
165  NeedSYMBOLorNUMBER();
166  item = new WORKSHEET_DATAITEM_TEXT( FromUTF8() );
168  aLayout->Append( item );
169  break;
170 
171  default:
172  Unexpected( CurText() );
173  break;
174  }
175  }
176 }
177 
179 {
180  T token;
181  while( ( token = NextTok() ) != T_RIGHT )
182  {
183  if( token == T_EOF)
184  break;
185 
186  switch( token )
187  {
188  case T_LEFT:
189  break;
190 
191  case T_linewidth:
193  NeedRIGHT();
194  break;
195 
196  case T_textsize:
199  NeedRIGHT();
200  break;
201 
202  case T_textlinewidth:
204  NeedRIGHT();
205  break;
206 
207  case T_left_margin:
208  aLayout->SetLeftMargin( parseDouble() );
209  NeedRIGHT();
210  break;
211 
212  case T_right_margin:
213  aLayout->SetRightMargin( parseDouble() );
214  NeedRIGHT();
215  break;
216 
217  case T_top_margin:
218  aLayout->SetTopMargin( parseDouble() );
219  NeedRIGHT();
220  break;
221 
222  case T_bottom_margin:
223  aLayout->SetBottomMargin( parseDouble() );
224  NeedRIGHT();
225  break;
226 
227  default:
228  Unexpected( CurText() );
229  break;
230  }
231  }
232 }
233 
235 {
236  T token;
237 
238  while( ( token = NextTok() ) != T_RIGHT )
239  {
240  if( token == T_EOF)
241  break;
242 
243  if( token == T_LEFT )
244  token = NextTok();
245 
246  switch( token )
247  {
248  case T_comment:
249  NeedSYMBOLorNUMBER();
250  aItem->m_Info = FromUTF8();
251  NeedRIGHT();
252  break;
253 
254  case T_pos:
255  parseCoordinate( aItem->m_Pos );
256  break;
257 
258  case T_name:
259  NeedSYMBOLorNUMBER();
260  aItem->m_Name = FromUTF8();
261  NeedRIGHT();
262  break;
263 
264  case T_option:
265  readOption( aItem );
266  break;
267 
268  case T_pts:
269  parsePolyOutline( aItem );
270  aItem->CloseContour();
271  break;
272 
273  case T_rotate:
274  aItem->m_Orient = parseDouble();
275  NeedRIGHT();
276  break;
277 
278  case T_repeat:
279  aItem->m_RepeatCount = parseInt( -1, 100 );
280  NeedRIGHT();
281  break;
282 
283  case T_incrx:
284  aItem->m_IncrementVector.x = parseDouble();
285  NeedRIGHT();
286  break;
287 
288  case T_incry:
289  aItem->m_IncrementVector.y = parseDouble();
290  NeedRIGHT();
291  break;
292 
293  case T_linewidth:
294  aItem->m_LineWidth = parseDouble();
295  NeedRIGHT();
296  break;
297 
298  default:
299  Unexpected( CurText() );
300  break;
301  }
302  }
303 
304  aItem->SetBoundingBox();
305 }
306 
308 {
309  DPOINT corner;
310  T token;
311 
312  while( ( token = NextTok() ) != T_RIGHT )
313  {
314  if( token == T_EOF)
315  break;
316 
317  if( token == T_LEFT )
318  token = NextTok();
319 
320  switch( token )
321  {
322  case T_xy:
323  corner.x = parseDouble();
324  corner.y = parseDouble();
325  aItem->AppendCorner( corner );
326  NeedRIGHT();
327  break;
328 
329  default:
330  Unexpected( CurText() );
331  break;
332  }
333  }
334 }
335 
336 
338 {
339  T token;
340  BITMAP_BASE* image = new BITMAP_BASE;
341  aItem->m_ImageBitmap = image;
342 
343  while( ( token = NextTok() ) != T_RIGHT )
344  {
345  if( token == T_EOF)
346  break;
347 
348  if( token == T_LEFT )
349  token = NextTok();
350 
351  switch( token )
352  {
353  case T_name:
354  NeedSYMBOLorNUMBER();
355  aItem->m_Name = FromUTF8();
356  NeedRIGHT();
357  break;
358 
359  case T_pos:
360  parseCoordinate( aItem->m_Pos );
361  break;
362 
363  case T_repeat:
364  aItem->m_RepeatCount = parseInt( -1, 100 );
365  NeedRIGHT();
366  break;
367 
368  case T_incrx:
369  aItem->m_IncrementVector.x = parseDouble();
370  NeedRIGHT();
371  break;
372 
373  case T_incry:
374  aItem->m_IncrementVector.y = parseDouble();
375  NeedRIGHT();
376  break;
377 
378  case T_linewidth:
379  aItem->m_LineWidth = parseDouble();
380  NeedRIGHT();
381  break;
382 
383  case T_scale:
384  aItem->m_ImageBitmap->SetScale( parseDouble() );
385  NeedRIGHT();
386  break;
387 
388  case T_pngdata:
389  readPngdata( aItem );
390  break;
391 
392  case T_option:
393  readOption( aItem );
394  break;
395 
396  default:
397  Unexpected( CurText() );
398  break;
399  }
400  }
401 }
402 
404 {
405  std::string tmp;
406  T token;
407 
408  while( ( token = NextTok() ) != T_RIGHT )
409  {
410  if( token == T_EOF)
411  break;
412 
413  if( token == T_LEFT )
414  token = NextTok();
415 
416  switch( token )
417  {
418  case T_data:
419  NeedSYMBOLorNUMBER();
420  tmp += CurStr();
421  tmp += "\n";
422  NeedRIGHT();
423  break;
424 
425  default:
426  Unexpected( CurText() );
427  break;
428  }
429  }
430 
431  tmp += "EndData";
432 
433  wxString msg;
434  STRING_LINE_READER str_reader( tmp, wxT("Png kicad_wks data") );
435 
436  if( ! aItem->m_ImageBitmap->LoadData( str_reader, msg ) )
437  {
438  wxLogMessage(msg);
439  }
440 }
441 
442 
444 {
445  T token;
446 
447  while( ( token = NextTok() ) != T_RIGHT )
448  {
449  if( token == T_EOF)
450  break;
451 
452  switch( token )
453  {
454  case T_page1only:
455  aItem->SetPage1Option( 1 );
456  break;
457 
458  case T_notonpage1:
459  aItem->SetPage1Option( -1 );
460  break;
461 
462  default:
463  Unexpected( CurText() );
464  break;
465  }
466  }
467 }
468 
469 
471 {
472  T token;
473 
474  while( ( token = NextTok() ) != T_RIGHT )
475  {
476  if( token == T_EOF)
477  break;
478 
479  if( token == T_LEFT )
480  token = NextTok();
481  else
482  {
483  // If another token than T_LEFT is read here, this is an error
484  // however, due to a old bug in kicad, the token T_end can be found
485  // without T_LEFT in a very few .wks files (perhaps only one in a demo).
486  // So this ugly hack disables the error detection.
487  if( token != T_end )
488  Unexpected( CurText() );
489  }
490 
491  switch( token )
492  {
493  case T_comment:
494  NeedSYMBOLorNUMBER();
495  aItem->m_Info = FromUTF8();
496  NeedRIGHT();
497  break;
498 
499  case T_option:
500  readOption( aItem );
501  break;
502 
503  case T_name:
504  NeedSYMBOLorNUMBER();
505  aItem->m_Name = FromUTF8();
506  NeedRIGHT();
507  break;
508 
509  case T_start:
510  parseCoordinate( aItem->m_Pos );
511  break;
512 
513  case T_end:
514  parseCoordinate( aItem->m_End );
515  break;
516 
517  case T_repeat:
518  aItem->m_RepeatCount = parseInt( -1, 100 );
519  NeedRIGHT();
520  break;
521 
522  case T_incrx:
523  aItem->m_IncrementVector.x = parseDouble();
524  NeedRIGHT();
525  break;
526 
527  case T_incry:
528  aItem->m_IncrementVector.y = parseDouble();
529  NeedRIGHT();
530  break;
531 
532  case T_linewidth:
533  aItem->m_LineWidth = parseDouble();
534  NeedRIGHT();
535  break;
536 
537  default:
538  Unexpected( CurText() );
539  break;
540  }
541  }
542 }
543 
544 
546 {
547  T token;
548 
549  while( ( token = NextTok() ) != T_RIGHT )
550  {
551  if( token == T_EOF)
552  break;
553 
554  if( token == T_LEFT )
555  token = NextTok();
556 
557  switch( token )
558  {
559  case T_comment:
560  NeedSYMBOLorNUMBER();
561  aItem->m_Info = FromUTF8();
562  NeedRIGHT();
563  break;
564 
565  case T_option:
566  readOption( aItem );
567  break;
568 
569  case T_name:
570  NeedSYMBOLorNUMBER();
571  aItem->m_Name = FromUTF8();
572  NeedRIGHT();
573  break;
574 
575  case T_pos:
576  parseCoordinate( aItem->m_Pos );
577  break;
578 
579  case T_repeat:
580  aItem->m_RepeatCount = parseInt( -1, 100 );
581  NeedRIGHT();
582  break;
583 
584  case T_incrx:
585  aItem->m_IncrementVector.x = parseDouble();
586  NeedRIGHT();
587  break;
588 
589  case T_incry:
590  aItem->m_IncrementVector.y = parseDouble();
591  NeedRIGHT();
592  break;
593 
594  case T_incrlabel:
595  aItem->m_IncrementLabel = parseInt(INT_MIN, INT_MAX);
596  NeedRIGHT();
597  break;
598 
599  case T_maxlen:
600  aItem->m_BoundingBoxSize.x = parseDouble();
601  NeedRIGHT();
602  break;
603 
604  case T_maxheight:
605  aItem->m_BoundingBoxSize.y = parseDouble();
606  NeedRIGHT();
607  break;
608 
609  case T_font:
610  while( ( token = NextTok() ) != T_RIGHT )
611  {
612  if( token == T_EOF)
613  break;
614 
615  switch( token )
616  {
617  case T_LEFT:
618  break;
619 
620  case T_bold:
621  aItem->SetBold( true );
622  break;
623 
624  case T_italic:
625  aItem->SetItalic( true );
626  break;
627 
628  case T_size:
629  aItem->m_TextSize.x = parseDouble();
630  aItem->m_TextSize.y = parseDouble();
631  NeedRIGHT();
632  break;
633 
634  case T_linewidth:
635  aItem->m_LineWidth = parseDouble();
636  NeedRIGHT();
637  break;
638 
639  default:
640  Unexpected( CurText() );
641  break;
642  }
643  }
644  break;
645 
646  case T_justify:
647  while( ( token = NextTok() ) != T_RIGHT )
648  {
649  if( token == T_EOF)
650  break;
651 
652  switch( token )
653  {
654  case T_center:
657  break;
658 
659  case T_left:
661  break;
662 
663  case T_right:
665  break;
666 
667  case T_top:
669  break;
670 
671  case T_bottom:
673  break;
674 
675  default:
676  Unexpected( CurText() );
677  break;
678  }
679  }
680  break;
681 
682  case T_rotate:
683  aItem->m_Orient = parseDouble();
684  NeedRIGHT();
685  break;
686 
687  default:
688  Unexpected( CurText() );
689  break;
690  }
691  }
692 }
693 
694 // parse an expression like " 25 1 ltcorner)"
696 {
697  T token;
698 
699  aCoord.m_Pos.x = parseDouble();
700  aCoord.m_Pos.y = parseDouble();
701 
702  while( ( token = NextTok() ) != T_RIGHT )
703  {
704  switch( token )
705  {
706  case T_ltcorner:
707  aCoord.m_Anchor = LT_CORNER; // left top corner
708  break;
709 
710  case T_lbcorner:
711  aCoord.m_Anchor = LB_CORNER; // left bottom corner
712  break;
713 
714  case T_rbcorner:
715  aCoord.m_Anchor = RB_CORNER; // right bottom corner
716  break;
717 
718  case T_rtcorner:
719  aCoord.m_Anchor = RT_CORNER; // right top corner
720  break;
721 
722  default:
723  Unexpected( CurText() );
724  break;
725  }
726  }
727 }
728 
729 int PAGE_LAYOUT_READER_PARSER::parseInt( int aMin, int aMax )
730 {
731  T token = NextTok();
732 
733  if( token != T_NUMBER )
734  Expecting( T_NUMBER );
735 
736  int val = atoi( CurText() );
737 
738  if( val < aMin )
739  val = aMin;
740  else if( val > aMax )
741  val = aMax;
742 
743  return val;
744 }
745 
746 
748 {
749  T token = NextTok();
750 
751  if( token != T_NUMBER )
752  Expecting( T_NUMBER );
753 
754  double val = strtod( CurText(), NULL );
755 
756  return val;
757 }
758 
759 // defaultPageLayout is the default page layout description
760 // using the S expr.
761 // see page_layout_default_shape.cpp
762 extern const char defaultPageLayout[];
763 
765 {
766  SetPageLayout( defaultPageLayout, false, wxT( "default page" ) );
767 }
768 
769 // Returns defaultPageLayout as a string;
771 {
772  return wxString( defaultPageLayout );
773 }
774 
775 // emptyPageLayout is a "empty" page layout description
776 // there is a 0 length line to fool something somewhere.
777 // using the S expr.
778 // see page_layout_empty_description.cpp
779 extern const char emptyPageLayout[];
780 
782 {
783  SetPageLayout( emptyPageLayout, false, wxT( "empty page" ) );
784 }
785 
786 
788 {
789  return wxString( emptyPageLayout );
790 }
791 
792 
793 void WORKSHEET_LAYOUT::SetPageLayout( const char* aPageLayout, bool Append, const wxString& aSource )
794 {
795  if( ! Append )
796  ClearList();
797 
798  PAGE_LAYOUT_READER_PARSER lp_parser( aPageLayout, wxT( "Sexpr_string" ) );
799 
800  try
801  {
802  lp_parser.Parse( this );
803  }
804  catch( const IO_ERROR& ioe )
805  {
806  wxLogMessage( ioe.What() );
807  }
808 }
809 
810 
811 void WORKSHEET_LAYOUT::SetPageLayout( const wxString& aFullFileName, bool Append )
812 {
813  wxString fullFileName = aFullFileName;
814 
815  if( !Append )
816  {
817  if( fullFileName.IsEmpty() )
818  wxGetEnv( wxT( "KICAD_WKSFILE" ), &fullFileName );
819 
820  if( fullFileName.IsEmpty() || !wxFileExists( fullFileName ) )
821  {
822  #if 0
823  if( !fullFileName.IsEmpty() )
824  {
825  wxLogMessage( wxT("Page layout file <%s> not found"),
826  fullFileName.GetData() );
827  }
828  #endif
829  SetDefaultLayout();
830  return;
831  }
832  }
833 
834  wxFile wksFile( fullFileName );
835 
836  if( ! wksFile.IsOpened() )
837  {
838  if( !Append )
839  SetDefaultLayout();
840  return;
841  }
842 
843  int filelen = wksFile.Length();
844  char * buffer = new char[filelen+10];
845 
846  if( wksFile.Read( buffer, filelen ) != filelen )
847  wxLogMessage( _("The file \"%s\" was not fully read"),
848  fullFileName.GetData() );
849  else
850  {
851  buffer[filelen]=0;
852 
853  if( ! Append )
854  ClearList();
855 
856  PAGE_LAYOUT_READER_PARSER pl_parser( buffer, fullFileName );
857 
858  try
859  {
860  pl_parser.Parse( this );
861  }
862  catch( const IO_ERROR& ioe )
863  {
864  wxLogMessage( ioe.What() );
865  }
866  }
867 
868  delete[] buffer;
869 }
static DSIZE m_DefaultTextSize
EDA_TEXT_HJUSTIFY_T m_Hjustify
void parseCoordinate(POINT_COORD &aCoord)
int parseInt(int aMin, int aMax)
Function parseInt parses an integer and constrains it between two values.
void Parse(void *yyp, int yymajor, ParseTOKENTYPE yyminorParseARG_PDECL)
Class LOCALE_IO is a class that can be instantiated within a scope in which you are expecting excepti...
Definition: common.h:166
const char emptyPageLayout[]
void parseText(WORKSHEET_DATAITEM_TEXT *aItem)
parse a text item starting by "(tbtext" and read parameters.
void SetBoundingBox()
calculate the bounding box of the set polygons
EDA_TEXT_VJUSTIFY_T m_Vjustify
void SetScale(double aScale)
Definition: bitmap_base.h:83
void readPngdata(WORKSHEET_DATAITEM_BITMAP *aItem)
void AppendCorner(const DPOINT &aCorner)
add a corner in corner list
double parseDouble()
Function parseDouble parses a double.
void SetDefaultLayout()
Fills the list with the default layout shape.
void SetLeftMargin(double aMargin)
void SetTopMargin(double aMargin)
static wxString EmptyLayout()
Returns a string containing the empty layout shape.
PAGE_LAYOUT_READER_PARSER(const char *aLine, const wxString &aSource)
This class handle bitmap images in KiCad.
Definition: bitmap_base.h:44
void SetBottomMargin(double aMargin)
static double parseDouble(FILE_LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Parses an ASCII point string with possible leading whitespace into a double precision floating point ...
void Append(WORKSHEET_DATAITEM *aItem)
Add an item to the list of items.
void SetItalic(bool aState)
Function SetItalic Toggles on/off the italic option flag.
const char defaultPageLayout[]
void parseBitmap(WORKSHEET_DATAITEM_BITMAP *aItem)
parse a bitmap item starting by "( bitmap" and read parameters.
description of graphic items and texts to build a title block
Class PAGE_LAYOUT_READER_PARSER holds data and functions pertinent to parsing a S-expression file for...
static wxString DefaultLayout()
Returns a string containing the empty layout shape.
void parsePolyOutline(WORKSHEET_DATAITEM_POLYPOLYGON *aItem)
parse a list of corners starting by "( pts" and read coordinates.
WORKSHEET_LAYOUT handles the graphic items list to draw/plot the title block and other items (page re...
static double m_DefaultTextThickness
static double m_DefaultLineWidth
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
void parseGraphic(WORKSHEET_DATAITEM *aItem)
parse a graphic item starting by "(line" or "(rect" and read parameters.
void SetEmptyLayout()
Fills the list with an empty layout shape.
bool LoadData(LINE_READER &aLine, wxString &aErrorMsg)
Load an image data saved by SaveData (png, in Hexadecimal form)
void SetBold(bool aState)
Function SetBold Toggles on/off the bold option flag.
void CloseContour()
Closes the current contour, by storing the index of the last corner of the current polygon in m_polyI...
classes and function to generate graphics to plt or draw titles blocks and frame references ...
void Parse(WORKSHEET_LAYOUT *aLayout)
Basic classes for most KiCad items.
void SetPage1Option(int aChoice)
Set the option for page 1.
Class STRING_LINE_READER is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:254
void parsePolygon(WORKSHEET_DATAITEM_POLYPOLYGON *aItem)
parse a polygon item starting by "( polygon" and read parameters.
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
void parseSetup(WORKSHEET_LAYOUT *aLayout)
static long parseInt(const wxString &aValue, double aScalar)
Definition: gpcb_plugin.cpp:52
void SetRightMargin(double aMargin)
void SetPageLayout(const wxString &aFullFileName=wxEmptyString, bool Append=false)
Populates the list with a custom layout, or the default layout, if no custom layout available...
void readOption(WORKSHEET_DATAITEM *aItem)