summaryrefslogtreecommitdiff
path: root/common/page_layout
diff options
context:
space:
mode:
Diffstat (limited to 'common/page_layout')
-rw-r--r--common/page_layout/class_worksheet_dataitem.cpp577
-rw-r--r--common/page_layout/class_worksheet_layout.cpp248
-rw-r--r--common/page_layout/page_layout_default_description.cpp164
-rw-r--r--common/page_layout/page_layout_graphic_items.cpp423
-rw-r--r--common/page_layout/page_layout_reader.cpp875
-rw-r--r--common/page_layout/page_layout_reader.keywords48
-rw-r--r--common/page_layout/title_block_shapes.cpp258
7 files changed, 2593 insertions, 0 deletions
diff --git a/common/page_layout/class_worksheet_dataitem.cpp b/common/page_layout/class_worksheet_dataitem.cpp
new file mode 100644
index 0000000..b5e673f
--- /dev/null
+++ b/common/page_layout/class_worksheet_dataitem.cpp
@@ -0,0 +1,577 @@
+/**
+ * @file class_worksheet_dataitem.cpp
+ * @brief description of graphic items and texts to build a title block
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2013 Jean-Pierre Charras <jp.charras at wanadoo.fr>.
+ * Copyright (C) 1992-2013 KiCad Developers, see change_log.txt for contributors.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+
+/*
+ * the class WORKSHEET_DATAITEM (and derived) defines
+ * a basic shape of a page layout ( frame references and title block )
+ * Basic shapes are line, rect and texts
+ * the WORKSHEET_DATAITEM coordinates units is the mm, and are relative to
+ * one of 4 page corners.
+ *
+ * These items cannot be drawn or plot "as this". they should be converted
+ * to a "draw list" (WS_DRAW_ITEM_BASE and derived items)
+
+ * The list of these items is stored in a WORKSHEET_LAYOUT instance.
+ *
+ * When building the draw list:
+ * the WORKSHEET_LAYOUT is used to create a WS_DRAW_ITEM_LIST
+ * coordinates are converted to draw/plot coordinates.
+ * texts are expanded if they contain format symbols.
+ * Items with m_RepeatCount > 1 are created m_RepeatCount times
+ *
+ * the WORKSHEET_LAYOUT is created only once.
+ * the WS_DRAW_ITEM_LIST is created each time the page layout is plot/drawn
+ *
+ * the WORKSHEET_LAYOUT instance is created from a S expression which
+ * describes the page layout (can be the default page layout or a custom file).
+ */
+
+#include <fctsys.h>
+#include <drawtxt.h>
+#include <worksheet.h>
+#include <class_title_block.h>
+#include <worksheet_shape_builder.h>
+#include <class_worksheet_dataitem.h>
+
+
+// Static members of class WORKSHEET_DATAITEM:
+double WORKSHEET_DATAITEM::m_WSunits2Iu = 1.0;
+DPOINT WORKSHEET_DATAITEM::m_RB_Corner;
+DPOINT WORKSHEET_DATAITEM::m_LT_Corner;
+double WORKSHEET_DATAITEM::m_DefaultLineWidth = 0.0;
+DSIZE WORKSHEET_DATAITEM::m_DefaultTextSize( TB_DEFAULT_TEXTSIZE, TB_DEFAULT_TEXTSIZE );
+double WORKSHEET_DATAITEM::m_DefaultTextThickness = 0.0;
+bool WORKSHEET_DATAITEM::m_SpecialMode = false;
+EDA_COLOR_T WORKSHEET_DATAITEM::m_Color = RED; // the default color to draw items
+EDA_COLOR_T WORKSHEET_DATAITEM::m_AltColor = RED; // an alternate color to draw items
+EDA_COLOR_T WORKSHEET_DATAITEM::m_SelectedColor = BROWN; // the color to draw selected items
+
+// The constructor:
+WORKSHEET_DATAITEM::WORKSHEET_DATAITEM( WS_ItemType aType )
+{
+ m_type = aType;
+ m_flags = 0;
+ m_RepeatCount = 1;
+ m_IncrementLabel = 1;
+ m_LineWidth = 0;
+}
+
+// move item to aPosition
+// starting point is moved to aPosition
+// the Ending point is moved to a position which keeps the item size
+// (if both coordinates have the same corner reference)
+// MoveToUi and MoveTo takes the graphic position (i.e relative to the left top
+// paper corner
+void WORKSHEET_DATAITEM::MoveToUi( wxPoint aPosition )
+{
+ DPOINT pos_mm;
+ pos_mm.x = aPosition.x / m_WSunits2Iu;
+ pos_mm.y = aPosition.y / m_WSunits2Iu;
+
+ MoveTo( pos_mm );
+}
+
+void WORKSHEET_DATAITEM::MoveTo( DPOINT aPosition )
+{
+ DPOINT vector = aPosition - GetStartPos();
+ DPOINT endpos = vector + GetEndPos();
+
+ MoveStartPointTo( aPosition );
+ MoveEndPointTo( endpos );
+}
+
+/* move the starting point of the item to a new position
+ * aPosition = the new position of the starting point, in mm
+ */
+void WORKSHEET_DATAITEM::MoveStartPointTo( DPOINT aPosition )
+{
+ DPOINT position;
+
+ // Calculate the position of the starting point
+ // relative to the reference corner
+ // aPosition is the position relative to the right top paper corner
+ switch( m_Pos.m_Anchor )
+ {
+ case RB_CORNER:
+ position = m_RB_Corner - aPosition;
+ break;
+
+ case RT_CORNER:
+ position.x = m_RB_Corner.x - aPosition.x;
+ position.y = aPosition.y - m_LT_Corner.y;
+ break;
+
+ case LB_CORNER:
+ position.x = aPosition.x - m_LT_Corner.x;
+ position.y = m_RB_Corner.y - aPosition.y;
+ break;
+
+ case LT_CORNER:
+ position = aPosition - m_LT_Corner;
+ break;
+ }
+
+ m_Pos.m_Pos = position;
+}
+
+/* move the starting point of the item to a new position
+ * aPosition = the new position of the starting point in graphic units
+ */
+void WORKSHEET_DATAITEM::MoveStartPointToUi( wxPoint aPosition )
+{
+ DPOINT pos_mm;
+ pos_mm.x = aPosition.x / m_WSunits2Iu;
+ pos_mm.y = aPosition.y / m_WSunits2Iu;
+
+ MoveStartPointTo( pos_mm );
+}
+
+/**
+ * move the ending point of the item to a new position
+ * has meaning only for items defined by 2 points
+ * (segments and rectangles)
+ * aPosition = the new position of the ending point, in mm
+ */
+void WORKSHEET_DATAITEM::MoveEndPointTo( DPOINT aPosition )
+{
+ DPOINT position;
+
+ // Calculate the position of the starting point
+ // relative to the reference corner
+ // aPosition is the position relative to the right top paper corner
+ switch( m_End.m_Anchor )
+ {
+ case RB_CORNER:
+ position = m_RB_Corner - aPosition;
+ break;
+
+ case RT_CORNER:
+ position.x = m_RB_Corner.x - aPosition.x;
+ position.y = aPosition.y - m_LT_Corner.y;
+ break;
+
+ case LB_CORNER:
+ position.x = aPosition.x - m_LT_Corner.x;
+ position.y = m_RB_Corner.y - aPosition.y;
+ break;
+
+ case LT_CORNER:
+ position = aPosition - m_LT_Corner;
+ break;
+ }
+
+ // Modify m_End only for items having 2 coordinates
+ switch( GetType() )
+ {
+ case WS_SEGMENT:
+ case WS_RECT:
+ m_End.m_Pos = position;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* move the ending point of the item to a new position
+ * has meaning only for items defined by 2 points
+ * (segments and rectangles)
+ * aPosition = the new position of the ending point in graphic units
+ */
+void WORKSHEET_DATAITEM::MoveEndPointToUi( wxPoint aPosition )
+{
+ DPOINT pos_mm;
+ pos_mm.x = aPosition.x / m_WSunits2Iu;
+ pos_mm.y = aPosition.y / m_WSunits2Iu;
+
+ MoveEndPointTo( pos_mm );
+}
+
+const DPOINT WORKSHEET_DATAITEM::GetStartPos( int ii ) const
+{
+ DPOINT pos;
+ pos.x = m_Pos.m_Pos.x + ( m_IncrementVector.x * ii );
+ pos.y = m_Pos.m_Pos.y + ( m_IncrementVector.y * ii );
+
+ switch( m_Pos.m_Anchor )
+ {
+ case RB_CORNER: // right bottom corner
+ pos = m_RB_Corner - pos;
+ break;
+
+ case RT_CORNER: // right top corner
+ pos.x = m_RB_Corner.x - pos.x;
+ pos.y = m_LT_Corner.y + pos.y;
+ break;
+
+ case LB_CORNER: // left bottom corner
+ pos.x = m_LT_Corner.x + pos.x;
+ pos.y = m_RB_Corner.y - pos.y;
+ break;
+
+ case LT_CORNER: // left top corner
+ pos = m_LT_Corner + pos;
+ break;
+ }
+
+ return pos;
+}
+
+const wxPoint WORKSHEET_DATAITEM::GetStartPosUi( int ii ) const
+{
+ DPOINT pos = GetStartPos( ii );
+ pos = pos * m_WSunits2Iu;
+ return wxPoint( KiROUND(pos.x), KiROUND(pos.y) );
+}
+
+const DPOINT WORKSHEET_DATAITEM::GetEndPos( int ii ) const
+{
+ DPOINT pos;
+ pos.x = m_End.m_Pos.x + ( m_IncrementVector.x * ii );
+ pos.y = m_End.m_Pos.y + ( m_IncrementVector.y * ii );
+ switch( m_End.m_Anchor )
+ {
+ case RB_CORNER: // right bottom corner
+ pos = m_RB_Corner - pos;
+ break;
+
+ case RT_CORNER: // right top corner
+ pos.x = m_RB_Corner.x - pos.x;
+ pos.y = m_LT_Corner.y + pos.y;
+ break;
+
+ case LB_CORNER: // left bottom corner
+ pos.x = m_LT_Corner.x + pos.x;
+ pos.y = m_RB_Corner.y - pos.y;
+ break;
+
+ case LT_CORNER: // left top corner
+ pos = m_LT_Corner + pos;
+ break;
+ }
+
+ return pos;
+}
+
+const wxPoint WORKSHEET_DATAITEM::GetEndPosUi( int ii ) const
+{
+ DPOINT pos = GetEndPos( ii );
+ pos = pos * m_WSunits2Iu;
+ return wxPoint( KiROUND(pos.x), KiROUND(pos.y) );
+}
+
+
+bool WORKSHEET_DATAITEM::IsInsidePage( int ii ) const
+{
+ DPOINT pos = GetStartPos( ii );
+
+ for( int kk = 0; kk < 1; kk++ )
+ {
+ if( m_RB_Corner.x < pos.x || m_LT_Corner.x > pos.x )
+ return false;
+
+ if( m_RB_Corner.y < pos.y || m_LT_Corner.y > pos.y )
+ return false;
+
+ pos = GetEndPos( ii );
+ }
+
+ return true;
+}
+
+const wxString WORKSHEET_DATAITEM::GetClassName() const
+{
+ wxString name;
+ switch( GetType() )
+ {
+ case WS_TEXT: name = wxT("Text"); break;
+ case WS_SEGMENT: name = wxT("Line"); break;
+ case WS_RECT: name = wxT("Rect"); break;
+ case WS_POLYPOLYGON: name = wxT("Poly"); break;
+ case WS_BITMAP: name = wxT("Bitmap"); break;
+ }
+
+ return name;
+}
+
+/* return 0 if the item has no specific option for page 1
+ * 1 if the item is only on page 1
+ * -1 if the item is not on page 1
+ */
+int WORKSHEET_DATAITEM::GetPage1Option()
+{
+ if(( m_flags & PAGE1OPTION) == PAGE1OPTION_NOTONPAGE1 )
+ return -1;
+
+ if(( m_flags & PAGE1OPTION) == PAGE1OPTION_PAGE1ONLY )
+ return 1;
+
+ return 0;
+}
+
+/* Set the option for page 1
+ * aChoice = 0 if the item has no specific option for page 1
+ * > 0 if the item is only on page 1
+ * < 0 if the item is not on page 1
+ */
+void WORKSHEET_DATAITEM::SetPage1Option( int aChoice )
+{
+ ClearFlags( PAGE1OPTION );
+
+ if( aChoice > 0)
+ SetFlags( PAGE1OPTION_PAGE1ONLY );
+
+ else if( aChoice < 0)
+ SetFlags( PAGE1OPTION_NOTONPAGE1 );
+
+}
+
+
+WORKSHEET_DATAITEM_POLYPOLYGON::WORKSHEET_DATAITEM_POLYPOLYGON() :
+ WORKSHEET_DATAITEM( WS_POLYPOLYGON )
+{
+ m_Orient = 0.0;
+}
+
+const DPOINT WORKSHEET_DATAITEM_POLYPOLYGON::GetCornerPosition( unsigned aIdx,
+ int aRepeat ) const
+{
+ DPOINT pos = m_Corners[aIdx];
+
+ // Rotation:
+ RotatePoint( &pos.x, &pos.y, m_Orient * 10 );
+ pos += GetStartPos( aRepeat );
+ return pos;
+}
+
+void WORKSHEET_DATAITEM_POLYPOLYGON::SetBoundingBox()
+{
+ if( m_Corners.size() == 0 )
+ {
+ m_minCoord.x = m_maxCoord.x = 0.0;
+ m_minCoord.y = m_maxCoord.y = 0.0;
+ return;
+ }
+
+ DPOINT pos;
+ pos = m_Corners[0];
+ RotatePoint( &pos.x, &pos.y, m_Orient * 10 );
+ m_minCoord = m_maxCoord = pos;
+
+ for( unsigned ii = 1; ii < m_Corners.size(); ii++ )
+ {
+ pos = m_Corners[ii];
+ RotatePoint( &pos.x, &pos.y, m_Orient * 10 );
+
+ if( m_minCoord.x > pos.x )
+ m_minCoord.x = pos.x;
+
+ if( m_minCoord.y > pos.y )
+ m_minCoord.y = pos.y;
+
+ if( m_maxCoord.x < pos.x )
+ m_maxCoord.x = pos.x;
+
+ if( m_maxCoord.y < pos.y )
+ m_maxCoord.y = pos.y;
+ }
+}
+
+bool WORKSHEET_DATAITEM_POLYPOLYGON::IsInsidePage( int ii ) const
+{
+ DPOINT pos = GetStartPos( ii );
+ pos += m_minCoord; // left top pos of bounding box
+
+ if( m_LT_Corner.x > pos.x || m_LT_Corner.y > pos.y )
+ return false;
+
+ pos = GetStartPos( ii );
+ pos += m_maxCoord; // rignt bottom pos of bounding box
+
+ if( m_RB_Corner.x < pos.x || m_RB_Corner.y < pos.y )
+ return false;
+
+ return true;
+}
+
+const wxPoint WORKSHEET_DATAITEM_POLYPOLYGON::GetCornerPositionUi( unsigned aIdx,
+ int aRepeat ) const
+{
+ DPOINT pos = GetCornerPosition( aIdx, aRepeat );
+ pos = pos * m_WSunits2Iu;
+ return wxPoint( int(pos.x), int(pos.y) );
+}
+
+WORKSHEET_DATAITEM_TEXT::WORKSHEET_DATAITEM_TEXT( const wxString& aTextBase ) :
+ WORKSHEET_DATAITEM( WS_TEXT )
+{
+ m_TextBase = aTextBase;
+ m_IncrementLabel = 1;
+ m_Hjustify = GR_TEXT_HJUSTIFY_LEFT;
+ m_Vjustify = GR_TEXT_VJUSTIFY_CENTER;
+ m_Orient = 0.0;
+ m_LineWidth = 0.0; // 0.0 means use default value
+}
+
+void WORKSHEET_DATAITEM_TEXT::TransfertSetupToGraphicText( WS_DRAW_ITEM_TEXT* aGText )
+{
+ aGText->SetHorizJustify( m_Hjustify ) ;
+ aGText->SetVertJustify( m_Vjustify );
+ aGText->SetOrientation( m_Orient * 10 ); // graphic text orient unit = 0.1 degree
+}
+
+void WORKSHEET_DATAITEM_TEXT::IncrementLabel( int aIncr )
+{
+ int last = m_TextBase.Len() -1;
+
+ wxChar lbchar = m_TextBase[last];
+ m_FullText = m_TextBase;
+ m_FullText.RemoveLast();
+
+ if( lbchar >= '0' && lbchar <= '9' )
+ // A number is expected:
+ m_FullText << (int)( aIncr + lbchar - '0' );
+ else
+ m_FullText << (wxChar) ( aIncr + lbchar );
+}
+
+// Replace the '\''n' sequence by EOL
+// and the sequence '\''\' by only one '\' in m_FullText
+// if m_FullText is a multiline text (i.e.contains '\n') return true
+bool WORKSHEET_DATAITEM_TEXT::ReplaceAntiSlashSequence()
+{
+ bool multiline = false;
+
+ for( unsigned ii = 0; ii < m_FullText.Len(); ii++ )
+ {
+ if( m_FullText[ii] == '\n' )
+ multiline = true;
+
+ else if( m_FullText[ii] == '\\' )
+ {
+ if( ++ii >= m_FullText.Len() )
+ break;
+
+ if( m_FullText[ii] == '\\' )
+ {
+ // a double \\ sequence is replaced by a single \ char
+ m_FullText.Remove(ii, 1);
+ ii--;
+ }
+ else if( m_FullText[ii] == 'n' )
+ {
+ // Replace the "\n" sequence by a EOL char
+ multiline = true;
+ m_FullText[ii] = '\n';
+ m_FullText.Remove(ii-1, 1);
+ ii--;
+ }
+ }
+ }
+
+ return multiline;
+}
+
+void WORKSHEET_DATAITEM_TEXT::SetConstrainedTextSize()
+{
+ m_ConstrainedTextSize = m_TextSize;
+
+ if( m_ConstrainedTextSize.x == 0 )
+ m_ConstrainedTextSize.x = m_DefaultTextSize.x;
+
+ if( m_ConstrainedTextSize.y == 0 )
+ m_ConstrainedTextSize.y = m_DefaultTextSize.y;
+
+ if( m_BoundingBoxSize.x || m_BoundingBoxSize.y )
+ {
+ int linewidth = 0;
+ // to know the X and Y size of the line, we should use
+ // EDA_TEXT::GetTextBox()
+ // but this function uses integers
+ // So, to avoid truncations with our unit in mm, use microns.
+ wxSize size_micron;
+ size_micron.x = KiROUND( m_ConstrainedTextSize.x * 1000.0 );
+ size_micron.y = KiROUND( m_ConstrainedTextSize.y * 1000.0 );
+ WS_DRAW_ITEM_TEXT dummy( WS_DRAW_ITEM_TEXT( this, this->m_FullText,
+ wxPoint(0,0),
+ size_micron,
+ linewidth, BLACK,
+ IsItalic(), IsBold() ) );
+ dummy.SetMultilineAllowed( true );
+ TransfertSetupToGraphicText( &dummy );
+ EDA_RECT rect = dummy.GetTextBox();
+ DSIZE size;
+ size.x = rect.GetWidth() / 1000.0;
+ size.y = rect.GetHeight() / 1000.0;
+
+ if( m_BoundingBoxSize.x && size.x > m_BoundingBoxSize.x )
+ m_ConstrainedTextSize.x *= m_BoundingBoxSize.x / size.x;
+
+ if( m_BoundingBoxSize.y && size.y > m_BoundingBoxSize.y )
+ m_ConstrainedTextSize.y *= m_BoundingBoxSize.y / size.y;
+ }
+}
+
+/* set the pixel scale factor of the bitmap
+ * this factor depend on the application internal unit
+ * and the PPI bitmap factor
+ * the pixel scale factor should be initialized before drawing the bitmap
+ */
+void WORKSHEET_DATAITEM_BITMAP::SetPixelScaleFactor()
+{
+ if( m_ImageBitmap )
+ {
+ // m_WSunits2Iu is the page layout unit to application internal unit
+ // i.e. the mm to to application internal unit
+ // however the bitmap definition is always known in pixels per inches
+ double scale = m_WSunits2Iu * 25.4 / m_ImageBitmap->GetPPI();
+ m_ImageBitmap->SetPixelScaleFactor( scale );
+ }
+}
+
+/* return the PPI of the bitmap
+ */
+int WORKSHEET_DATAITEM_BITMAP::GetPPI() const
+{
+ if( m_ImageBitmap )
+ return m_ImageBitmap->GetPPI() / m_ImageBitmap->m_Scale;
+
+ return 300;
+}
+
+/*adjust the PPI of the bitmap
+ */
+void WORKSHEET_DATAITEM_BITMAP::SetPPI( int aBitmapPPI )
+{
+ if( m_ImageBitmap )
+ m_ImageBitmap->m_Scale = (double) m_ImageBitmap->GetPPI() / aBitmapPPI;
+}
+
diff --git a/common/page_layout/class_worksheet_layout.cpp b/common/page_layout/class_worksheet_layout.cpp
new file mode 100644
index 0000000..94c11a1
--- /dev/null
+++ b/common/page_layout/class_worksheet_layout.cpp
@@ -0,0 +1,248 @@
+/**
+ * @file class_worksheet_layout.cpp
+ * @brief description of graphic items and texts to build a title block
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2013 Jean-Pierre Charras <jp.charras at wanadoo.fr>.
+ * Copyright (C) 1992-2013 KiCad Developers, see change_log.txt for contributors.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+
+/*
+ * the class WORKSHEET_DATAITEM (and derived ) defines
+ * a basic shape of a page layout ( frame references and title block )
+ * The list of these items is stored in a WORKSHEET_LAYOUT instance.
+ *
+ *
+ * These items cannot be drawn or plot "as this". they should be converted
+ * to a "draw list". When building the draw list:
+ * the WORKSHEET_LAYOUT is used to create a WS_DRAW_ITEM_LIST
+ * coordinates are converted to draw/plot coordinates.
+ * texts are expanded if they contain format symbols.
+ * Items with m_RepeatCount > 1 are created m_RepeatCount times
+ *
+ * the WORKSHEET_LAYOUT is created only once.
+ * the WS_DRAW_ITEM_LIST is created each time the page layout is plot/drawn
+ *
+ * the WORKSHEET_LAYOUT instance is created from a S expression which
+ * describes the page layout (can be the default page layout or a custom file).
+ */
+
+#include <fctsys.h>
+#include <kiface_i.h>
+#include <drawtxt.h>
+#include <worksheet.h>
+#include <class_title_block.h>
+#include <worksheet_shape_builder.h>
+#include <class_worksheet_dataitem.h>
+
+
+// The layout shape used in the application
+// It is accessible by WORKSHEET_LAYOUT::GetTheInstance()
+static WORKSHEET_LAYOUT wksTheInstance;
+static WORKSHEET_LAYOUT* wksAltInstance;
+
+WORKSHEET_LAYOUT::WORKSHEET_LAYOUT()
+{
+ m_allowVoidList = false;
+ m_leftMargin = 10.0; // the left page margin in mm
+ m_rightMargin = 10.0; // the right page margin in mm
+ m_topMargin = 10.0; // the top page margin in mm
+ m_bottomMargin = 10.0; // the bottom page margin in mm
+}
+
+/* static function: returns the instance of WORKSHEET_LAYOUT
+ * used in the application
+ */
+WORKSHEET_LAYOUT& WORKSHEET_LAYOUT::GetTheInstance()
+{
+ if( wksAltInstance )
+ return *wksAltInstance;
+ else
+ return wksTheInstance;
+}
+
+/**
+ * static function: Set an alternate instance of WORKSHEET_LAYOUT
+ * mainly used in page setting dialog
+ * @param aLayout = the alternate page layout.
+ * if null, restore the basic page layout
+ */
+void WORKSHEET_LAYOUT::SetAltInstance( WORKSHEET_LAYOUT* aLayout )
+{
+ wksAltInstance = aLayout;
+}
+
+
+void WORKSHEET_LAYOUT::SetLeftMargin( double aMargin )
+{
+ m_leftMargin = aMargin; // the left page margin in mm
+}
+
+
+void WORKSHEET_LAYOUT::SetRightMargin( double aMargin )
+{
+ m_rightMargin = aMargin; // the right page margin in mm
+}
+
+
+void WORKSHEET_LAYOUT::SetTopMargin( double aMargin )
+{
+ m_topMargin = aMargin; // the top page margin in mm
+}
+
+
+void WORKSHEET_LAYOUT::SetBottomMargin( double aMargin )
+{
+ m_bottomMargin = aMargin; // the bottom page margin in mm
+}
+
+
+void WORKSHEET_LAYOUT::ClearList()
+{
+ for( unsigned ii = 0; ii < m_list.size(); ii++ )
+ delete m_list[ii];
+ m_list.clear();
+}
+
+
+void WORKSHEET_LAYOUT::Insert( WORKSHEET_DATAITEM* aItem, unsigned aIdx )
+{
+ if ( aIdx >= GetCount() )
+ Append( aItem );
+ else
+ m_list.insert( m_list.begin() + aIdx, aItem );
+}
+
+
+bool WORKSHEET_LAYOUT::Remove( unsigned aIdx )
+{
+ if ( aIdx >= GetCount() )
+ return false;
+ m_list.erase( m_list.begin() + aIdx );
+ return true;
+}
+
+
+bool WORKSHEET_LAYOUT::Remove( WORKSHEET_DATAITEM* aItem )
+{
+ unsigned idx = 0;
+
+ while( idx < m_list.size() )
+ {
+ if( m_list[idx] == aItem )
+ break;
+
+ idx++;
+ }
+
+ return Remove( idx );
+}
+
+
+int WORKSHEET_LAYOUT::GetItemIndex( WORKSHEET_DATAITEM* aItem ) const
+{
+ unsigned idx = 0;
+ while( idx < m_list.size() )
+ {
+ if( m_list[idx] == aItem )
+ return (int) idx;
+
+ idx++;
+ }
+
+ return -1;
+}
+
+/* return the item from its index aIdx, or NULL if does not exist
+ */
+WORKSHEET_DATAITEM* WORKSHEET_LAYOUT::GetItem( unsigned aIdx ) const
+{
+ if( aIdx < m_list.size() )
+ return m_list[aIdx];
+ else
+ return NULL;
+}
+
+
+const wxString WORKSHEET_LAYOUT::MakeShortFileName( const wxString& aFullFileName,
+ const wxString& aProjectPath )
+{
+ wxString shortFileName = aFullFileName;
+ wxFileName fn = aFullFileName;
+
+ if( fn.IsRelative() )
+ return shortFileName;
+
+ if( ! aProjectPath.IsEmpty() && aFullFileName.StartsWith( aProjectPath ) )
+ {
+ fn.MakeRelativeTo( aProjectPath );
+ shortFileName = fn.GetFullPath();
+ return shortFileName;
+ }
+
+ wxString fileName = Kiface().KifaceSearch().FindValidPath( fn.GetFullName() );
+
+ if( !fileName.IsEmpty() )
+ {
+ fn = fileName;
+ shortFileName = fn.GetFullName();
+ return shortFileName;
+ }
+
+ return shortFileName;
+}
+
+
+const wxString WORKSHEET_LAYOUT::MakeFullFileName( const wxString& aShortFileName,
+ const wxString& aProjectPath )
+{
+ wxString fullFileName = ExpandEnvVarSubstitutions( aShortFileName );
+
+ if( fullFileName.IsEmpty() )
+ return fullFileName;
+
+ wxFileName fn = fullFileName;
+
+ if( fn.IsAbsolute() )
+ return fullFileName;
+
+ // the path is not absolute: search it in project path, and then in
+ // kicad valid paths
+ if( !aProjectPath.IsEmpty() )
+ {
+ fn.MakeAbsolute( aProjectPath );
+
+ if( wxFileExists( fn.GetFullPath() ) )
+ return fn.GetFullPath();
+ }
+
+ fn = fullFileName;
+ wxString name = Kiface().KifaceSearch().FindValidPath( fn.GetFullName() );
+
+ if( !name.IsEmpty() )
+ fullFileName = name;
+
+ return fullFileName;
+}
diff --git a/common/page_layout/page_layout_default_description.cpp b/common/page_layout/page_layout_default_description.cpp
new file mode 100644
index 0000000..fd8ba46
--- /dev/null
+++ b/common/page_layout/page_layout_default_description.cpp
@@ -0,0 +1,164 @@
+/**
+ * @file common/page_layout/page_layout_default_description.cpp
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2013 Jean-Pierre Charras <jp.charras at wanadoo.fr>.
+ * Copyright (C) 1992-2013 KiCad Developers, see change_log.txt for contributors.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* keyword used in page layout description are listed
+ * in page_layout_reader.keywords file
+ */
+
+/*
+ * Items use coordinates.
+ * A coordinate is defined relative to a page corner
+ * A coordinate is the X pos, the Y pos, and the corner which is the coordinate origin
+ * the default is the bottom right corner
+ * example: (start 10 0 ltcorner) or (start 20 10)
+ * The direction depends on the corner: a positive coordinate define a point
+ * from the corner origin, to the opposite corner.
+ *
+ * Items are defined by a name, coordinates in mm and some attributes,
+ * and can be repeated.
+ * for instance (repeat 2) (incrx 2) (incry 2) repeat the item 2 times,
+ * and coordinates are incremented by 2 on X direction, and 2 on Y direction
+ * Comments are allowed. they are inside (), and start by the keyword comment
+ * example:
+ * (comment rect around the title block)
+ *
+ * Lines and rect are defined by 2 coordinates start and end, and attributes.
+ * Attributes are linewidth and repeat parameters.
+ * example:
+ * (line (start 50 2 ltcorner) (end 50 0 ltcorner) (repeat 30) (incrx 50) )
+ * (rect (comment rect around the title block) (linewidth 0.15) (start 110 34) (end 2 2) )
+ *
+ * Texts are defined by the text (between quotes), the position, and attributes
+ * example
+ * "(tbtext \"1\" (pos 25 1 lbcorner) (font (size 1.3 1.3)) (repeat 100) (incrx 50) )"
+ * the text can be rotated by (rotation <value>) with value = rot angle in degrees
+ * (font (size 1.3 1.3) bold italic) defines a specific size,
+ * with bold and italic options
+ * (justify <justif keyword>) controls the text justification (the default is left)
+ * justif keyword is center, left, right, top and bottom
+ * (justify center top) is a text centered on X axis and top aligned on vertical axis
+ * The text size can be constrained:
+ * (maxlen <value>) and (maxheight <value>) force the actual text x and/or y size to be
+ * reduced to limit the text height to the maxheight value,
+ * and the full text x size to the maxlen value.
+ * If the actual text size is smaller than limits, its size is not modified.
+ *
+ * Texts can include a format symbol, a la printf.
+ * At run time these format symbols will be replaced by their actual value.
+ *
+ * format symbols are:
+ *
+ * %% = replaced by %
+ * %K = Kicad version
+ * %Z = paper format name (A4, USLetter ...)
+ * %Y = company name
+ * %D = date
+ * %R = revision
+ * %S = sheet number
+ * %N = number of sheets
+ * %Cx = comment (x = 0 to 9 to identify the comment)
+ * %F = filename
+ * %P = sheet path (sheet full name)
+ * %T = title
+ *
+ * example:
+ * (tbtext \"Size: %Z\" ...) displays "Size A4" or Size USLetter"
+ *
+ * Poly Polygons
+ * Set of filled polygons are supported.
+ *
+ * The main purpose is to allow logos, or complex shapes
+ * They support the repeat and rotation options
+ * They are defined by
+ * (polygon (position ..) <rotation> <linewidth>
+ * the parameter linewidth defines the pen size used to draw/plot
+ * the polygon outlines (default = 0)
+ * example:
+ * (polygon (pos 134 18 rbcorner) (rotate 20) (linewidth 0.00254)
+ *
+ * and a list of corners like
+ * (pts (xy 20.574 8.382) (xy 19.9009 8.382) (xy 19.9009 6.26364) (xy 19.7485 5.98932)
+ * .... )
+ *
+ * each sequence like
+ * (pts (xy 20.574 8.382) (xy 19.9009 8.382) (xy 19.9009 6.26364) (xy 19.7485 5.98932)
+ * .... )
+ * defines a polygon.
+ * Each coordinate is relative to the polygon position.
+ * Therefore a "polygon" is in fact a set of polygons, of a poly polygon
+ *
+ */
+
+#include <worksheet.h> // defaultPageLayout
+
+
+// height of the band reference grid 2.0 mm
+// worksheet frame reference text size 1.3 mm
+// default text size 1.5 mm
+// default line width 0.15 mm
+// frame ref pitch 50 mm
+
+// export defaultPageLayout:
+extern const char defaultPageLayout[];
+
+// Default page layout (sizes are in mm)
+const char defaultPageLayout[] = "( page_layout\n"
+ "(setup (textsize 1.5 1.5) (linewidth 0.15) (textlinewidth 0.15)\n"
+ "(left_margin 10)(right_margin 10)(top_margin 10)(bottom_margin 10))\n"
+ "(rect (comment \"rect around the title block\") (linewidth 0.15) (start 110 34) (end 2 2) )\n"
+ "(rect (start 0 0 ltcorner) (end 0 0 rbcorner) (repeat 2) (incrx 2) (incry 2) )\n"
+ "(line (start 50 2 ltcorner) (end 50 0 ltcorner) (repeat 30) (incrx 50) )\n"
+ "(tbtext \"1\" (pos 25 1 ltcorner) (font (size 1.3 1.3))(repeat 100) (incrx 50) )\n"
+ "(line (start 50 2 lbcorner) (end 50 0 lbcorner) (repeat 30) (incrx 50) )\n"
+ "(tbtext \"1\" (pos 25 1 lbcorner) (font (size 1.3 1.3)) (repeat 100) (incrx 50) )\n"
+ "(line (start 0 50 ltcorner) (end 2 50 ltcorner) (repeat 30) (incry 50) )\n"
+ "(tbtext \"A\" (pos 1 25 ltcorner) (font (size 1.3 1.3)) (justify center)(repeat 100) (incry 50) )\n"
+ "(line (start 0 50 rtcorner) (end 2 50 rtcorner) (repeat 30) (incry 50) )\n"
+ "(tbtext \"A\" (pos 1 25 rtcorner) (font (size 1.3 1.3)) (justify center) (repeat 100) (incry 50) )\n"
+ "(tbtext \"Date: %D\" (pos 87 6.9) )\n"
+ "(line (start 110 5.5) (end 2 5.5) )\n"
+ "(tbtext \"%K\" (pos 109 4.1) (comment \"Kicad version\" ) )\n"
+ "(line (start 110 8.5) (end 2 8.5) )\n"
+ "(tbtext \"Rev: %R\" (pos 24 6.9)(font bold)(justify left) )\n"
+ "(tbtext \"Size: %Z\" (comment \"Paper format name\")(pos 109 6.9) )\n"
+ "(tbtext \"Id: %S/%N\" (comment \"Sheet id\")(pos 24 4.1) )\n"
+ "(line (start 110 12.5) (end 2 12.5) )\n"
+ "(tbtext \"Title: %T\" (pos 109 10.7)(font bold italic (size 2 2)) )\n"
+ "(tbtext \"File: %F\" (pos 109 14.3) )\n"
+ "(line (start 110 18.5) (end 2 18.5) )\n"
+ "(tbtext \"Sheet: %P\" (pos 109 17) )\n"
+ "(tbtext \"%Y\" (comment \"Company name\") (pos 109 20)(font bold) )\n"
+ "(tbtext \"%C0\" (comment \"Comment 0\") (pos 109 23) )\n"
+ "(tbtext \"%C1\" (comment \"Comment 1\") (pos 109 26) )\n"
+ "(tbtext \"%C2\" (comment \"Comment 2\") (pos 109 29) )\n"
+ "(tbtext \"%C3\" (comment \"Comment 3\") (pos 109 32) )\n"
+ "(line (start 90 8.5) (end 90 5.5) )\n"
+ "(line (start 26 8.5) (end 26 2) )\n"
+ ")\n"
+;
diff --git a/common/page_layout/page_layout_graphic_items.cpp b/common/page_layout/page_layout_graphic_items.cpp
new file mode 100644
index 0000000..c927e93
--- /dev/null
+++ b/common/page_layout/page_layout_graphic_items.cpp
@@ -0,0 +1,423 @@
+/**
+ * @file page_layout_graphic_items.cpp
+ * @brief description of graphic items and texts to build a title block
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2013 Jean-Pierre Charras <jp.charras at wanadoo.fr>.
+ * Copyright (C) 1992-2013 KiCad Developers, see change_log.txt for contributors.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+
+/*
+ * the class WORKSHEET_DATAITEM (and WORKSHEET_DATAITEM_TEXT) defines
+ * a basic shape of a page layout ( frame references and title block )
+ * Basic shapes are line, rect and texts
+ * the WORKSHEET_DATAITEM coordinates units is the mm, and are relative to
+ * one of 4 page corners.
+ *
+ * These items cannot be drawn or plot "as this". they should be converted
+ * to a "draw list" (WS_DRAW_ITEM_BASE and derived items)
+
+ * The list of these items is stored in a WORKSHEET_LAYOUT instance.
+ *
+ * When building the draw list:
+ * the WORKSHEET_LAYOUT is used to create a WS_DRAW_ITEM_LIST
+ * coordinates are converted to draw/plot coordinates.
+ * texts are expanded if they contain format symbols.
+ * Items with m_RepeatCount > 1 are created m_RepeatCount times
+ *
+ * the WORKSHEET_LAYOUT is created only once.
+ * the WS_DRAW_ITEM_LIST is created each time the page layout is plotted/drawn
+ *
+ * the WORKSHEET_LAYOUT instance is created from a S expression which
+ * describes the page layout (can be the default page layout or a custom file).
+ */
+
+#include <fctsys.h>
+#include <drawtxt.h>
+#include <worksheet.h>
+#include <class_title_block.h>
+#include <worksheet_shape_builder.h>
+#include <class_worksheet_dataitem.h>
+
+/* a helper function to draw graphic symbols at start point or end point of
+ * an item.
+ * The start point symbol is a filled rectangle
+ * The start point symbol is a filled circle
+ */
+inline void drawMarker( EDA_RECT* aClipBox, wxDC* aDC,
+ const wxPoint& aPos, int aSize, bool aEndPointShape = false )
+{
+ int markerHalfSize = aSize/2;
+
+ if( aEndPointShape )
+ GRFilledCircle( aClipBox, aDC, aPos.x, aPos.y, markerHalfSize,
+ 0, GREEN, GREEN );
+ else
+ GRFilledRect( aClipBox, aDC,
+ aPos.x - markerHalfSize, aPos.y - markerHalfSize,
+ aPos.x + markerHalfSize, aPos.y + markerHalfSize,
+ 0, GREEN, GREEN );
+}
+
+/* Draws the item list created by BuildWorkSheetGraphicList
+ * aClipBox = the clipping rect, or NULL if no clipping
+ * aDC = the current Device Context
+ * The not selected items are drawn first (most of items)
+ * The selected items are drawn after (usually 0 or 1)
+ * to be sure they are seen, even for overlapping items
+ */
+void WS_DRAW_ITEM_LIST::Draw( EDA_RECT* aClipBox, wxDC* aDC )
+{
+ // The not selected items are drawn first (most of items)
+ for( WS_DRAW_ITEM_BASE* item = GetFirst(); item; item = GetNext() )
+ {
+ if( item->GetParent() && item->GetParent()->IsSelected() )
+ continue;
+
+ item->DrawWsItem( aClipBox, aDC );
+ }
+
+ // The selected items are drawn after (usually 0 or 1)
+ int markerSize = WORKSHEET_DATAITEM::GetMarkerSizeUi();
+
+ for( WS_DRAW_ITEM_BASE* item = GetFirst(); item; item = GetNext() )
+ {
+ if( !item->GetParent() || !item->GetParent()->IsSelected() )
+ continue;
+
+ item->DrawWsItem( aClipBox, aDC );
+
+ switch( item->GetType() )
+ {
+ case WS_DRAW_ITEM_BASE::wsg_line:
+ {
+ WS_DRAW_ITEM_LINE* line = (WS_DRAW_ITEM_LINE*) item;
+
+ if( markerSize )
+ {
+ drawMarker( aClipBox, aDC, line->GetStart(), markerSize );
+ drawMarker( aClipBox, aDC, line->GetEnd(), markerSize, true );
+ }
+ }
+ break;
+
+ case WS_DRAW_ITEM_BASE::wsg_rect:
+ {
+ WS_DRAW_ITEM_RECT* rect = (WS_DRAW_ITEM_RECT*) item;
+
+ if( markerSize )
+ {
+ drawMarker( aClipBox, aDC, rect->GetStart(), markerSize );
+ drawMarker( aClipBox, aDC, rect->GetEnd(), markerSize, true );
+ }
+ }
+ break;
+
+ case WS_DRAW_ITEM_BASE::wsg_text:
+ {
+ WS_DRAW_ITEM_TEXT* text = (WS_DRAW_ITEM_TEXT*) item;
+
+ if( markerSize )
+ drawMarker( aClipBox, aDC, text->GetTextPosition(),
+ markerSize );
+ }
+ break;
+
+ case WS_DRAW_ITEM_BASE::wsg_poly:
+ {
+ WS_DRAW_ITEM_POLYGON* poly = (WS_DRAW_ITEM_POLYGON*) item;
+
+ if( markerSize )
+ {
+ drawMarker( aClipBox, aDC, poly->GetPosition(),
+ markerSize );
+ }
+ }
+ break;
+
+ case WS_DRAW_ITEM_BASE::wsg_bitmap:
+ {
+ WS_DRAW_ITEM_BITMAP* bitmap = (WS_DRAW_ITEM_BITMAP*) item;
+
+ if( markerSize )
+ {
+ drawMarker( aClipBox, aDC, bitmap->GetPosition(),
+ markerSize );
+ }
+ }
+ break;
+ }
+ }
+}
+
+WS_DRAW_ITEM_TEXT::WS_DRAW_ITEM_TEXT( WORKSHEET_DATAITEM* aParent,
+ wxString& aText, wxPoint aPos, wxSize aSize,
+ int aPenWidth, EDA_COLOR_T aColor,
+ bool aItalic, bool aBold ) :
+ WS_DRAW_ITEM_BASE( aParent, wsg_text, aColor ), EDA_TEXT( aText )
+{
+ SetTextPosition( aPos );
+ SetSize( aSize );
+ SetThickness( aPenWidth );
+ SetItalic( aItalic );
+ SetBold( aBold );
+}
+
+void WS_DRAW_ITEM_TEXT::DrawWsItem( EDA_RECT* aClipBox, wxDC* aDC )
+{
+ Draw( aClipBox, aDC, wxPoint(0,0),
+ GetColor(), UNSPECIFIED_DRAWMODE, FILLED, UNSPECIFIED_COLOR );
+}
+
+// return true if the point aPosition is on the text
+bool WS_DRAW_ITEM_TEXT::HitTest( const wxPoint& aPosition) const
+{
+ return EDA_TEXT::TextHitTest( aPosition, 0 );
+}
+
+/* return true if the point aPosition is on the starting point of this item
+ */
+bool WS_DRAW_ITEM_TEXT::HitTestStartPoint( const wxPoint& aPosition)
+{
+ wxPoint pos = GetTextPosition();
+
+ if( std::abs( pos.x - aPosition.x) <= WORKSHEET_DATAITEM::GetMarkerSizeUi()/2 &&
+ std::abs( pos.y - aPosition.y) <= WORKSHEET_DATAITEM::GetMarkerSizeUi()/2 )
+ return true;
+
+ return false;
+}
+
+void WS_DRAW_ITEM_POLYGON::DrawWsItem( EDA_RECT* aClipBox, wxDC* aDC )
+{
+ GRPoly( aClipBox, aDC,
+ m_Corners.size(), &m_Corners[0],
+ IsFilled() ? FILLED_SHAPE : NO_FILL,
+ GetPenWidth(),
+ GetColor(), GetColor() );
+}
+
+// return true if the point aPosition is inside one of polygons
+#include <polygon_test_point_inside.h>
+bool WS_DRAW_ITEM_POLYGON::HitTest( const wxPoint& aPosition) const
+{
+ return TestPointInsidePolygon( &m_Corners[0],
+ m_Corners.size(), aPosition );
+}
+
+/* return true if the point aPosition is on the starting point of this item
+ */
+bool WS_DRAW_ITEM_POLYGON::HitTestStartPoint( const wxPoint& aPosition)
+{
+ wxPoint pos = GetPosition();
+
+ if( std::abs( pos.x - aPosition.x) <= WORKSHEET_DATAITEM::GetMarkerSizeUi()/2 &&
+ std::abs( pos.y - aPosition.y) <= WORKSHEET_DATAITEM::GetMarkerSizeUi()/2 )
+ return true;
+
+ return false;
+}
+
+void WS_DRAW_ITEM_RECT::DrawWsItem( EDA_RECT* aClipBox, wxDC* aDC )
+{
+ GRRect( aClipBox, aDC,
+ GetStart().x, GetStart().y,
+ GetEnd().x, GetEnd().y,
+ GetPenWidth(), GetColor() );
+}
+
+// return true if the point aPosition is on the rect outline
+bool WS_DRAW_ITEM_RECT::HitTest( const wxPoint& aPosition) const
+{
+ int dist = GetPenWidth()/2;
+ wxPoint start = GetStart();
+ wxPoint end;
+ end.x = GetEnd().x;
+ end.y = start.y;
+
+ // Upper line
+ if( TestSegmentHit( aPosition, start, end, dist ) )
+ return true;
+
+ // Right line
+ start = end;
+ end.y = GetEnd().y;
+ if( TestSegmentHit( aPosition, start, end, dist ) )
+ return true;
+
+ // lower line
+ start = end;
+ end.x = GetStart().x;
+ if( TestSegmentHit( aPosition, start, end, dist ) )
+ return true;
+
+ // left line
+ start = end;
+ end = GetStart();
+ if( TestSegmentHit( aPosition, start, end, dist ) )
+ return true;
+
+ return false;
+}
+
+/* return true if the point aPosition is on the starting point of this item
+ */
+bool WS_DRAW_ITEM_RECT::HitTestStartPoint( const wxPoint& aPosition)
+{
+ wxPoint dist = GetStart() - aPosition;
+
+ if( std::abs( dist.x) <= WORKSHEET_DATAITEM::GetMarkerSizeUi()/2 &&
+ std::abs( dist.y) <= WORKSHEET_DATAITEM::GetMarkerSizeUi()/2 )
+ return true;
+
+ return false;
+}
+
+/* return true if the point aPosition is on the ending point of this item
+ */
+bool WS_DRAW_ITEM_RECT::HitTestEndPoint( const wxPoint& aPosition)
+{
+ wxPoint pos = GetEnd();
+
+ int dist = (int) hypot( pos.x - aPosition.x, pos.y - aPosition.y );
+
+ if( dist <= WORKSHEET_DATAITEM::GetMarkerSizeUi()/2 )
+ return true;
+
+ return false;
+}
+
+void WS_DRAW_ITEM_LINE::DrawWsItem( EDA_RECT* aClipBox, wxDC* aDC )
+{
+ GRLine( aClipBox, aDC, GetStart(), GetEnd(),
+ GetPenWidth(), GetColor() );
+}
+
+// return true if the point aPosition is on the text
+bool WS_DRAW_ITEM_LINE::HitTest( const wxPoint& aPosition) const
+{
+ return TestSegmentHit( aPosition, GetStart(), GetEnd(), GetPenWidth()/2 );
+}
+
+/* return true if the point aPosition is on the starting point of this item
+ */
+bool WS_DRAW_ITEM_LINE::HitTestStartPoint( const wxPoint& aPosition)
+{
+ wxPoint dist = GetStart() - aPosition;
+
+ if( std::abs( dist.x) <= WORKSHEET_DATAITEM::GetMarkerSizeUi()/2 &&
+ std::abs( dist.y) <= WORKSHEET_DATAITEM::GetMarkerSizeUi()/2 )
+ return true;
+
+ return false;
+}
+
+/* return true if the point aPosition is on the ending point of this item
+ */
+bool WS_DRAW_ITEM_LINE::HitTestEndPoint( const wxPoint& aPosition)
+{
+ wxPoint dist = GetEnd() - aPosition;
+
+ if( std::abs( dist.x) <= WORKSHEET_DATAITEM::GetMarkerSizeUi()/2 &&
+ std::abs( dist.y) <= WORKSHEET_DATAITEM::GetMarkerSizeUi()/2 )
+ return true;
+
+ return false;
+}
+
+/* Locate graphic items in m_graphicList at location aPosition
+ * aList = the list of items found
+ * aPosition is the position (in user units) to locate items
+ */
+void WS_DRAW_ITEM_LIST::Locate( std::vector <WS_DRAW_ITEM_BASE*>& aList,
+ const wxPoint& aPosition)
+{
+ for( WS_DRAW_ITEM_BASE* item = GetFirst(); item; item = GetNext() )
+ {
+ item->m_Flags &= ~(LOCATE_STARTPOINT|LOCATE_ENDPOINT);
+ bool found = false;
+
+ if( item->HitTestStartPoint ( aPosition ) )
+ {
+ item->m_Flags |= LOCATE_STARTPOINT;
+ found = true;
+ }
+
+ if( item->HitTestEndPoint ( aPosition ) )
+ {
+ item->m_Flags |= LOCATE_ENDPOINT;
+ found = true;
+ }
+
+ if( found || item->HitTest( aPosition ) )
+ {
+ aList.push_back( item );
+ }
+ }
+}
+
+/** The function to draw a WS_DRAW_ITEM_BITMAP
+ */
+void WS_DRAW_ITEM_BITMAP::DrawWsItem( EDA_RECT* aClipBox, wxDC* aDC )
+{
+ WORKSHEET_DATAITEM_BITMAP* parent = (WORKSHEET_DATAITEM_BITMAP*)GetParent();
+
+ if( parent->m_ImageBitmap )
+ {
+ parent->m_ImageBitmap->DrawBitmap( NULL, aDC, m_pos );
+ }
+}
+
+/**
+ * Virtual function
+ * return true if the point aPosition is on bitmap
+ */
+bool WS_DRAW_ITEM_BITMAP::HitTest( const wxPoint& aPosition) const
+{
+ const WORKSHEET_DATAITEM_BITMAP* parent = static_cast<const WORKSHEET_DATAITEM_BITMAP*>( GetParent() );
+
+ if( parent->m_ImageBitmap == NULL )
+ return false;
+
+ EDA_RECT rect = parent->m_ImageBitmap->GetBoundingBox();
+ rect.Move( m_pos );
+ return rect.Contains( aPosition );
+}
+
+
+/**
+ * return true if the point aPosition is on the reference point of this item.
+ */
+bool WS_DRAW_ITEM_BITMAP::HitTestStartPoint( const wxPoint& aPosition)
+{
+ wxPoint dist = m_pos - aPosition;
+
+ if( std::abs( dist.x) <= WORKSHEET_DATAITEM::GetMarkerSizeUi()/2 &&
+ std::abs( dist.y) <= WORKSHEET_DATAITEM::GetMarkerSizeUi()/2 )
+ return true;
+
+ return false;
+}
+
diff --git a/common/page_layout/page_layout_reader.cpp b/common/page_layout/page_layout_reader.cpp
new file mode 100644
index 0000000..a282989
--- /dev/null
+++ b/common/page_layout/page_layout_reader.cpp
@@ -0,0 +1,875 @@
+/**
+ * @file common/page_layout/page_layout_reader.cpp
+ * @brief read an S expression of description of graphic items and texts
+ * to build a title block and page layout
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2013 Jean-Pierre Charras <jp.charras at wanadoo.fr>.
+ * Copyright (C) 1992-2013 KiCad Developers, see change_log.txt for contributors.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <fctsys.h>
+#include <base_struct.h>
+#include <worksheet.h>
+#include <worksheet_shape_builder.h>
+#include <class_worksheet_dataitem.h>
+#include <page_layout_reader_lexer.h>
+
+
+using namespace TB_READER_T;
+
+/**
+ * Class PAGE_LAYOUT_READER_PARSER
+ * holds data and functions pertinent to parsing a S-expression file
+ * for a WORKSHEET_LAYOUT.
+ */
+class PAGE_LAYOUT_READER_PARSER : public PAGE_LAYOUT_READER_LEXER
+{
+public:
+ PAGE_LAYOUT_READER_PARSER( const char* aLine, const wxString& aSource );
+ void Parse( WORKSHEET_LAYOUT* aLayout )
+ throw( PARSE_ERROR, IO_ERROR );
+
+private:
+
+ /**
+ * Function parseInt
+ * parses an integer and constrains it between two values.
+ * @param aMin is the smallest return value.
+ * @param aMax is the largest return value.
+ * @return int - the parsed integer.
+ */
+ int parseInt( int aMin, int aMax );
+
+ /**
+ * Function parseDouble
+ * parses a double
+ * @return double - the parsed double.
+ */
+ double parseDouble();
+
+ void parseSetup( WORKSHEET_LAYOUT* aLayout ) throw( IO_ERROR, PARSE_ERROR );
+
+ /**
+ * parse a graphic item starting by "(line" or "(rect" and read parameters.
+ */
+ void parseGraphic( WORKSHEET_DATAITEM * aItem ) throw( IO_ERROR, PARSE_ERROR );
+
+ /**
+ * parse a text item starting by "(tbtext" and read parameters.
+ */
+ void parseText( WORKSHEET_DATAITEM_TEXT * aItem ) throw( IO_ERROR, PARSE_ERROR );
+
+ /**
+ * parse a polygon item starting by "( polygon" and read parameters.
+ * the list of corners included in this description is read by parsePolyOutline
+ */
+ void parsePolygon( WORKSHEET_DATAITEM_POLYPOLYGON * aItem )
+ throw( IO_ERROR, PARSE_ERROR );
+
+ /**
+ * parse a list of corners starting by "( pts" and read coordinates.
+ */
+ void parsePolyOutline( WORKSHEET_DATAITEM_POLYPOLYGON * aItem )
+ throw( IO_ERROR, PARSE_ERROR );
+
+
+ /**
+ * parse a bitmap item starting by "( bitmap" and read parameters.
+ */
+ void parseBitmap( WORKSHEET_DATAITEM_BITMAP * aItem )
+ throw( IO_ERROR, PARSE_ERROR );
+
+ void parseCoordinate( POINT_COORD& aCoord) throw( IO_ERROR, PARSE_ERROR );
+ void readOption( WORKSHEET_DATAITEM * aItem ) throw( IO_ERROR, PARSE_ERROR );
+ void readPngdata( WORKSHEET_DATAITEM_BITMAP * aItem ) throw( IO_ERROR, PARSE_ERROR );
+};
+
+// PCB_PLOT_PARAMS_PARSER
+
+PAGE_LAYOUT_READER_PARSER::PAGE_LAYOUT_READER_PARSER( const char* aLine, const wxString& aSource ) :
+ PAGE_LAYOUT_READER_LEXER( aLine, aSource )
+{
+}
+
+
+void PAGE_LAYOUT_READER_PARSER::Parse( WORKSHEET_LAYOUT* aLayout )
+ throw( PARSE_ERROR, IO_ERROR )
+{
+ T token;
+ WORKSHEET_DATAITEM * item;
+
+ LOCALE_IO toggle;
+
+ while( ( token = NextTok() ) != T_RIGHT )
+ {
+ if( token == T_EOF)
+ break;
+
+ if( token == T_LEFT )
+ token = NextTok();
+
+ if( token == T_page_layout )
+ continue;
+
+ switch( token )
+ {
+ case T_setup: // Defines default values for graphic items
+ parseSetup( aLayout );
+ break;
+
+ case T_line:
+ item = new WORKSHEET_DATAITEM( WORKSHEET_DATAITEM::WS_SEGMENT );
+ parseGraphic( item );
+ aLayout->Append( item );
+ break;
+
+ case T_rect:
+ item = new WORKSHEET_DATAITEM( WORKSHEET_DATAITEM::WS_RECT );
+ parseGraphic( item );
+ aLayout->Append( item );
+ break;
+
+ case T_polygon:
+ item = new WORKSHEET_DATAITEM_POLYPOLYGON();
+ parsePolygon( (WORKSHEET_DATAITEM_POLYPOLYGON*) item );
+ aLayout->Append( item );
+ break;
+
+ case T_bitmap:
+ item = new WORKSHEET_DATAITEM_BITMAP( NULL );
+ parseBitmap( (WORKSHEET_DATAITEM_BITMAP*) item );
+ aLayout->Append( item );
+ break;
+
+ case T_tbtext:
+ NeedSYMBOLorNUMBER();
+ item = new WORKSHEET_DATAITEM_TEXT( FromUTF8() );
+ parseText( (WORKSHEET_DATAITEM_TEXT*) item );
+ aLayout->Append( item );
+ break;
+
+ default:
+ Unexpected( CurText() );
+ break;
+ }
+ }
+}
+
+void PAGE_LAYOUT_READER_PARSER::parseSetup( WORKSHEET_LAYOUT* aLayout )
+ throw( IO_ERROR, PARSE_ERROR )
+{
+ T token;
+ while( ( token = NextTok() ) != T_RIGHT )
+ {
+ if( token == T_EOF)
+ break;
+
+ switch( token )
+ {
+ case T_LEFT:
+ break;
+
+ case T_linewidth:
+ WORKSHEET_DATAITEM::m_DefaultLineWidth = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_textsize:
+ WORKSHEET_DATAITEM::m_DefaultTextSize.x = parseDouble();
+ WORKSHEET_DATAITEM::m_DefaultTextSize.y = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_textlinewidth:
+ WORKSHEET_DATAITEM::m_DefaultTextThickness = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_left_margin:
+ aLayout->SetLeftMargin( parseDouble() );
+ NeedRIGHT();
+ break;
+
+ case T_right_margin:
+ aLayout->SetRightMargin( parseDouble() );
+ NeedRIGHT();
+ break;
+
+ case T_top_margin:
+ aLayout->SetTopMargin( parseDouble() );
+ NeedRIGHT();
+ break;
+
+ case T_bottom_margin:
+ aLayout->SetBottomMargin( parseDouble() );
+ NeedRIGHT();
+ break;
+
+ default:
+ Unexpected( CurText() );
+ break;
+ }
+ }
+}
+
+void PAGE_LAYOUT_READER_PARSER::parsePolygon( WORKSHEET_DATAITEM_POLYPOLYGON * aItem )
+ throw( IO_ERROR, PARSE_ERROR )
+{
+ T token;
+
+ while( ( token = NextTok() ) != T_RIGHT )
+ {
+ if( token == T_EOF)
+ break;
+
+ if( token == T_LEFT )
+ token = NextTok();
+
+ switch( token )
+ {
+ case T_comment:
+ NeedSYMBOLorNUMBER();
+ aItem->m_Info = FromUTF8();
+ NeedRIGHT();
+ break;
+
+ case T_pos:
+ parseCoordinate( aItem->m_Pos );
+ break;
+
+ case T_name:
+ NeedSYMBOLorNUMBER();
+ aItem->m_Name = FromUTF8();
+ NeedRIGHT();
+ break;
+
+ case T_option:
+ readOption( aItem );
+ break;
+
+ case T_pts:
+ parsePolyOutline( aItem );
+ aItem->CloseContour();
+ break;
+
+ case T_rotate:
+ aItem->m_Orient = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_repeat:
+ aItem->m_RepeatCount = parseInt( -1, 100 );
+ NeedRIGHT();
+ break;
+
+ case T_incrx:
+ aItem->m_IncrementVector.x = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_incry:
+ aItem->m_IncrementVector.y = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_linewidth:
+ aItem->m_LineWidth = parseDouble();
+ NeedRIGHT();
+ break;
+
+ default:
+ Unexpected( CurText() );
+ break;
+ }
+ }
+
+ aItem->SetBoundingBox();
+}
+
+void PAGE_LAYOUT_READER_PARSER::parsePolyOutline( WORKSHEET_DATAITEM_POLYPOLYGON * aItem )
+ throw( IO_ERROR, PARSE_ERROR )
+{
+ DPOINT corner;
+ T token;
+
+ while( ( token = NextTok() ) != T_RIGHT )
+ {
+ if( token == T_EOF)
+ break;
+
+ if( token == T_LEFT )
+ token = NextTok();
+
+ switch( token )
+ {
+ case T_xy:
+ corner.x = parseDouble();
+ corner.y = parseDouble();
+ aItem->AppendCorner( corner );
+ NeedRIGHT();
+ break;
+
+ default:
+ Unexpected( CurText() );
+ break;
+ }
+ }
+}
+
+#include <wx/mstream.h>
+void PAGE_LAYOUT_READER_PARSER::parseBitmap( WORKSHEET_DATAITEM_BITMAP * aItem )
+ throw( IO_ERROR, PARSE_ERROR )
+{
+ T token;
+ BITMAP_BASE* image = new BITMAP_BASE;
+ aItem->m_ImageBitmap = image;
+
+ while( ( token = NextTok() ) != T_RIGHT )
+ {
+ if( token == T_EOF)
+ break;
+
+ if( token == T_LEFT )
+ token = NextTok();
+
+ switch( token )
+ {
+ case T_name:
+ NeedSYMBOLorNUMBER();
+ aItem->m_Name = FromUTF8();
+ NeedRIGHT();
+ break;
+
+ case T_pos:
+ parseCoordinate( aItem->m_Pos );
+ break;
+
+ case T_repeat:
+ aItem->m_RepeatCount = parseInt( -1, 100 );
+ NeedRIGHT();
+ break;
+
+ case T_incrx:
+ aItem->m_IncrementVector.x = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_incry:
+ aItem->m_IncrementVector.y = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_linewidth:
+ aItem->m_LineWidth = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_scale:
+ aItem->m_ImageBitmap->m_Scale = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_pngdata:
+ readPngdata( aItem );
+ break;
+
+ case T_option:
+ readOption( aItem );
+ break;
+
+ default:
+ Unexpected( CurText() );
+ break;
+ }
+ }
+}
+
+void PAGE_LAYOUT_READER_PARSER::readPngdata( WORKSHEET_DATAITEM_BITMAP * aItem )
+ throw( IO_ERROR, PARSE_ERROR )
+{
+ std::string tmp;
+ T token;
+
+ while( ( token = NextTok() ) != T_RIGHT )
+ {
+ if( token == T_EOF)
+ break;
+
+ if( token == T_LEFT )
+ token = NextTok();
+
+ switch( token )
+ {
+ case T_data:
+ NeedSYMBOLorNUMBER();
+ tmp += CurStr();
+ tmp += "\n";
+ NeedRIGHT();
+ break;
+
+ default:
+ Unexpected( CurText() );
+ break;
+ }
+ }
+
+ tmp += "EndData";
+
+ wxString msg;
+ STRING_LINE_READER reader( tmp, wxT("Png kicad_wks data") );
+ if( ! aItem->m_ImageBitmap->LoadData( reader, msg ) )
+ {
+ wxLogMessage(msg);
+ }
+}
+
+
+void PAGE_LAYOUT_READER_PARSER::readOption( WORKSHEET_DATAITEM * aItem )
+ throw( IO_ERROR, PARSE_ERROR )
+{
+ T token;
+
+ while( ( token = NextTok() ) != T_RIGHT )
+ {
+ if( token == T_EOF)
+ break;
+
+ switch( token )
+ {
+ case T_page1only:
+ aItem->SetPage1Option( 1 );
+ break;
+
+ case T_notonpage1:
+ aItem->SetPage1Option( -1 );
+ break;
+
+ default:
+ Unexpected( CurText() );
+ break;
+ }
+ }
+}
+
+
+void PAGE_LAYOUT_READER_PARSER::parseGraphic( WORKSHEET_DATAITEM * aItem )
+ throw( IO_ERROR, PARSE_ERROR )
+{
+ T token;
+
+ while( ( token = NextTok() ) != T_RIGHT )
+ {
+ if( token == T_EOF)
+ break;
+
+ if( token == T_LEFT )
+ token = NextTok();
+ else
+ {
+ // If an other token than T_LEFT is read here, this is an error
+ // however, due to a old bug in kicad, the token T_end can be found
+ // without T_LEFT in a very few .wks files (perhaps only one in a demo).
+ // So this ugly hack disables the error detection.
+ if( token != T_end )
+ Unexpected( CurText() );
+ }
+
+ switch( token )
+ {
+ case T_comment:
+ NeedSYMBOLorNUMBER();
+ aItem->m_Info = FromUTF8();
+ NeedRIGHT();
+ break;
+
+ case T_option:
+ readOption( aItem );
+ break;
+
+ case T_name:
+ NeedSYMBOLorNUMBER();
+ aItem->m_Name = FromUTF8();
+ NeedRIGHT();
+ break;
+
+ case T_start:
+ parseCoordinate( aItem->m_Pos );
+ break;
+
+ case T_end:
+ parseCoordinate( aItem->m_End );
+ break;
+
+ case T_repeat:
+ aItem->m_RepeatCount = parseInt( -1, 100 );
+ NeedRIGHT();
+ break;
+
+ case T_incrx:
+ aItem->m_IncrementVector.x = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_incry:
+ aItem->m_IncrementVector.y = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_linewidth:
+ aItem->m_LineWidth = parseDouble();
+ NeedRIGHT();
+ break;
+
+ default:
+ Unexpected( CurText() );
+ break;
+ }
+ }
+}
+
+
+void PAGE_LAYOUT_READER_PARSER::parseText( WORKSHEET_DATAITEM_TEXT* aItem )
+ throw( IO_ERROR, PARSE_ERROR )
+{
+ T token;
+
+ while( ( token = NextTok() ) != T_RIGHT )
+ {
+ if( token == T_EOF)
+ break;
+
+ if( token == T_LEFT )
+ token = NextTok();
+
+ switch( token )
+ {
+ case T_comment:
+ NeedSYMBOLorNUMBER();
+ aItem->m_Info = FromUTF8();
+ NeedRIGHT();
+ break;
+
+ case T_option:
+ readOption( aItem );
+ break;
+
+ case T_name:
+ NeedSYMBOLorNUMBER();
+ aItem->m_Name = FromUTF8();
+ NeedRIGHT();
+ break;
+
+ case T_pos:
+ parseCoordinate( aItem->m_Pos );
+ break;
+
+ case T_repeat:
+ aItem->m_RepeatCount = parseInt( -1, 100 );
+ NeedRIGHT();
+ break;
+
+ case T_incrx:
+ aItem->m_IncrementVector.x = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_incry:
+ aItem->m_IncrementVector.y = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_incrlabel:
+ aItem->m_IncrementLabel = parseInt(INT_MIN, INT_MAX);
+ NeedRIGHT();
+ break;
+
+ case T_maxlen:
+ aItem->m_BoundingBoxSize.x = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_maxheight:
+ aItem->m_BoundingBoxSize.y = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_font:
+ while( ( token = NextTok() ) != T_RIGHT )
+ {
+ if( token == T_EOF)
+ break;
+
+ switch( token )
+ {
+ case T_LEFT:
+ break;
+
+ case T_bold:
+ aItem->SetBold( true );
+ break;
+
+ case T_italic:
+ aItem->SetItalic( true );
+ break;
+
+ case T_size:
+ aItem->m_TextSize.x = parseDouble();
+ aItem->m_TextSize.y = parseDouble();
+ NeedRIGHT();
+ break;
+
+ case T_linewidth:
+ aItem->m_LineWidth = parseDouble();
+ NeedRIGHT();
+ break;
+
+ default:
+ Unexpected( CurText() );
+ break;
+ }
+ }
+ break;
+
+ case T_justify:
+ while( ( token = NextTok() ) != T_RIGHT )
+ {
+ if( token == T_EOF)
+ break;
+
+ switch( token )
+ {
+ case T_center:
+ aItem->m_Hjustify = GR_TEXT_HJUSTIFY_CENTER;
+ aItem->m_Vjustify = GR_TEXT_VJUSTIFY_CENTER;
+ break;
+
+ case T_left:
+ aItem->m_Hjustify = GR_TEXT_HJUSTIFY_LEFT;
+ break;
+
+ case T_right:
+ aItem->m_Hjustify = GR_TEXT_HJUSTIFY_RIGHT;
+ break;
+
+ case T_top:
+ aItem->m_Vjustify = GR_TEXT_VJUSTIFY_TOP;
+ break;
+
+ case T_bottom:
+ aItem->m_Vjustify = GR_TEXT_VJUSTIFY_BOTTOM;
+ break;
+
+ default:
+ Unexpected( CurText() );
+ break;
+ }
+ }
+ break;
+
+ case T_rotate:
+ aItem->m_Orient = parseDouble();
+ NeedRIGHT();
+ break;
+
+ default:
+ Unexpected( CurText() );
+ break;
+ }
+ }
+}
+
+// parse an expression like " 25 1 ltcorner)"
+void PAGE_LAYOUT_READER_PARSER::parseCoordinate( POINT_COORD& aCoord)
+ throw( IO_ERROR, PARSE_ERROR )
+{
+ T token;
+
+ aCoord.m_Pos.x = parseDouble();
+ aCoord.m_Pos.y = parseDouble();
+
+ while( ( token = NextTok() ) != T_RIGHT )
+ {
+ switch( token )
+ {
+ case T_ltcorner:
+ aCoord.m_Anchor = LT_CORNER; // left top corner
+ break;
+
+ case T_lbcorner:
+ aCoord.m_Anchor = LB_CORNER; // left bottom corner
+ break;
+
+ case T_rbcorner:
+ aCoord.m_Anchor = RB_CORNER; // right bottom corner
+ break;
+
+ case T_rtcorner:
+ aCoord.m_Anchor = RT_CORNER; // right top corner
+ break;
+
+ default:
+ Unexpected( CurText() );
+ break;
+ }
+ }
+}
+
+int PAGE_LAYOUT_READER_PARSER::parseInt( int aMin, int aMax )
+{
+ T token = NextTok();
+
+ if( token != T_NUMBER )
+ Expecting( T_NUMBER );
+
+ int val = atoi( CurText() );
+
+ if( val < aMin )
+ val = aMin;
+ else if( val > aMax )
+ val = aMax;
+
+ return val;
+}
+
+
+double PAGE_LAYOUT_READER_PARSER::parseDouble()
+{
+ T token = NextTok();
+
+ if( token != T_NUMBER )
+ Expecting( T_NUMBER );
+
+ double val = strtod( CurText(), NULL );
+
+ return val;
+}
+
+// defaultPageLayout is the default page layout description
+// using the S expr.
+// see page_layout_default_shape.cpp
+extern const char defaultPageLayout[];
+
+void WORKSHEET_LAYOUT::SetDefaultLayout()
+{
+ ClearList();
+ PAGE_LAYOUT_READER_PARSER lp_parser( defaultPageLayout, wxT( "default page" ) );
+
+ try
+ {
+ lp_parser.Parse( this );
+ }
+ catch( const IO_ERROR& ioe )
+ {
+ wxLogMessage( ioe.errorText );
+ }
+}
+
+/**
+ * Populates the list from a S expr description stored in a string
+ * @param aPageLayout = the S expr string
+ */
+void WORKSHEET_LAYOUT::SetPageLayout( const char* aPageLayout, bool Append )
+{
+ if( ! Append )
+ ClearList();
+
+ PAGE_LAYOUT_READER_PARSER lp_parser( aPageLayout, wxT( "Sexpr_string" ) );
+
+ try
+ {
+ lp_parser.Parse( this );
+ }
+ catch( const IO_ERROR& ioe )
+ {
+ wxLogMessage( ioe.errorText );
+ }
+}
+
+#include <wx/file.h>
+
+// SetLayout() try to load the aFullFileName custom layout file,
+// if aFullFileName is empty, try the filename defined by the
+// environment variable KICAD_WKSFILE (a *.kicad_wks filename).
+// if does not exists, loads the default page layout.
+void WORKSHEET_LAYOUT::SetPageLayout( const wxString& aFullFileName, bool Append )
+{
+ wxString fullFileName = aFullFileName;
+
+ if( !Append )
+ {
+ if( fullFileName.IsEmpty() )
+ wxGetEnv( wxT( "KICAD_WKSFILE" ), &fullFileName );
+
+ if( fullFileName.IsEmpty() || !wxFileExists( fullFileName ) )
+ {
+ #if 0
+ if( !fullFileName.IsEmpty() )
+ {
+ wxLogMessage( wxT("Page layout file <%s> not found"),
+ fullFileName.GetData() );
+ }
+ #endif
+ SetDefaultLayout();
+ return;
+ }
+ }
+
+ wxFile wksFile( fullFileName );
+
+ if( ! wksFile.IsOpened() )
+ {
+ if( !Append )
+ SetDefaultLayout();
+ return;
+ }
+
+ int filelen = wksFile.Length();
+ char * buffer = new char[filelen+10];
+
+ if( wksFile.Read( buffer, filelen ) != filelen )
+ wxLogMessage( _("The file <%s> was not fully read"),
+ fullFileName.GetData() );
+ else
+ {
+ buffer[filelen]=0;
+
+ if( ! Append )
+ ClearList();
+
+ PAGE_LAYOUT_READER_PARSER pl_parser( buffer, fullFileName );
+
+ try
+ {
+ pl_parser.Parse( this );
+ }
+ catch( const IO_ERROR& ioe )
+ {
+ wxLogMessage( ioe.errorText );
+ }
+ }
+
+ delete[] buffer;
+}
+
diff --git a/common/page_layout/page_layout_reader.keywords b/common/page_layout/page_layout_reader.keywords
new file mode 100644
index 0000000..625dd59
--- /dev/null
+++ b/common/page_layout/page_layout_reader.keywords
@@ -0,0 +1,48 @@
+page_layout
+setup
+left_margin
+right_margin
+top_margin
+bottom_margin
+linewidth
+textlinewidth
+textsize
+comment
+option
+page1only
+notonpage1
+line
+rect
+polygon
+bitmap
+tbtext
+ltcorner
+lbcorner
+rbcorner
+rtcorner
+name
+pos
+start
+end
+scale
+pngdata
+data
+pts
+xy
+maxlen
+maxheight
+font
+bold
+italic
+size
+justify
+left
+center
+right
+top
+bottom
+rotate
+repeat
+incrx
+incry
+incrlabel
diff --git a/common/page_layout/title_block_shapes.cpp b/common/page_layout/title_block_shapes.cpp
new file mode 100644
index 0000000..c7a8385
--- /dev/null
+++ b/common/page_layout/title_block_shapes.cpp
@@ -0,0 +1,258 @@
+/**
+ * @file title_block_shapes.cpp
+ * @brief description of graphic items and texts to build a title block
+ */
+
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 1992-2013 Jean-Pierre Charras <jp.charras at wanadoo.fr>.
+ * Copyright (C) 1992-2013 KiCad Developers, see change_log.txt for contributors.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+
+/*
+ * the class WORKSHEET_DATAITEM (and WORKSHEET_DATAITEM_TEXT) defines
+ * a basic shape of a page layout ( frame references and title block )
+ * Basic shapes are line, rect and texts
+ * the WORKSHEET_DATAITEM coordinates units is the mm, and are relative to
+ * one of 4 page corners.
+ *
+ * These items cannot be drawn or plot "as this". they should be converted
+ * to a "draw list" (WS_DRAW_ITEM_BASE and derived items)
+
+ * The list of these items is stored in a WORKSHEET_LAYOUT instance.
+ *
+ * When building the draw list:
+ * the WORKSHEET_LAYOUT is used to create a WS_DRAW_ITEM_LIST
+ * coordinates are converted to draw/plot coordinates.
+ * texts are expanded if they contain format symbols.
+ * Items with m_RepeatCount > 1 are created m_RepeatCount times
+ *
+ * the WORKSHEET_LAYOUT is created only once.
+ * the WS_DRAW_ITEM_LIST is created each time the page layout is plot/drawn
+ *
+ * the WORKSHEET_LAYOUT instance is created from a S expression which
+ * describes the page layout (can be the default page layout or a custom file).
+ */
+
+#include <fctsys.h>
+#include <drawtxt.h>
+#include <class_page_info.h>
+#include <worksheet.h>
+#include <class_title_block.h>
+#include <worksheet_shape_builder.h>
+#include <class_worksheet_dataitem.h>
+
+
+void WS_DRAW_ITEM_LIST::BuildWorkSheetGraphicList(
+ const PAGE_INFO& aPageInfo,
+ const TITLE_BLOCK& aTitleBlock,
+ EDA_COLOR_T aColor, EDA_COLOR_T aAltColor )
+{
+ WORKSHEET_LAYOUT& pglayout = WORKSHEET_LAYOUT::GetTheInstance();
+
+ #define milsTomm (25.4/1000)
+
+ m_titleBlock = &aTitleBlock;
+ m_paperFormat = &aPageInfo.GetType();
+
+ wxPoint LTmargin( Mm2mils( pglayout.GetLeftMargin() ),
+ Mm2mils( pglayout.GetTopMargin() ) );
+ wxPoint RBmargin( Mm2mils( pglayout.GetRightMargin() ),
+ Mm2mils( pglayout.GetBottomMargin() ) );
+
+ SetMargins( LTmargin, RBmargin );
+ SetPageSize( aPageInfo.GetSizeMils() );
+
+ // Build the basic layout shape, if the layout list is empty
+ if( pglayout.GetCount() == 0 && !pglayout.VoidListAllowed() )
+ pglayout.SetPageLayout();
+
+ WORKSHEET_DATAITEM::m_WSunits2Iu = m_milsToIu / milsTomm;
+ WORKSHEET_DATAITEM::m_Color = aColor; // the default color to draw items
+ WORKSHEET_DATAITEM::m_AltColor = aAltColor; // an alternate color to draw items
+
+ // Left top corner position
+ DPOINT lt_corner;
+ lt_corner.x = pglayout.GetLeftMargin();
+ lt_corner.y = pglayout.GetTopMargin();
+ WORKSHEET_DATAITEM::m_LT_Corner = lt_corner;
+
+ // Right bottom corner position
+ DPOINT rb_corner;
+ rb_corner.x = (m_pageSize.x*milsTomm) - pglayout.GetRightMargin();
+ rb_corner.y = (m_pageSize.y*milsTomm) - pglayout.GetBottomMargin();
+ WORKSHEET_DATAITEM::m_RB_Corner = rb_corner;
+
+ WS_DRAW_ITEM_TEXT* gtext;
+ int pensize;
+
+ for( unsigned ii = 0; ; ii++ )
+ {
+ WORKSHEET_DATAITEM* wsItem = pglayout.GetItem( ii );
+
+ if( wsItem == NULL )
+ break;
+
+ // Generate it only if the page option allows this
+ if( wsItem->GetPage1Option() < 0 // Not on page 1
+ && m_sheetNumber <= 1 )
+ continue;
+
+ if( wsItem->GetPage1Option() > 0 // Only on page 1
+ && m_sheetNumber > 1 )
+ continue;
+
+ EDA_COLOR_T color = wsItem->GetItemColor();
+
+ pensize = wsItem->GetPenSizeUi();
+
+ switch( wsItem->GetType() )
+ {
+ case WORKSHEET_DATAITEM::WS_TEXT:
+ {
+ WORKSHEET_DATAITEM_TEXT * wsText = (WORKSHEET_DATAITEM_TEXT*)wsItem;
+ bool multilines = false;
+
+ if( wsText->m_SpecialMode )
+ wsText->m_FullText = wsText->m_TextBase;
+ else
+ {
+ wsText->m_FullText = BuildFullText( wsText->m_TextBase );
+ multilines = wsText->ReplaceAntiSlashSequence();
+ }
+
+ if( wsText->m_FullText.IsEmpty() )
+ break;
+
+ if( pensize == 0 )
+ pensize = m_penSize;
+
+ wsText->SetConstrainedTextSize();
+ wxSize textsize;
+
+ textsize.x = KiROUND( wsText->m_ConstrainedTextSize.x
+ * WORKSHEET_DATAITEM::m_WSunits2Iu );
+ textsize.y = KiROUND( wsText->m_ConstrainedTextSize.y
+ * WORKSHEET_DATAITEM::m_WSunits2Iu );
+
+ if( wsText->IsBold())
+ pensize = GetPenSizeForBold( std::min( textsize.x, textsize.y ) );
+
+ for( int jj = 0; jj < wsText->m_RepeatCount; jj++)
+ {
+ if( jj && ! wsText->IsInsidePage( jj ) )
+ continue;
+
+ Append( gtext = new WS_DRAW_ITEM_TEXT( wsText, wsText->m_FullText,
+ wsText->GetStartPosUi( jj ),
+ textsize,
+ pensize, color,
+ wsText->IsItalic(),
+ wsText->IsBold() ) );
+ gtext->SetMultilineAllowed( multilines );
+ wsText->TransfertSetupToGraphicText( gtext );
+
+ // Increment label for the next text
+ // (has no meaning for multiline texts)
+ if( wsText->m_RepeatCount > 1 && !multilines )
+ wsText->IncrementLabel( (jj+1)*wsText->m_IncrementLabel);
+ }
+ }
+ break;
+
+ case WORKSHEET_DATAITEM::WS_SEGMENT:
+ if( pensize == 0 )
+ pensize = m_penSize;
+
+ for( int jj = 0; jj < wsItem->m_RepeatCount; jj++ )
+ {
+ if( jj && ! wsItem->IsInsidePage( jj ) )
+ continue;
+ Append( new WS_DRAW_ITEM_LINE( wsItem, wsItem->GetStartPosUi( jj ),
+ wsItem->GetEndPosUi( jj ),
+ pensize, color ) );
+ }
+ break;
+
+ case WORKSHEET_DATAITEM::WS_RECT:
+ if( pensize == 0 )
+ pensize = m_penSize;
+
+ for( int jj = 0; jj < wsItem->m_RepeatCount; jj++ )
+ {
+ if( jj && ! wsItem->IsInsidePage( jj ) )
+ break;
+
+ Append( new WS_DRAW_ITEM_RECT( wsItem, wsItem->GetStartPosUi( jj ),
+ wsItem->GetEndPosUi( jj ),
+ pensize, color ) );
+ }
+ break;
+
+ case WORKSHEET_DATAITEM::WS_POLYPOLYGON:
+ {
+ WORKSHEET_DATAITEM_POLYPOLYGON * wspoly =
+ (WORKSHEET_DATAITEM_POLYPOLYGON*) wsItem;
+ for( int jj = 0; jj < wsItem->m_RepeatCount; jj++ )
+ {
+ if( jj && ! wsItem->IsInsidePage( jj ) )
+ continue;
+
+ for( int kk = 0; kk < wspoly->GetPolyCount(); kk++ )
+ {
+ const bool fill = true;
+ WS_DRAW_ITEM_POLYGON* poly = new WS_DRAW_ITEM_POLYGON( wspoly,
+ wspoly->GetStartPosUi( jj ),
+ fill, pensize, color );
+ Append( poly );
+
+ // Create polygon outline
+ unsigned ist = wspoly->GetPolyIndexStart( kk );
+ unsigned iend = wspoly->GetPolyIndexEnd( kk );
+ while( ist <= iend )
+ poly->m_Corners.push_back(
+ wspoly->GetCornerPositionUi( ist++, jj ) );
+
+ }
+ }
+ }
+ break;
+
+ case WORKSHEET_DATAITEM::WS_BITMAP:
+
+ ((WORKSHEET_DATAITEM_BITMAP*)wsItem)->SetPixelScaleFactor();
+
+ for( int jj = 0; jj < wsItem->m_RepeatCount; jj++ )
+ {
+ if( jj && ! wsItem->IsInsidePage( jj ) )
+ continue;
+
+ Append( new WS_DRAW_ITEM_BITMAP( wsItem,
+ wsItem->GetStartPosUi( jj ) ) );
+ }
+ break;
+
+ }
+ }
+}
+