779 lines
21 KiB
C++
779 lines
21 KiB
C++
/*
|
|
* 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-2023 KiCad Developers, see AUTHORS.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 DS_DATA_ITEM (and derived) defines
|
|
* a basic shape of a drawing sheet (frame references and title block)
|
|
* Basic shapes are line, rect and texts
|
|
* the DS_DATA_ITEM 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" (DS_DRAW_ITEM_BASE and derived items)
|
|
|
|
* The list of these items is stored in a DS_DATA_MODEL instance.
|
|
*
|
|
* When building the draw list:
|
|
* the DS_DATA_MODEL is used to create a DS_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 DS_DATA_MODEL is created only once.
|
|
* the DS_DRAW_ITEM_LIST is created each time the drawing sheet is plotted/drawn
|
|
*
|
|
* the DS_DATA_MODEL instance is created from a S expression which
|
|
* describes the drawing sheet (can be the default drawing sheet or a custom file).
|
|
*/
|
|
|
|
#include <gr_text.h>
|
|
#include <math/util.h> // for KiROUND
|
|
#include <view/view.h>
|
|
#include <title_block.h>
|
|
#include <drawing_sheet/ds_data_model.h>
|
|
#include <drawing_sheet/ds_data_item.h>
|
|
#include <drawing_sheet/ds_draw_item.h>
|
|
#include <drawing_sheet/ds_painter.h>
|
|
#include <trigo.h>
|
|
|
|
using KIGFX::COLOR4D;
|
|
|
|
|
|
DS_DATA_ITEM::DS_DATA_ITEM( DS_ITEM_TYPE aType )
|
|
{
|
|
m_pageOption = ALL_PAGES;
|
|
m_type = aType;
|
|
m_RepeatCount = 1;
|
|
m_IncrementLabel = 1;
|
|
m_LineWidth = 0;
|
|
}
|
|
|
|
|
|
DS_DATA_ITEM::~DS_DATA_ITEM()
|
|
{
|
|
for( DS_DRAW_ITEM_BASE* item : m_drawItems )
|
|
delete item;
|
|
}
|
|
|
|
|
|
void DS_DATA_ITEM::SyncDrawItems( DS_DRAW_ITEM_LIST* aCollector, KIGFX::VIEW* aView )
|
|
{
|
|
int pensize = GetPenSizeIU();
|
|
|
|
if( pensize == 0 )
|
|
pensize = aCollector ? aCollector->GetDefaultPenSize() : 0;
|
|
|
|
std::map<size_t, EDA_ITEM_FLAGS> itemFlags;
|
|
DS_DRAW_ITEM_BASE* item = nullptr;
|
|
|
|
for( size_t i = 0; i < m_drawItems.size(); ++i )
|
|
{
|
|
item = m_drawItems[ i ];
|
|
itemFlags[ i ] = item->GetFlags();
|
|
|
|
if( aCollector )
|
|
aCollector->Remove( item );
|
|
|
|
if( aView )
|
|
aView->Remove( item );
|
|
|
|
delete item;
|
|
}
|
|
|
|
m_drawItems.clear();
|
|
|
|
for( int j = 0; j < m_RepeatCount; j++ )
|
|
{
|
|
if( j > 0 && !IsInsidePage( j ) )
|
|
continue;
|
|
|
|
if( m_type == DS_SEGMENT )
|
|
item = new DS_DRAW_ITEM_LINE( this, j, GetStartPosIU( j ), GetEndPosIU( j ), pensize );
|
|
else if( m_type == DS_RECT )
|
|
item = new DS_DRAW_ITEM_RECT( this, j, GetStartPosIU( j ), GetEndPosIU( j ), pensize );
|
|
else
|
|
{
|
|
wxFAIL_MSG( wxS( "Unknown drawing sheet item type" ) );
|
|
continue;
|
|
}
|
|
|
|
item->SetFlags( itemFlags[ j ] );
|
|
m_drawItems.push_back( item );
|
|
|
|
if( aCollector )
|
|
aCollector->Append( item );
|
|
|
|
if( aView )
|
|
aView->Add( item );
|
|
}
|
|
}
|
|
|
|
|
|
int DS_DATA_ITEM::GetPenSizeIU()
|
|
{
|
|
DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
|
|
|
|
if( m_LineWidth != 0 )
|
|
return KiROUND( m_LineWidth * model.m_WSunits2Iu );
|
|
else
|
|
return KiROUND( model.m_DefaultLineWidth * model.m_WSunits2Iu );
|
|
}
|
|
|
|
|
|
void DS_DATA_ITEM::MoveToIU( const VECTOR2I& aPosition )
|
|
{
|
|
VECTOR2D pos_mm;
|
|
pos_mm.x = aPosition.x / DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
|
|
pos_mm.y = aPosition.y / DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
|
|
|
|
MoveTo( pos_mm );
|
|
}
|
|
|
|
|
|
void DS_DATA_ITEM::MoveTo( const VECTOR2D& aPosition )
|
|
{
|
|
VECTOR2D vector = aPosition - GetStartPos();
|
|
VECTOR2D endpos = vector + GetEndPos();
|
|
|
|
MoveStartPointTo( aPosition );
|
|
MoveEndPointTo( endpos );
|
|
|
|
for( DS_DRAW_ITEM_BASE* drawItem : m_drawItems )
|
|
{
|
|
drawItem->SetPosition( GetStartPosIU( drawItem->GetIndexInPeer() ) );
|
|
drawItem->SetEnd( GetEndPosIU( drawItem->GetIndexInPeer() ) );
|
|
}
|
|
}
|
|
|
|
|
|
void DS_DATA_ITEM::MoveStartPointTo( const VECTOR2D& aPosition )
|
|
{
|
|
DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
|
|
VECTOR2D 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 = model.m_RB_Corner - aPosition;
|
|
break;
|
|
|
|
case RT_CORNER:
|
|
position.x = model.m_RB_Corner.x - aPosition.x;
|
|
position.y = aPosition.y - model.m_LT_Corner.y;
|
|
break;
|
|
|
|
case LB_CORNER:
|
|
position.x = aPosition.x - model.m_LT_Corner.x;
|
|
position.y = model.m_RB_Corner.y - aPosition.y;
|
|
break;
|
|
|
|
case LT_CORNER:
|
|
position = aPosition - model.m_LT_Corner;
|
|
break;
|
|
}
|
|
|
|
m_Pos.m_Pos = position;
|
|
}
|
|
|
|
|
|
void DS_DATA_ITEM::MoveStartPointToIU( const VECTOR2I& aPosition )
|
|
{
|
|
VECTOR2D pos_mm( aPosition.x / DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu,
|
|
aPosition.y / DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu );
|
|
|
|
MoveStartPointTo( pos_mm );
|
|
}
|
|
|
|
|
|
void DS_DATA_ITEM::MoveEndPointTo( const VECTOR2D& aPosition )
|
|
{
|
|
DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
|
|
VECTOR2D 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 = model.m_RB_Corner - aPosition;
|
|
break;
|
|
|
|
case RT_CORNER:
|
|
position.x = model.m_RB_Corner.x - aPosition.x;
|
|
position.y = aPosition.y - model.m_LT_Corner.y;
|
|
break;
|
|
|
|
case LB_CORNER:
|
|
position.x = aPosition.x - model.m_LT_Corner.x;
|
|
position.y = model.m_RB_Corner.y - aPosition.y;
|
|
break;
|
|
|
|
case LT_CORNER:
|
|
position = aPosition - model.m_LT_Corner;
|
|
break;
|
|
}
|
|
|
|
// Modify m_End only for items having 2 coordinates
|
|
switch( GetType() )
|
|
{
|
|
case DS_SEGMENT:
|
|
case DS_RECT:
|
|
m_End.m_Pos = position;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void DS_DATA_ITEM::MoveEndPointToIU( const VECTOR2I& aPosition )
|
|
{
|
|
VECTOR2D pos_mm;
|
|
pos_mm.x = aPosition.x / DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
|
|
pos_mm.y = aPosition.y / DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
|
|
|
|
MoveEndPointTo( pos_mm );
|
|
}
|
|
|
|
|
|
const VECTOR2D DS_DATA_ITEM::GetStartPos( int ii ) const
|
|
{
|
|
DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
|
|
VECTOR2D pos( m_Pos.m_Pos.x + ( m_IncrementVector.x * ii ),
|
|
m_Pos.m_Pos.y + ( m_IncrementVector.y * ii ) );
|
|
|
|
switch( m_Pos.m_Anchor )
|
|
{
|
|
case RB_CORNER: // right bottom corner
|
|
pos = model.m_RB_Corner - pos;
|
|
break;
|
|
|
|
case RT_CORNER: // right top corner
|
|
pos.x = model.m_RB_Corner.x - pos.x;
|
|
pos.y = model.m_LT_Corner.y + pos.y;
|
|
break;
|
|
|
|
case LB_CORNER: // left bottom corner
|
|
pos.x = model.m_LT_Corner.x + pos.x;
|
|
pos.y = model.m_RB_Corner.y - pos.y;
|
|
break;
|
|
|
|
case LT_CORNER: // left top corner
|
|
pos = model.m_LT_Corner + pos;
|
|
break;
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
|
|
|
|
const VECTOR2I DS_DATA_ITEM::GetStartPosIU( int ii ) const
|
|
{
|
|
VECTOR2D pos = GetStartPos( ii ) * DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
|
|
return VECTOR2I( KiROUND( pos.x ), KiROUND( pos.y ) );
|
|
}
|
|
|
|
|
|
const VECTOR2D DS_DATA_ITEM::GetEndPos( int ii ) const
|
|
{
|
|
VECTOR2D pos( m_End.m_Pos.x + ( m_IncrementVector.x * ii ),
|
|
m_End.m_Pos.y + ( m_IncrementVector.y * ii ) );
|
|
|
|
switch( m_End.m_Anchor )
|
|
{
|
|
case RB_CORNER: // right bottom corner
|
|
pos = DS_DATA_MODEL::GetTheInstance().m_RB_Corner - pos;
|
|
break;
|
|
|
|
case RT_CORNER: // right top corner
|
|
pos.x = DS_DATA_MODEL::GetTheInstance().m_RB_Corner.x - pos.x;
|
|
pos.y = DS_DATA_MODEL::GetTheInstance().m_LT_Corner.y + pos.y;
|
|
break;
|
|
|
|
case LB_CORNER: // left bottom corner
|
|
pos.x = DS_DATA_MODEL::GetTheInstance().m_LT_Corner.x + pos.x;
|
|
pos.y = DS_DATA_MODEL::GetTheInstance().m_RB_Corner.y - pos.y;
|
|
break;
|
|
|
|
case LT_CORNER: // left top corner
|
|
pos = DS_DATA_MODEL::GetTheInstance().m_LT_Corner + pos;
|
|
break;
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
|
|
|
|
const VECTOR2I DS_DATA_ITEM::GetEndPosIU( int ii ) const
|
|
{
|
|
VECTOR2D pos = GetEndPos( ii );
|
|
pos = pos * DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
|
|
return VECTOR2I( KiROUND( pos.x ), KiROUND( pos.y ) );
|
|
}
|
|
|
|
|
|
bool DS_DATA_ITEM::IsInsidePage( int ii ) const
|
|
{
|
|
DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
|
|
|
|
for( const VECTOR2D& pos : { GetStartPos( ii ), GetEndPos( ii ) } )
|
|
{
|
|
if( model.m_RB_Corner.x < pos.x || model.m_LT_Corner.x > pos.x )
|
|
return false;
|
|
|
|
if( model.m_RB_Corner.y < pos.y || model.m_LT_Corner.y > pos.y )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
const wxString DS_DATA_ITEM::GetClassName() const
|
|
{
|
|
wxString name;
|
|
|
|
switch( GetType() )
|
|
{
|
|
case DS_TEXT: name = _( "Text" ); break;
|
|
case DS_SEGMENT: name = _( "Line" ); break;
|
|
case DS_RECT: name = _( "Rectangle" ); break;
|
|
case DS_POLYPOLYGON: name = _( "Imported Shape" ); break;
|
|
case DS_BITMAP: name = _( "Image" ); break;
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
|
|
DS_DATA_ITEM_POLYGONS::DS_DATA_ITEM_POLYGONS() :
|
|
DS_DATA_ITEM( DS_POLYPOLYGON )
|
|
{
|
|
}
|
|
|
|
|
|
void DS_DATA_ITEM_POLYGONS::SyncDrawItems( DS_DRAW_ITEM_LIST* aCollector, KIGFX::VIEW* aView )
|
|
{
|
|
std::map<int, EDA_ITEM_FLAGS> itemFlags;
|
|
DS_DRAW_ITEM_BASE* item = nullptr;
|
|
|
|
for( size_t i = 0; i < m_drawItems.size(); ++i )
|
|
{
|
|
item = m_drawItems[ i ];
|
|
itemFlags[ i ] = item->GetFlags();
|
|
|
|
if( aCollector )
|
|
aCollector->Remove( item );
|
|
|
|
if( aView )
|
|
aView->Remove( item );
|
|
|
|
delete item;
|
|
}
|
|
|
|
m_drawItems.clear();
|
|
|
|
for( int j = 0; j < m_RepeatCount; j++ )
|
|
{
|
|
if( j > 0 && !IsInsidePage( j ) )
|
|
continue;
|
|
|
|
int pensize = GetPenSizeIU();
|
|
auto poly_shape = new DS_DRAW_ITEM_POLYPOLYGONS( this, j, GetStartPosIU( j ), pensize );
|
|
poly_shape->SetFlags( itemFlags[ j ] );
|
|
m_drawItems.push_back( poly_shape );
|
|
|
|
// Transfer all outlines (basic polygons)
|
|
SHAPE_POLY_SET& polygons = poly_shape->GetPolygons();
|
|
|
|
for( int kk = 0; kk < GetPolyCount(); kk++ )
|
|
{
|
|
// Create new outline
|
|
unsigned ist = GetPolyIndexStart( kk );
|
|
unsigned iend = GetPolyIndexEnd( kk );
|
|
|
|
polygons.NewOutline();
|
|
|
|
while( ist <= iend )
|
|
polygons.Append( GetCornerPositionIU( ist++, j ) );
|
|
}
|
|
|
|
if( aCollector )
|
|
aCollector->Append( poly_shape );
|
|
|
|
if( aView )
|
|
aView->Add( poly_shape );
|
|
}
|
|
}
|
|
|
|
|
|
int DS_DATA_ITEM_POLYGONS::GetPenSizeIU()
|
|
{
|
|
return KiROUND( m_LineWidth * DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu );
|
|
}
|
|
|
|
|
|
const VECTOR2D DS_DATA_ITEM_POLYGONS::GetCornerPosition( unsigned aIdx, int aRepeat ) const
|
|
{
|
|
VECTOR2D pos = m_Corners[aIdx];
|
|
|
|
// Rotation:
|
|
RotatePoint( &pos.x, &pos.y, m_Orient );
|
|
pos += GetStartPos( aRepeat );
|
|
return pos;
|
|
}
|
|
|
|
|
|
void DS_DATA_ITEM_POLYGONS::SetBoundingBox()
|
|
{
|
|
if( m_Corners.size() == 0 )
|
|
{
|
|
m_minCoord.x = m_maxCoord.x = 0.0;
|
|
m_minCoord.y = m_maxCoord.y = 0.0;
|
|
return;
|
|
}
|
|
|
|
VECTOR2I pos;
|
|
pos = m_Corners[0];
|
|
RotatePoint( &pos.x, &pos.y, m_Orient );
|
|
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 );
|
|
|
|
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 DS_DATA_ITEM_POLYGONS::IsInsidePage( int ii ) const
|
|
{
|
|
DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
|
|
|
|
VECTOR2D pos = GetStartPos( ii );
|
|
pos += m_minCoord; // left top pos of bounding box
|
|
|
|
if( model.m_LT_Corner.x > pos.x || model.m_LT_Corner.y > pos.y )
|
|
return false;
|
|
|
|
pos = GetStartPos( ii );
|
|
pos += m_maxCoord; // right bottom pos of bounding box
|
|
|
|
if( model.m_RB_Corner.x < pos.x || model.m_RB_Corner.y < pos.y )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
const VECTOR2I DS_DATA_ITEM_POLYGONS::GetCornerPositionIU( unsigned aIdx, int aRepeat ) const
|
|
{
|
|
VECTOR2D pos = GetCornerPosition( aIdx, aRepeat );
|
|
pos = pos * DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
|
|
return VECTOR2I( int( pos.x ), int( pos.y ) );
|
|
}
|
|
|
|
|
|
DS_DATA_ITEM_TEXT::DS_DATA_ITEM_TEXT( const wxString& aTextBase ) :
|
|
DS_DATA_ITEM( DS_TEXT )
|
|
{
|
|
m_TextBase = aTextBase;
|
|
m_IncrementLabel = 1;
|
|
m_Hjustify = GR_TEXT_H_ALIGN_LEFT;
|
|
m_Vjustify = GR_TEXT_V_ALIGN_CENTER;
|
|
m_Italic = false;
|
|
m_Bold = false;
|
|
m_Font = nullptr;
|
|
m_TextColor = COLOR4D::UNSPECIFIED;
|
|
m_Orient = 0.0;
|
|
m_LineWidth = 0.0; // 0 means use default value
|
|
}
|
|
|
|
|
|
void DS_DATA_ITEM_TEXT::SyncDrawItems( DS_DRAW_ITEM_LIST* aCollector, KIGFX::VIEW* aView )
|
|
{
|
|
int pensize = GetPenSizeIU();
|
|
bool multilines = false;
|
|
|
|
if( DS_DATA_MODEL::GetTheInstance().m_EditMode )
|
|
{
|
|
m_FullText = m_TextBase;
|
|
}
|
|
else
|
|
{
|
|
m_FullText = aCollector ? aCollector->BuildFullText( m_TextBase ) : wxString();
|
|
multilines = ReplaceAntiSlashSequence();
|
|
}
|
|
|
|
if( pensize == 0 )
|
|
pensize = aCollector ? aCollector->GetDefaultPenSize() : 1;
|
|
|
|
SetConstrainedTextSize();
|
|
VECTOR2I textsize;
|
|
|
|
textsize.x = KiROUND( m_ConstrainedTextSize.x * DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu );
|
|
textsize.y = KiROUND( m_ConstrainedTextSize.y * DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu );
|
|
|
|
if( m_Bold )
|
|
pensize = GetPenSizeForBold( std::min( textsize.x, textsize.y ) );
|
|
|
|
std::map<size_t, EDA_ITEM_FLAGS> itemFlags;
|
|
DS_DRAW_ITEM_TEXT* text = nullptr;
|
|
|
|
for( size_t i = 0; i < m_drawItems.size(); ++i )
|
|
{
|
|
text = (DS_DRAW_ITEM_TEXT*) m_drawItems[ i ];
|
|
itemFlags[ i ] = text->GetFlags();
|
|
|
|
if( aCollector )
|
|
aCollector->Remove( text );
|
|
|
|
if( aView )
|
|
aView->Remove( text );
|
|
|
|
delete text;
|
|
}
|
|
|
|
m_drawItems.clear();
|
|
|
|
for( int j = 0; j < m_RepeatCount; ++j )
|
|
{
|
|
if( j > 0 && !IsInsidePage( j ) )
|
|
continue;
|
|
|
|
EDA_IU_SCALE iuscale = aCollector ? aCollector->GetIuScale()
|
|
: DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
|
|
|
|
text = new DS_DRAW_ITEM_TEXT( iuscale, this, j, m_FullText, GetStartPosIU( j ), textsize,
|
|
pensize, m_Font, m_Italic, m_Bold, m_TextColor );
|
|
|
|
text->SetFlags( itemFlags[ j ] );
|
|
m_drawItems.push_back( text );
|
|
|
|
if( aCollector )
|
|
aCollector->Append( text );
|
|
|
|
if( aView )
|
|
aView->Add( text );
|
|
|
|
text->SetHorizJustify( m_Hjustify );
|
|
text->SetVertJustify( m_Vjustify );
|
|
text->SetTextAngle( EDA_ANGLE( m_Orient, DEGREES_T ) );
|
|
text->SetMultilineAllowed( multilines );
|
|
|
|
// Increment label for the next text (has no meaning for multiline texts)
|
|
if( m_RepeatCount > 1 && !multilines )
|
|
IncrementLabel( ( j + 1 ) * m_IncrementLabel );
|
|
}
|
|
}
|
|
|
|
|
|
int DS_DATA_ITEM_TEXT::GetPenSizeIU()
|
|
{
|
|
DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
|
|
|
|
if( m_LineWidth != 0 )
|
|
return KiROUND( m_LineWidth * model.m_WSunits2Iu );
|
|
else
|
|
return KiROUND( model.m_DefaultTextThickness * model.m_WSunits2Iu );
|
|
}
|
|
|
|
|
|
void DS_DATA_ITEM_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 DS_DATA_ITEM_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 DS_DATA_ITEM_TEXT::SetConstrainedTextSize()
|
|
{
|
|
m_ConstrainedTextSize = m_TextSize;
|
|
|
|
if( m_ConstrainedTextSize.x == 0 )
|
|
m_ConstrainedTextSize.x = DS_DATA_MODEL::GetTheInstance().m_DefaultTextSize.x;
|
|
|
|
if( m_ConstrainedTextSize.y == 0 )
|
|
m_ConstrainedTextSize.y = DS_DATA_MODEL::GetTheInstance().m_DefaultTextSize.y;
|
|
|
|
if( m_BoundingBoxSize.x > 0 || m_BoundingBoxSize.y > 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.
|
|
VECTOR2I size_micron;
|
|
#define FSCALE 1000.0
|
|
int linewidth = 0;
|
|
size_micron.x = KiROUND( m_ConstrainedTextSize.x * FSCALE );
|
|
size_micron.y = KiROUND( m_ConstrainedTextSize.y * FSCALE );
|
|
DS_DRAW_ITEM_TEXT dummy( unityScale, this, 0, m_FullText, VECTOR2I( 0, 0 ), size_micron,
|
|
linewidth, m_Font, m_Italic, m_Bold, m_TextColor );
|
|
dummy.SetMultilineAllowed( true );
|
|
dummy.SetHorizJustify( m_Hjustify ) ;
|
|
dummy.SetVertJustify( m_Vjustify );
|
|
dummy.SetTextAngle( EDA_ANGLE( m_Orient, DEGREES_T ) );
|
|
|
|
BOX2I rect = dummy.GetTextBox();
|
|
VECTOR2D size;
|
|
size.x = KiROUND( (int) rect.GetWidth() / FSCALE );
|
|
size.y = KiROUND( (int) rect.GetHeight() / FSCALE );
|
|
|
|
if( m_BoundingBoxSize.x > 0 && size.x > m_BoundingBoxSize.x )
|
|
m_ConstrainedTextSize.x *= m_BoundingBoxSize.x / size.x;
|
|
|
|
if( m_BoundingBoxSize.y > 0 && size.y > m_BoundingBoxSize.y )
|
|
m_ConstrainedTextSize.y *= m_BoundingBoxSize.y / size.y;
|
|
}
|
|
}
|
|
|
|
|
|
void DS_DATA_ITEM_BITMAP::SyncDrawItems( DS_DRAW_ITEM_LIST* aCollector, KIGFX::VIEW* aView )
|
|
{
|
|
std::map<size_t, EDA_ITEM_FLAGS> itemFlags;
|
|
DS_DRAW_ITEM_BASE* item = nullptr;
|
|
|
|
for( size_t i = 0; i < m_drawItems.size(); ++i )
|
|
{
|
|
item = m_drawItems[ i ];
|
|
itemFlags[ i ] = item->GetFlags();
|
|
|
|
if( aCollector )
|
|
aCollector->Remove( item );
|
|
|
|
if( aView )
|
|
aView->Remove( item );
|
|
|
|
delete item;
|
|
}
|
|
|
|
if( aCollector )
|
|
{
|
|
double pix_size_iu = aCollector->GetMilsToIUfactor() * 1000 / m_ImageBitmap->GetPPI();
|
|
m_ImageBitmap->SetPixelSizeIu( pix_size_iu );
|
|
}
|
|
|
|
if( !m_ImageBitmap->GetOriginalImageData() )
|
|
return;
|
|
|
|
m_drawItems.clear();
|
|
|
|
for( int j = 0; j < m_RepeatCount; j++ )
|
|
{
|
|
if( j > 0 && !IsInsidePage( j ) )
|
|
continue;
|
|
|
|
DS_DRAW_ITEM_BITMAP* bitmap = new DS_DRAW_ITEM_BITMAP( this, j, GetStartPosIU( j ) );
|
|
|
|
bitmap->SetFlags( itemFlags[ j ] );
|
|
m_drawItems.push_back( bitmap );
|
|
|
|
if( aCollector )
|
|
aCollector->Append( bitmap );
|
|
|
|
if( aView )
|
|
aView->Add( bitmap );
|
|
}
|
|
}
|
|
|
|
|
|
int DS_DATA_ITEM_BITMAP::GetPPI() const
|
|
{
|
|
if( m_ImageBitmap )
|
|
return m_ImageBitmap->GetPPI() / m_ImageBitmap->GetScale();
|
|
|
|
return 300;
|
|
}
|
|
|
|
|
|
void DS_DATA_ITEM_BITMAP::SetPPI( int aBitmapPPI )
|
|
{
|
|
if( m_ImageBitmap )
|
|
m_ImageBitmap->SetScale( (double) m_ImageBitmap->GetPPI() / aBitmapPPI );
|
|
}
|