diff options
Diffstat (limited to 'common/page_layout')
-rw-r--r-- | common/page_layout/class_worksheet_dataitem.cpp | 577 | ||||
-rw-r--r-- | common/page_layout/class_worksheet_layout.cpp | 248 | ||||
-rw-r--r-- | common/page_layout/page_layout_default_description.cpp | 164 | ||||
-rw-r--r-- | common/page_layout/page_layout_graphic_items.cpp | 423 | ||||
-rw-r--r-- | common/page_layout/page_layout_reader.cpp | 875 | ||||
-rw-r--r-- | common/page_layout/page_layout_reader.keywords | 48 | ||||
-rw-r--r-- | common/page_layout/title_block_shapes.cpp | 258 |
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; + + } + } +} + |