Performance enhancements for fonts.
This commit is contained in:
parent
438c63f587
commit
04c76f10e9
|
@ -303,7 +303,6 @@ set( FONT_SRCS
|
||||||
font/stroke_font.cpp
|
font/stroke_font.cpp
|
||||||
font/outline_font.cpp
|
font/outline_font.cpp
|
||||||
font/outline_decomposer.cpp
|
font/outline_decomposer.cpp
|
||||||
font/triangulate.cpp
|
|
||||||
font/fontconfig.cpp
|
font/fontconfig.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,8 @@ GR_TEXT_V_ALIGN_T EDA_TEXT::MapVertJustify( int aVertJustify )
|
||||||
|
|
||||||
|
|
||||||
EDA_TEXT::EDA_TEXT( const wxString& text ) :
|
EDA_TEXT::EDA_TEXT( const wxString& text ) :
|
||||||
m_text( text )
|
m_text( text ),
|
||||||
|
m_bounding_box_cache_valid( false )
|
||||||
{
|
{
|
||||||
int sz = Mils2iu( DEFAULT_SIZE_TEXT );
|
int sz = Mils2iu( DEFAULT_SIZE_TEXT );
|
||||||
SetTextSize( wxSize( sz, sz ) );
|
SetTextSize( wxSize( sz, sz ) );
|
||||||
|
@ -134,6 +135,9 @@ EDA_TEXT::EDA_TEXT( const EDA_TEXT& aText )
|
||||||
KIFONT::OUTLINE_GLYPH* outline_glyph = static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() );
|
KIFONT::OUTLINE_GLYPH* outline_glyph = static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() );
|
||||||
m_render_cache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline_glyph ) );
|
m_render_cache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline_glyph ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_bounding_box_cache_valid = aText.m_bounding_box_cache_valid;
|
||||||
|
m_bounding_box_cache = aText.m_bounding_box_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,6 +166,9 @@ EDA_TEXT& EDA_TEXT::operator=( const EDA_TEXT& aText )
|
||||||
m_render_cache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline_glyph ) );
|
m_render_cache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline_glyph ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_bounding_box_cache_valid = aText.m_bounding_box_cache_valid;
|
||||||
|
m_bounding_box_cache = aText.m_bounding_box_cache;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +176,11 @@ EDA_TEXT& EDA_TEXT::operator=( const EDA_TEXT& aText )
|
||||||
void EDA_TEXT::SetText( const wxString& aText )
|
void EDA_TEXT::SetText( const wxString& aText )
|
||||||
{
|
{
|
||||||
m_text = aText;
|
m_text = aText;
|
||||||
|
|
||||||
cacheShownText();
|
cacheShownText();
|
||||||
|
|
||||||
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -179,77 +190,87 @@ void EDA_TEXT::CopyText( const EDA_TEXT& aSrc )
|
||||||
m_shown_text = aSrc.m_shown_text;
|
m_shown_text = aSrc.m_shown_text;
|
||||||
m_shown_text_has_text_var_refs = aSrc.m_shown_text_has_text_var_refs;
|
m_shown_text_has_text_var_refs = aSrc.m_shown_text_has_text_var_refs;
|
||||||
|
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetTextThickness( int aWidth )
|
void EDA_TEXT::SetTextThickness( int aWidth )
|
||||||
{
|
{
|
||||||
m_attributes.m_StrokeWidth = aWidth;
|
m_attributes.m_StrokeWidth = aWidth;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetTextAngle( const EDA_ANGLE& aAngle )
|
void EDA_TEXT::SetTextAngle( const EDA_ANGLE& aAngle )
|
||||||
{
|
{
|
||||||
m_attributes.m_Angle = aAngle;
|
m_attributes.m_Angle = aAngle;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetItalic( bool aItalic )
|
void EDA_TEXT::SetItalic( bool aItalic )
|
||||||
{
|
{
|
||||||
m_attributes.m_Italic = aItalic;
|
m_attributes.m_Italic = aItalic;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetBold( bool aBold )
|
void EDA_TEXT::SetBold( bool aBold )
|
||||||
{
|
{
|
||||||
m_attributes.m_Bold = aBold;
|
m_attributes.m_Bold = aBold;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetVisible( bool aVisible )
|
void EDA_TEXT::SetVisible( bool aVisible )
|
||||||
{
|
{
|
||||||
m_attributes.m_Visible = aVisible;
|
m_attributes.m_Visible = aVisible;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetMirrored( bool isMirrored )
|
void EDA_TEXT::SetMirrored( bool isMirrored )
|
||||||
{
|
{
|
||||||
m_attributes.m_Mirrored = isMirrored;
|
m_attributes.m_Mirrored = isMirrored;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetMultilineAllowed( bool aAllow )
|
void EDA_TEXT::SetMultilineAllowed( bool aAllow )
|
||||||
{
|
{
|
||||||
m_attributes.m_Multiline = aAllow;
|
m_attributes.m_Multiline = aAllow;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetHorizJustify( GR_TEXT_H_ALIGN_T aType )
|
void EDA_TEXT::SetHorizJustify( GR_TEXT_H_ALIGN_T aType )
|
||||||
{
|
{
|
||||||
m_attributes.m_Halign = aType;
|
m_attributes.m_Halign = aType;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetVertJustify( GR_TEXT_V_ALIGN_T aType )
|
void EDA_TEXT::SetVertJustify( GR_TEXT_V_ALIGN_T aType )
|
||||||
{
|
{
|
||||||
m_attributes.m_Valign = aType;
|
m_attributes.m_Valign = aType;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetKeepUpright( bool aKeepUpright )
|
void EDA_TEXT::SetKeepUpright( bool aKeepUpright )
|
||||||
{
|
{
|
||||||
m_attributes.m_KeepUpright = aKeepUpright;
|
m_attributes.m_KeepUpright = aKeepUpright;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -257,7 +278,8 @@ void EDA_TEXT::SetAttributes( const EDA_TEXT& aSrc )
|
||||||
{
|
{
|
||||||
m_attributes = aSrc.m_attributes;
|
m_attributes = aSrc.m_attributes;
|
||||||
m_pos = aSrc.m_pos;
|
m_pos = aSrc.m_pos;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -267,7 +289,8 @@ void EDA_TEXT::SwapText( EDA_TEXT& aTradingPartner )
|
||||||
std::swap( m_shown_text, aTradingPartner.m_shown_text );
|
std::swap( m_shown_text, aTradingPartner.m_shown_text );
|
||||||
std::swap( m_shown_text_has_text_var_refs, aTradingPartner.m_shown_text_has_text_var_refs );
|
std::swap( m_shown_text_has_text_var_refs, aTradingPartner.m_shown_text_has_text_var_refs );
|
||||||
|
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -276,7 +299,11 @@ void EDA_TEXT::SwapAttributes( EDA_TEXT& aTradingPartner )
|
||||||
std::swap( m_attributes, aTradingPartner.m_attributes );
|
std::swap( m_attributes, aTradingPartner.m_attributes );
|
||||||
std::swap( m_pos, aTradingPartner.m_pos );
|
std::swap( m_pos, aTradingPartner.m_pos );
|
||||||
|
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
aTradingPartner.ClearRenderCache();
|
||||||
|
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
|
aTradingPartner.m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -304,8 +331,12 @@ int EDA_TEXT::GetEffectiveTextPenWidth( int aDefaultWidth ) const
|
||||||
bool EDA_TEXT::Replace( const wxFindReplaceData& aSearchData )
|
bool EDA_TEXT::Replace( const wxFindReplaceData& aSearchData )
|
||||||
{
|
{
|
||||||
bool retval = EDA_ITEM::Replace( aSearchData, m_text );
|
bool retval = EDA_ITEM::Replace( aSearchData, m_text );
|
||||||
|
|
||||||
cacheShownText();
|
cacheShownText();
|
||||||
|
|
||||||
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,35 +344,40 @@ bool EDA_TEXT::Replace( const wxFindReplaceData& aSearchData )
|
||||||
void EDA_TEXT::SetFont( KIFONT::FONT* aFont )
|
void EDA_TEXT::SetFont( KIFONT::FONT* aFont )
|
||||||
{
|
{
|
||||||
m_attributes.m_Font = aFont;
|
m_attributes.m_Font = aFont;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetLineSpacing( double aLineSpacing )
|
void EDA_TEXT::SetLineSpacing( double aLineSpacing )
|
||||||
{
|
{
|
||||||
m_attributes.m_LineSpacing = aLineSpacing;
|
m_attributes.m_LineSpacing = aLineSpacing;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetTextSize( const wxSize& aNewSize )
|
void EDA_TEXT::SetTextSize( const wxSize& aNewSize )
|
||||||
{
|
{
|
||||||
m_attributes.m_Size = aNewSize;
|
m_attributes.m_Size = aNewSize;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetTextWidth( int aWidth )
|
void EDA_TEXT::SetTextWidth( int aWidth )
|
||||||
{
|
{
|
||||||
m_attributes.m_Size.x = aWidth;
|
m_attributes.m_Size.x = aWidth;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::SetTextHeight( int aHeight )
|
void EDA_TEXT::SetTextHeight( int aHeight )
|
||||||
{
|
{
|
||||||
m_attributes.m_Size.y = aHeight;
|
m_attributes.m_Size.y = aHeight;
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -368,17 +404,17 @@ void EDA_TEXT::Offset( const VECTOR2I& aOffset )
|
||||||
m_pos += aOffset;
|
m_pos += aOffset;
|
||||||
|
|
||||||
for( std::unique_ptr<KIFONT::GLYPH>& glyph : m_render_cache )
|
for( std::unique_ptr<KIFONT::GLYPH>& glyph : m_render_cache )
|
||||||
{
|
static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() )->Move( aOffset );
|
||||||
KIFONT::OUTLINE_GLYPH* outline_glyph = static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() );
|
|
||||||
outline_glyph->Move( aOffset );
|
m_bounding_box_cache.Move( aOffset );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_TEXT::Empty()
|
void EDA_TEXT::Empty()
|
||||||
{
|
{
|
||||||
m_text.Empty();
|
m_text.Empty();
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -395,7 +431,8 @@ void EDA_TEXT::cacheShownText()
|
||||||
m_shown_text_has_text_var_refs = m_shown_text.Contains( wxT( "${" ) );
|
m_shown_text_has_text_var_refs = m_shown_text.Contains( wxT( "${" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
m_render_cache.clear();
|
ClearRenderCache();
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -410,6 +447,19 @@ KIFONT::FONT* EDA_TEXT::GetDrawFont() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void EDA_TEXT::ClearRenderCache()
|
||||||
|
{
|
||||||
|
m_render_cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EDA_TEXT::ClearBoundingBoxCache()
|
||||||
|
{
|
||||||
|
m_bounding_box_cache_valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<KIFONT::GLYPH>>*
|
std::vector<std::unique_ptr<KIFONT::GLYPH>>*
|
||||||
EDA_TEXT::GetRenderCache( const wxString& forResolvedText ) const
|
EDA_TEXT::GetRenderCache( const wxString& forResolvedText ) const
|
||||||
{
|
{
|
||||||
|
@ -424,7 +474,7 @@ EDA_TEXT::GetRenderCache( const wxString& forResolvedText ) const
|
||||||
m_render_cache.clear();
|
m_render_cache.clear();
|
||||||
|
|
||||||
KIFONT::OUTLINE_FONT* font = static_cast<KIFONT::OUTLINE_FONT*>( GetFont() );
|
KIFONT::OUTLINE_FONT* font = static_cast<KIFONT::OUTLINE_FONT*>( GetFont() );
|
||||||
font->GetLinesAsGlyphs( m_render_cache, this );
|
font->GetLinesAsGlyphs( &m_render_cache, this );
|
||||||
|
|
||||||
m_render_cache_angle = resolvedAngle;
|
m_render_cache_angle = resolvedAngle;
|
||||||
m_render_cache_text = forResolvedText;
|
m_render_cache_text = forResolvedText;
|
||||||
|
@ -474,6 +524,9 @@ int EDA_TEXT::GetInterline() const
|
||||||
|
|
||||||
EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const
|
EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const
|
||||||
{
|
{
|
||||||
|
if( m_bounding_box_cache_valid && aLine < 0 && !aInvertY )
|
||||||
|
return m_bounding_box_cache;
|
||||||
|
|
||||||
EDA_RECT rect;
|
EDA_RECT rect;
|
||||||
wxArrayString strings;
|
wxArrayString strings;
|
||||||
wxString text = GetShownText();
|
wxString text = GetShownText();
|
||||||
|
@ -498,8 +551,7 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const
|
||||||
double penWidth( thickness );
|
double penWidth( thickness );
|
||||||
bool bold = IsBold();
|
bool bold = IsBold();
|
||||||
bool italic = IsItalic();
|
bool italic = IsItalic();
|
||||||
VECTOR2D extents = font->StringBoundaryLimits( text, fontSize, penWidth, bold, italic );
|
int dx = font->StringBoundaryLimits( text, fontSize, penWidth, bold, italic ).x;
|
||||||
int dx = KiROUND( extents.x );
|
|
||||||
int dy = GetInterline();
|
int dy = GetInterline();
|
||||||
|
|
||||||
// Creates bounding box (rectangle) for horizontal, left and top justified text. The
|
// Creates bounding box (rectangle) for horizontal, left and top justified text. The
|
||||||
|
@ -521,7 +573,7 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const
|
||||||
for( unsigned ii = 1; ii < strings.GetCount(); ii++ )
|
for( unsigned ii = 1; ii < strings.GetCount(); ii++ )
|
||||||
{
|
{
|
||||||
text = strings.Item( ii );
|
text = strings.Item( ii );
|
||||||
dx = KiROUND( font->StringBoundaryLimits( text, fontSize, penWidth, bold, italic ).x );
|
dx = font->StringBoundaryLimits( text, fontSize, penWidth, bold, italic ).x;
|
||||||
textsize.x = std::max( textsize.x, dx );
|
textsize.x = std::max( textsize.x, dx );
|
||||||
textsize.y += dy;
|
textsize.y += dy;
|
||||||
}
|
}
|
||||||
|
@ -561,6 +613,12 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const
|
||||||
|
|
||||||
rect.Normalize(); // Make h and v sizes always >= 0
|
rect.Normalize(); // Make h and v sizes always >= 0
|
||||||
|
|
||||||
|
if( aLine < 0 && !aInvertY )
|
||||||
|
{
|
||||||
|
m_bounding_box_cache_valid = true;
|
||||||
|
m_bounding_box_cache = rect;
|
||||||
|
}
|
||||||
|
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -797,25 +855,18 @@ std::shared_ptr<SHAPE_COMPOUND> EDA_TEXT::GetEffectiveTextShape( ) const
|
||||||
{
|
{
|
||||||
KIFONT::OUTLINE_GLYPH* glyph = static_cast<KIFONT::OUTLINE_GLYPH*>( baseGlyph.get() );
|
KIFONT::OUTLINE_GLYPH* glyph = static_cast<KIFONT::OUTLINE_GLYPH*>( baseGlyph.get() );
|
||||||
|
|
||||||
glyph->CacheTriangulation();
|
glyph->Triangulate(
|
||||||
|
[&]( int aPolygonIndex, const VECTOR2D& aVertex1, const VECTOR2D& aVertex2,
|
||||||
|
const VECTOR2D& aVertex3 )
|
||||||
|
{
|
||||||
|
SHAPE_SIMPLE* triShape = new SHAPE_SIMPLE;
|
||||||
|
|
||||||
for( unsigned int ii = 0; ii < glyph->TriangulatedPolyCount(); ++ii )
|
triShape->Append( aVertex1 );
|
||||||
{
|
triShape->Append( aVertex2 );
|
||||||
const SHAPE_POLY_SET::TRIANGULATED_POLYGON* tri = glyph->TriangulatedPolygon( ii );
|
triShape->Append( aVertex3 );
|
||||||
|
|
||||||
for( size_t jj = 0; jj < tri->GetTriangleCount(); ++jj )
|
shape->AddShape( triShape );
|
||||||
{
|
} );
|
||||||
VECTOR2I a, b, c;
|
|
||||||
tri->GetTriangle( jj, a, b, c );
|
|
||||||
SHAPE_SIMPLE* triShape = new SHAPE_SIMPLE;
|
|
||||||
|
|
||||||
triShape->Append( a );
|
|
||||||
triShape->Append( b );
|
|
||||||
triShape->Append( c );
|
|
||||||
|
|
||||||
shape->AddShape( triShape );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -104,72 +104,9 @@ bool FONT::IsStroke( const wxString& aFontName )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw a string.
|
|
||||||
*
|
|
||||||
* @param aGal
|
|
||||||
* @param aTextItem is the underlying text item
|
|
||||||
* @param aPosition is the text position
|
|
||||||
* @return bounding box width/height
|
|
||||||
*/
|
|
||||||
VECTOR2D FONT::doDrawString( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition,
|
|
||||||
bool aParse, const TEXT_ATTRIBUTES& aAttrs ) const
|
|
||||||
{
|
|
||||||
if( aText.empty() )
|
|
||||||
return VECTOR2D( 0.0, 0.0 );
|
|
||||||
|
|
||||||
wxArrayString strings;
|
|
||||||
std::vector<VECTOR2I> positions;
|
|
||||||
VECTOR2D boundingBox;
|
|
||||||
std::vector<VECTOR2D> lineBoundingBoxes;
|
|
||||||
|
|
||||||
getLinePositions( aText, aPosition, strings, positions, lineBoundingBoxes, aAttrs );
|
|
||||||
|
|
||||||
for( size_t i = 0; i < strings.GetCount(); i++ )
|
|
||||||
{
|
|
||||||
VECTOR2D lineBoundingBox;
|
|
||||||
|
|
||||||
if( aParse )
|
|
||||||
{
|
|
||||||
MARKUP::MARKUP_PARSER markupParser( std::string( strings.Item( i ) ) );
|
|
||||||
//auto parse_result = markupParser.Parse();
|
|
||||||
VECTOR2I cursor = positions[i];
|
|
||||||
|
|
||||||
std::function<void( const std::unique_ptr<MARKUP::NODE>& )> nodeHandler =
|
|
||||||
[&]( const std::unique_ptr<MARKUP::NODE>& aNode )
|
|
||||||
{
|
|
||||||
if( !aNode->is_root() && aNode->has_content() )
|
|
||||||
{
|
|
||||||
VECTOR2D itemBoundingBox = Draw( aGal, aNode->string(), cursor,
|
|
||||||
aPosition, aAttrs );
|
|
||||||
lineBoundingBox += itemBoundingBox;
|
|
||||||
cursor += itemBoundingBox;
|
|
||||||
}
|
|
||||||
|
|
||||||
for( const auto& child : aNode->children )
|
|
||||||
nodeHandler( child );
|
|
||||||
};
|
|
||||||
|
|
||||||
nodeHandler( markupParser.Parse() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lineBoundingBox = Draw( aGal, strings.Item( i ), positions[i], aPosition, aAttrs );
|
|
||||||
}
|
|
||||||
|
|
||||||
boundingBox.x = fmax( boundingBox.x, lineBoundingBox.x );
|
|
||||||
}
|
|
||||||
|
|
||||||
boundingBox.y = ( strings.GetCount() + 1 ) * GetInterline( aAttrs.m_Size.y );
|
|
||||||
|
|
||||||
return boundingBox;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void FONT::getLinePositions( const UTF8& aText, const VECTOR2I& aPosition,
|
void FONT::getLinePositions( const UTF8& aText, const VECTOR2I& aPosition,
|
||||||
wxArrayString& aTextLines, std::vector<VECTOR2I>& aPositions,
|
wxArrayString& aTextLines, std::vector<VECTOR2I>& aPositions,
|
||||||
std::vector<VECTOR2D>& aBoundingBoxes,
|
std::vector<VECTOR2I>& aExtents, const TEXT_ATTRIBUTES& aAttrs ) const
|
||||||
const TEXT_ATTRIBUTES& aAttrs ) const
|
|
||||||
{
|
{
|
||||||
wxStringSplit( aText, aTextLines, '\n' );
|
wxStringSplit( aText, aTextLines, '\n' );
|
||||||
int lineCount = aTextLines.Count();
|
int lineCount = aTextLines.Count();
|
||||||
|
@ -180,12 +117,12 @@ void FONT::getLinePositions( const UTF8& aText, const VECTOR2I& aPosition,
|
||||||
|
|
||||||
for( int i = 0; i < lineCount; i++ )
|
for( int i = 0; i < lineCount; i++ )
|
||||||
{
|
{
|
||||||
VECTOR2D pos( aPosition.x, aPosition.y + i * interline );
|
VECTOR2I pos( aPosition.x, aPosition.y + i * interline );
|
||||||
VECTOR2D end = boundingBoxSingleLine( nullptr, aTextLines[i], pos, aAttrs.m_Size,
|
VECTOR2I end = boundingBoxSingleLine( nullptr, aTextLines[i], pos, aAttrs.m_Size,
|
||||||
aAttrs.m_Italic );
|
aAttrs.m_Italic );
|
||||||
VECTOR2D bBox( end - pos );
|
VECTOR2I bBox( end - pos );
|
||||||
|
|
||||||
aBoundingBoxes.push_back( bBox );
|
aExtents.push_back( bBox );
|
||||||
|
|
||||||
if( i == 0 )
|
if( i == 0 )
|
||||||
height += aAttrs.m_Size.y;
|
height += aAttrs.m_Size.y;
|
||||||
|
@ -205,7 +142,7 @@ void FONT::getLinePositions( const UTF8& aText, const VECTOR2I& aPosition,
|
||||||
|
|
||||||
for( int i = 0; i < lineCount; i++ )
|
for( int i = 0; i < lineCount; i++ )
|
||||||
{
|
{
|
||||||
VECTOR2I lineSize = aBoundingBoxes.at( i );
|
VECTOR2I lineSize = aExtents.at( i );
|
||||||
wxPoint lineOffset( offset );
|
wxPoint lineOffset( offset );
|
||||||
|
|
||||||
lineOffset.y += i * interline;
|
lineOffset.y += i * interline;
|
||||||
|
@ -247,46 +184,35 @@ void FONT::DrawText( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosit
|
||||||
* object, such as a run of superscript characters)
|
* object, such as a run of superscript characters)
|
||||||
* @param aAttrs are the styling attributes of the text, including its rotation
|
* @param aAttrs are the styling attributes of the text, including its rotation
|
||||||
*/
|
*/
|
||||||
VECTOR2D FONT::Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition,
|
void FONT::Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition,
|
||||||
const VECTOR2I& aCursor, const TEXT_ATTRIBUTES& aAttrs ) const
|
const VECTOR2I& aCursor, const TEXT_ATTRIBUTES& aAttrs ) const
|
||||||
{
|
{
|
||||||
if( !aGal || aText.empty() )
|
if( !aGal || aText.empty() )
|
||||||
return VECTOR2D( 0, 0 );
|
return;
|
||||||
|
|
||||||
VECTOR2D position( aPosition - aCursor );
|
VECTOR2I position( aPosition - aCursor );
|
||||||
|
|
||||||
// Split multiline strings into separate ones and draw them line by line
|
// Split multiline strings into separate ones and draw them line by line
|
||||||
wxArrayString strings_list;
|
wxArrayString strings_list;
|
||||||
std::vector<VECTOR2I> positions;
|
std::vector<VECTOR2I> positions;
|
||||||
std::vector<VECTOR2D> boundingBoxes;
|
std::vector<VECTOR2I> extents;
|
||||||
|
|
||||||
getLinePositions( aText, position, strings_list, positions, boundingBoxes, aAttrs );
|
getLinePositions( aText, position, strings_list, positions, extents, aAttrs );
|
||||||
|
|
||||||
VECTOR2D boundingBox( 0, 0 );
|
|
||||||
BOX2I lineBoundingBox;
|
|
||||||
|
|
||||||
aGal->SetLineWidth( aAttrs.m_StrokeWidth );
|
aGal->SetLineWidth( aAttrs.m_StrokeWidth );
|
||||||
|
|
||||||
for( size_t i = 0; i < strings_list.GetCount(); i++ )
|
for( size_t i = 0; i < strings_list.GetCount(); i++ )
|
||||||
{
|
{
|
||||||
(void) drawSingleLineText( aGal, &lineBoundingBox, strings_list[i], positions[i],
|
drawSingleLineText( aGal, nullptr, strings_list[i], positions[i], aAttrs.m_Size,
|
||||||
aAttrs.m_Size, aAttrs.m_Angle, aAttrs.m_Mirrored, aPosition,
|
aAttrs.m_Angle, aAttrs.m_Mirrored, aPosition, aAttrs.m_Italic );
|
||||||
aAttrs.m_Italic );
|
|
||||||
// expand bounding box of whole text
|
|
||||||
boundingBox.x = std::max( boundingBox.x, (double) lineBoundingBox.GetWidth() );
|
|
||||||
|
|
||||||
double lineHeight = GetInterline( aAttrs.m_Size.y, aAttrs.m_LineSpacing );
|
|
||||||
boundingBox.y += lineHeight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return boundingBox;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return position of cursor for drawing next substring
|
* @return position of cursor for drawing next substring
|
||||||
*/
|
*/
|
||||||
VECTOR2D drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>& aGlyphs,
|
VECTOR2I drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||||
const std::unique_ptr<MARKUP::NODE>& aNode, const VECTOR2I& aPosition,
|
const std::unique_ptr<MARKUP::NODE>& aNode, const VECTOR2I& aPosition,
|
||||||
const KIFONT::FONT* aFont, const VECTOR2D& aSize, const EDA_ANGLE& aAngle,
|
const KIFONT::FONT* aFont, const VECTOR2D& aSize, const EDA_ANGLE& aAngle,
|
||||||
bool aMirror, const VECTOR2I& aOrigin, TEXT_STYLE_FLAGS aTextStyle )
|
bool aMirror, const VECTOR2I& aOrigin, TEXT_STYLE_FLAGS aTextStyle )
|
||||||
|
@ -328,7 +254,7 @@ VECTOR2D drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>& a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VECTOR2D FONT::drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>& aGlyphs,
|
VECTOR2I FONT::drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||||
const UTF8& aText, const VECTOR2I& aPosition, const VECTOR2D& aSize,
|
const UTF8& aText, const VECTOR2I& aPosition, const VECTOR2D& aSize,
|
||||||
const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
|
const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
|
||||||
TEXT_STYLE_FLAGS aTextStyle ) const
|
TEXT_STYLE_FLAGS aTextStyle ) const
|
||||||
|
@ -341,16 +267,13 @@ VECTOR2D FONT::drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VECTOR2D FONT::drawSingleLineText( KIGFX::GAL* aGal, BOX2I* aBoundingBox, const UTF8& aText,
|
void FONT::drawSingleLineText( KIGFX::GAL* aGal, BOX2I* aBoundingBox, const UTF8& aText,
|
||||||
const VECTOR2I& aPosition, const VECTOR2D& aSize,
|
const VECTOR2I& aPosition, const VECTOR2D& aSize,
|
||||||
const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
|
const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
|
||||||
bool aItalic ) const
|
bool aItalic ) const
|
||||||
{
|
{
|
||||||
if( !aGal )
|
if( !aGal )
|
||||||
{
|
return;
|
||||||
// do nothing, cursor does not move
|
|
||||||
return aPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEXT_STYLE_FLAGS textStyle = 0;
|
TEXT_STYLE_FLAGS textStyle = 0;
|
||||||
|
|
||||||
|
@ -358,23 +281,21 @@ VECTOR2D FONT::drawSingleLineText( KIGFX::GAL* aGal, BOX2I* aBoundingBox, const
|
||||||
textStyle |= TEXT_STYLE::ITALIC;
|
textStyle |= TEXT_STYLE::ITALIC;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<GLYPH>> glyphs;
|
std::vector<std::unique_ptr<GLYPH>> glyphs;
|
||||||
VECTOR2D nextPosition = drawMarkup( aBoundingBox, glyphs, aText, aPosition, aSize, aAngle,
|
|
||||||
aMirror, aOrigin, textStyle );
|
(void) drawMarkup( aBoundingBox, &glyphs, aText, aPosition, aSize, aAngle, aMirror, aOrigin,
|
||||||
|
textStyle );
|
||||||
|
|
||||||
for( const std::unique_ptr<GLYPH>& glyph : glyphs )
|
for( const std::unique_ptr<GLYPH>& glyph : glyphs )
|
||||||
aGal->DrawGlyph( *glyph.get() );
|
aGal->DrawGlyph( *glyph.get() );
|
||||||
|
|
||||||
return nextPosition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VECTOR2D FONT::StringBoundaryLimits( const UTF8& aText, const VECTOR2D& aSize, int aThickness,
|
VECTOR2I FONT::StringBoundaryLimits( const UTF8& aText, const VECTOR2D& aSize, int aThickness,
|
||||||
bool aBold, bool aItalic ) const
|
bool aBold, bool aItalic ) const
|
||||||
{
|
{
|
||||||
// TODO do we need to parse every time - have we already parsed?
|
// TODO do we need to parse every time - have we already parsed?
|
||||||
std::vector<std::unique_ptr<GLYPH>> glyphs; // ignored
|
BOX2I boundingBox;
|
||||||
BOX2I boundingBox;
|
TEXT_STYLE_FLAGS textStyle = 0;
|
||||||
TEXT_STYLE_FLAGS textStyle = 0;
|
|
||||||
|
|
||||||
if( aBold )
|
if( aBold )
|
||||||
textStyle |= TEXT_STYLE::BOLD;
|
textStyle |= TEXT_STYLE::BOLD;
|
||||||
|
@ -382,8 +303,8 @@ VECTOR2D FONT::StringBoundaryLimits( const UTF8& aText, const VECTOR2D& aSize, i
|
||||||
if( aItalic )
|
if( aItalic )
|
||||||
textStyle |= TEXT_STYLE::ITALIC;
|
textStyle |= TEXT_STYLE::ITALIC;
|
||||||
|
|
||||||
(void) drawMarkup( &boundingBox, glyphs, aText, VECTOR2D(), aSize, EDA_ANGLE::ANGLE_0,
|
(void) drawMarkup( &boundingBox, nullptr, aText, VECTOR2I(), aSize, EDA_ANGLE::ANGLE_0, false,
|
||||||
false, VECTOR2D(), textStyle );
|
VECTOR2I(), textStyle );
|
||||||
|
|
||||||
if( IsStroke() )
|
if( IsStroke() )
|
||||||
{
|
{
|
||||||
|
@ -399,18 +320,16 @@ VECTOR2D FONT::StringBoundaryLimits( const UTF8& aText, const VECTOR2D& aSize, i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VECTOR2D FONT::boundingBoxSingleLine( BOX2I* aBoundingBox, const UTF8& aText,
|
VECTOR2I FONT::boundingBoxSingleLine( BOX2I* aBBox, const UTF8& aText, const VECTOR2I& aPosition,
|
||||||
const VECTOR2I& aPosition, const VECTOR2D& aSize,
|
const VECTOR2D& aSize, bool aItalic ) const
|
||||||
bool aItalic ) const
|
|
||||||
{
|
{
|
||||||
TEXT_STYLE_FLAGS textStyle = 0;
|
TEXT_STYLE_FLAGS textStyle = 0;
|
||||||
|
|
||||||
if( aItalic )
|
if( aItalic )
|
||||||
textStyle |= TEXT_STYLE::ITALIC;
|
textStyle |= TEXT_STYLE::ITALIC;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<GLYPH>> glyphs; // ignored
|
VECTOR2I extents = drawMarkup( aBBox, nullptr, aText, aPosition, aSize, EDA_ANGLE::ANGLE_0,
|
||||||
VECTOR2D nextPosition = drawMarkup( aBoundingBox, glyphs, aText, aPosition, aSize,
|
false, VECTOR2I(), textStyle );
|
||||||
EDA_ANGLE::ANGLE_0, false, VECTOR2I(), textStyle );
|
|
||||||
|
|
||||||
return nextPosition;
|
return extents;
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,3 +108,23 @@ BOX2D OUTLINE_GLYPH::BoundingBox()
|
||||||
BOX2I bbox = BBox();
|
BOX2I bbox = BBox();
|
||||||
return BOX2D( bbox.GetOrigin(), bbox.GetSize() );
|
return BOX2D( bbox.GetOrigin(), bbox.GetSize() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void OUTLINE_GLYPH::Triangulate( TRIANGULATE_CALLBACK aCallback ) const
|
||||||
|
{
|
||||||
|
const_cast<OUTLINE_GLYPH*>( this )->CacheTriangulation();
|
||||||
|
|
||||||
|
for( unsigned int i = 0; i < TriangulatedPolyCount(); i++ )
|
||||||
|
{
|
||||||
|
const SHAPE_POLY_SET::TRIANGULATED_POLYGON* polygon = TriangulatedPolygon( i );
|
||||||
|
|
||||||
|
for ( size_t j = 0; j < polygon->GetTriangleCount(); j++ )
|
||||||
|
{
|
||||||
|
VECTOR2I a, b, c;
|
||||||
|
polygon->GetTriangle( j, a, b, c );
|
||||||
|
aCallback( i, a, b, c );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -227,35 +227,43 @@ BOX2I OUTLINE_FONT::getBoundingBox( const std::vector<std::unique_ptr<GLYPH>>& a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VECTOR2I OUTLINE_FONT::GetLinesAsGlyphs( std::vector<std::unique_ptr<GLYPH>>& aGlyphs,
|
void OUTLINE_FONT::GetLinesAsGlyphs( std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||||
const EDA_TEXT* aText ) const
|
const EDA_TEXT* aText ) const
|
||||||
{
|
{
|
||||||
wxArrayString strings;
|
wxArrayString strings;
|
||||||
std::vector<VECTOR2I> positions;
|
std::vector<VECTOR2I> positions;
|
||||||
VECTOR2I ret;
|
std::vector<VECTOR2I> extents;
|
||||||
std::vector<VECTOR2D> boundingBoxes;
|
|
||||||
TEXT_ATTRIBUTES attrs = aText->GetAttributes();
|
TEXT_ATTRIBUTES attrs = aText->GetAttributes();
|
||||||
TEXT_STYLE_FLAGS textStyle = 0;
|
|
||||||
|
|
||||||
attrs.m_Angle = aText->GetDrawRotation();
|
attrs.m_Angle = aText->GetDrawRotation();
|
||||||
|
|
||||||
if( aText->IsItalic() )
|
return GetLinesAsGlyphs( aGlyphs, aText->GetShownText(), aText->GetTextPos(), attrs );
|
||||||
textStyle |= TEXT_STYLE::ITALIC;
|
|
||||||
|
|
||||||
getLinePositions( aText->GetShownText(), aText->GetTextPos(), strings, positions, boundingBoxes,
|
|
||||||
attrs );
|
|
||||||
|
|
||||||
for( size_t i = 0; i < strings.GetCount(); i++ )
|
|
||||||
{
|
|
||||||
ret = drawMarkup( nullptr, aGlyphs, UTF8( strings.Item( i ) ), positions[i], attrs.m_Size,
|
|
||||||
attrs.m_Angle, attrs.m_Mirrored, aText->GetTextPos(), textStyle );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>& aGlyphs,
|
void OUTLINE_FONT::GetLinesAsGlyphs( std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||||
|
const UTF8& aText, const VECTOR2I& aPosition,
|
||||||
|
const TEXT_ATTRIBUTES& aAttrs ) const
|
||||||
|
{
|
||||||
|
wxArrayString strings;
|
||||||
|
std::vector<VECTOR2I> positions;
|
||||||
|
std::vector<VECTOR2I> extents;
|
||||||
|
TEXT_STYLE_FLAGS textStyle = 0;
|
||||||
|
|
||||||
|
if( aAttrs.m_Italic )
|
||||||
|
textStyle |= TEXT_STYLE::ITALIC;
|
||||||
|
|
||||||
|
getLinePositions( aText, aPosition, strings, positions, extents, aAttrs );
|
||||||
|
|
||||||
|
for( size_t i = 0; i < strings.GetCount(); i++ )
|
||||||
|
{
|
||||||
|
(void) drawMarkup( nullptr, aGlyphs, UTF8( strings.Item( i ) ), positions[i],
|
||||||
|
aAttrs.m_Size, aAttrs.m_Angle, aAttrs.m_Mirrored, aPosition, textStyle );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||||
const UTF8& aText, const VECTOR2D& aSize,
|
const UTF8& aText, const VECTOR2D& aSize,
|
||||||
const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
|
const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
|
||||||
bool aMirror, const VECTOR2I& aOrigin,
|
bool aMirror, const VECTOR2I& aOrigin,
|
||||||
|
@ -294,104 +302,88 @@ VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_pt
|
||||||
hb_glyph_position_t& pos = glyphPos[i];
|
hb_glyph_position_t& pos = glyphPos[i];
|
||||||
int codepoint = glyphInfo[i].codepoint;
|
int codepoint = glyphInfo[i].codepoint;
|
||||||
|
|
||||||
FT_Load_Glyph( face, codepoint, FT_LOAD_NO_BITMAP );
|
if( aGlyphs )
|
||||||
|
|
||||||
FT_GlyphSlot faceGlyph = face->glyph;
|
|
||||||
|
|
||||||
// contours is a collection of all outlines in the glyph;
|
|
||||||
// example: glyph for 'o' generally contains 2 contours,
|
|
||||||
// one for the glyph outline and one for the hole
|
|
||||||
CONTOURS contours;
|
|
||||||
|
|
||||||
OUTLINE_DECOMPOSER decomposer( faceGlyph->outline );
|
|
||||||
decomposer.OutlineToSegments( &contours );
|
|
||||||
|
|
||||||
std::unique_ptr<OUTLINE_GLYPH> glyph = std::make_unique<OUTLINE_GLYPH>();
|
|
||||||
std::vector<SHAPE_LINE_CHAIN> holes;
|
|
||||||
std::vector<SHAPE_LINE_CHAIN> outlines;
|
|
||||||
|
|
||||||
for( CONTOUR& c : contours )
|
|
||||||
{
|
{
|
||||||
GLYPH_POINTS points = c.points;
|
FT_Load_Glyph( face, codepoint, FT_LOAD_NO_BITMAP );
|
||||||
SHAPE_LINE_CHAIN shape;
|
|
||||||
|
|
||||||
for( const VECTOR2D& v : points )
|
FT_GlyphSlot faceGlyph = face->glyph;
|
||||||
|
|
||||||
|
// contours is a collection of all outlines in the glyph;
|
||||||
|
// example: glyph for 'o' generally contains 2 contours,
|
||||||
|
// one for the glyph outline and one for the hole
|
||||||
|
CONTOURS contours;
|
||||||
|
|
||||||
|
OUTLINE_DECOMPOSER decomposer( faceGlyph->outline );
|
||||||
|
decomposer.OutlineToSegments( &contours );
|
||||||
|
|
||||||
|
std::unique_ptr<OUTLINE_GLYPH> glyph = std::make_unique<OUTLINE_GLYPH>();
|
||||||
|
std::vector<SHAPE_LINE_CHAIN> holes;
|
||||||
|
|
||||||
|
for( CONTOUR& c : contours )
|
||||||
{
|
{
|
||||||
VECTOR2D pt( v + cursor );
|
GLYPH_POINTS points = c.points;
|
||||||
|
SHAPE_LINE_CHAIN shape;
|
||||||
|
|
||||||
topLeft.x = std::min( topLeft.x, pt.x );
|
for( const VECTOR2D& v : points )
|
||||||
topLeft.y = std::max( topLeft.y, pt.y );
|
|
||||||
topRight.x = std::max( topRight.x, pt.x );
|
|
||||||
topRight.y = std::max( topRight.y, pt.y );
|
|
||||||
|
|
||||||
if( IsSubscript( aTextStyle ) )
|
|
||||||
pt.y -= 0.25 * scaler;
|
|
||||||
else if( IsSuperscript( aTextStyle ) )
|
|
||||||
pt.y += 0.45 * scaler;
|
|
||||||
|
|
||||||
pt *= scaleFactor;
|
|
||||||
pt += aPosition;
|
|
||||||
|
|
||||||
if( aMirror )
|
|
||||||
pt.x = aOrigin.x - ( pt.x - aOrigin.x );
|
|
||||||
|
|
||||||
if( !aAngle.IsZero() )
|
|
||||||
RotatePoint( pt, aOrigin, aAngle );
|
|
||||||
|
|
||||||
shape.Append( pt.x, pt.y );
|
|
||||||
}
|
|
||||||
|
|
||||||
shape.SetClosed( true );
|
|
||||||
|
|
||||||
if( contourIsHole( c ) )
|
|
||||||
holes.push_back( std::move( shape ) );
|
|
||||||
else
|
|
||||||
outlines.push_back( std::move( shape ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
for( SHAPE_LINE_CHAIN& outline : outlines )
|
|
||||||
{
|
|
||||||
if( outline.PointCount() )
|
|
||||||
glyph->AddOutline( outline );
|
|
||||||
}
|
|
||||||
|
|
||||||
int nthHole = 0;
|
|
||||||
|
|
||||||
for( SHAPE_LINE_CHAIN& hole : holes )
|
|
||||||
{
|
|
||||||
if( hole.PointCount() )
|
|
||||||
{
|
|
||||||
VECTOR2I firstPoint = hole.GetPoint( 0 );
|
|
||||||
int nthOutline = -1;
|
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
for( SHAPE_LINE_CHAIN& outline : outlines )
|
|
||||||
{
|
{
|
||||||
if( outline.PointInside( firstPoint ) )
|
VECTOR2D pt( v + cursor );
|
||||||
{
|
|
||||||
nthOutline = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
n++;
|
topLeft.x = std::min( topLeft.x, pt.x );
|
||||||
|
topLeft.y = std::max( topLeft.y, pt.y );
|
||||||
|
topRight.x = std::max( topRight.x, pt.x );
|
||||||
|
topRight.y = std::max( topRight.y, pt.y );
|
||||||
|
|
||||||
|
if( IsSubscript( aTextStyle ) )
|
||||||
|
pt.y -= 0.25 * scaler;
|
||||||
|
else if( IsSuperscript( aTextStyle ) )
|
||||||
|
pt.y += 0.45 * scaler;
|
||||||
|
|
||||||
|
pt *= scaleFactor;
|
||||||
|
pt += aPosition;
|
||||||
|
|
||||||
|
if( aMirror )
|
||||||
|
pt.x = aOrigin.x - ( pt.x - aOrigin.x );
|
||||||
|
|
||||||
|
if( !aAngle.IsZero() )
|
||||||
|
RotatePoint( pt, aOrigin, aAngle );
|
||||||
|
|
||||||
|
shape.Append( pt.x, pt.y );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nthOutline > -1 )
|
shape.SetClosed( true );
|
||||||
glyph->AddHole( hole, n );
|
|
||||||
|
if( contourIsHole( c ) )
|
||||||
|
holes.push_back( std::move( shape ) );
|
||||||
|
else
|
||||||
|
glyph->AddOutline( std::move( shape ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
nthHole++;
|
for( SHAPE_LINE_CHAIN& hole : holes )
|
||||||
}
|
{
|
||||||
|
if( hole.PointCount() )
|
||||||
|
{
|
||||||
|
for( int ii = 0; ii < glyph->OutlineCount(); ++ii )
|
||||||
|
{
|
||||||
|
if( glyph->Outline( ii ).PointInside( hole.GetPoint( 0 ) ) )
|
||||||
|
{
|
||||||
|
glyph->AddHole( std::move( hole ), ii );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
aGlyphs.push_back( std::move( glyph ) );
|
if( glyph->HasHoles() )
|
||||||
|
glyph->Fracture( SHAPE_POLY_SET::PM_FAST ); // FONT TODO verify aFastMode
|
||||||
|
|
||||||
|
aGlyphs->push_back( std::move( glyph ) );
|
||||||
|
}
|
||||||
|
|
||||||
cursor.x += pos.x_advance;
|
cursor.x += pos.x_advance;
|
||||||
cursor.y += pos.y_advance;
|
cursor.y += pos.y_advance;
|
||||||
}
|
}
|
||||||
|
|
||||||
VECTOR2I cursorEnd( cursor );
|
if( IsOverbar( aTextStyle ) && aGlyphs )
|
||||||
|
|
||||||
if( IsOverbar( aTextStyle ) )
|
|
||||||
{
|
{
|
||||||
topLeft *= scaleFactor;
|
topLeft *= scaleFactor;
|
||||||
topRight *= scaleFactor;
|
topRight *= scaleFactor;
|
||||||
|
@ -415,12 +407,12 @@ VECTOR2I OUTLINE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_pt
|
||||||
ERROR_INSIDE );
|
ERROR_INSIDE );
|
||||||
|
|
||||||
std::unique_ptr<OUTLINE_GLYPH> overbarGlyph = std::make_unique<OUTLINE_GLYPH>( overbar );
|
std::unique_ptr<OUTLINE_GLYPH> overbarGlyph = std::make_unique<OUTLINE_GLYPH>( overbar );
|
||||||
aGlyphs.push_back( std::move( overbarGlyph ) );
|
aGlyphs->push_back( std::move( overbarGlyph ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_buffer_destroy( buf );
|
hb_buffer_destroy( buf );
|
||||||
|
|
||||||
VECTOR2I cursorDisplacement( cursorEnd.x * scaleFactor.x, -cursorEnd.y * scaleFactor.y );
|
VECTOR2I cursorDisplacement( cursor.x * scaleFactor.x, -cursor.y * scaleFactor.y );
|
||||||
|
|
||||||
if( aBBox )
|
if( aBBox )
|
||||||
{
|
{
|
||||||
|
|
|
@ -195,7 +195,7 @@ double STROKE_FONT::ComputeOverbarVerticalPosition( double aGlyphHeight ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>& aGlyphs,
|
VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||||
const UTF8& aText, const VECTOR2D& aSize,
|
const UTF8& aText, const VECTOR2D& aSize,
|
||||||
const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
|
const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
|
||||||
bool aMirror, const VECTOR2I& aOrigin,
|
bool aMirror, const VECTOR2I& aOrigin,
|
||||||
|
@ -252,10 +252,20 @@ VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr
|
||||||
{
|
{
|
||||||
STROKE_GLYPH* source = static_cast<STROKE_GLYPH*>( m_glyphs->at( dd ).get() );
|
STROKE_GLYPH* source = static_cast<STROKE_GLYPH*>( m_glyphs->at( dd ).get() );
|
||||||
|
|
||||||
aGlyphs.push_back( source->Transform( glyphSize, cursor, tilt, aAngle, aMirror,
|
if( aGlyphs )
|
||||||
aOrigin ) );
|
{
|
||||||
|
aGlyphs->push_back( source->Transform( glyphSize, cursor, tilt, aAngle, aMirror,
|
||||||
|
aOrigin ) );
|
||||||
|
}
|
||||||
|
|
||||||
cursor.x = aGlyphs.back()->BoundingBox().GetEnd().x;
|
VECTOR2D glyphExtents = source->BoundingBox().GetEnd();
|
||||||
|
|
||||||
|
glyphExtents *= glyphSize;
|
||||||
|
|
||||||
|
if( tilt )
|
||||||
|
glyphExtents.x -= glyphExtents.y * tilt;
|
||||||
|
|
||||||
|
cursor.x += glyphExtents.x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,8 +273,6 @@ VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr
|
||||||
|
|
||||||
if( aTextStyle & TEXT_STYLE::OVERBAR )
|
if( aTextStyle & TEXT_STYLE::OVERBAR )
|
||||||
{
|
{
|
||||||
std::unique_ptr<STROKE_GLYPH> overbarGlyph = std::make_unique<STROKE_GLYPH>();
|
|
||||||
|
|
||||||
barOffset.y = ComputeOverbarVerticalPosition( glyphSize.y );
|
barOffset.y = ComputeOverbarVerticalPosition( glyphSize.y );
|
||||||
|
|
||||||
if( aTextStyle & TEXT_STYLE::ITALIC )
|
if( aTextStyle & TEXT_STYLE::ITALIC )
|
||||||
|
@ -279,11 +287,16 @@ VECTOR2I STROKE_FONT::GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr
|
||||||
RotatePoint( barEnd, aOrigin, aAngle );
|
RotatePoint( barEnd, aOrigin, aAngle );
|
||||||
}
|
}
|
||||||
|
|
||||||
overbarGlyph->AddPoint( barStart );
|
if( aGlyphs )
|
||||||
overbarGlyph->AddPoint( barEnd );
|
{
|
||||||
overbarGlyph->Finalize();
|
std::unique_ptr<STROKE_GLYPH> overbarGlyph = std::make_unique<STROKE_GLYPH>();
|
||||||
|
|
||||||
aGlyphs.push_back( std::move( overbarGlyph ) );
|
overbarGlyph->AddPoint( barStart );
|
||||||
|
overbarGlyph->AddPoint( barEnd );
|
||||||
|
overbarGlyph->Finalize();
|
||||||
|
|
||||||
|
aGlyphs->push_back( std::move( overbarGlyph ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( aBBox )
|
if( aBBox )
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 Ola Rinta-Koski
|
|
||||||
* Copyright (C) 2021 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include <font/triangulate.h>
|
|
||||||
|
|
||||||
void Triangulate( const SHAPE_POLY_SET& aPolylist, TRIANGULATE_CALLBACK aCallback,
|
|
||||||
void* aCallbackData )
|
|
||||||
{
|
|
||||||
SHAPE_POLY_SET polys( aPolylist );
|
|
||||||
|
|
||||||
polys.Fracture( SHAPE_POLY_SET::PM_FAST ); // TODO verify aFastMode
|
|
||||||
polys.CacheTriangulation();
|
|
||||||
|
|
||||||
for( unsigned int i = 0; i < polys.TriangulatedPolyCount(); i++ )
|
|
||||||
{
|
|
||||||
const SHAPE_POLY_SET::TRIANGULATED_POLYGON* polygon = polys.TriangulatedPolygon( i );
|
|
||||||
for ( size_t j = 0; j < polygon->GetTriangleCount(); j++ )
|
|
||||||
{
|
|
||||||
VECTOR2I a;
|
|
||||||
VECTOR2I b;
|
|
||||||
VECTOR2I c;
|
|
||||||
|
|
||||||
polygon->GetTriangle( j, a, b, c );
|
|
||||||
aCallback( i, a, b, c, aCallbackData );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1786,44 +1786,44 @@ void CAIRO_GAL_BASE::DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTota
|
||||||
// eventually glyphs should not be drawn as polygons at all,
|
// eventually glyphs should not be drawn as polygons at all,
|
||||||
// but as bitmaps with antialiasing, this is just a stopgap measure
|
// but as bitmaps with antialiasing, this is just a stopgap measure
|
||||||
// of getting some form of outline font display
|
// of getting some form of outline font display
|
||||||
auto triangleCallback = [&]( int aPolygonIndex, const VECTOR2D& aVertex1,
|
auto triangleCallback =
|
||||||
const VECTOR2D& aVertex2, const VECTOR2D& aVertex3,
|
[&]( int aPolygonIndex, const VECTOR2D& aVertex1, const VECTOR2D& aVertex2,
|
||||||
void* aCallbackData )
|
const VECTOR2D& aVertex3, void* aCallbackData )
|
||||||
{
|
{
|
||||||
#if 1
|
#if 1
|
||||||
syncLineWidth();
|
syncLineWidth();
|
||||||
|
|
||||||
const auto p0 = roundp( xform( aVertex1 ) );
|
const auto p0 = roundp( xform( aVertex1 ) );
|
||||||
const auto p1 = roundp( xform( aVertex2 ) );
|
const auto p1 = roundp( xform( aVertex2 ) );
|
||||||
const auto p2 = roundp( xform( aVertex3 ) );
|
const auto p2 = roundp( xform( aVertex3 ) );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
cairo_move_to( currentContext, aVertex1.x, aVertex1.y );
|
cairo_move_to( currentContext, aVertex1.x, aVertex1.y );
|
||||||
cairo_line_to( currentContext, aVertex2.x, aVertex2.y );
|
cairo_line_to( currentContext, aVertex2.x, aVertex2.y );
|
||||||
cairo_line_to( currentContext, aVertex3.x, aVertex3.y );
|
cairo_line_to( currentContext, aVertex3.x, aVertex3.y );
|
||||||
cairo_line_to( currentContext, aVertex1.x, aVertex1.y );
|
cairo_line_to( currentContext, aVertex1.x, aVertex1.y );
|
||||||
*/
|
*/
|
||||||
cairo_move_to( m_currentContext, p0.x, p0.y );
|
cairo_move_to( m_currentContext, p0.x, p0.y );
|
||||||
cairo_line_to( m_currentContext, p1.x, p1.y );
|
cairo_line_to( m_currentContext, p1.x, p1.y );
|
||||||
cairo_line_to( m_currentContext, p2.x, p2.y );
|
cairo_line_to( m_currentContext, p2.x, p2.y );
|
||||||
cairo_close_path( m_currentContext );
|
cairo_close_path( m_currentContext );
|
||||||
/*
|
/*
|
||||||
setSourceRgba( currentContext, fillColor );
|
setSourceRgba( currentContext, fillColor );
|
||||||
SetIsFill( true );
|
SetIsFill( true );
|
||||||
cairo_set_fill_rule( currentContext, CAIRO_FILL_RULE_EVEN_ODD );
|
cairo_set_fill_rule( currentContext, CAIRO_FILL_RULE_EVEN_ODD );
|
||||||
flushPath();
|
flushPath();
|
||||||
*/
|
*/
|
||||||
//cairo_fill( currentContext );
|
//cairo_fill( currentContext );
|
||||||
#else
|
#else
|
||||||
// just a silly test
|
// just a silly test
|
||||||
/*
|
/*
|
||||||
DrawRectangle(aVertex1, aVertex2);
|
DrawRectangle(aVertex1, aVertex2);
|
||||||
DrawRectangle(aVertex2, aVertex3);
|
DrawRectangle(aVertex2, aVertex3);
|
||||||
DrawRectangle(aVertex3, aVertex1);
|
DrawRectangle(aVertex3, aVertex1);
|
||||||
*/
|
*/
|
||||||
DrawTriangle( aVertex1, aVertex2, aVertex3 );
|
DrawTriangle( aVertex1, aVertex2, aVertex3 );
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
Triangulate( aGlyph, triangleCallback );
|
Triangulate( aGlyph, triangleCallback );
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,6 @@
|
||||||
#include <bezier_curves.h>
|
#include <bezier_curves.h>
|
||||||
#include <math/util.h> // for KiROUND
|
#include <math/util.h> // for KiROUND
|
||||||
#include <trace_helpers.h>
|
#include <trace_helpers.h>
|
||||||
#include <font/triangulate.h>
|
|
||||||
|
|
||||||
#include <wx/frame.h>
|
#include <wx/frame.h>
|
||||||
|
|
||||||
|
@ -2425,24 +2424,16 @@ void OPENGL_GAL::DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTotal )
|
||||||
{
|
{
|
||||||
const auto& outlineGlyph = static_cast<const KIFONT::OUTLINE_GLYPH&>( aGlyph );
|
const auto& outlineGlyph = static_cast<const KIFONT::OUTLINE_GLYPH&>( aGlyph );
|
||||||
|
|
||||||
fillPolygonAsTriangles( outlineGlyph );
|
m_currentManager->Shader( SHADER_NONE );
|
||||||
|
m_currentManager->Color( m_fillColor );
|
||||||
|
|
||||||
|
outlineGlyph.Triangulate(
|
||||||
|
[&]( int aPolygonIndex, const VECTOR2D& aVertex1, const VECTOR2D& aVertex2,
|
||||||
|
const VECTOR2D& aVertex3 )
|
||||||
|
{
|
||||||
|
m_currentManager->Vertex( aVertex1.x, aVertex1.y, m_layerDepth );
|
||||||
|
m_currentManager->Vertex( aVertex2.x, aVertex2.y, m_layerDepth );
|
||||||
|
m_currentManager->Vertex( aVertex3.x, aVertex3.y, m_layerDepth );
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void OPENGL_GAL::fillPolygonAsTriangles( const SHAPE_POLY_SET& aPolyList )
|
|
||||||
{
|
|
||||||
m_currentManager->Shader( SHADER_NONE );
|
|
||||||
m_currentManager->Color( m_fillColor );
|
|
||||||
|
|
||||||
auto triangleCallback = [&]( int aPolygonIndex, const VECTOR2D& aVertex1,
|
|
||||||
const VECTOR2D& aVertex2, const VECTOR2D& aVertex3,
|
|
||||||
void* aCallbackData )
|
|
||||||
{
|
|
||||||
m_currentManager->Vertex( aVertex1.x, aVertex1.y, m_layerDepth );
|
|
||||||
m_currentManager->Vertex( aVertex2.x, aVertex2.y, m_layerDepth );
|
|
||||||
m_currentManager->Vertex( aVertex3.x, aVertex3.y, m_layerDepth );
|
|
||||||
};
|
|
||||||
|
|
||||||
Triangulate( aPolyList, triangleCallback );
|
|
||||||
}
|
|
||||||
|
|
|
@ -1118,10 +1118,10 @@ const EDA_RECT LIB_PIN::GetBoundingBox( bool aIncludeInvisibles, bool aPinOnly )
|
||||||
if( showNum )
|
if( showNum )
|
||||||
{
|
{
|
||||||
VECTOR2D fontSize( m_numTextSize, m_numTextSize );
|
VECTOR2D fontSize( m_numTextSize, m_numTextSize );
|
||||||
VECTOR2D numSize = font->StringBoundaryLimits( number, fontSize, penWidth, false, false );
|
VECTOR2I numSize = font->StringBoundaryLimits( number, fontSize, penWidth, false, false );
|
||||||
|
|
||||||
numberTextLength = KiROUND( numSize.x );
|
numberTextLength = numSize.x;
|
||||||
numberTextHeight = KiROUND( numSize.y );
|
numberTextHeight = numSize.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( m_shape == GRAPHIC_PINSHAPE::INVERTED || m_shape == GRAPHIC_PINSHAPE::INVERTED_CLOCK )
|
if( m_shape == GRAPHIC_PINSHAPE::INVERTED || m_shape == GRAPHIC_PINSHAPE::INVERTED_CLOCK )
|
||||||
|
@ -1136,10 +1136,10 @@ const EDA_RECT LIB_PIN::GetBoundingBox( bool aIncludeInvisibles, bool aPinOnly )
|
||||||
if( showName )
|
if( showName )
|
||||||
{
|
{
|
||||||
VECTOR2D fontSize( m_nameTextSize, m_nameTextSize );
|
VECTOR2D fontSize( m_nameTextSize, m_nameTextSize );
|
||||||
VECTOR2D nameSize = font->StringBoundaryLimits( name, fontSize, penWidth, false, false );
|
VECTOR2I nameSize = font->StringBoundaryLimits( name, fontSize, penWidth, false, false );
|
||||||
|
|
||||||
nameTextLength = KiROUND( nameSize.x ) + nameTextOffset;
|
nameTextLength = nameSize.x + nameTextOffset;
|
||||||
nameTextHeight = KiROUND( nameSize.y ) + Mils2iu( PIN_TEXT_MARGIN );
|
nameTextHeight = nameSize.y + Mils2iu( PIN_TEXT_MARGIN );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nameTextOffset ) // for values > 0, pin name is inside the body
|
if( nameTextOffset ) // for values > 0, pin name is inside the body
|
||||||
|
|
|
@ -432,6 +432,19 @@ std::unique_ptr< LIB_SYMBOL > LIB_SYMBOL::Flatten() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LIB_SYMBOL::ClearCaches()
|
||||||
|
{
|
||||||
|
for( LIB_ITEM& item : m_drawings )
|
||||||
|
{
|
||||||
|
if( EDA_TEXT* eda_text = dynamic_cast<EDA_TEXT*>( &item ) )
|
||||||
|
{
|
||||||
|
eda_text->ClearBoundingBoxCache();
|
||||||
|
eda_text->ClearRenderCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const wxString LIB_SYMBOL::GetLibraryName() const
|
const wxString LIB_SYMBOL::GetLibraryName() const
|
||||||
{
|
{
|
||||||
if( m_library )
|
if( m_library )
|
||||||
|
|
|
@ -126,6 +126,8 @@ public:
|
||||||
LIB_SYMBOL_REF& GetParent() { return m_parent; }
|
LIB_SYMBOL_REF& GetParent() { return m_parent; }
|
||||||
const LIB_SYMBOL_REF& GetParent() const { return m_parent; }
|
const LIB_SYMBOL_REF& GetParent() const { return m_parent; }
|
||||||
|
|
||||||
|
void ClearCaches();
|
||||||
|
|
||||||
virtual wxString GetClass() const override
|
virtual wxString GetClass() const override
|
||||||
{
|
{
|
||||||
return wxT( "LIB_SYMBOL" );
|
return wxT( "LIB_SYMBOL" );
|
||||||
|
|
|
@ -213,7 +213,8 @@ public:
|
||||||
/**
|
/**
|
||||||
* Mark an item for refresh.
|
* Mark an item for refresh.
|
||||||
*/
|
*/
|
||||||
void UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete = false, bool aUpdateRtree = false );
|
virtual void UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete = false,
|
||||||
|
bool aUpdateRtree = false );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark selected items for refresh.
|
* Mark selected items for refresh.
|
||||||
|
|
|
@ -649,6 +649,14 @@ void SCH_EDIT_FRAME::SetCurrentSheet( const SCH_SHEET_PATH& aSheet )
|
||||||
|
|
||||||
void SCH_EDIT_FRAME::HardRedraw()
|
void SCH_EDIT_FRAME::HardRedraw()
|
||||||
{
|
{
|
||||||
|
SCH_SCREEN* screen = GetCurrentSheet().LastScreen();
|
||||||
|
|
||||||
|
for( SCH_ITEM* item : screen->Items() )
|
||||||
|
item->ClearCaches();
|
||||||
|
|
||||||
|
for( std::pair<const wxString, LIB_SYMBOL*>& libSymbol : screen->GetLibSymbols() )
|
||||||
|
libSymbol.second->ClearCaches();
|
||||||
|
|
||||||
RecalculateConnections( LOCAL_CLEANUP );
|
RecalculateConnections( LOCAL_CLEANUP );
|
||||||
|
|
||||||
FocusOnItem( nullptr );
|
FocusOnItem( nullptr );
|
||||||
|
@ -1752,3 +1760,12 @@ void SCH_EDIT_FRAME::SaveSymbolToSchematic( const LIB_SYMBOL& aSymbol,
|
||||||
GetCanvas()->Refresh();
|
GetCanvas()->Refresh();
|
||||||
OnModify();
|
OnModify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SCH_EDIT_FRAME::UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete, bool aUpdateRtree )
|
||||||
|
{
|
||||||
|
SCH_BASE_FRAME::UpdateItem( aItem, isAddOrDelete, aUpdateRtree );
|
||||||
|
|
||||||
|
if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
|
||||||
|
sch_item->ClearCaches();
|
||||||
|
}
|
|
@ -429,6 +429,9 @@ public:
|
||||||
|
|
||||||
void SetCurrentSheet( const SCH_SHEET_PATH& aSheet );
|
void SetCurrentSheet( const SCH_SHEET_PATH& aSheet );
|
||||||
|
|
||||||
|
void UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete = false,
|
||||||
|
bool aUpdateRtree = false ) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rebuild the GAL and redraw the screen. Call when something went wrong.
|
* Rebuild the GAL and redraw the screen. Call when something went wrong.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -52,13 +52,16 @@
|
||||||
#include <eeschema_id.h>
|
#include <eeschema_id.h>
|
||||||
#include <tool/tool_manager.h>
|
#include <tool/tool_manager.h>
|
||||||
#include <tools/ee_actions.h>
|
#include <tools/ee_actions.h>
|
||||||
|
#include <font/outline_font.h>
|
||||||
|
|
||||||
|
|
||||||
SCH_FIELD::SCH_FIELD( const VECTOR2I& aPos, int aFieldId, SCH_ITEM* aParent,
|
SCH_FIELD::SCH_FIELD( const VECTOR2I& aPos, int aFieldId, SCH_ITEM* aParent,
|
||||||
const wxString& aName ) :
|
const wxString& aName ) :
|
||||||
SCH_ITEM( aParent, SCH_FIELD_T ),
|
SCH_ITEM( aParent, SCH_FIELD_T ),
|
||||||
EDA_TEXT( wxEmptyString ),
|
EDA_TEXT( wxEmptyString ),
|
||||||
m_id( 0 ),
|
m_id( 0 ),
|
||||||
m_name( aName )
|
m_name( aName ),
|
||||||
|
m_renderCacheValid( false )
|
||||||
{
|
{
|
||||||
SetTextPos( aPos );
|
SetTextPos( aPos );
|
||||||
SetId( aFieldId ); // will also set the layer
|
SetId( aFieldId ); // will also set the layer
|
||||||
|
@ -66,11 +69,53 @@ SCH_FIELD::SCH_FIELD( const VECTOR2I& aPos, int aFieldId, SCH_ITEM* aParent,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SCH_FIELD::SCH_FIELD( const SCH_FIELD& aField ) :
|
||||||
|
SCH_ITEM( aField ),
|
||||||
|
EDA_TEXT( aField )
|
||||||
|
{
|
||||||
|
m_id = aField.m_id;
|
||||||
|
m_name = aField.m_name;
|
||||||
|
|
||||||
|
m_renderCache.clear();
|
||||||
|
|
||||||
|
for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aField.m_renderCache )
|
||||||
|
{
|
||||||
|
KIFONT::OUTLINE_GLYPH* outline_glyph = static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() );
|
||||||
|
m_renderCache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline_glyph ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_renderCacheValid = aField.m_renderCacheValid;
|
||||||
|
m_renderCachePos = aField.m_renderCachePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SCH_FIELD::~SCH_FIELD()
|
SCH_FIELD::~SCH_FIELD()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SCH_FIELD& SCH_FIELD::operator=( const SCH_FIELD& aField )
|
||||||
|
{
|
||||||
|
EDA_TEXT::operator=( aField );
|
||||||
|
|
||||||
|
m_id = aField.m_id;
|
||||||
|
m_name = aField.m_name;
|
||||||
|
|
||||||
|
m_renderCache.clear();
|
||||||
|
|
||||||
|
for( const std::unique_ptr<KIFONT::GLYPH>& glyph : aField.m_renderCache )
|
||||||
|
{
|
||||||
|
KIFONT::OUTLINE_GLYPH* outline_glyph = static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() );
|
||||||
|
m_renderCache.emplace_back( std::make_unique<KIFONT::OUTLINE_GLYPH>( *outline_glyph ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_renderCacheValid = aField.m_renderCacheValid;
|
||||||
|
m_renderCachePos = aField.m_renderCachePos;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
EDA_ITEM* SCH_FIELD::Clone() const
|
EDA_ITEM* SCH_FIELD::Clone() const
|
||||||
{
|
{
|
||||||
return new SCH_FIELD( *this );
|
return new SCH_FIELD( *this );
|
||||||
|
@ -226,6 +271,54 @@ KIFONT::FONT* SCH_FIELD::GetDrawFont() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SCH_FIELD::ClearCaches()
|
||||||
|
{
|
||||||
|
ClearRenderCache();
|
||||||
|
EDA_TEXT::ClearBoundingBoxCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SCH_FIELD::ClearRenderCache()
|
||||||
|
{
|
||||||
|
EDA_TEXT::ClearRenderCache();
|
||||||
|
m_renderCacheValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<KIFONT::GLYPH>>*
|
||||||
|
SCH_FIELD::GetRenderCache( const wxString& forResolvedText, const VECTOR2I& forPosition,
|
||||||
|
TEXT_ATTRIBUTES& aAttrs ) const
|
||||||
|
{
|
||||||
|
if( GetDrawFont()->IsOutline() )
|
||||||
|
{
|
||||||
|
if( m_renderCache.empty() || !m_renderCacheValid )
|
||||||
|
{
|
||||||
|
m_renderCache.clear();
|
||||||
|
|
||||||
|
KIFONT::OUTLINE_FONT* font = static_cast<KIFONT::OUTLINE_FONT*>( GetDrawFont() );
|
||||||
|
font->GetLinesAsGlyphs( &m_renderCache, forResolvedText, forPosition, aAttrs );
|
||||||
|
|
||||||
|
m_renderCachePos = forPosition;
|
||||||
|
m_renderCacheValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_renderCachePos != forPosition )
|
||||||
|
{
|
||||||
|
VECTOR2I delta = forPosition - m_renderCachePos;
|
||||||
|
|
||||||
|
for( std::unique_ptr<KIFONT::GLYPH>& glyph : m_renderCache )
|
||||||
|
static_cast<KIFONT::OUTLINE_GLYPH*>( glyph.get() )->Move( delta );
|
||||||
|
|
||||||
|
m_renderCachePos = forPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &m_renderCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SCH_FIELD::Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset )
|
void SCH_FIELD::Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset )
|
||||||
{
|
{
|
||||||
wxDC* DC = aSettings->GetPrintDC();
|
wxDC* DC = aSettings->GetPrintDC();
|
||||||
|
|
|
@ -52,10 +52,12 @@ public:
|
||||||
SCH_FIELD( const VECTOR2I& aPos, int aFieldId, SCH_ITEM* aParent,
|
SCH_FIELD( const VECTOR2I& aPos, int aFieldId, SCH_ITEM* aParent,
|
||||||
const wxString& aName = wxEmptyString );
|
const wxString& aName = wxEmptyString );
|
||||||
|
|
||||||
// Do not create a copy constructor. The one generated by the compiler is adequate.
|
SCH_FIELD( const SCH_FIELD& aText );
|
||||||
|
|
||||||
~SCH_FIELD();
|
~SCH_FIELD();
|
||||||
|
|
||||||
|
SCH_FIELD& operator=( const SCH_FIELD& aField );
|
||||||
|
|
||||||
static inline bool ClassOf( const EDA_ITEM* aItem )
|
static inline bool ClassOf( const EDA_ITEM* aItem )
|
||||||
{
|
{
|
||||||
return aItem && SCH_FIELD_T == aItem->Type();
|
return aItem && SCH_FIELD_T == aItem->Type();
|
||||||
|
@ -156,6 +158,13 @@ public:
|
||||||
|
|
||||||
KIFONT::FONT* GetDrawFont() const override;
|
KIFONT::FONT* GetDrawFont() const override;
|
||||||
|
|
||||||
|
void ClearCaches() override;
|
||||||
|
void ClearRenderCache() override;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<KIFONT::GLYPH>>*
|
||||||
|
GetRenderCache( const wxString& forResolvedText, const VECTOR2I& forPosition,
|
||||||
|
TEXT_ATTRIBUTES& aAttrs ) const;
|
||||||
|
|
||||||
void Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset ) override;
|
void Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset ) override;
|
||||||
|
|
||||||
void Move( const VECTOR2I& aMoveVector ) override
|
void Move( const VECTOR2I& aMoveVector ) override
|
||||||
|
@ -222,6 +231,10 @@ private:
|
||||||
int m_id; ///< Field index, @see enum MANDATORY_FIELD_T
|
int m_id; ///< Field index, @see enum MANDATORY_FIELD_T
|
||||||
|
|
||||||
wxString m_name;
|
wxString m_name;
|
||||||
|
|
||||||
|
mutable bool m_renderCacheValid;
|
||||||
|
mutable VECTOR2I m_renderCachePos;
|
||||||
|
mutable std::vector<std::unique_ptr<KIFONT::GLYPH>> m_renderCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -230,6 +230,26 @@ void SCH_ITEM::SwapData( SCH_ITEM* aItem )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SCH_ITEM::ClearCaches()
|
||||||
|
{
|
||||||
|
auto clearTextCaches =
|
||||||
|
[]( SCH_ITEM* aItem )
|
||||||
|
{
|
||||||
|
EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
|
||||||
|
|
||||||
|
if( text )
|
||||||
|
{
|
||||||
|
text->ClearBoundingBoxCache();
|
||||||
|
text->ClearRenderCache();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
clearTextCaches( this );
|
||||||
|
|
||||||
|
RunOnChildren( clearTextCaches );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SCH_ITEM::operator < ( const SCH_ITEM& aItem ) const
|
bool SCH_ITEM::operator < ( const SCH_ITEM& aItem ) const
|
||||||
{
|
{
|
||||||
if( Type() != aItem.Type() )
|
if( Type() != aItem.Type() )
|
||||||
|
|
|
@ -429,6 +429,8 @@ public:
|
||||||
|
|
||||||
virtual void RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction ) { }
|
virtual void RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction ) { }
|
||||||
|
|
||||||
|
virtual void ClearCaches();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if this schematic item has line stoke properties.
|
* Check if this schematic item has line stoke properties.
|
||||||
*
|
*
|
||||||
|
|
|
@ -464,7 +464,7 @@ void SCH_PAINTER::boxText( const wxString& aText, const VECTOR2D& aPosition,
|
||||||
aAttrs.m_Italic );
|
aAttrs.m_Italic );
|
||||||
}
|
}
|
||||||
|
|
||||||
VECTOR2D extents = font->StringBoundaryLimits( aText, aAttrs.m_Size, aAttrs.m_StrokeWidth,
|
VECTOR2I extents = font->StringBoundaryLimits( aText, aAttrs.m_Size, aAttrs.m_StrokeWidth,
|
||||||
aAttrs.m_Bold, aAttrs.m_Italic );
|
aAttrs.m_Bold, aAttrs.m_Italic );
|
||||||
EDA_RECT box( (VECTOR2I) aPosition, wxSize( extents.x, aAttrs.m_Size.y ) );
|
EDA_RECT box( (VECTOR2I) aPosition, wxSize( extents.x, aAttrs.m_Size.y ) );
|
||||||
|
|
||||||
|
@ -718,11 +718,10 @@ void SCH_PAINTER::draw( const LIB_FIELD *aField, int aLayer )
|
||||||
|
|
||||||
if( drawingShadows && eeconfig()->m_Selection.text_as_box )
|
if( drawingShadows && eeconfig()->m_Selection.text_as_box )
|
||||||
{
|
{
|
||||||
bbox.RevertYAxis();
|
|
||||||
m_gal->SetIsStroke( true );
|
m_gal->SetIsStroke( true );
|
||||||
m_gal->SetIsFill( true );
|
m_gal->SetIsFill( true );
|
||||||
m_gal->SetLineWidth( getTextThickness( aField, drawingShadows ) );
|
m_gal->SetLineWidth( getTextThickness( aField, drawingShadows ) );
|
||||||
m_gal->DrawRectangle( mapCoords( bbox.GetPosition() ), mapCoords( bbox.GetEnd() ) );
|
m_gal->DrawRectangle( bbox.GetPosition(), bbox.GetEnd() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -765,18 +764,27 @@ void SCH_PAINTER::draw( const LIB_TEXT *aText, int aLayer )
|
||||||
}
|
}
|
||||||
|
|
||||||
EDA_RECT bBox = aText->GetBoundingBox();
|
EDA_RECT bBox = aText->GetBoundingBox();
|
||||||
bBox.RevertYAxis();
|
VECTOR2D pos = bBox.Centre();
|
||||||
VECTOR2D pos = mapCoords( bBox.Centre() );
|
|
||||||
|
|
||||||
m_gal->SetFillColor( color );
|
m_gal->SetFillColor( color );
|
||||||
m_gal->SetStrokeColor( color );
|
m_gal->SetStrokeColor( color );
|
||||||
|
|
||||||
TEXT_ATTRIBUTES attrs( aText->GetAttributes() );
|
if( drawingShadows && eeconfig()->m_Selection.text_as_box )
|
||||||
attrs.m_Halign = GR_TEXT_H_ALIGN_CENTER;
|
{
|
||||||
attrs.m_Valign = GR_TEXT_V_ALIGN_CENTER;
|
m_gal->SetIsStroke( true );
|
||||||
attrs.m_StrokeWidth = getTextThickness( aText, drawingShadows );
|
m_gal->SetIsFill( true );
|
||||||
|
m_gal->SetLineWidth( getTextThickness( aText, drawingShadows ) );
|
||||||
|
m_gal->DrawRectangle( bBox.GetPosition(), bBox.GetEnd() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TEXT_ATTRIBUTES attrs( aText->GetAttributes() );
|
||||||
|
attrs.m_Halign = GR_TEXT_H_ALIGN_CENTER;
|
||||||
|
attrs.m_Valign = GR_TEXT_V_ALIGN_CENTER;
|
||||||
|
attrs.m_StrokeWidth = getTextThickness( aText, drawingShadows );
|
||||||
|
|
||||||
strokeText( aText->GetText(), pos, attrs );
|
strokeText( aText->GetText(), pos, attrs );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1477,7 +1485,6 @@ void SCH_PAINTER::draw( const SCH_TEXT *aText, int aLayer )
|
||||||
if( drawingShadows && eeconfig()->m_Selection.text_as_box )
|
if( drawingShadows && eeconfig()->m_Selection.text_as_box )
|
||||||
{
|
{
|
||||||
EDA_RECT bBox = aText->GetBoundingBox();
|
EDA_RECT bBox = aText->GetBoundingBox();
|
||||||
bBox.Offset( text_offset.x, text_offset.y );
|
|
||||||
bBox.RevertYAxis();
|
bBox.RevertYAxis();
|
||||||
m_gal->SetIsStroke( true );
|
m_gal->SetIsStroke( true );
|
||||||
m_gal->SetIsFill( true );
|
m_gal->SetIsFill( true );
|
||||||
|
@ -1503,7 +1510,7 @@ void SCH_PAINTER::draw( const SCH_TEXT *aText, int aLayer )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strokeText( shownText, aText->GetTextPos(), attrs );
|
strokeText( shownText, aText->GetTextPos() + text_offset, attrs );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1705,13 +1712,27 @@ void SCH_PAINTER::draw( const SCH_FIELD *aField, int aLayer )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
wxString shownText = aField->GetShownText();
|
||||||
TEXT_ATTRIBUTES attributes = aField->GetAttributes();
|
TEXT_ATTRIBUTES attributes = aField->GetAttributes();
|
||||||
|
|
||||||
attributes.m_Halign = GR_TEXT_H_ALIGN_CENTER;
|
attributes.m_Halign = GR_TEXT_H_ALIGN_CENTER;
|
||||||
attributes.m_Valign = GR_TEXT_V_ALIGN_CENTER;
|
attributes.m_Valign = GR_TEXT_V_ALIGN_CENTER;
|
||||||
attributes.m_StrokeWidth = getTextThickness( aField, drawingShadows );
|
attributes.m_StrokeWidth = getTextThickness( aField, drawingShadows );
|
||||||
attributes.m_Angle = orient;
|
attributes.m_Angle = orient;
|
||||||
|
|
||||||
strokeText( aField->GetShownText(), textpos, attributes );
|
std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
|
||||||
|
|
||||||
|
cache = aField->GetRenderCache( shownText, textpos, attributes );
|
||||||
|
|
||||||
|
if( cache )
|
||||||
|
{
|
||||||
|
for( const std::unique_ptr<KIFONT::GLYPH>& glyph : *cache )
|
||||||
|
m_gal->DrawGlyph( *glyph.get() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strokeText( shownText, textpos, attributes );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the umbilical line
|
// Draw the umbilical line
|
||||||
|
|
|
@ -1049,7 +1049,10 @@ const EDA_RECT SCH_LABEL_BASE::GetBoundingBox() const
|
||||||
EDA_RECT box( GetBodyBoundingBox() );
|
EDA_RECT box( GetBodyBoundingBox() );
|
||||||
|
|
||||||
for( const SCH_FIELD& field : m_fields )
|
for( const SCH_FIELD& field : m_fields )
|
||||||
box.Merge( field.GetBoundingBox() );
|
{
|
||||||
|
if( field.IsVisible() )
|
||||||
|
box.Merge( field.GetBoundingBox() );
|
||||||
|
}
|
||||||
|
|
||||||
box.Normalize();
|
box.Normalize();
|
||||||
|
|
||||||
|
|
|
@ -1165,6 +1165,8 @@ void SYMBOL_EDIT_FRAME::HardRedraw()
|
||||||
else
|
else
|
||||||
item.SetSelected();
|
item.SetSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_symbol->ClearCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
RebuildView();
|
RebuildView();
|
||||||
|
@ -1482,3 +1484,15 @@ bool SYMBOL_EDIT_FRAME::IsSymbolEditable() const
|
||||||
{
|
{
|
||||||
return m_symbol && ( !IsSymbolFromLegacyLibrary() || IsSymbolFromSchematic() );
|
return m_symbol && ( !IsSymbolFromLegacyLibrary() || IsSymbolFromSchematic() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SYMBOL_EDIT_FRAME::UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete, bool aUpdateRtree )
|
||||||
|
{
|
||||||
|
SCH_BASE_FRAME::UpdateItem( aItem, isAddOrDelete, aUpdateRtree );
|
||||||
|
|
||||||
|
if( EDA_TEXT* eda_text = dynamic_cast<EDA_TEXT*>( aItem ) )
|
||||||
|
{
|
||||||
|
eda_text->ClearBoundingBoxCache();
|
||||||
|
eda_text->ClearRenderCache();
|
||||||
|
}
|
||||||
|
}
|
|
@ -323,6 +323,9 @@ public:
|
||||||
|
|
||||||
void RebuildView();
|
void RebuildView();
|
||||||
|
|
||||||
|
void UpdateItem( EDA_ITEM* aItem, bool isAddOrDelete = false,
|
||||||
|
bool aUpdateRtree = false ) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rebuild the GAL and redraw the screen. Call when something went wrong.
|
* Rebuild the GAL and redraw the screen. Call when something went wrong.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -342,7 +342,8 @@ public:
|
||||||
virtual GR_TEXT_H_ALIGN_T GetDrawHorizJustify() const { return GetHorizJustify(); };
|
virtual GR_TEXT_H_ALIGN_T GetDrawHorizJustify() const { return GetHorizJustify(); };
|
||||||
virtual GR_TEXT_V_ALIGN_T GetDrawVertJustify() const { return GetVertJustify(); };
|
virtual GR_TEXT_V_ALIGN_T GetDrawVertJustify() const { return GetVertJustify(); };
|
||||||
|
|
||||||
void ClearRenderCache() { m_render_cache.clear(); }
|
virtual void ClearRenderCache();
|
||||||
|
virtual void ClearBoundingBoxCache();
|
||||||
|
|
||||||
std::vector<std::unique_ptr<KIFONT::GLYPH>>*
|
std::vector<std::unique_ptr<KIFONT::GLYPH>>*
|
||||||
GetRenderCache( const wxString& forResolvedText ) const;
|
GetRenderCache( const wxString& forResolvedText ) const;
|
||||||
|
@ -369,16 +370,19 @@ private:
|
||||||
const COLOR4D& aColor, OUTLINE_MODE aFillMode, const wxString& aText,
|
const COLOR4D& aColor, OUTLINE_MODE aFillMode, const wxString& aText,
|
||||||
const VECTOR2I& aPos );
|
const VECTOR2I& aPos );
|
||||||
|
|
||||||
wxString m_text;
|
wxString m_text;
|
||||||
wxString m_shown_text; // Cache of unescaped text for efficient access
|
wxString m_shown_text; // Cache of unescaped text for efficient access
|
||||||
bool m_shown_text_has_text_var_refs;
|
bool m_shown_text_has_text_var_refs;
|
||||||
|
|
||||||
mutable wxString m_render_cache_text;
|
mutable wxString m_render_cache_text;
|
||||||
mutable EDA_ANGLE m_render_cache_angle;
|
mutable EDA_ANGLE m_render_cache_angle;
|
||||||
mutable std::vector<std::unique_ptr<KIFONT::GLYPH>> m_render_cache;
|
mutable std::vector<std::unique_ptr<KIFONT::GLYPH>> m_render_cache;
|
||||||
|
|
||||||
TEXT_ATTRIBUTES m_attributes;
|
mutable bool m_bounding_box_cache_valid;
|
||||||
VECTOR2I m_pos;
|
mutable EDA_RECT m_bounding_box_cache;
|
||||||
|
|
||||||
|
TEXT_ATTRIBUTES m_attributes;
|
||||||
|
VECTOR2I m_pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -122,15 +122,14 @@ public:
|
||||||
* @param aCursor is the current text position (for multiple text blocks within a single text
|
* @param aCursor is the current text position (for multiple text blocks within a single text
|
||||||
* object, such as a run of superscript characters)
|
* object, such as a run of superscript characters)
|
||||||
* @param aAttrs are the styling attributes of the text, including its rotation
|
* @param aAttrs are the styling attributes of the text, including its rotation
|
||||||
* @return bounding box
|
|
||||||
*/
|
*/
|
||||||
VECTOR2D Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition,
|
void Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition,
|
||||||
const VECTOR2I& aCursor, const TEXT_ATTRIBUTES& aAttrs ) const;
|
const VECTOR2I& aCursor, const TEXT_ATTRIBUTES& aAttrs ) const;
|
||||||
|
|
||||||
VECTOR2D Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition,
|
void Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition,
|
||||||
const TEXT_ATTRIBUTES& aAttributes ) const
|
const TEXT_ATTRIBUTES& aAttributes ) const
|
||||||
{
|
{
|
||||||
return Draw( aGal, aText, aPosition, VECTOR2I( 0, 0 ), aAttributes );
|
Draw( aGal, aText, aPosition, VECTOR2I( 0, 0 ), aAttributes );
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void DrawText( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition,
|
virtual void DrawText( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition,
|
||||||
|
@ -141,7 +140,7 @@ public:
|
||||||
*
|
*
|
||||||
* @return a VECTOR2D giving the width and height of text.
|
* @return a VECTOR2D giving the width and height of text.
|
||||||
*/
|
*/
|
||||||
VECTOR2D StringBoundaryLimits( const UTF8& aText, const VECTOR2D& aSize, int aThickness,
|
VECTOR2I StringBoundaryLimits( const UTF8& aText, const VECTOR2D& aSize, int aThickness,
|
||||||
bool aBold, bool aItalic ) const;
|
bool aBold, bool aItalic ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -170,7 +169,7 @@ public:
|
||||||
* @param aTextStyle text style flags
|
* @param aTextStyle text style flags
|
||||||
* @return text cursor position after this text
|
* @return text cursor position after this text
|
||||||
*/
|
*/
|
||||||
virtual VECTOR2I GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>& aGlyphs,
|
virtual VECTOR2I GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||||
const UTF8& aText, const VECTOR2D& aSize,
|
const UTF8& aText, const VECTOR2D& aSize,
|
||||||
const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
|
const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
|
||||||
bool aMirror, const VECTOR2I& aOrigin,
|
bool aMirror, const VECTOR2I& aOrigin,
|
||||||
|
@ -206,10 +205,10 @@ protected:
|
||||||
* @param aOrigin is the point around which the text should be rotated, mirrored, etc.
|
* @param aOrigin is the point around which the text should be rotated, mirrored, etc.
|
||||||
* @return new cursor position in non-rotated, non-mirrored coordinates
|
* @return new cursor position in non-rotated, non-mirrored coordinates
|
||||||
*/
|
*/
|
||||||
VECTOR2D drawSingleLineText( KIGFX::GAL* aGal, BOX2I* aBoundingBox, const UTF8& aText,
|
void drawSingleLineText( KIGFX::GAL* aGal, BOX2I* aBoundingBox, const UTF8& aText,
|
||||||
const VECTOR2I& aPosition, const VECTOR2D& aSize,
|
const VECTOR2I& aPosition, const VECTOR2D& aSize,
|
||||||
const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
|
const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
|
||||||
bool aItalic ) const;
|
bool aItalic ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the bounding box for a single line of text.
|
* Computes the bounding box for a single line of text.
|
||||||
|
@ -221,15 +220,14 @@ protected:
|
||||||
* @param aSize is the cap-height and em-width of the text.
|
* @param aSize is the cap-height and em-width of the text.
|
||||||
* @return new cursor position
|
* @return new cursor position
|
||||||
*/
|
*/
|
||||||
VECTOR2D boundingBoxSingleLine( BOX2I* aBBox, const UTF8& aText, const VECTOR2I& aPosition,
|
VECTOR2I boundingBoxSingleLine( BOX2I* aBBox, const UTF8& aText, const VECTOR2I& aPosition,
|
||||||
const VECTOR2D& aSize, bool aItalic ) const;
|
const VECTOR2D& aSize, bool aItalic ) const;
|
||||||
|
|
||||||
void getLinePositions( const UTF8& aText, const VECTOR2I& aPosition,
|
void getLinePositions( const UTF8& aText, const VECTOR2I& aPosition,
|
||||||
wxArrayString& aTextLines, std::vector<VECTOR2I>& aPositions,
|
wxArrayString& aTextLines, std::vector<VECTOR2I>& aPositions,
|
||||||
std::vector<VECTOR2D>& aBoundingBoxes,
|
std::vector<VECTOR2I>& aExtents, const TEXT_ATTRIBUTES& aAttrs ) const;
|
||||||
const TEXT_ATTRIBUTES& aAttributes ) const;
|
|
||||||
|
|
||||||
VECTOR2D drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>& aGlyphs,
|
VECTOR2I drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||||
const UTF8& aText, const VECTOR2I& aPosition, const VECTOR2D& aSize,
|
const UTF8& aText, const VECTOR2I& aPosition, const VECTOR2D& aSize,
|
||||||
const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
|
const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
|
||||||
TEXT_STYLE_FLAGS aTextStyle ) const;
|
TEXT_STYLE_FLAGS aTextStyle ) const;
|
||||||
|
@ -240,9 +238,6 @@ protected:
|
||||||
private:
|
private:
|
||||||
static FONT* getDefaultFont();
|
static FONT* getDefaultFont();
|
||||||
|
|
||||||
VECTOR2D doDrawString( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2I& aPosition,
|
|
||||||
bool aParse, const TEXT_ATTRIBUTES& aAttrs ) const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
wxString m_fontName; ///< Font name
|
wxString m_fontName; ///< Font name
|
||||||
wxString m_fontFileName; ///< Font file name
|
wxString m_fontFileName; ///< Font file name
|
||||||
|
|
|
@ -31,6 +31,10 @@
|
||||||
#include <geometry/shape_poly_set.h>
|
#include <geometry/shape_poly_set.h>
|
||||||
#include <wx/debug.h>
|
#include <wx/debug.h>
|
||||||
|
|
||||||
|
typedef std::function<void( int, const VECTOR2I& aPoint1, const VECTOR2I& aPoint2,
|
||||||
|
const VECTOR2I& aPoint3 )>
|
||||||
|
TRIANGULATE_CALLBACK;
|
||||||
|
|
||||||
namespace KIFONT
|
namespace KIFONT
|
||||||
{
|
{
|
||||||
class GLYPH
|
class GLYPH
|
||||||
|
@ -64,6 +68,8 @@ public:
|
||||||
bool IsOutline() const override { return true; }
|
bool IsOutline() const override { return true; }
|
||||||
|
|
||||||
BOX2D BoundingBox() override;
|
BOX2D BoundingBox() override;
|
||||||
|
|
||||||
|
void Triangulate( TRIANGULATE_CALLBACK aCallback ) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ public:
|
||||||
*/
|
*/
|
||||||
double GetInterline( double aGlyphHeight = 0.0, double aLineSpacing = 1.0 ) const override;
|
double GetInterline( double aGlyphHeight = 0.0, double aLineSpacing = 1.0 ) const override;
|
||||||
|
|
||||||
VECTOR2I GetTextAsGlyphs( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>& aGlyphs,
|
VECTOR2I GetTextAsGlyphs( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||||
const UTF8& aText, const VECTOR2D& aSize, const VECTOR2I& aPosition,
|
const UTF8& aText, const VECTOR2D& aSize, const VECTOR2I& aPosition,
|
||||||
const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
|
const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
|
||||||
TEXT_STYLE_FLAGS aTextStyle ) const override;
|
TEXT_STYLE_FLAGS aTextStyle ) const override;
|
||||||
|
@ -106,8 +106,11 @@ public:
|
||||||
* @param aGlyphs returns text glyphs
|
* @param aGlyphs returns text glyphs
|
||||||
* @param aText the text item
|
* @param aText the text item
|
||||||
*/
|
*/
|
||||||
VECTOR2I GetLinesAsGlyphs( std::vector<std::unique_ptr<GLYPH>>& aGlyphs,
|
void GetLinesAsGlyphs( std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||||
const EDA_TEXT* aText ) const;
|
const EDA_TEXT* aText ) const;
|
||||||
|
|
||||||
|
void GetLinesAsGlyphs( std::vector<std::unique_ptr<GLYPH>>* aGlyphs, const UTF8& aText,
|
||||||
|
const VECTOR2I& aPosition, const TEXT_ATTRIBUTES& aAttrs ) const;
|
||||||
|
|
||||||
const FT_Face& GetFace() const { return m_face; }
|
const FT_Face& GetFace() const { return m_face; }
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ public:
|
||||||
*/
|
*/
|
||||||
double GetInterline( double aGlyphHeight, double aLineSpacing = 1.0 ) const override;
|
double GetInterline( double aGlyphHeight, double aLineSpacing = 1.0 ) const override;
|
||||||
|
|
||||||
VECTOR2I GetTextAsGlyphs( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>& aGlyphs,
|
VECTOR2I GetTextAsGlyphs( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
|
||||||
const UTF8& aText, const VECTOR2D& aSize, const VECTOR2I& aPosition,
|
const UTF8& aText, const VECTOR2D& aSize, const VECTOR2I& aPosition,
|
||||||
const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
|
const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
|
||||||
TEXT_STYLE_FLAGS aTextStyle ) const override;
|
TEXT_STYLE_FLAGS aTextStyle ) const override;
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 Ola Rinta-Koski
|
|
||||||
* Copyright (C) 2021-2022 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef TRIANGULATE_H
|
|
||||||
#define TRIANGULATE_H
|
|
||||||
|
|
||||||
#include <math/vector2d.h>
|
|
||||||
#include <font/glyph.h>
|
|
||||||
#include <geometry/shape_poly_set.h>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
|
|
||||||
typedef std::function<void( int, const VECTOR2I& aPoint1, const VECTOR2I& aPoint2,
|
|
||||||
const VECTOR2I& aPoint3, void* aCallbackData )>
|
|
||||||
TRIANGULATE_CALLBACK;
|
|
||||||
|
|
||||||
void Triangulate( const SHAPE_POLY_SET& aPolylist, TRIANGULATE_CALLBACK aCallback,
|
|
||||||
void* aCallbackData = nullptr );
|
|
||||||
|
|
||||||
#endif // TRIANGULATE_H
|
|
|
@ -524,8 +524,6 @@ private:
|
||||||
|
|
||||||
VECTOR2D getScreenPixelSize() const;
|
VECTOR2D getScreenPixelSize() const;
|
||||||
|
|
||||||
void fillPolygonAsTriangles( const SHAPE_POLY_SET& aPolyList );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic OpenGL initialization and feature checks.
|
* Basic OpenGL initialization and feature checks.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue