Move to new font engine.
This commit is contained in:
parent
e41a4d406a
commit
89c0f8e297
|
@ -32,7 +32,6 @@ set( GAL_SRCS
|
|||
gal/gal_display_options.cpp
|
||||
gal/graphics_abstraction_layer.cpp
|
||||
gal/hidpi_gl_canvas.cpp
|
||||
gal/stroke_font.cpp
|
||||
|
||||
view/view_controls.cpp
|
||||
view/view_overlay.cpp
|
||||
|
@ -295,6 +294,8 @@ set( PLUGINS_EAGLE_SRCS
|
|||
|
||||
set( FONT_SRCS
|
||||
font/font.cpp
|
||||
font/glyph.cpp
|
||||
font/stroke_font.cpp
|
||||
)
|
||||
|
||||
set( COMMON_SRCS
|
||||
|
|
|
@ -107,6 +107,20 @@ void BASIC_GAL::DrawPolyline( const std::deque<VECTOR2D>& aPointList )
|
|||
}
|
||||
|
||||
|
||||
void BASIC_GAL::DrawPolyline( const std::vector<VECTOR2D>& aPointList )
|
||||
{
|
||||
if( aPointList.size() < 2 )
|
||||
return;
|
||||
|
||||
std::vector<VECTOR2I> polyline_corners;
|
||||
|
||||
for( const VECTOR2D& pt : aPointList )
|
||||
polyline_corners.emplace_back( (VECTOR2I) transform( pt ) );
|
||||
|
||||
doDrawPolyline( polyline_corners );
|
||||
}
|
||||
|
||||
|
||||
void BASIC_GAL::DrawPolyline( const VECTOR2D aPointList[], int aListSize )
|
||||
{
|
||||
if( aListSize < 2 )
|
||||
|
@ -150,3 +164,18 @@ void BASIC_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint
|
|||
m_callback( startVector.x, startVector.y, endVector.x, endVector.y, m_callbackData );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BASIC_GAL::DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTotal )
|
||||
{
|
||||
if( aGlyph.IsStroke() )
|
||||
{
|
||||
for( const std::vector<VECTOR2D>& pointList : aGlyph.GetPoints() )
|
||||
DrawPolyline( pointList );
|
||||
}
|
||||
#if 0 // FONT TODO
|
||||
else if( aGlyph.IsOutline() )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -230,20 +230,21 @@ void KIGFX::DS_PAINTER::draw( const DS_DRAW_ITEM_POLYPOLYGONS* aItem, int aLayer
|
|||
|
||||
void KIGFX::DS_PAINTER::draw( const DS_DRAW_ITEM_TEXT* aItem, int aLayer ) const
|
||||
{
|
||||
VECTOR2D position( aItem->GetTextPos().x, aItem->GetTextPos().y );
|
||||
int penWidth = std::max( aItem->GetEffectiveTextPenWidth(),
|
||||
KIFONT::FONT* font = aItem->GetFont();
|
||||
|
||||
if( !font )
|
||||
font = KIFONT::FONT::GetFont( wxEmptyString, aItem->IsBold(), aItem->IsItalic() );
|
||||
|
||||
const COLOR4D& color = m_renderSettings.GetColor( aItem, aLayer );
|
||||
|
||||
m_gal->SetStrokeColor( color );
|
||||
m_gal->SetFillColor( color );
|
||||
|
||||
TEXT_ATTRIBUTES attrs = aItem->GetAttributes();
|
||||
attrs.m_StrokeWidth = std::max( aItem->GetEffectiveTextPenWidth(),
|
||||
m_renderSettings.GetDefaultPenWidth() );
|
||||
|
||||
m_gal->Save();
|
||||
m_gal->Translate( position );
|
||||
m_gal->Rotate( -aItem->GetTextAngle().AsRadians() );
|
||||
m_gal->SetStrokeColor( m_renderSettings.GetColor( aItem, aLayer ) );
|
||||
m_gal->SetLineWidth( penWidth );
|
||||
m_gal->SetTextAttributes( aItem );
|
||||
m_gal->SetIsFill( false );
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->StrokeText( aItem->GetShownText(), VECTOR2D( 0, 0 ), 0.0 );
|
||||
m_gal->Restore();
|
||||
font->Draw( m_gal, aItem->GetShownText(), aItem->GetTextPos(), attrs );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
#include <eda_rect.h> // for EDA_RECT
|
||||
#include <eda_text.h> // for EDA_TEXT, TEXT_EFFECTS, GR_TEXT_VJUSTIF...
|
||||
#include <gal/color4d.h> // for COLOR4D, COLOR4D::BLACK
|
||||
#include <gal/stroke_font.h> // for STROKE_FONT
|
||||
#include <gr_text.h> // for GRText
|
||||
#include <string_utils.h> // for UnescapeString
|
||||
#include <math/util.h> // for KiROUND
|
||||
|
@ -203,20 +202,6 @@ void EDA_TEXT::cacheShownText()
|
|||
}
|
||||
|
||||
|
||||
int EDA_TEXT::LenSize( const wxString& aLine, int aThickness ) const
|
||||
{
|
||||
basic_gal.SetFontItalic( IsItalic() );
|
||||
basic_gal.SetFontBold( IsBold() );
|
||||
basic_gal.SetFontUnderlined( false );
|
||||
basic_gal.SetLineWidth( (float) aThickness );
|
||||
basic_gal.SetGlyphSize( VECTOR2D( GetTextSize() ) );
|
||||
|
||||
VECTOR2D tsize = basic_gal.GetTextLineSize( aLine );
|
||||
|
||||
return KiROUND( tsize.x );
|
||||
}
|
||||
|
||||
|
||||
wxString EDA_TEXT::ShortenedShownText() const
|
||||
{
|
||||
wxString tmp = GetShownText();
|
||||
|
@ -234,7 +219,12 @@ wxString EDA_TEXT::ShortenedShownText() const
|
|||
|
||||
int EDA_TEXT::GetInterline() const
|
||||
{
|
||||
return KiROUND( KIGFX::STROKE_FONT::GetInterline( GetTextHeight() ) );
|
||||
KIFONT::FONT* font = GetFont();
|
||||
|
||||
if( !font )
|
||||
font = KIFONT::FONT::GetFont( wxEmptyString, m_attributes.m_Bold, m_attributes.m_Italic );
|
||||
|
||||
return KiROUND( font->GetInterline( GetTextHeight() ) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -274,21 +264,19 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const
|
|||
}
|
||||
|
||||
// calculate the H and V size
|
||||
const auto& font = basic_gal.GetStrokeFont();
|
||||
KIFONT::FONT* font = KIFONT::FONT::GetFont();
|
||||
VECTOR2D fontSize( GetTextSize() );
|
||||
double penWidth( thickness );
|
||||
int dx = KiROUND( font.ComputeStringBoundaryLimits( text, fontSize, penWidth ).x );
|
||||
int dx = KiROUND( font->StringBoundaryLimits( text, fontSize, penWidth ).x );
|
||||
int dy = GetInterline();
|
||||
|
||||
// Creates bounding box (rectangle) for horizontal, left and top justified text. The
|
||||
// bounding box will be moved later according to the actual text options
|
||||
wxSize textsize = wxSize( dx, dy );
|
||||
wxSize textsize = wxSize( dx, fontSize.y );
|
||||
VECTOR2I pos = GetTextPos();
|
||||
|
||||
if( IsMultilineAllowed() && aLine > 0 && ( aLine < static_cast<int>( strings.GetCount() ) ) )
|
||||
{
|
||||
pos.y -= aLine * GetInterline();
|
||||
}
|
||||
|
||||
if( aInvertY )
|
||||
pos.y = -pos.y;
|
||||
|
@ -299,7 +287,7 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const
|
|||
{ // A overbar adds an extra size to the text
|
||||
// Height from the base line text of chars like [ or {
|
||||
double curr_height = GetTextHeight() * 1.15;
|
||||
double overbarPosition = font.ComputeOverbarVerticalPosition( fontSize.y );
|
||||
double overbarPosition = font->ComputeOverbarVerticalPosition( fontSize.y );
|
||||
int extra_height = KiROUND( overbarPosition - curr_height );
|
||||
|
||||
extra_height += thickness / 2;
|
||||
|
@ -314,7 +302,7 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const
|
|||
for( unsigned ii = 1; ii < strings.GetCount(); ii++ )
|
||||
{
|
||||
text = strings.Item( ii );
|
||||
dx = KiROUND( font.ComputeStringBoundaryLimits( text, fontSize, penWidth ).x );
|
||||
dx = KiROUND( font->StringBoundaryLimits( text, fontSize, penWidth ).x );
|
||||
textsize.x = std::max( textsize.x, dx );
|
||||
textsize.y += dy;
|
||||
}
|
||||
|
@ -336,7 +324,7 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const
|
|||
break;
|
||||
|
||||
case GR_TEXT_H_ALIGN_CENTER:
|
||||
rect.SetX( rect.GetX() - (rect.GetWidth() / 2) );
|
||||
rect.SetX( rect.GetX() - rect.GetWidth() / 2 );
|
||||
break;
|
||||
|
||||
case GR_TEXT_H_ALIGN_RIGHT:
|
||||
|
@ -347,38 +335,9 @@ EDA_RECT EDA_TEXT::GetTextBox( int aLine, bool aInvertY ) const
|
|||
|
||||
switch( GetVertJustify() )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP:
|
||||
break;
|
||||
|
||||
case GR_TEXT_V_ALIGN_CENTER:
|
||||
rect.SetY( rect.GetY() - ( dy / 2) );
|
||||
break;
|
||||
|
||||
case GR_TEXT_V_ALIGN_BOTTOM:
|
||||
rect.SetY( rect.GetY() - dy );
|
||||
break;
|
||||
}
|
||||
|
||||
if( linecount > 1 )
|
||||
{
|
||||
int yoffset;
|
||||
linecount -= 1;
|
||||
|
||||
switch( GetVertJustify() )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP:
|
||||
break;
|
||||
|
||||
case GR_TEXT_V_ALIGN_CENTER:
|
||||
yoffset = linecount * GetInterline() / 2;
|
||||
rect.SetY( rect.GetY() - yoffset );
|
||||
break;
|
||||
|
||||
case GR_TEXT_V_ALIGN_BOTTOM:
|
||||
yoffset = linecount * GetInterline();
|
||||
rect.SetY( rect.GetY() - yoffset );
|
||||
break;
|
||||
}
|
||||
case GR_TEXT_V_ALIGN_TOP: break;
|
||||
case GR_TEXT_V_ALIGN_CENTER: rect.SetY( rect.GetY() - rect.GetHeight() / 2 ); break;
|
||||
case GR_TEXT_V_ALIGN_BOTTOM: rect.SetY( rect.GetY() - rect.GetHeight() ); break;
|
||||
}
|
||||
|
||||
// Many fonts draw diacriticals, descenders, etc. outside the X-height of the font. This
|
||||
|
|
|
@ -24,14 +24,18 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <core/wx_stl_compat.h>
|
||||
#include <font/font.h>
|
||||
|
||||
#include <wx/font.h>
|
||||
#include <string_utils.h>
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <font/stroke_font.h>
|
||||
#include <trigo.h>
|
||||
#include <markup_parser.h>
|
||||
|
||||
using namespace KIFONT;
|
||||
|
||||
FONT* FONT::s_defaultFont = nullptr;
|
||||
std::map<wxString, FONT*> FONT::s_fontMap;
|
||||
|
||||
std::map< std::tuple<wxString, bool, bool>, FONT*> FONT::s_fontMap;
|
||||
|
||||
|
||||
FONT::FONT()
|
||||
|
@ -45,3 +49,393 @@ const wxString& FONT::Name() const
|
|||
}
|
||||
|
||||
|
||||
FONT* FONT::getDefaultFont()
|
||||
{
|
||||
// FONT TODO: default font should be user-selectable in Eeschema but the KiCad stroke
|
||||
// font in Pcbnew
|
||||
|
||||
if( !s_defaultFont )
|
||||
s_defaultFont = STROKE_FONT::LoadFont( wxEmptyString );
|
||||
|
||||
return s_defaultFont;
|
||||
}
|
||||
|
||||
|
||||
FONT* FONT::GetFont( const wxString& aFontName, bool aBold, bool aItalic )
|
||||
{
|
||||
if( aFontName.empty() )
|
||||
return getDefaultFont();
|
||||
|
||||
std::tuple<wxString, bool, bool> key = { aFontName, aBold, aItalic };
|
||||
|
||||
FONT* font = s_fontMap[key];
|
||||
|
||||
if( !font )
|
||||
{
|
||||
wxFont wx_font( wxFontInfo().FaceName( aFontName ).Bold( aBold ).Italic( aItalic ) );
|
||||
wxString fullfontname = wx_font.GetNativeFontInfoDesc();
|
||||
|
||||
#if 0
|
||||
// FONT TODO: load a real font
|
||||
font->m_fontName = aFontName;
|
||||
#else
|
||||
font = getDefaultFont();
|
||||
#endif
|
||||
|
||||
s_fontMap[key] = font;
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
|
||||
bool FONT::IsStroke( const wxString& aFontName )
|
||||
{
|
||||
#if 0 // FONT TODO
|
||||
// Stroke fonts will be loaded under all four bold/italic combinations, so we only have
|
||||
// to check for one.
|
||||
std::tuple<wxString, bool, bool> key = { aFontName, false, false };
|
||||
|
||||
FONT* font = s_fontMap[key];
|
||||
|
||||
return font && font->IsStroke();
|
||||
#else
|
||||
return aFontName == _( "Default Font" );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 VECTOR2D& aPosition,
|
||||
bool aParse, const TEXT_ATTRIBUTES& aAttrs ) const
|
||||
{
|
||||
if( aText.empty() )
|
||||
return VECTOR2D( 0.0, 0.0 );
|
||||
|
||||
wxArrayString strings;
|
||||
std::vector<wxPoint> positions;
|
||||
int n_lines;
|
||||
VECTOR2D boundingBox;
|
||||
std::vector<VECTOR2D> lineBoundingBoxes;
|
||||
|
||||
getLinePositions( aText, aPosition, strings, positions, n_lines, lineBoundingBoxes, aAttrs );
|
||||
|
||||
for( int i = 0; i < n_lines; i++ )
|
||||
{
|
||||
VECTOR2D lineBoundingBox;
|
||||
if( aParse )
|
||||
{
|
||||
MARKUP::MARKUP_PARSER markupParser( std::string( strings.Item( i ) ) );
|
||||
//auto parse_result = markupParser.Parse();
|
||||
VECTOR2D 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 = ( n_lines + 1 ) * GetInterline( aAttrs.m_Size.y );
|
||||
|
||||
return boundingBox;
|
||||
}
|
||||
|
||||
|
||||
void FONT::getLinePositions( const UTF8& aText, const VECTOR2D& aPosition,
|
||||
wxArrayString& aStringList, std::vector<wxPoint>& aPositions,
|
||||
int& aLineCount, std::vector<VECTOR2D>& aBoundingBoxes,
|
||||
const TEXT_ATTRIBUTES& aAttrs ) const
|
||||
{
|
||||
wxStringSplit( aText, aStringList, '\n' );
|
||||
aLineCount = aStringList.Count();
|
||||
aPositions.reserve( aLineCount );
|
||||
|
||||
wxPoint origin( aPosition.x, aPosition.y );
|
||||
int interline = GetInterline( aAttrs.m_Size.y, aAttrs.m_LineSpacing );
|
||||
int height = 0;
|
||||
|
||||
for( int i = 0; i < aLineCount; i++ )
|
||||
{
|
||||
VECTOR2D pos( origin.x, origin.y + i * interline );
|
||||
VECTOR2D end = boundingBoxSingleLine( nullptr, aStringList[i], pos, aAttrs.m_Size,
|
||||
aAttrs.m_Angle, aAttrs.m_Italic );
|
||||
VECTOR2D bBox( end - pos );
|
||||
|
||||
aBoundingBoxes.push_back( bBox );
|
||||
|
||||
if( i == 0 )
|
||||
height += aAttrs.m_Size.y;
|
||||
else
|
||||
height += interline;
|
||||
}
|
||||
|
||||
wxPoint offset( 0, 0 );
|
||||
offset.y += aAttrs.m_Size.y;
|
||||
|
||||
switch( aAttrs.m_Valign )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP: break;
|
||||
case GR_TEXT_V_ALIGN_CENTER: offset.y -= height / 2; break;
|
||||
case GR_TEXT_V_ALIGN_BOTTOM: offset.y -= height; break;
|
||||
}
|
||||
|
||||
int mirrorX = aAttrs.m_Mirrored ? -1 : 1;
|
||||
|
||||
for( int i = 0; i < aLineCount; i++ )
|
||||
{
|
||||
VECTOR2D lineSize = aBoundingBoxes.at( i );
|
||||
wxPoint lineOffset( offset );
|
||||
lineOffset.y += i * interline;
|
||||
|
||||
switch( aAttrs.m_Halign )
|
||||
{
|
||||
case GR_TEXT_H_ALIGN_LEFT: break;
|
||||
case GR_TEXT_H_ALIGN_CENTER: lineOffset.x = mirrorX * -lineSize.x / 2; break;
|
||||
case GR_TEXT_H_ALIGN_RIGHT: lineOffset.x = mirrorX * -lineSize.x; break;
|
||||
}
|
||||
|
||||
wxPoint pos( aPosition.x + lineOffset.x, aPosition.y + lineOffset.y );
|
||||
RotatePoint( &pos, origin, aAttrs.m_Angle );
|
||||
|
||||
aPositions.push_back( pos );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VECTOR2D FONT::getBoundingBox( const UTF8& aText, TEXT_STYLE_FLAGS aTextStyle,
|
||||
const TEXT_ATTRIBUTES& aAttributes ) const
|
||||
{
|
||||
if( aText.empty() )
|
||||
return VECTOR2D( 0.0, 0.0 );
|
||||
|
||||
if( false ) // aParse ) // FONT TODO: parse markup!
|
||||
{
|
||||
MARKUP::MARKUP_PARSER markupParser( aText );
|
||||
auto parse_result = markupParser.Parse();
|
||||
|
||||
/* ... */
|
||||
}
|
||||
|
||||
wxArrayString strings;
|
||||
std::vector<wxPoint> positions;
|
||||
int n_lines;
|
||||
VECTOR2D boundingBox;
|
||||
std::vector<VECTOR2D> boundingBoxes;
|
||||
|
||||
getLinePositions( aText, VECTOR2D( 0.0, 0.0 ), strings, positions, n_lines, boundingBoxes,
|
||||
aAttributes );
|
||||
|
||||
int i = 1;
|
||||
|
||||
for( VECTOR2D lineBoundingBox : boundingBoxes )
|
||||
{
|
||||
boundingBox.x = fmax( boundingBox.x, lineBoundingBox.x );
|
||||
boundingBox.y += lineBoundingBox.y;
|
||||
i++;
|
||||
}
|
||||
|
||||
return boundingBox;
|
||||
}
|
||||
|
||||
|
||||
void FONT::DrawText( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2D& aPosition,
|
||||
const TEXT_ATTRIBUTES& aAttributes ) const
|
||||
{
|
||||
// FONT TODO: do we need to set the attributes to the gal at all?
|
||||
aGal->SetHorizontalJustify( aAttributes.m_Halign );
|
||||
aGal->SetVerticalJustify( aAttributes.m_Valign );
|
||||
aGal->SetGlyphSize( aAttributes.m_Size );
|
||||
aGal->SetFontItalic( aAttributes.m_Italic );
|
||||
aGal->SetFontBold( aAttributes.m_Bold );
|
||||
aGal->SetTextMirrored( aAttributes.m_Mirrored );
|
||||
|
||||
Draw( aGal, aText, aPosition, aAttributes );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draw a string.
|
||||
*
|
||||
* @param aGal
|
||||
* @param aText is the text to be drawn.
|
||||
* @param aPosition is the text position in world coordinates.
|
||||
* @param aAngle is the text rotation angle
|
||||
*/
|
||||
VECTOR2D FONT::Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2D& aPosition,
|
||||
const VECTOR2D& aOrigin, const TEXT_ATTRIBUTES& aAttrs ) const
|
||||
{
|
||||
if( !aGal || aText.empty() )
|
||||
return VECTOR2D( 0, 0 );
|
||||
|
||||
VECTOR2D position( aPosition - aOrigin );
|
||||
|
||||
// Context needs to be saved before any transformations
|
||||
//aGal->Save();
|
||||
|
||||
// Split multiline strings into separate ones and draw them line by line
|
||||
wxArrayString strings_list;
|
||||
std::vector<wxPoint> positions;
|
||||
std::vector<VECTOR2D> boundingBoxes;
|
||||
int n;
|
||||
|
||||
getLinePositions( aText, position, strings_list, positions, n, boundingBoxes, aAttrs );
|
||||
|
||||
VECTOR2D boundingBox( 0, 0 );
|
||||
BOX2I lineBoundingBox;
|
||||
|
||||
for( int i = 0; i < n; i++ )
|
||||
{
|
||||
aGal->Save();
|
||||
aGal->Translate( positions[i] );
|
||||
aGal->SetLineWidth( aAttrs.m_StrokeWidth );
|
||||
|
||||
if( !aAttrs.m_Angle.IsZero() )
|
||||
aGal->Rotate( aAttrs.m_Angle.Invert().AsRadians() );
|
||||
|
||||
(void) drawSingleLineText( aGal, &lineBoundingBox, strings_list[i], VECTOR2D( 0, 0 ),
|
||||
aAttrs.m_Size, aAttrs.m_Angle, aAttrs.m_Italic,
|
||||
aAttrs.m_Mirrored );
|
||||
aGal->Restore();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// undo rotation
|
||||
//aGal->Restore();
|
||||
|
||||
return boundingBox;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return position of cursor for drawing next substring
|
||||
*/
|
||||
VECTOR2D FONT::drawMarkup( BOX2I* aBoundingBox, GLYPH_LIST& aGlyphs,
|
||||
const std::unique_ptr<MARKUP::NODE>& aNode, const VECTOR2D& aPosition,
|
||||
const VECTOR2D& aGlyphSize, const EDA_ANGLE& aAngle,
|
||||
TEXT_STYLE_FLAGS aTextStyle, int aLevel ) const
|
||||
{
|
||||
VECTOR2D nextPosition = aPosition;
|
||||
|
||||
TEXT_STYLE_FLAGS textStyle = aTextStyle;
|
||||
|
||||
if( !aNode->is_root() )
|
||||
{
|
||||
if( aNode->isSubscript() )
|
||||
textStyle = TEXT_STYLE::SUBSCRIPT;
|
||||
else if( aNode->isSuperscript() )
|
||||
textStyle = TEXT_STYLE::SUPERSCRIPT;
|
||||
|
||||
if( aNode->isOverbar() )
|
||||
textStyle |= TEXT_STYLE::OVERBAR;
|
||||
|
||||
if( aNode->has_content() )
|
||||
{
|
||||
std::string txt = aNode->string();
|
||||
//std::vector<SHAPE_POLY_SET> glyphs;
|
||||
wxPoint pt( aPosition.x, aPosition.y );
|
||||
|
||||
BOX2I bbox;
|
||||
nextPosition = GetTextAsPolygon( &bbox, aGlyphs, txt, aGlyphSize, pt, aAngle, textStyle );
|
||||
|
||||
if( aBoundingBox )
|
||||
{
|
||||
BOX2I boundingBox;
|
||||
boundingBox = aBoundingBox->Merge( bbox );
|
||||
aBoundingBox->SetOrigin( boundingBox.GetOrigin() );
|
||||
aBoundingBox->SetSize( boundingBox.GetSize() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( const auto& child : aNode->children )
|
||||
{
|
||||
nextPosition = drawMarkup( aBoundingBox, aGlyphs, child, nextPosition, aGlyphSize, aAngle,
|
||||
textStyle, aLevel + 1 );
|
||||
}
|
||||
|
||||
return nextPosition;
|
||||
}
|
||||
|
||||
|
||||
VECTOR2D FONT::drawSingleLineText( KIGFX::GAL* aGal, BOX2I* aBoundingBox, const UTF8& aText,
|
||||
const VECTOR2D& aPosition, const VECTOR2D& aGlyphSize,
|
||||
const EDA_ANGLE& aAngle, bool aIsItalic, bool aIsMirrored ) const
|
||||
{
|
||||
if( !aGal )
|
||||
{
|
||||
// do nothing, cursor does not move
|
||||
return aPosition;
|
||||
}
|
||||
|
||||
MARKUP::MARKUP_PARSER markupParser( aText );
|
||||
std::unique_ptr<MARKUP::NODE> markupRoot = markupParser.Parse();
|
||||
TEXT_STYLE_FLAGS textStyle = 0;
|
||||
|
||||
if( aIsItalic )
|
||||
textStyle |= TEXT_STYLE::ITALIC;
|
||||
|
||||
|
||||
GLYPH_LIST glyphs;
|
||||
VECTOR2D nextPosition = drawMarkup( aBoundingBox, glyphs, markupRoot, aPosition, aGlyphSize,
|
||||
aAngle, textStyle );
|
||||
|
||||
for( const std::shared_ptr<GLYPH>& glyph : glyphs )
|
||||
{
|
||||
if( aIsMirrored )
|
||||
glyph->Mirror( aPosition );
|
||||
|
||||
aGal->DrawGlyph( glyph );
|
||||
}
|
||||
|
||||
return nextPosition;
|
||||
}
|
||||
|
||||
|
||||
VECTOR2D FONT::boundingBoxSingleLine( BOX2I* aBoundingBox, const UTF8& aText,
|
||||
const VECTOR2D& aPosition, const VECTOR2D& aGlyphSize,
|
||||
const EDA_ANGLE& aAngle, bool aIsItalic ) const
|
||||
{
|
||||
MARKUP::MARKUP_PARSER markupParser( aText );
|
||||
std::unique_ptr<MARKUP::NODE> markupRoot = markupParser.Parse();
|
||||
TEXT_STYLE_FLAGS textStyle = 0;
|
||||
|
||||
if( aIsItalic )
|
||||
textStyle |= TEXT_STYLE::ITALIC;
|
||||
|
||||
GLYPH_LIST glyphs; // ignored
|
||||
VECTOR2D nextPosition = drawMarkup( aBoundingBox, glyphs, markupRoot, aPosition, aGlyphSize,
|
||||
aAngle, false, textStyle );
|
||||
|
||||
return nextPosition;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2021 Ola Rinta-Koski <gitlab@rinta-koski.net>
|
||||
* 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 <vector>
|
||||
#include <font/glyph.h>
|
||||
|
||||
using namespace KIFONT;
|
||||
|
||||
|
||||
STROKE_GLYPH::STROKE_GLYPH( const STROKE_GLYPH& aGlyph )
|
||||
{
|
||||
for( const std::vector<VECTOR2D>& pointList : aGlyph.m_pointLists )
|
||||
m_pointLists.push_back( pointList );
|
||||
}
|
||||
|
||||
|
||||
void STROKE_GLYPH::AddPoint( const VECTOR2D& aPoint )
|
||||
{
|
||||
if( !m_penIsDown )
|
||||
{
|
||||
std::vector<VECTOR2D> v;
|
||||
m_pointLists.push_back( v );
|
||||
m_penIsDown = true;
|
||||
}
|
||||
|
||||
m_pointLists.back().push_back( aPoint );
|
||||
}
|
||||
|
||||
|
||||
void STROKE_GLYPH::RaisePen()
|
||||
{
|
||||
if( m_penIsDown )
|
||||
m_pointLists.back().shrink_to_fit();
|
||||
|
||||
m_penIsDown = false;
|
||||
}
|
||||
|
||||
|
||||
void STROKE_GLYPH::Finalize()
|
||||
{
|
||||
if( !m_pointLists.empty() && !m_pointLists.back().empty() )
|
||||
m_pointLists.back().shrink_to_fit();
|
||||
}
|
||||
|
||||
|
||||
BOX2D STROKE_GLYPH::BoundingBox()
|
||||
{
|
||||
if( m_boundingBox.GetWidth() == 0 && m_boundingBox.GetHeight() == 0 )
|
||||
{
|
||||
bool first = true;
|
||||
|
||||
for( const std::vector<VECTOR2D>& pointList : m_pointLists )
|
||||
{
|
||||
for( const VECTOR2D& point : pointList )
|
||||
{
|
||||
if( first )
|
||||
{
|
||||
m_boundingBox.SetOrigin( point );
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_boundingBox.Merge( point );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_boundingBox;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<GLYPH> STROKE_GLYPH::Resize( const VECTOR2D& aGlyphSize ) const
|
||||
{
|
||||
std::shared_ptr<STROKE_GLYPH> glyph = std::make_shared<STROKE_GLYPH>( *this );
|
||||
|
||||
glyph->clearBoundingBox();
|
||||
|
||||
bool first = true;
|
||||
|
||||
for( std::vector<VECTOR2D>& pointList : glyph->m_pointLists )
|
||||
{
|
||||
for( VECTOR2D& point : pointList )
|
||||
{
|
||||
point.x = point.x * aGlyphSize.x;
|
||||
point.y = point.y * aGlyphSize.y;
|
||||
|
||||
if( first )
|
||||
{
|
||||
glyph->m_boundingBox.SetOrigin( point );
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
glyph->m_boundingBox.Merge( point );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return glyph;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<GLYPH> STROKE_GLYPH::Translate( const VECTOR2D& aOffset ) const
|
||||
{
|
||||
auto glyph = std::make_shared<STROKE_GLYPH>( *this );
|
||||
|
||||
glyph->clearBoundingBox();
|
||||
|
||||
bool first = true;
|
||||
|
||||
for( std::vector<VECTOR2D>& pointList : glyph->m_pointLists )
|
||||
{
|
||||
for( VECTOR2D& point : pointList )
|
||||
{
|
||||
point.x += aOffset.x;
|
||||
point.y += aOffset.y;
|
||||
|
||||
if( first )
|
||||
{
|
||||
glyph->m_boundingBox.SetOrigin( point );
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
glyph->m_boundingBox.Merge( point );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return glyph;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<GLYPH> STROKE_GLYPH::Transform( const VECTOR2D& aGlyphSize, const VECTOR2D& aOffset,
|
||||
double aTilt )
|
||||
{
|
||||
std::shared_ptr<STROKE_GLYPH> glyph = std::make_shared<STROKE_GLYPH>( *this );
|
||||
|
||||
glyph->clearBoundingBox();
|
||||
|
||||
bool first = true;
|
||||
|
||||
for( std::vector<VECTOR2D>& pointList : glyph->m_pointLists )
|
||||
{
|
||||
for( VECTOR2D& point : pointList )
|
||||
{
|
||||
point.x *= aGlyphSize.x;
|
||||
point.y *= aGlyphSize.y;
|
||||
|
||||
if( aTilt )
|
||||
point.x -= point.y * aTilt;
|
||||
|
||||
point.x += aOffset.x;
|
||||
point.y += aOffset.y;
|
||||
|
||||
if( first )
|
||||
{
|
||||
glyph->m_boundingBox.SetOrigin( point );
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
glyph->m_boundingBox.Merge( point );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return glyph;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<GLYPH> STROKE_GLYPH::Mirror( bool aMirror, const VECTOR2D& aMirrorOrigin ) const
|
||||
{
|
||||
// TODO figure out a way to not make a copy if aMirror is false
|
||||
auto glyph = std::make_shared<STROKE_GLYPH>( *this );
|
||||
|
||||
if( aMirror )
|
||||
glyph->Mirror( aMirrorOrigin );
|
||||
|
||||
return glyph;
|
||||
}
|
||||
|
||||
|
||||
void STROKE_GLYPH::Mirror( const VECTOR2D& aMirrorOrigin )
|
||||
{
|
||||
double originX = aMirrorOrigin.x;
|
||||
|
||||
clearBoundingBox();
|
||||
|
||||
bool first = true;
|
||||
|
||||
for( std::vector<VECTOR2D>& pointList : m_pointLists )
|
||||
{
|
||||
for( VECTOR2D& point : pointList )
|
||||
{
|
||||
if( first )
|
||||
{
|
||||
//originX = point.x;
|
||||
point.x = originX - ( point.x - originX );
|
||||
m_boundingBox.SetOrigin( point );
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
point.x = originX - ( point.x - originX );
|
||||
m_boundingBox.Merge( point );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
|
||||
* Copyright (C) 2013 CERN
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
* Copyright (C) 2016 Kicad Developers, see change_log.txt for contributors.
|
||||
*
|
||||
* Stroke font class
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/textfile.h>
|
||||
#include <newstroke_font.h>
|
||||
#include <font/glyph.h>
|
||||
#include <font/stroke_font.h>
|
||||
#include <markup_parser.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
#include <trigo.h>
|
||||
|
||||
using namespace KIFONT;
|
||||
|
||||
|
||||
///< Factor that determines relative vertical position of the overbar.
|
||||
static constexpr double OVERBAR_POSITION_FACTOR = 1.33;
|
||||
|
||||
///< Scale factor for a glyph
|
||||
static constexpr double STROKE_FONT_SCALE = 1.0 / 21.0;
|
||||
|
||||
///< Tilt factor for italic style (the is is the scaling factor
|
||||
///< on dY relative coordinates to give a tilt shape
|
||||
static constexpr double ITALIC_TILT = 1.0 / 8;
|
||||
|
||||
///< Factor that determines the pitch between 2 lines.
|
||||
static constexpr double INTERLINE_PITCH_RATIO = 1.62; // The golden mean
|
||||
|
||||
static constexpr int FONT_OFFSET = -10;
|
||||
|
||||
|
||||
bool g_defaultFontInitialized = false;
|
||||
GLYPH_LIST g_defaultFontGlyphs; ///< Glyph list
|
||||
std::vector<BOX2D>* g_defaultFontGlyphBoundingBoxes; ///< Bounding boxes of the glyphs
|
||||
|
||||
|
||||
STROKE_FONT::STROKE_FONT() :
|
||||
m_glyphs( nullptr ),
|
||||
m_glyphBoundingBoxes( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
STROKE_FONT* STROKE_FONT::LoadFont( const wxString& aFontName )
|
||||
{
|
||||
if( aFontName.empty() )
|
||||
{
|
||||
STROKE_FONT* font = new STROKE_FONT();
|
||||
font->loadNewStrokeFont( newstroke_font, newstroke_font_bufsize );
|
||||
return font;
|
||||
}
|
||||
else
|
||||
{
|
||||
// FONT TODO: support for other stroke fonts?
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void STROKE_FONT::loadNewStrokeFont( const char* const aNewStrokeFont[], int aNewStrokeFontSize )
|
||||
{
|
||||
if( !g_defaultFontInitialized )
|
||||
{
|
||||
g_defaultFontGlyphs.reserve( aNewStrokeFontSize );
|
||||
|
||||
g_defaultFontGlyphBoundingBoxes = new std::vector<BOX2D>;
|
||||
g_defaultFontGlyphBoundingBoxes->reserve( aNewStrokeFontSize );
|
||||
|
||||
for( int j = 0; j < aNewStrokeFontSize; j++ )
|
||||
{
|
||||
auto glyph = std::make_shared<STROKE_GLYPH>();
|
||||
double glyphStartX = 0.0;
|
||||
|
||||
std::vector<VECTOR2D>* pointList = nullptr;
|
||||
|
||||
int i = 0;
|
||||
|
||||
while( aNewStrokeFont[j][i] )
|
||||
{
|
||||
VECTOR2D point( 0.0, 0.0 );
|
||||
char coordinate[2] = {
|
||||
0,
|
||||
};
|
||||
|
||||
for( int k : { 0, 1 } )
|
||||
coordinate[k] = aNewStrokeFont[j][i + k];
|
||||
|
||||
if( i < 2 )
|
||||
{
|
||||
// The first two values contain the width of the char
|
||||
glyphStartX = ( coordinate[0] - 'R' ) * STROKE_FONT_SCALE;
|
||||
}
|
||||
else if( ( coordinate[0] == ' ' ) && ( coordinate[1] == 'R' ) )
|
||||
{
|
||||
glyph->RaisePen();
|
||||
}
|
||||
else
|
||||
{
|
||||
// In stroke font, coordinates values are coded as <value> + 'R', where
|
||||
// <value> is an ASCII char.
|
||||
// therefore every coordinate description of the Hershey format has an offset,
|
||||
// it has to be subtracted
|
||||
// Note:
|
||||
// * the stroke coordinates are stored in reduced form (-1.0 to +1.0),
|
||||
// and the actual size is stroke coordinate * glyph size
|
||||
// * a few shapes have a height slightly bigger than 1.0 ( like '{' '[' )
|
||||
point.x = (double) ( coordinate[0] - 'R' ) * STROKE_FONT_SCALE - glyphStartX;
|
||||
|
||||
// FONT_OFFSET is here for historical reasons, due to the way the stroke font
|
||||
// was built. It allows shapes coordinates like W M ... to be >= 0
|
||||
// Only shapes like j y have coordinates < 0
|
||||
point.y = (double) ( coordinate[1] - 'R' + FONT_OFFSET ) * STROKE_FONT_SCALE;
|
||||
|
||||
if( !pointList )
|
||||
pointList = new std::vector<VECTOR2D>;
|
||||
|
||||
glyph->AddPoint( point );
|
||||
}
|
||||
|
||||
i += 2;
|
||||
}
|
||||
|
||||
glyph->Finalize();
|
||||
|
||||
// Compute the bounding box of the glyph
|
||||
g_defaultFontGlyphBoundingBoxes->emplace_back( glyph->BoundingBox() );
|
||||
g_defaultFontGlyphs.push_back( glyph );
|
||||
m_maxGlyphWidth = std::max( m_maxGlyphWidth,
|
||||
g_defaultFontGlyphBoundingBoxes->back().GetWidth() );
|
||||
}
|
||||
|
||||
g_defaultFontInitialized = true;
|
||||
}
|
||||
|
||||
m_glyphs = &g_defaultFontGlyphs;
|
||||
m_glyphBoundingBoxes = g_defaultFontGlyphBoundingBoxes;
|
||||
}
|
||||
|
||||
|
||||
double STROKE_FONT::GetInterline( double aGlyphHeight, double aLineSpacing ) const
|
||||
{
|
||||
// Do not add the glyph thickness to the interline. This makes bold text line-spacing
|
||||
// different from normal text, which is poor typography.
|
||||
return ( aGlyphHeight * aLineSpacing * INTERLINE_PITCH_RATIO );
|
||||
}
|
||||
|
||||
|
||||
double STROKE_FONT::ComputeOverbarVerticalPosition( double aGlyphHeight ) const
|
||||
{
|
||||
return aGlyphHeight * OVERBAR_POSITION_FACTOR;
|
||||
}
|
||||
|
||||
|
||||
VECTOR2D STROKE_FONT::ComputeTextLineSize( const KIGFX::GAL* aGal, const UTF8& aText ) const
|
||||
{
|
||||
//TODO default glyph size (and line width) is a guess
|
||||
VECTOR2D glyphSize = aGal ? aGal->GetGlyphSize() : VECTOR2D( 16.0, 16.0 );
|
||||
double lineWidth = aGal ? aGal->GetLineWidth() : 1.0;
|
||||
return StringBoundaryLimits( aGal, aText, glyphSize, lineWidth );
|
||||
}
|
||||
|
||||
|
||||
VECTOR2D STROKE_FONT::StringBoundaryLimits( const KIGFX::GAL* aGal, const UTF8& aText,
|
||||
const VECTOR2D& aGlyphSize,
|
||||
double aGlyphThickness ) const
|
||||
{
|
||||
// TODO do we need to parse every time - have we already parsed?
|
||||
MARKUP::MARKUP_PARSER markupParser( aText );
|
||||
auto root = markupParser.Parse();
|
||||
|
||||
GLYPH_LIST glyphs; // ignored
|
||||
BOX2I boundingBox;
|
||||
|
||||
(void) drawMarkup( &boundingBox, glyphs, root, VECTOR2D(), aGlyphSize, EDA_ANGLE::ANGLE_0,
|
||||
false, 0 /* TODO: this should really include italic */ );
|
||||
|
||||
return boundingBox.GetSize();
|
||||
}
|
||||
|
||||
|
||||
VECTOR2D STROKE_FONT::getBoundingBox( const UTF8& aString, const VECTOR2D& aGlyphSize,
|
||||
TEXT_STYLE_FLAGS aTextStyle ) const
|
||||
{
|
||||
// TODO: take glyph thickness into account!
|
||||
return StringBoundaryLimits( nullptr, aString, aGlyphSize, 0 );
|
||||
}
|
||||
|
||||
|
||||
VECTOR2I STROKE_FONT::GetTextAsPolygon( BOX2I* aBoundingBox, GLYPH_LIST& aGlyphs,
|
||||
const UTF8& aText, const VECTOR2D& aGlyphSize,
|
||||
const wxPoint& aPosition, const EDA_ANGLE& aAngle,
|
||||
TEXT_STYLE_FLAGS aTextStyle ) const
|
||||
{
|
||||
wxPoint cursor( aPosition );
|
||||
VECTOR2D glyphSize( aGlyphSize );
|
||||
double tilt = ( aTextStyle & TEXT_STYLE::ITALIC ) ? ITALIC_TILT : 0.0;
|
||||
|
||||
if( aTextStyle & TEXT_STYLE::SUBSCRIPT || aTextStyle & TEXT_STYLE::SUPERSCRIPT )
|
||||
{
|
||||
constexpr double subscriptSuperscriptMultiplier = 0.7;
|
||||
glyphSize.x *= subscriptSuperscriptMultiplier;
|
||||
glyphSize.y *= subscriptSuperscriptMultiplier;
|
||||
|
||||
if( aTextStyle & TEXT_STYLE::SUBSCRIPT )
|
||||
{
|
||||
constexpr double subscriptVerticalMultiplier = 0.3;
|
||||
cursor.y += glyphSize.y * subscriptVerticalMultiplier;
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr double superscriptVerticalMultiplier = 0.5;
|
||||
cursor.y -= glyphSize.y * superscriptVerticalMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
for( UTF8::uni_iter i = aText.ubegin(), end = aText.uend(); i < end; ++i )
|
||||
{
|
||||
// Index into bounding boxes table
|
||||
int dd = (signed) *i - ' ';
|
||||
|
||||
if( dd >= (int) m_glyphBoundingBoxes->size() || dd < 0 )
|
||||
{
|
||||
switch( *i )
|
||||
{
|
||||
case '\t':
|
||||
// TAB->SPACE
|
||||
dd = 0;
|
||||
break;
|
||||
default:
|
||||
// everything else is turned into a '?'
|
||||
dd = '?' - ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if( dd == 0 )
|
||||
{
|
||||
// 'space' character - draw nothing, advance cursor position
|
||||
constexpr double spaceAdvance = 0.6;
|
||||
cursor.x += glyphSize.x * spaceAdvance;
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr double interGlyphSpaceMultiplier = 0.15;
|
||||
double interGlyphSpace = glyphSize.x * interGlyphSpaceMultiplier;
|
||||
STROKE_GLYPH* source = static_cast<STROKE_GLYPH*>( m_glyphs->at( dd ).get() );
|
||||
|
||||
aGlyphs.push_back( source->Transform( glyphSize, cursor, tilt ) );
|
||||
|
||||
cursor.x = aGlyphs.back()->BoundingBox().GetEnd().x + interGlyphSpace;
|
||||
}
|
||||
}
|
||||
|
||||
VECTOR2D barOffset( 0.0, 0.0 );
|
||||
|
||||
if( aTextStyle & TEXT_STYLE::OVERBAR )
|
||||
{
|
||||
std::shared_ptr<STROKE_GLYPH> overbarGlyph = std::make_shared<STROKE_GLYPH>();
|
||||
|
||||
barOffset.y = ComputeOverbarVerticalPosition( glyphSize.y );
|
||||
|
||||
if( aTextStyle & TEXT_STYLE::ITALIC )
|
||||
barOffset.x = barOffset.y * ITALIC_TILT;
|
||||
|
||||
overbarGlyph->AddPoint( VECTOR2D( aPosition.x + barOffset.x, cursor.y - barOffset.y ) );
|
||||
overbarGlyph->AddPoint( VECTOR2D( cursor.x + barOffset.x, cursor.y - barOffset.y ) );
|
||||
overbarGlyph->Finalize();
|
||||
|
||||
aGlyphs.push_back( overbarGlyph );
|
||||
}
|
||||
|
||||
if( aBoundingBox )
|
||||
{
|
||||
aBoundingBox->SetOrigin( aPosition.x, aPosition.y );
|
||||
aBoundingBox->SetEnd( cursor.x + barOffset.x, cursor.y + std::max( glyphSize.y, barOffset.y ) );
|
||||
aBoundingBox->Normalize();
|
||||
}
|
||||
|
||||
return VECTOR2I( cursor.x, aPosition.y );
|
||||
}
|
|
@ -286,11 +286,13 @@ void CAIRO_GAL_BASE::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& a
|
|||
|
||||
// Draw the rounded end point of the segment
|
||||
double arcStartAngle = lineAngle - M_PI / 2.0;
|
||||
cairo_arc( m_currentContext, center_b.x, center_b.y, radius, arcStartAngle, arcStartAngle + M_PI );
|
||||
cairo_arc( m_currentContext, center_b.x, center_b.y, radius, arcStartAngle,
|
||||
arcStartAngle + M_PI );
|
||||
|
||||
// Draw the rounded start point of the segment
|
||||
arcStartAngle = lineAngle + M_PI / 2.0;
|
||||
cairo_arc( m_currentContext, center_a.x, center_a.y, radius, arcStartAngle, arcStartAngle + M_PI );
|
||||
cairo_arc( m_currentContext, center_a.x, center_a.y, radius, arcStartAngle,
|
||||
arcStartAngle + M_PI );
|
||||
|
||||
flushPath();
|
||||
}
|
||||
|
@ -1194,6 +1196,31 @@ void CAIRO_GAL_BASE::drawPoly( const std::deque<VECTOR2D>& aPointList )
|
|||
}
|
||||
|
||||
|
||||
void CAIRO_GAL_BASE::drawPoly( const std::vector<VECTOR2D>& aPointList )
|
||||
{
|
||||
wxCHECK( aPointList.size() > 1, /* void */ );
|
||||
|
||||
// Iterate over the point list and draw the segments
|
||||
std::vector<VECTOR2D>::const_iterator it = aPointList.begin();
|
||||
|
||||
syncLineWidth();
|
||||
|
||||
const VECTOR2D p = roundp( xform( it->x, it->y ) );
|
||||
|
||||
cairo_move_to( m_currentContext, p.x, p.y );
|
||||
|
||||
for( ++it; it != aPointList.end(); ++it )
|
||||
{
|
||||
const VECTOR2D p2 = roundp( xform( it->x, it->y ) );
|
||||
|
||||
cairo_line_to( m_currentContext, p2.x, p2.y );
|
||||
}
|
||||
|
||||
flushPath();
|
||||
m_isElementAdded = true;
|
||||
}
|
||||
|
||||
|
||||
void CAIRO_GAL_BASE::drawPoly( const VECTOR2D aPointList[], int aListSize )
|
||||
{
|
||||
wxCHECK( aListSize > 1, /* void */ );
|
||||
|
@ -1732,3 +1759,85 @@ void CAIRO_GAL_BASE::DrawGrid()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CAIRO_GAL_BASE::DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTotal )
|
||||
{
|
||||
if( aGlyph.IsStroke() )
|
||||
{
|
||||
for( const std::vector<VECTOR2D>& pointList : aGlyph.GetPoints() )
|
||||
drawPoly( pointList );
|
||||
}
|
||||
#if 0 // FONT TODO
|
||||
else if( aGlyph.IsOutline() )
|
||||
{
|
||||
if( aNth == 0 )
|
||||
{
|
||||
cairo_close_path( m_currentContext );
|
||||
flushPath();
|
||||
|
||||
cairo_new_path( m_currentContext );
|
||||
SetIsFill( true );
|
||||
SetIsStroke( false );
|
||||
}
|
||||
|
||||
// eventually glyphs should not be drawn as polygons at all,
|
||||
// but as bitmaps with antialiasing, this is just a stopgap measure
|
||||
// of getting some form of outline font display
|
||||
auto triangleCallback = [&]( int aPolygonIndex, const VECTOR2D& aVertex1,
|
||||
const VECTOR2D& aVertex2, const VECTOR2D& aVertex3,
|
||||
void* aCallbackData )
|
||||
{
|
||||
#if 1
|
||||
syncLineWidth();
|
||||
|
||||
const auto p0 = roundp( xform( aVertex1 ) );
|
||||
const auto p1 = roundp( xform( aVertex2 ) );
|
||||
const auto p2 = roundp( xform( aVertex3 ) );
|
||||
|
||||
/*
|
||||
cairo_move_to( currentContext, aVertex1.x, aVertex1.y );
|
||||
cairo_line_to( currentContext, aVertex2.x, aVertex2.y );
|
||||
cairo_line_to( currentContext, aVertex3.x, aVertex3.y );
|
||||
cairo_line_to( currentContext, aVertex1.x, aVertex1.y );
|
||||
*/
|
||||
cairo_move_to( m_currentContext, p0.x, p0.y );
|
||||
cairo_line_to( m_currentContext, p1.x, p1.y );
|
||||
cairo_line_to( m_currentContext, p2.x, p2.y );
|
||||
cairo_close_path( m_currentContext );
|
||||
/*
|
||||
setSourceRgba( currentContext, fillColor );
|
||||
SetIsFill( true );
|
||||
cairo_set_fill_rule( currentContext, CAIRO_FILL_RULE_EVEN_ODD );
|
||||
flushPath();
|
||||
*/
|
||||
//cairo_fill( currentContext );
|
||||
#else
|
||||
// just a silly test
|
||||
/*
|
||||
DrawRectangle(aVertex1, aVertex2);
|
||||
DrawRectangle(aVertex2, aVertex3);
|
||||
DrawRectangle(aVertex3, aVertex1);
|
||||
*/
|
||||
DrawTriangle( aVertex1, aVertex2, aVertex3 );
|
||||
#endif
|
||||
};
|
||||
|
||||
Triangulate( aGlyph, triangleCallback );
|
||||
|
||||
if( aNth == aTotal - 1 )
|
||||
{
|
||||
/*
|
||||
cairo_close_path( currentContext );
|
||||
setSourceRgba( currentContext, fillColor );
|
||||
cairo_set_fill_rule( currentContext, CAIRO_FILL_RULE_EVEN_ODD );
|
||||
cairo_fill_preserve( currentContext );
|
||||
setSourceRgba( currentContext, strokeColor );
|
||||
cairo_stroke( currentContext );
|
||||
*/
|
||||
flushPath();
|
||||
m_isElementAdded = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <gal/definitions.h>
|
||||
#include <font/font.h>
|
||||
|
||||
#include <math/util.h> // for KiROUND
|
||||
|
||||
|
@ -38,7 +39,6 @@ using namespace KIGFX;
|
|||
|
||||
GAL::GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions ) :
|
||||
m_options( aDisplayOptions ),
|
||||
m_strokeFont( this ),
|
||||
// m_currentNativeCursor is initialized with KICURSOR::DEFAULT value to avoid
|
||||
// if comparison with uninitialized value on SetNativeCursorStyle method.
|
||||
// Some classes inheriting from GAL has different SetNativeCursorStyle method
|
||||
|
@ -86,8 +86,6 @@ GAL::GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions ) :
|
|||
// Initialize text properties
|
||||
ResetTextAttributes();
|
||||
|
||||
m_strokeFont.LoadNewStrokeFont( newstroke_font, newstroke_font_bufsize );
|
||||
|
||||
// subscribe for settings updates
|
||||
m_observerLink = m_options.Subscribe( this );
|
||||
}
|
||||
|
@ -152,15 +150,9 @@ bool GAL::updatedGalDisplayOptions( const GAL_DISPLAY_OPTIONS& aOptions )
|
|||
}
|
||||
|
||||
|
||||
void GAL::SetTextAttributes( const EDA_TEXT* aText )
|
||||
void GAL::SetTextAttributes( const TEXT_ATTRIBUTES& aAttributes )
|
||||
{
|
||||
SetGlyphSize( VECTOR2D( aText->GetTextSize() ) );
|
||||
SetHorizontalJustify( aText->GetHorizJustify() );
|
||||
SetVerticalJustify( aText->GetVertJustify() );
|
||||
SetFontBold( aText->IsBold() );
|
||||
SetFontItalic( aText->IsItalic() );
|
||||
SetFontUnderlined( false );
|
||||
SetTextMirrored( aText->IsMirrored() );
|
||||
m_attributes = aAttributes;
|
||||
}
|
||||
|
||||
|
||||
|
@ -180,15 +172,6 @@ void GAL::ResetTextAttributes()
|
|||
}
|
||||
|
||||
|
||||
VECTOR2D GAL::GetTextLineSize( const UTF8& aText ) const
|
||||
{
|
||||
// Compute the X and Y size of a given text.
|
||||
// Because computeTextLineSize expects a one line text,
|
||||
// aText is expected to be only one line text.
|
||||
return m_strokeFont.computeTextLineSize( aText );
|
||||
}
|
||||
|
||||
|
||||
void GAL::ComputeWorldScreenMatrix()
|
||||
{
|
||||
computeWorldScale();
|
||||
|
@ -277,6 +260,65 @@ COLOR4D GAL::getCursorColor() const
|
|||
}
|
||||
|
||||
|
||||
void GAL::StrokeText( const wxString& aText, const VECTOR2D& aPosition, double aRotationAngle,
|
||||
KIFONT::FONT* aFont, double aLineSpacing )
|
||||
{
|
||||
if( aText.IsEmpty() )
|
||||
return;
|
||||
|
||||
if( !aFont )
|
||||
aFont = KIFONT::FONT::GetFont( wxEmptyString );
|
||||
|
||||
TEXT_ATTRIBUTES attributes;
|
||||
attributes.m_Angle = EDA_ANGLE( aRotationAngle, EDA_ANGLE::RADIANS );
|
||||
attributes.m_Halign = GetHorizontalJustify();
|
||||
attributes.m_Valign = GetVerticalJustify();
|
||||
attributes.m_LineSpacing = aLineSpacing;
|
||||
|
||||
aFont->Draw( this, aText, aPosition, attributes );
|
||||
}
|
||||
|
||||
|
||||
void GAL::DrawGlyphs( const KIFONT::GLYPH_LIST& aGlyphs )
|
||||
{
|
||||
int nth = 0;
|
||||
int total = aGlyphs.size();
|
||||
|
||||
for( const std::shared_ptr<KIFONT::GLYPH>& glyph : aGlyphs )
|
||||
{
|
||||
DrawGlyph( glyph, nth, total );
|
||||
nth++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Fallback for implementations that don't implement bitmap text: use stroke font
|
||||
*/
|
||||
void GAL::BitmapText( const wxString& aText, const VECTOR2D& aPosition, double aRotationAngle )
|
||||
{
|
||||
// Handle flipped view
|
||||
if( m_globalFlipX )
|
||||
m_attributes.m_Mirrored = !m_attributes.m_Mirrored;
|
||||
|
||||
// Bitmap font is slightly smaller and slightly heavier than the stroke font so we
|
||||
// compensate a bit before stroking
|
||||
float saveLineWidth = m_lineWidth;
|
||||
VECTOR2D saveGlyphSize = m_attributes.m_Size;
|
||||
{
|
||||
m_lineWidth *= 1.2f;
|
||||
m_attributes.m_Size = m_attributes.m_Size * 0.8;
|
||||
|
||||
StrokeText( aText, aPosition, aRotationAngle );
|
||||
}
|
||||
m_lineWidth = saveLineWidth;
|
||||
m_attributes.m_Size = saveGlyphSize;
|
||||
|
||||
if( m_globalFlipX )
|
||||
m_attributes.m_Mirrored = !m_attributes.m_Mirrored;
|
||||
}
|
||||
|
||||
|
||||
bool GAL::SetNativeCursorStyle( KICURSOR aCursor )
|
||||
{
|
||||
if( m_currentNativeCursor == aCursor )
|
||||
|
|
|
@ -1027,6 +1027,17 @@ void OPENGL_GAL::DrawPolyline( const std::deque<VECTOR2D>& aPointList )
|
|||
}
|
||||
|
||||
|
||||
void OPENGL_GAL::DrawPolyline( const std::vector<VECTOR2D>& aPointList )
|
||||
{
|
||||
drawPolyline(
|
||||
[&]( int idx )
|
||||
{
|
||||
return aPointList[idx];
|
||||
},
|
||||
aPointList.size() );
|
||||
}
|
||||
|
||||
|
||||
void OPENGL_GAL::DrawPolyline( const VECTOR2D aPointList[], int aListSize )
|
||||
{
|
||||
drawPolyline(
|
||||
|
@ -2380,3 +2391,21 @@ void OPENGL_GAL::ComputeWorldScreenMatrix()
|
|||
|
||||
GAL::ComputeWorldScreenMatrix();
|
||||
}
|
||||
|
||||
|
||||
void OPENGL_GAL::DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTotal )
|
||||
{
|
||||
if( aGlyph.IsStroke() )
|
||||
{
|
||||
for( const std::vector<VECTOR2D>& pointList : aGlyph.GetPoints() )
|
||||
DrawPolyline( pointList );
|
||||
}
|
||||
#if 0 // FONT TODO
|
||||
else if( aGlyph.IsOutline() )
|
||||
{
|
||||
fillPolygonAsTriangles( aGlyph.GetPolylist() );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,640 +0,0 @@
|
|||
/*
|
||||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
|
||||
* Copyright (C) 2013 CERN
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
* Copyright (C) 2016-2021 Kicad Developers, see change_log.txt for contributors.
|
||||
*
|
||||
* Stroke font class
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <gal/stroke_font.h>
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <math/util.h> // for KiROUND
|
||||
#include <wx/string.h>
|
||||
#include <gr_text.h>
|
||||
|
||||
|
||||
using namespace KIGFX;
|
||||
|
||||
const double STROKE_FONT::INTERLINE_PITCH_RATIO = 1.61;
|
||||
const double STROKE_FONT::OVERBAR_POSITION_FACTOR = 1.33;
|
||||
const double STROKE_FONT::UNDERLINE_POSITION_FACTOR = 0.41;
|
||||
const double STROKE_FONT::BOLD_FACTOR = 1.3;
|
||||
const double STROKE_FONT::STROKE_FONT_SCALE = 1.0 / 21.0;
|
||||
const double STROKE_FONT::ITALIC_TILT = 1.0 / 8;
|
||||
|
||||
|
||||
GLYPH_LIST* g_newStrokeFontGlyphs = nullptr; ///< Glyph list
|
||||
std::vector<BOX2D>* g_newStrokeFontGlyphBoundingBoxes; ///< Bounding boxes of the glyphs
|
||||
|
||||
|
||||
STROKE_FONT::STROKE_FONT( GAL* aGal ) :
|
||||
m_gal( aGal ),
|
||||
m_glyphs( nullptr ),
|
||||
m_glyphBoundingBoxes( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool STROKE_FONT::LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNewStrokeFontSize )
|
||||
{
|
||||
if( g_newStrokeFontGlyphs )
|
||||
{
|
||||
m_glyphs = g_newStrokeFontGlyphs;
|
||||
m_glyphBoundingBoxes = g_newStrokeFontGlyphBoundingBoxes;
|
||||
return true;
|
||||
}
|
||||
|
||||
g_newStrokeFontGlyphs = new GLYPH_LIST;
|
||||
g_newStrokeFontGlyphs->reserve( aNewStrokeFontSize );
|
||||
|
||||
g_newStrokeFontGlyphBoundingBoxes = new std::vector<BOX2D>;
|
||||
g_newStrokeFontGlyphBoundingBoxes->reserve( aNewStrokeFontSize );
|
||||
|
||||
for( int j = 0; j < aNewStrokeFontSize; j++ )
|
||||
{
|
||||
GLYPH* glyph = new GLYPH;
|
||||
double glyphStartX = 0.0;
|
||||
double glyphEndX = 0.0;
|
||||
double glyphWidth = 0.0;
|
||||
|
||||
std::vector<VECTOR2D>* pointList = nullptr;
|
||||
|
||||
int strokes = 0;
|
||||
int i = 0;
|
||||
|
||||
while( aNewStrokeFont[j][i] )
|
||||
{
|
||||
|
||||
if( aNewStrokeFont[j][i] == ' ' && aNewStrokeFont[j][i+1] == 'R' )
|
||||
strokes++;
|
||||
|
||||
i += 2;
|
||||
}
|
||||
|
||||
glyph->reserve( strokes + 1 );
|
||||
|
||||
i = 0;
|
||||
|
||||
while( aNewStrokeFont[j][i] )
|
||||
{
|
||||
VECTOR2D point( 0.0, 0.0 );
|
||||
char coordinate[2] = { 0, };
|
||||
|
||||
for( int k : { 0, 1 } )
|
||||
coordinate[k] = aNewStrokeFont[j][i + k];
|
||||
|
||||
if( i < 2 )
|
||||
{
|
||||
// The first two values contain the width of the char
|
||||
glyphStartX = ( coordinate[0] - 'R' ) * STROKE_FONT_SCALE;
|
||||
glyphEndX = ( coordinate[1] - 'R' ) * STROKE_FONT_SCALE;
|
||||
glyphWidth = glyphEndX - glyphStartX;
|
||||
}
|
||||
else if( ( coordinate[0] == ' ' ) && ( coordinate[1] == 'R' ) )
|
||||
{
|
||||
if( pointList )
|
||||
pointList->shrink_to_fit();
|
||||
|
||||
// Raise pen
|
||||
pointList = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In stroke font, coordinates values are coded as <value> + 'R',
|
||||
// <value> is an ASCII char.
|
||||
// therefore every coordinate description of the Hershey format has an offset,
|
||||
// it has to be subtracted
|
||||
// Note:
|
||||
// * the stroke coordinates are stored in reduced form (-1.0 to +1.0),
|
||||
// and the actual size is stroke coordinate * glyph size
|
||||
// * a few shapes have a height slightly bigger than 1.0 ( like '{' '[' )
|
||||
point.x = (double) ( coordinate[0] - 'R' ) * STROKE_FONT_SCALE - glyphStartX;
|
||||
#define FONT_OFFSET -10
|
||||
// FONT_OFFSET is here for historical reasons, due to the way the stroke font
|
||||
// was built. It allows shapes coordinates like W M ... to be >= 0
|
||||
// Only shapes like j y have coordinates < 0
|
||||
point.y = (double) ( coordinate[1] - 'R' + FONT_OFFSET ) * STROKE_FONT_SCALE;
|
||||
|
||||
if( !pointList )
|
||||
{
|
||||
pointList = new std::vector<VECTOR2D>;
|
||||
glyph->push_back( pointList );
|
||||
}
|
||||
|
||||
pointList->push_back( point );
|
||||
}
|
||||
|
||||
i += 2;
|
||||
}
|
||||
|
||||
if( pointList )
|
||||
pointList->shrink_to_fit();
|
||||
|
||||
// Compute the bounding box of the glyph
|
||||
g_newStrokeFontGlyphBoundingBoxes->emplace_back( computeBoundingBox( glyph, glyphWidth ) );
|
||||
g_newStrokeFontGlyphs->push_back( glyph );
|
||||
}
|
||||
|
||||
m_glyphs = g_newStrokeFontGlyphs;
|
||||
m_glyphBoundingBoxes = g_newStrokeFontGlyphBoundingBoxes;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Static function:
|
||||
double STROKE_FONT::GetInterline( double aGlyphHeight )
|
||||
{
|
||||
// Do not add the glyph thickness to the interline. This makes bold text line-spacing
|
||||
// different from normal text, which is poor typography.
|
||||
return ( aGlyphHeight * INTERLINE_PITCH_RATIO );
|
||||
}
|
||||
|
||||
|
||||
BOX2D STROKE_FONT::computeBoundingBox( const GLYPH* aGLYPH, double aGlyphWidth ) const
|
||||
{
|
||||
VECTOR2D min( 0, 0 );
|
||||
VECTOR2D max( aGlyphWidth, 0 );
|
||||
|
||||
for( const std::vector<VECTOR2D>* pointList : *aGLYPH )
|
||||
{
|
||||
for( const VECTOR2D& point : *pointList )
|
||||
{
|
||||
min.y = std::min( min.y, point.y );
|
||||
max.y = std::max( max.y, point.y );
|
||||
}
|
||||
}
|
||||
|
||||
return BOX2D( min, max - min );
|
||||
}
|
||||
|
||||
|
||||
void STROKE_FONT::Draw( const UTF8& aText, const VECTOR2D& aPosition, double aRotationAngle )
|
||||
{
|
||||
if( aText.empty() )
|
||||
return;
|
||||
|
||||
// Context needs to be saved before any transformations
|
||||
m_gal->Save();
|
||||
|
||||
m_gal->Translate( aPosition );
|
||||
m_gal->Rotate( -aRotationAngle );
|
||||
|
||||
// Single line height
|
||||
int lineHeight = KiROUND( GetInterline( m_gal->GetGlyphSize().y ) );
|
||||
int lineCount = linesCount( aText );
|
||||
const VECTOR2D& glyphSize = m_gal->GetGlyphSize();
|
||||
|
||||
// align the 1st line of text
|
||||
switch( m_gal->GetVerticalJustify() )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP:
|
||||
m_gal->Translate( VECTOR2D( 0, glyphSize.y ) );
|
||||
break;
|
||||
|
||||
case GR_TEXT_V_ALIGN_CENTER:
|
||||
m_gal->Translate( VECTOR2D( 0, glyphSize.y / 2.0 ) );
|
||||
break;
|
||||
|
||||
case GR_TEXT_V_ALIGN_BOTTOM:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( lineCount > 1 )
|
||||
{
|
||||
switch( m_gal->GetVerticalJustify() )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP:
|
||||
break;
|
||||
|
||||
case GR_TEXT_V_ALIGN_CENTER:
|
||||
m_gal->Translate( VECTOR2D(0, -( lineCount - 1 ) * lineHeight / 2) );
|
||||
break;
|
||||
|
||||
case GR_TEXT_V_ALIGN_BOTTOM:
|
||||
m_gal->Translate( VECTOR2D(0, -( lineCount - 1 ) * lineHeight ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_gal->SetIsStroke( true );
|
||||
//m_gal->SetIsFill( false );
|
||||
|
||||
if( m_gal->IsFontBold() )
|
||||
m_gal->SetLineWidth( m_gal->GetLineWidth() * BOLD_FACTOR );
|
||||
|
||||
// Split multiline strings into separate ones and draw them line by line
|
||||
size_t begin = 0;
|
||||
size_t newlinePos = aText.find( '\n' );
|
||||
|
||||
while( newlinePos != aText.npos )
|
||||
{
|
||||
size_t length = newlinePos - begin;
|
||||
|
||||
drawSingleLineText( aText.substr( begin, length ) );
|
||||
m_gal->Translate( VECTOR2D( 0.0, lineHeight ) );
|
||||
|
||||
begin = newlinePos + 1;
|
||||
newlinePos = aText.find( '\n', begin );
|
||||
}
|
||||
|
||||
// Draw the last (or the only one) line
|
||||
if( !aText.empty() )
|
||||
drawSingleLineText( aText.substr( begin ) );
|
||||
|
||||
m_gal->Restore();
|
||||
}
|
||||
|
||||
|
||||
void STROKE_FONT::drawSingleLineText( const UTF8& aText )
|
||||
{
|
||||
double xOffset;
|
||||
double yOffset;
|
||||
VECTOR2D baseGlyphSize( m_gal->GetGlyphSize() );
|
||||
double overbar_italic_comp = computeOverbarVerticalPosition() * ITALIC_TILT;
|
||||
|
||||
if( m_gal->IsTextMirrored() )
|
||||
overbar_italic_comp = -overbar_italic_comp;
|
||||
|
||||
// Compute the text size
|
||||
VECTOR2D textSize = computeTextLineSize( aText );
|
||||
double half_thickness = m_gal->GetLineWidth()/2;
|
||||
|
||||
// Context needs to be saved before any transformations
|
||||
m_gal->Save();
|
||||
|
||||
// First adjust: the text X position is corrected by half_thickness
|
||||
// because when the text with thickness is draw, its full size is textSize,
|
||||
// but the position of lines is half_thickness to textSize - half_thickness
|
||||
// so we must translate the coordinates by half_thickness on the X axis
|
||||
// to place the text inside the 0 to textSize X area.
|
||||
m_gal->Translate( VECTOR2D( half_thickness, 0 ) );
|
||||
|
||||
// Adjust the text position to the given horizontal justification
|
||||
switch( m_gal->GetHorizontalJustify() )
|
||||
{
|
||||
case GR_TEXT_H_ALIGN_CENTER:
|
||||
m_gal->Translate( VECTOR2D( -textSize.x / 2.0, 0 ) );
|
||||
break;
|
||||
|
||||
case GR_TEXT_H_ALIGN_RIGHT:
|
||||
if( !m_gal->IsTextMirrored() )
|
||||
m_gal->Translate( VECTOR2D( -textSize.x, 0 ) );
|
||||
break;
|
||||
|
||||
case GR_TEXT_H_ALIGN_LEFT:
|
||||
if( m_gal->IsTextMirrored() )
|
||||
m_gal->Translate( VECTOR2D( -textSize.x, 0 ) );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( m_gal->IsTextMirrored() )
|
||||
{
|
||||
// In case of mirrored text invert the X scale of points and their X direction
|
||||
// (m_glyphSize.x) and start drawing from the position where text normally should end
|
||||
// (textSize.x)
|
||||
xOffset = textSize.x - m_gal->GetLineWidth();
|
||||
baseGlyphSize.x = -baseGlyphSize.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
xOffset = 0.0;
|
||||
}
|
||||
|
||||
// The overbar is indented inward at the beginning of an italicized section, but
|
||||
// must not be indented on subsequent letters to ensure that the bar segments
|
||||
// overlap.
|
||||
bool lastHadOverbar = false;
|
||||
int overbarDepth = -1;
|
||||
int superSubDepth = -1;
|
||||
int braceNesting = 0;
|
||||
VECTOR2D glyphSize = baseGlyphSize;
|
||||
|
||||
// Allocate only once (for performance)
|
||||
std::vector<VECTOR2D> ptListScaled;
|
||||
int char_count = 0;
|
||||
|
||||
yOffset = 0;
|
||||
|
||||
for( UTF8::uni_iter chIt = aText.ubegin(), end = aText.uend(); chIt < end; ++chIt )
|
||||
{
|
||||
// Handle tabs as locked to the nearest 4th column (counting in space-widths).
|
||||
// The choice of spaces is somewhat arbitrary but sufficient for aligning text; while
|
||||
// it can produce tabs that go backwards when following wide characters, spacing in
|
||||
// widest-char-widths produces tab spacing that is much too wide (and would change the
|
||||
// layout of existing boards).
|
||||
if( *chIt == '\t' )
|
||||
{
|
||||
char_count = ( char_count / 4 + 1 ) * 4 - 1;
|
||||
xOffset = baseGlyphSize.x * char_count;
|
||||
|
||||
glyphSize = baseGlyphSize;
|
||||
yOffset = 0;
|
||||
}
|
||||
else if( *chIt == '^' && superSubDepth == -1 )
|
||||
{
|
||||
UTF8::uni_iter lookahead = chIt;
|
||||
|
||||
if( ++lookahead != end && *lookahead == '{' )
|
||||
{
|
||||
chIt = lookahead;
|
||||
superSubDepth = braceNesting;
|
||||
braceNesting++;
|
||||
|
||||
glyphSize = baseGlyphSize * 0.8;
|
||||
yOffset = -baseGlyphSize.y * 0.3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if( *chIt == '_' && superSubDepth == -1 )
|
||||
{
|
||||
UTF8::uni_iter lookahead = chIt;
|
||||
|
||||
if( ++lookahead != end && *lookahead == '{' )
|
||||
{
|
||||
chIt = lookahead;
|
||||
superSubDepth = braceNesting;
|
||||
braceNesting++;
|
||||
|
||||
glyphSize = baseGlyphSize * 0.8;
|
||||
yOffset = baseGlyphSize.y * 0.1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if( *chIt == '~' && overbarDepth == -1 )
|
||||
{
|
||||
UTF8::uni_iter lookahead = chIt;
|
||||
|
||||
if( ++lookahead != end && *lookahead == '{' )
|
||||
{
|
||||
chIt = lookahead;
|
||||
overbarDepth = braceNesting;
|
||||
braceNesting++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if( *chIt == '{' )
|
||||
{
|
||||
braceNesting++;
|
||||
}
|
||||
else if( *chIt == '}' )
|
||||
{
|
||||
if( braceNesting > 0 )
|
||||
braceNesting--;
|
||||
|
||||
if( braceNesting == superSubDepth )
|
||||
{
|
||||
superSubDepth = -1;
|
||||
|
||||
glyphSize = baseGlyphSize;
|
||||
yOffset = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( braceNesting == overbarDepth )
|
||||
{
|
||||
overbarDepth = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Index into bounding boxes table
|
||||
int dd = (signed) *chIt - ' ';
|
||||
|
||||
if( dd >= (int) m_glyphBoundingBoxes->size() || dd < 0 )
|
||||
{
|
||||
int substitute = *chIt == '\t' ? ' ' : '?';
|
||||
dd = substitute - ' ';
|
||||
}
|
||||
|
||||
const GLYPH* glyph = m_glyphs->at( dd );
|
||||
const BOX2D& bbox = m_glyphBoundingBoxes->at( dd );
|
||||
|
||||
if( overbarDepth != -1 )
|
||||
{
|
||||
double overbar_start_x = xOffset;
|
||||
double overbar_start_y = - computeOverbarVerticalPosition();
|
||||
double overbar_end_x = xOffset + glyphSize.x * bbox.GetEnd().x;
|
||||
double overbar_end_y = overbar_start_y;
|
||||
|
||||
if( !lastHadOverbar )
|
||||
{
|
||||
if( m_gal->IsFontItalic() )
|
||||
overbar_start_x += overbar_italic_comp;
|
||||
|
||||
lastHadOverbar = true;
|
||||
}
|
||||
|
||||
VECTOR2D startOverbar( overbar_start_x, overbar_start_y );
|
||||
VECTOR2D endOverbar( overbar_end_x, overbar_end_y );
|
||||
|
||||
m_gal->DrawLine( startOverbar, endOverbar );
|
||||
}
|
||||
else
|
||||
{
|
||||
lastHadOverbar = false;
|
||||
}
|
||||
|
||||
if( m_gal->IsFontUnderlined() )
|
||||
{
|
||||
double vOffset = computeUnderlineVerticalPosition();
|
||||
VECTOR2D startUnderline( xOffset, - vOffset );
|
||||
VECTOR2D endUnderline( xOffset + glyphSize.x * bbox.GetEnd().x, - vOffset );
|
||||
|
||||
m_gal->DrawLine( startUnderline, endUnderline );
|
||||
}
|
||||
|
||||
for( const std::vector<VECTOR2D>* ptList : *glyph )
|
||||
{
|
||||
int ptCount = 0;
|
||||
ptListScaled.clear();
|
||||
|
||||
for( const VECTOR2D& pt : *ptList )
|
||||
{
|
||||
VECTOR2D scaledPt( pt.x * glyphSize.x + xOffset, pt.y * glyphSize.y + yOffset );
|
||||
|
||||
if( m_gal->IsFontItalic() )
|
||||
{
|
||||
// FIXME should be done other way - referring to the lowest Y value of point
|
||||
// because now italic fonts are translated a bit
|
||||
if( m_gal->IsTextMirrored() )
|
||||
scaledPt.x += scaledPt.y * STROKE_FONT::ITALIC_TILT;
|
||||
else
|
||||
scaledPt.x -= scaledPt.y * STROKE_FONT::ITALIC_TILT;
|
||||
}
|
||||
|
||||
ptListScaled.push_back( scaledPt );
|
||||
ptCount++;
|
||||
}
|
||||
|
||||
m_gal->DrawPolyline( &ptListScaled[0], ptCount );
|
||||
}
|
||||
|
||||
char_count++;
|
||||
xOffset += glyphSize.x * bbox.GetEnd().x;
|
||||
}
|
||||
|
||||
m_gal->Restore();
|
||||
}
|
||||
|
||||
|
||||
double STROKE_FONT::ComputeOverbarVerticalPosition( double aGlyphHeight ) const
|
||||
{
|
||||
// Static method.
|
||||
return aGlyphHeight * OVERBAR_POSITION_FACTOR;
|
||||
}
|
||||
|
||||
|
||||
double STROKE_FONT::computeOverbarVerticalPosition() const
|
||||
{
|
||||
// Compute the Y position of the overbar. This is the distance between
|
||||
// the text base line and the overbar axis.
|
||||
return ComputeOverbarVerticalPosition( m_gal->GetGlyphSize().y );
|
||||
}
|
||||
|
||||
|
||||
double STROKE_FONT::computeUnderlineVerticalPosition() const
|
||||
{
|
||||
// Compute the Y position of the underline. This is the distance between
|
||||
// the text base line and the underline axis.
|
||||
return - m_gal->GetGlyphSize().y * UNDERLINE_POSITION_FACTOR;
|
||||
}
|
||||
|
||||
|
||||
VECTOR2D STROKE_FONT::computeTextLineSize( const UTF8& aText ) const
|
||||
{
|
||||
return ComputeStringBoundaryLimits( aText, m_gal->GetGlyphSize(), m_gal->GetLineWidth() );
|
||||
}
|
||||
|
||||
|
||||
VECTOR2D STROKE_FONT::ComputeStringBoundaryLimits( const UTF8& aText, const VECTOR2D& aGlyphSize,
|
||||
double aGlyphThickness ) const
|
||||
{
|
||||
VECTOR2D string_bbox;
|
||||
int line_count = 1;
|
||||
double maxX = 0.0, curX = 0.0;
|
||||
|
||||
double curScale = 1.0;
|
||||
int overbarDepth = -1;
|
||||
int superSubDepth = -1;
|
||||
int braceNesting = 0;
|
||||
|
||||
for( UTF8::uni_iter chIt = aText.ubegin(), end = aText.uend(); chIt < end; ++chIt )
|
||||
{
|
||||
if( *chIt == '\n' )
|
||||
{
|
||||
curX = 0.0;
|
||||
maxX = std::max( maxX, curX );
|
||||
++line_count;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle tabs as locked to the nearest 4th column (counting in spaces)
|
||||
// The choice of spaces is somewhat arbitrary but sufficient for aligning text
|
||||
if( *chIt == '\t' )
|
||||
{
|
||||
double spaces = m_glyphBoundingBoxes->at( 0 ).GetEnd().x;
|
||||
double addlSpace = 3.0 * spaces - std::fmod( curX, 4.0 * spaces );
|
||||
|
||||
// Add the remaining space (between 0 and 3 spaces)
|
||||
curX += addlSpace;
|
||||
}
|
||||
else if( (*chIt == '^' || *chIt == '_') && superSubDepth == -1 )
|
||||
{
|
||||
UTF8::uni_iter lookahead = chIt;
|
||||
|
||||
if( ++lookahead != end && *lookahead == '{' )
|
||||
{
|
||||
// Process superscript
|
||||
chIt = lookahead;
|
||||
superSubDepth = braceNesting;
|
||||
braceNesting++;
|
||||
|
||||
curScale = 0.8;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if( *chIt == '~' && overbarDepth == -1 )
|
||||
{
|
||||
UTF8::uni_iter lookahead = chIt;
|
||||
|
||||
if( ++lookahead != end && *lookahead == '{' )
|
||||
{
|
||||
chIt = lookahead;
|
||||
overbarDepth = braceNesting;
|
||||
braceNesting++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if( *chIt == '{' )
|
||||
{
|
||||
braceNesting++;
|
||||
}
|
||||
else if( *chIt == '}' )
|
||||
{
|
||||
if( braceNesting > 0 )
|
||||
braceNesting--;
|
||||
|
||||
if( braceNesting == overbarDepth )
|
||||
{
|
||||
overbarDepth = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( braceNesting == superSubDepth )
|
||||
{
|
||||
superSubDepth = -1;
|
||||
|
||||
curScale = 1.0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Index in the bounding boxes table
|
||||
int dd = (signed) *chIt - ' ';
|
||||
|
||||
if( dd >= (int) m_glyphBoundingBoxes->size() || dd < 0 )
|
||||
{
|
||||
int substitute = *chIt == '\t' ? ' ' : '?';
|
||||
dd = substitute - ' ';
|
||||
}
|
||||
|
||||
const BOX2D& box = m_glyphBoundingBoxes->at( dd );
|
||||
curX += box.GetEnd().x * curScale;
|
||||
}
|
||||
|
||||
string_bbox.x = std::max( maxX, curX ) * aGlyphSize.x;
|
||||
string_bbox.x += aGlyphThickness;
|
||||
string_bbox.y = line_count * GetInterline( aGlyphSize.y );
|
||||
|
||||
// For italic correction, take in account italic tilt
|
||||
if( m_gal->IsFontItalic() )
|
||||
string_bbox.x += string_bbox.y * STROKE_FONT::ITALIC_TILT;
|
||||
|
||||
return string_bbox;
|
||||
}
|
|
@ -1,8 +1,3 @@
|
|||
/**
|
||||
* Functions to draw and plot text on screen
|
||||
* @file draw_graphic_text.cpp
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
|
@ -48,12 +43,24 @@ int GetPenSizeForBold( int aTextSize )
|
|||
}
|
||||
|
||||
|
||||
int GetPenSizeForBold( const wxSize& aTextSize )
|
||||
{
|
||||
return GetPenSizeForBold( std::min( aTextSize.x, aTextSize.y ) );
|
||||
}
|
||||
|
||||
|
||||
int GetPenSizeForNormal( int aTextSize )
|
||||
{
|
||||
return KiROUND( aTextSize / 8.0 );
|
||||
}
|
||||
|
||||
|
||||
int GetPenSizeForNormal( const wxSize& aTextSize )
|
||||
{
|
||||
return GetPenSizeForNormal( std::min( aTextSize.x, aTextSize.y ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Don't allow text to become cluttered up in its own fatness. Bold fonts are generally around
|
||||
* aSize/5 in width, so we limit them to aSize/4, and normal text to aSize/6.
|
||||
|
@ -89,15 +96,14 @@ int Clamp_Text_PenSize( int aPenSize, const VECTOR2I& aSize, bool aBold )
|
|||
}
|
||||
|
||||
|
||||
int GraphicTextWidth( const wxString& aText, const VECTOR2I& aSize, bool aItalic, bool aBold )
|
||||
int GraphicTextWidth( const wxString& aText, KIFONT::FONT* aFont, const VECTOR2I& aSize,
|
||||
bool aItalic, bool aBold )
|
||||
{
|
||||
basic_gal.SetFontItalic( aItalic );
|
||||
basic_gal.SetFontBold( aBold );
|
||||
basic_gal.SetGlyphSize( VECTOR2D( aSize ) );
|
||||
|
||||
VECTOR2D tsize = basic_gal.GetTextLineSize( aText );
|
||||
|
||||
return KiROUND( tsize.x );
|
||||
return KiROUND( aFont->ComputeTextLineSize( &basic_gal, aText ).x );
|
||||
}
|
||||
|
||||
|
||||
|
@ -134,6 +140,9 @@ void GRText( wxDC* aDC, const VECTOR2I& aPos, const COLOR4D& aColor, const wxStr
|
|||
{
|
||||
bool fill_mode = true;
|
||||
|
||||
if( !aFont )
|
||||
aFont = KIFONT::FONT::GetFont();
|
||||
|
||||
if( aWidth == 0 && aBold ) // Use default values if aWidth == 0
|
||||
aWidth = GetPenSizeForBold( std::min( aSize.x, aSize.y ) );
|
||||
|
||||
|
@ -145,28 +154,29 @@ void GRText( wxDC* aDC, const VECTOR2I& aPos, const COLOR4D& aColor, const wxStr
|
|||
|
||||
basic_gal.SetIsFill( fill_mode );
|
||||
basic_gal.SetLineWidth( aWidth );
|
||||
|
||||
EDA_TEXT dummy;
|
||||
dummy.SetItalic( aItalic );
|
||||
dummy.SetBold( aBold );
|
||||
dummy.SetHorizJustify( aH_justify );
|
||||
dummy.SetVertJustify( aV_justify );
|
||||
|
||||
wxSize size = wxSize( aSize.x, aSize.y );
|
||||
dummy.SetMirrored( size.x < 0 );
|
||||
|
||||
if( size.x < 0 )
|
||||
size.x = - size.x;
|
||||
|
||||
dummy.SetTextSize( size );
|
||||
|
||||
basic_gal.SetTextAttributes( &dummy );
|
||||
basic_gal.SetPlotter( aPlotter );
|
||||
basic_gal.SetCallback( aCallback, aCallbackData );
|
||||
basic_gal.m_DC = aDC;
|
||||
basic_gal.m_Color = aColor;
|
||||
basic_gal.SetClipBox( nullptr );
|
||||
basic_gal.StrokeText( aText, VECTOR2D( aPos ), aOrient.AsRadians() );
|
||||
|
||||
TEXT_ATTRIBUTES attributes;
|
||||
attributes.m_Angle = aOrient;
|
||||
attributes.m_StrokeWidth = aWidth;
|
||||
attributes.m_Italic = aItalic;
|
||||
attributes.m_Bold = aBold;
|
||||
attributes.m_Halign = aH_justify;
|
||||
attributes.m_Valign = aV_justify;
|
||||
|
||||
VECTOR2D size = aSize;
|
||||
attributes.m_Mirrored = size.x < 0;
|
||||
|
||||
if( size.x < 0 )
|
||||
size.x = - size.x;
|
||||
|
||||
attributes.m_Size = size;
|
||||
|
||||
aFont->Draw( &basic_gal, aText, VECTOR2D( aPos ), attributes );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
using namespace MARKUP;
|
||||
|
||||
|
||||
MARKUP::MARKUP_NODE MARKUP_PARSER::Parse()
|
||||
std::unique_ptr<NODE> MARKUP_PARSER::Parse()
|
||||
{
|
||||
//string_input<> in( source, "from_input" );
|
||||
auto root = parse_tree::parse<MARKUP::grammar, MARKUP::NODE, MARKUP::selector>( in );
|
||||
|
@ -33,22 +33,6 @@ MARKUP::MARKUP_NODE MARKUP_PARSER::Parse()
|
|||
}
|
||||
|
||||
|
||||
std::ostream& operator<<( std::ostream& os, const MARKUP_NODE& node )
|
||||
{
|
||||
os << "<";
|
||||
|
||||
if( !node->is_root() )
|
||||
os << node->asString();
|
||||
|
||||
for( const auto& child : node->children )
|
||||
os << " " << child;
|
||||
|
||||
os << ">";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
std::string NODE::typeString() const
|
||||
{
|
||||
std::stringstream os;
|
||||
|
|
|
@ -95,6 +95,7 @@
|
|||
#include <eda_rect.h>
|
||||
#include <eda_shape.h>
|
||||
#include <string_utils.h>
|
||||
#include <font/font.h>
|
||||
#include <macros.h>
|
||||
#include <trigo.h>
|
||||
|
||||
|
@ -794,7 +795,7 @@ void SVG_PLOTTER::Text( const VECTOR2I& aPos,
|
|||
|
||||
// aSize.x or aSize.y is < 0 for mirrored texts.
|
||||
// The actual text size value is the absolute value
|
||||
text_size.x = std::abs( GraphicTextWidth( aText, aSize, aItalic, aWidth ) );
|
||||
text_size.x = std::abs( GraphicTextWidth( aText, aFont, aSize, aItalic, aWidth ) );
|
||||
text_size.y = std::abs( aSize.x * 4/3 ); // Hershey font height to em size conversion
|
||||
DPOINT anchor_pos_dev = userToDeviceCoordinates( aPos );
|
||||
DPOINT text_pos_dev = userToDeviceCoordinates( text_pos );
|
||||
|
|
|
@ -22,13 +22,13 @@
|
|||
*/
|
||||
|
||||
#include <preview_items/draw_context.h>
|
||||
|
||||
#include <preview_items/preview_utils.h>
|
||||
|
||||
#include <view/view.h>
|
||||
|
||||
using namespace KIGFX::PREVIEW;
|
||||
|
||||
using KIGFX::COLOR4D;
|
||||
|
||||
|
||||
static constexpr double ANGLE_EPSILON = 1e-9;
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <view/view.h>
|
||||
|
||||
using namespace KIGFX::PREVIEW;
|
||||
using KIGFX::COLOR4D;
|
||||
|
||||
struct SELECTION_COLORS
|
||||
{
|
||||
|
|
|
@ -135,7 +135,11 @@ DIALOG_PIN_PROPERTIES::DIALOG_PIN_PROPERTIES( SYMBOL_EDIT_FRAME* parent, LIB_PIN
|
|||
m_initialized( false )
|
||||
{
|
||||
// Creates a dummy pin to show on a panel, inside this dialog:
|
||||
m_dummyParent = new LIB_SYMBOL( *m_pin->GetParent() );
|
||||
m_dummyPin = new LIB_PIN( *m_pin );
|
||||
m_dummyPin->SetParent( m_dummyParent );
|
||||
m_dummyParent->SetShowPinNames( true );
|
||||
m_dummyParent->SetShowPinNumbers( true );
|
||||
|
||||
m_bSizerInfo->Show( m_frame->m_SyncPinEdit );
|
||||
|
||||
|
@ -241,6 +245,7 @@ DIALOG_PIN_PROPERTIES::DIALOG_PIN_PROPERTIES( SYMBOL_EDIT_FRAME* parent, LIB_PIN
|
|||
DIALOG_PIN_PROPERTIES::~DIALOG_PIN_PROPERTIES()
|
||||
{
|
||||
delete m_dummyPin;
|
||||
delete m_dummyParent;
|
||||
|
||||
// Prevents crash bug in wxGrid's d'tor
|
||||
m_alternatesGrid->DestroyTable( m_alternatesDataModel );
|
||||
|
@ -366,7 +371,7 @@ void DIALOG_PIN_PROPERTIES::OnPaintShowPanel( wxPaintEvent& event )
|
|||
wxSize dc_size = dc.GetSize();
|
||||
dc.SetDeviceOrigin( dc_size.x / 2, dc_size.y / 2 );
|
||||
|
||||
// Give a parent to m_dummyPin only from draw purpose.
|
||||
// Give a parent to m_dummyPin for draw purposes.
|
||||
// In fact m_dummyPin should not have a parent, but draw functions need a parent
|
||||
// to know some options, about pin texts
|
||||
SYMBOL_EDIT_FRAME* symbolEditor = (SYMBOL_EDIT_FRAME*) GetParent();
|
||||
|
@ -383,6 +388,7 @@ void DIALOG_PIN_PROPERTIES::OnPaintShowPanel( wxPaintEvent& event )
|
|||
GRResetPenAndBrush( &dc );
|
||||
|
||||
LIB_SYMBOL_OPTIONS opts;
|
||||
opts.force_draw_pin_text = true;
|
||||
opts.draw_hidden_fields = true;
|
||||
opts.show_connect_point = true;
|
||||
|
||||
|
|
|
@ -73,6 +73,8 @@ protected:
|
|||
private:
|
||||
SYMBOL_EDIT_FRAME* m_frame;
|
||||
LIB_PIN* m_pin;
|
||||
|
||||
LIB_SYMBOL* m_dummyParent;
|
||||
LIB_PIN* m_dummyPin; // a working copy used to show changes
|
||||
|
||||
UNIT_BINDER m_posX;
|
||||
|
|
|
@ -212,8 +212,9 @@ void LIB_PIN::print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset,
|
|||
{
|
||||
printPinSymbol( aSettings, pos1, orient );
|
||||
|
||||
printPinTexts( aSettings, pos1, orient, part->GetPinNameOffset(), part->ShowPinNumbers(),
|
||||
part->ShowPinNames() );
|
||||
printPinTexts( aSettings, pos1, orient, part->GetPinNameOffset(),
|
||||
opts->force_draw_pin_text || part->ShowPinNumbers(),
|
||||
opts->force_draw_pin_text || part->ShowPinNames() );
|
||||
|
||||
if( showPinType )
|
||||
printPinElectricalTypeName( aSettings, pos1, orient );
|
||||
|
@ -1068,7 +1069,7 @@ void LIB_PIN::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITE
|
|||
|
||||
const EDA_RECT LIB_PIN::GetBoundingBox( bool aIncludeInvisibles, bool aPinOnly ) const
|
||||
{
|
||||
const KIGFX::STROKE_FONT& font = basic_gal.GetStrokeFont();
|
||||
KIFONT::FONT* font = KIFONT::FONT::GetFont();
|
||||
|
||||
EDA_RECT bbox;
|
||||
VECTOR2I begin;
|
||||
|
@ -1108,7 +1109,7 @@ const EDA_RECT LIB_PIN::GetBoundingBox( bool aIncludeInvisibles, bool aPinOnly )
|
|||
if( showNum )
|
||||
{
|
||||
VECTOR2D fontSize( m_numTextSize, m_numTextSize );
|
||||
VECTOR2D numSize = font.ComputeStringBoundaryLimits( number, fontSize, GetPenWidth() );
|
||||
VECTOR2D numSize = font->StringBoundaryLimits( number, fontSize, GetPenWidth() );
|
||||
|
||||
numberTextLength = KiROUND( numSize.x );
|
||||
numberTextHeight = KiROUND( numSize.y );
|
||||
|
@ -1126,7 +1127,7 @@ const EDA_RECT LIB_PIN::GetBoundingBox( bool aIncludeInvisibles, bool aPinOnly )
|
|||
if( showName )
|
||||
{
|
||||
VECTOR2D fontSize( m_nameTextSize, m_nameTextSize );
|
||||
VECTOR2D nameSize = font.ComputeStringBoundaryLimits( name, fontSize, GetPenWidth() );
|
||||
VECTOR2D nameSize = font->StringBoundaryLimits( name, fontSize, GetPenWidth() );
|
||||
|
||||
nameTextLength = KiROUND( nameSize.x ) + nameTextOffset;
|
||||
nameTextHeight = KiROUND( nameSize.y ) + Mils2iu( PIN_TEXT_MARGIN );
|
||||
|
|
|
@ -62,6 +62,7 @@ extern bool operator<( const LIB_SYMBOL& aItem1, const LIB_SYMBOL& aItem2 );
|
|||
struct LIB_SYMBOL_OPTIONS
|
||||
{
|
||||
TRANSFORM transform; // Coordinate adjustment settings
|
||||
bool force_draw_pin_text; // Whether or not to force the drawing of pin names and numbers
|
||||
bool draw_visible_fields; // Whether to draw "visible" fields
|
||||
bool draw_hidden_fields; // Whether to draw "hidden" fields
|
||||
bool show_elec_type; // Whether to show the pin electrical type
|
||||
|
@ -71,6 +72,7 @@ struct LIB_SYMBOL_OPTIONS
|
|||
LIB_SYMBOL_OPTIONS()
|
||||
{
|
||||
transform = DefaultTransform;
|
||||
force_draw_pin_text = false;
|
||||
draw_visible_fields = true;
|
||||
draw_hidden_fields = true;
|
||||
show_elec_type = false;
|
||||
|
|
|
@ -435,32 +435,57 @@ static bool isFieldsLayer( int aLayer )
|
|||
}
|
||||
|
||||
|
||||
void SCH_PAINTER::strokeText( const wxString& aText, const VECTOR2D& aPosition, double aAngle )
|
||||
void SCH_PAINTER::strokeText( const wxString& aText, const VECTOR2D& aPosition,
|
||||
const TEXT_ATTRIBUTES& aAttrs )
|
||||
{
|
||||
m_gal->StrokeText( aText, VECTOR2D( aPosition.x, aPosition.y ), aAngle );
|
||||
KIFONT::FONT* font = aAttrs.m_Font;
|
||||
|
||||
if( !font )
|
||||
font = KIFONT::FONT::GetFont( wxEmptyString, aAttrs.m_Bold, aAttrs.m_Italic );
|
||||
|
||||
m_gal->SetIsFill( font->IsOutline() );
|
||||
m_gal->SetIsStroke( font->IsStroke() );
|
||||
|
||||
font->Draw( m_gal, aText, aPosition, aAttrs );
|
||||
}
|
||||
|
||||
|
||||
void SCH_PAINTER::boxText( const wxString& aText, const VECTOR2D& aPosition, double aAngle )
|
||||
void SCH_PAINTER::boxText( const wxString& aText, const VECTOR2D& aPosition,
|
||||
const TEXT_ATTRIBUTES& aAttrs )
|
||||
{
|
||||
const STROKE_FONT& font = m_gal->GetStrokeFont();
|
||||
VECTOR2D extents = font.ComputeStringBoundaryLimits( aText, m_gal->GetGlyphSize(),
|
||||
m_gal->GetLineWidth() );
|
||||
EDA_RECT box( (VECTOR2I) aPosition, wxSize( extents.x, extents.y ) );
|
||||
KIFONT::FONT* font = aAttrs.m_Font;
|
||||
|
||||
if( m_gal->GetHorizontalJustify() == GR_TEXT_H_ALIGN_CENTER )
|
||||
box.SetX( box.GetX() - ( box.GetWidth() / 2) );
|
||||
else if( m_gal->GetHorizontalJustify() == GR_TEXT_H_ALIGN_RIGHT )
|
||||
box.SetX( box.GetX() - box.GetWidth() );
|
||||
if( !font )
|
||||
font = KIFONT::FONT::GetFont( wxEmptyString, aAttrs.m_Bold, aAttrs.m_Italic );
|
||||
|
||||
if( m_gal->GetVerticalJustify() == GR_TEXT_V_ALIGN_CENTER )
|
||||
box.SetY( box.GetY() - ( box.GetHeight() / 2) );
|
||||
else if( m_gal->GetVerticalJustify() == GR_TEXT_V_ALIGN_BOTTOM )
|
||||
box.SetY( box.GetY() - box.GetHeight() );
|
||||
VECTOR2D extents = font->StringBoundaryLimits( aText, aAttrs.m_Size, aAttrs.m_StrokeWidth );
|
||||
EDA_RECT box( (VECTOR2I) aPosition, wxSize( extents.x, aAttrs.m_Size.y ) );
|
||||
|
||||
switch( aAttrs.m_Halign )
|
||||
{
|
||||
case GR_TEXT_H_ALIGN_LEFT: break;
|
||||
case GR_TEXT_H_ALIGN_CENTER: box.SetX( box.GetX() - box.GetWidth() / 2 ); break;
|
||||
case GR_TEXT_H_ALIGN_RIGHT: box.SetX( box.GetX() - box.GetWidth() ); break;
|
||||
}
|
||||
|
||||
switch( aAttrs.m_Valign )
|
||||
{
|
||||
case GR_TEXT_V_ALIGN_TOP: break;
|
||||
case GR_TEXT_V_ALIGN_CENTER: box.SetY( box.GetY() - box.GetHeight() / 2 ); break;
|
||||
case GR_TEXT_V_ALIGN_BOTTOM: box.SetY( box.GetY() - box.GetHeight() ); break;
|
||||
}
|
||||
|
||||
// Many fonts draw diacriticals, descenders, etc. outside the X-height of the font. This
|
||||
// will cacth most (but probably not all) of them.
|
||||
box.Inflate( 0, aAttrs.m_StrokeWidth * 1.5 );
|
||||
|
||||
box.Normalize(); // Make h and v sizes always >= 0
|
||||
box = box.GetBoundingBoxRotated((VECTOR2I) aPosition, RAD2DECIDEG( aAngle ) );
|
||||
box = box.GetBoundingBoxRotated( (VECTOR2I) aPosition, aAttrs.m_Angle.AsTenthsOfADegree() );
|
||||
box.RevertYAxis();
|
||||
|
||||
m_gal->SetIsFill( true );
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->SetLineWidth( getShadowWidth( false ) );
|
||||
m_gal->DrawRectangle( mapCoords( box.GetOrigin() ), mapCoords( box.GetEnd() ) );
|
||||
}
|
||||
|
||||
|
@ -678,10 +703,7 @@ void SCH_PAINTER::draw( const LIB_FIELD *aField, int aLayer )
|
|||
return;
|
||||
}
|
||||
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->SetLineWidth( getTextThickness( aField, drawingShadows ) );
|
||||
m_gal->SetStrokeColor( color );
|
||||
m_gal->SetIsFill( drawingShadows && eeconfig()->m_Selection.text_as_box );
|
||||
m_gal->SetFillColor( color );
|
||||
|
||||
EDA_RECT bbox = aField->GetBoundingBox();
|
||||
|
@ -690,18 +712,19 @@ void SCH_PAINTER::draw( const LIB_FIELD *aField, int aLayer )
|
|||
if( drawingShadows && eeconfig()->m_Selection.text_as_box )
|
||||
{
|
||||
bbox.RevertYAxis();
|
||||
m_gal->SetLineWidth( m_gal->GetLineWidth() / 2 );
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->SetIsFill( true );
|
||||
m_gal->SetLineWidth( getTextThickness( aField, drawingShadows ) );
|
||||
m_gal->DrawRectangle( mapCoords( bbox.GetPosition() ), mapCoords( bbox.GetEnd() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_CENTER );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_CENTER );
|
||||
m_gal->SetGlyphSize( VECTOR2D( aField->GetTextSize() ) );
|
||||
m_gal->SetFontItalic( aField->IsItalic() );
|
||||
TEXT_ATTRIBUTES attrs( aField->GetAttributes() );
|
||||
attrs.m_Halign = GR_TEXT_H_ALIGN_CENTER;
|
||||
attrs.m_Valign = GR_TEXT_V_ALIGN_CENTER;
|
||||
attrs.m_StrokeWidth = getTextThickness( aField, drawingShadows );
|
||||
|
||||
strokeText( UnescapeString( aField->GetText() ), textpos,
|
||||
aField->GetTextAngle().AsRadians() );
|
||||
strokeText( UnescapeString( aField->GetText() ), textpos, attrs );
|
||||
}
|
||||
|
||||
// Draw the umbilical line when in the schematic editor
|
||||
|
@ -737,19 +760,16 @@ void SCH_PAINTER::draw( const LIB_TEXT *aText, int aLayer )
|
|||
EDA_RECT bBox = aText->GetBoundingBox();
|
||||
bBox.RevertYAxis();
|
||||
VECTOR2D pos = mapCoords( bBox.Centre() );
|
||||
double orient = aText->GetTextAngle().AsRadians();
|
||||
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_CENTER );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_CENTER );
|
||||
m_gal->SetLineWidth( getTextThickness( aText, drawingShadows ) );
|
||||
m_gal->SetIsFill( false );
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->SetFillColor( color );
|
||||
m_gal->SetStrokeColor( color );
|
||||
m_gal->SetGlyphSize( VECTOR2D( aText->GetTextSize() ) );
|
||||
m_gal->SetFontBold( aText->IsBold() );
|
||||
m_gal->SetFontItalic( aText->IsItalic() );
|
||||
m_gal->SetFontUnderlined( false );
|
||||
strokeText( aText->GetText(), pos, orient );
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1039,7 +1059,7 @@ void SCH_PAINTER::draw( LIB_PIN *aPin, int aLayer )
|
|||
if( m_schSettings.m_ShowPinsElectricalType )
|
||||
{
|
||||
size [OUTSIDE] = std::max( aPin->GetNameTextSize() * 3 / 4, Millimeter2iu( 0.7 ) );
|
||||
thickness[OUTSIDE] = float( size[OUTSIDE] ) / 6.0F;
|
||||
thickness[OUTSIDE] = float( size[OUTSIDE] ) / 8.0F;
|
||||
colour [OUTSIDE] = getRenderColor( aPin, LAYER_NOTES, drawingShadows );
|
||||
text [OUTSIDE] = aPin->GetElectricalTypeName();
|
||||
}
|
||||
|
@ -1062,42 +1082,31 @@ void SCH_PAINTER::draw( LIB_PIN *aPin, int aLayer )
|
|||
{
|
||||
float shadowWidth = getShadowWidth( aPin->IsBrightened() );
|
||||
|
||||
if( eeconfig()->m_Selection.text_as_box )
|
||||
{
|
||||
insideOffset -= thickness[INSIDE] / 2.0;
|
||||
outsideOffset -= thickness[OUTSIDE] / 2.0;
|
||||
aboveOffset -= thickness[ABOVE] + penWidth;
|
||||
belowOffset -= thickness[BELOW] + penWidth;
|
||||
}
|
||||
|
||||
for( float& t : thickness )
|
||||
t += shadowWidth;
|
||||
|
||||
insideOffset -= shadowWidth / 2.0;
|
||||
outsideOffset -= shadowWidth / 2.0;
|
||||
}
|
||||
|
||||
auto setupDC =
|
||||
[&]( int i )
|
||||
{
|
||||
m_gal->SetGlyphSize( VECTOR2D( size[i], size[i] ) );
|
||||
m_gal->SetIsStroke( !( drawingShadows && eeconfig()->m_Selection.text_as_box ) );
|
||||
m_gal->SetLineWidth( thickness[i] );
|
||||
m_gal->SetStrokeColor( colour[i] );
|
||||
m_gal->SetIsFill( drawingShadows && eeconfig()->m_Selection.text_as_box );
|
||||
m_gal->SetFillColor( colour[i] );
|
||||
};
|
||||
|
||||
auto drawText =
|
||||
[&]( const wxString& aText, const VECTOR2D& aPos, double aAngle )
|
||||
[&]( int i, const VECTOR2D& aPos, GR_TEXT_H_ALIGN_T hAlign, GR_TEXT_V_ALIGN_T vAlign,
|
||||
const EDA_ANGLE& aAngle )
|
||||
{
|
||||
if( aText.IsEmpty() )
|
||||
if( text[i].IsEmpty() )
|
||||
return;
|
||||
|
||||
m_gal->SetStrokeColor( colour[i] );
|
||||
m_gal->SetFillColor( colour[i] );
|
||||
|
||||
TEXT_ATTRIBUTES attrs;
|
||||
attrs.m_Size = VECTOR2D( size[i], size[i] );
|
||||
attrs.m_Halign = hAlign;
|
||||
attrs.m_Valign = vAlign;
|
||||
attrs.m_Angle = aAngle;
|
||||
attrs.m_StrokeWidth = thickness[i];
|
||||
|
||||
if( drawingShadows && eeconfig()->m_Selection.text_as_box )
|
||||
boxText( aText, aPos, aAngle );
|
||||
boxText( text[i], aPos, attrs );
|
||||
else
|
||||
strokeText( aText, aPos, aAngle );
|
||||
strokeText( text[i], aPos, attrs );
|
||||
};
|
||||
|
||||
switch( orient )
|
||||
|
@ -1105,125 +1114,92 @@ void SCH_PAINTER::draw( LIB_PIN *aPin, int aLayer )
|
|||
case PIN_LEFT:
|
||||
if( size[INSIDE] )
|
||||
{
|
||||
setupDC( INSIDE );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_RIGHT );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_CENTER );
|
||||
drawText( text[INSIDE], pos + VECTOR2D( -insideOffset - len, 0 ), 0 );
|
||||
drawText( INSIDE, pos + VECTOR2D( -insideOffset - len, 0 ),
|
||||
GR_TEXT_H_ALIGN_RIGHT, GR_TEXT_V_ALIGN_CENTER, EDA_ANGLE::HORIZONTAL );
|
||||
}
|
||||
if( size[OUTSIDE] )
|
||||
{
|
||||
setupDC( OUTSIDE );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_LEFT );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_CENTER );
|
||||
drawText( text[OUTSIDE], pos + VECTOR2D( outsideOffset, 0 ), 0 );
|
||||
drawText( OUTSIDE, pos + VECTOR2D( outsideOffset, 0 ),
|
||||
GR_TEXT_H_ALIGN_LEFT, GR_TEXT_V_ALIGN_CENTER, EDA_ANGLE::HORIZONTAL );
|
||||
}
|
||||
if( size[ABOVE] )
|
||||
{
|
||||
setupDC( ABOVE );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_CENTER );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_BOTTOM );
|
||||
drawText( text[ABOVE], pos + VECTOR2D( -len / 2.0, -aboveOffset ), 0 );
|
||||
drawText( ABOVE, pos + VECTOR2D( -len / 2.0, -aboveOffset ),
|
||||
GR_TEXT_H_ALIGN_CENTER, GR_TEXT_V_ALIGN_BOTTOM, EDA_ANGLE::HORIZONTAL );
|
||||
}
|
||||
if( size[BELOW] )
|
||||
{
|
||||
setupDC( BELOW );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_CENTER );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_TOP );
|
||||
drawText( text[BELOW], pos + VECTOR2D( -len / 2.0, belowOffset ), 0 );
|
||||
drawText( BELOW, pos + VECTOR2D( -len / 2.0, belowOffset ),
|
||||
GR_TEXT_H_ALIGN_CENTER, GR_TEXT_V_ALIGN_TOP, EDA_ANGLE::HORIZONTAL );
|
||||
}
|
||||
break;
|
||||
|
||||
case PIN_RIGHT:
|
||||
if( size[INSIDE] )
|
||||
{
|
||||
setupDC( INSIDE );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_LEFT );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_CENTER );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_LEFT );
|
||||
drawText( text[INSIDE], pos + VECTOR2D( insideOffset + len, 0 ), 0 );
|
||||
drawText( INSIDE, pos + VECTOR2D( insideOffset + len, 0 ),
|
||||
GR_TEXT_H_ALIGN_LEFT, GR_TEXT_V_ALIGN_CENTER, EDA_ANGLE::HORIZONTAL );
|
||||
}
|
||||
if( size[OUTSIDE] )
|
||||
{
|
||||
setupDC( OUTSIDE );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_RIGHT );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_CENTER );
|
||||
drawText( text[OUTSIDE], pos + VECTOR2D( -outsideOffset, 0 ), 0 );
|
||||
drawText( OUTSIDE, pos + VECTOR2D( -outsideOffset, 0 ),
|
||||
GR_TEXT_H_ALIGN_RIGHT, GR_TEXT_V_ALIGN_CENTER, EDA_ANGLE::HORIZONTAL );
|
||||
}
|
||||
if( size[ABOVE] )
|
||||
{
|
||||
setupDC( ABOVE );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_CENTER );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_BOTTOM );
|
||||
drawText( text[ABOVE], pos + VECTOR2D( len / 2.0, -aboveOffset ), 0 );
|
||||
drawText( ABOVE, pos + VECTOR2D( len / 2.0, -aboveOffset ),
|
||||
GR_TEXT_H_ALIGN_CENTER, GR_TEXT_V_ALIGN_BOTTOM, EDA_ANGLE::HORIZONTAL );
|
||||
}
|
||||
if( size[BELOW] )
|
||||
{
|
||||
setupDC( BELOW );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_CENTER );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_TOP );
|
||||
drawText( text[BELOW], pos + VECTOR2D( len / 2.0, belowOffset ), 0 );
|
||||
drawText( BELOW, pos + VECTOR2D( len / 2.0, belowOffset ),
|
||||
GR_TEXT_H_ALIGN_CENTER, GR_TEXT_V_ALIGN_TOP, EDA_ANGLE::HORIZONTAL );
|
||||
}
|
||||
break;
|
||||
|
||||
case PIN_DOWN:
|
||||
if( size[INSIDE] )
|
||||
{
|
||||
setupDC( INSIDE );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_RIGHT );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_CENTER );
|
||||
drawText( text[INSIDE], pos + VECTOR2D( 0, insideOffset + len ), M_PI / 2 );
|
||||
drawText( INSIDE, pos + VECTOR2D( 0, insideOffset + len ),
|
||||
GR_TEXT_H_ALIGN_RIGHT, GR_TEXT_V_ALIGN_CENTER, EDA_ANGLE::VERTICAL );
|
||||
}
|
||||
if( size[OUTSIDE] )
|
||||
{
|
||||
setupDC( OUTSIDE );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_LEFT );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_CENTER );
|
||||
drawText( text[OUTSIDE], pos + VECTOR2D( 0, -outsideOffset ), M_PI / 2 );
|
||||
drawText( OUTSIDE, pos + VECTOR2D( 0, -outsideOffset ),
|
||||
GR_TEXT_H_ALIGN_LEFT, GR_TEXT_V_ALIGN_CENTER, EDA_ANGLE::VERTICAL );
|
||||
}
|
||||
if( size[ABOVE] )
|
||||
{
|
||||
setupDC( ABOVE );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_CENTER );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_BOTTOM );
|
||||
drawText( text[ABOVE], pos + VECTOR2D( -aboveOffset, len / 2.0 ), M_PI / 2 );
|
||||
drawText( ABOVE, pos + VECTOR2D( -aboveOffset, len / 2.0 ),
|
||||
GR_TEXT_H_ALIGN_CENTER, GR_TEXT_V_ALIGN_BOTTOM, EDA_ANGLE::VERTICAL );
|
||||
}
|
||||
if( size[BELOW] )
|
||||
{
|
||||
setupDC( BELOW );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_CENTER );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_TOP );
|
||||
drawText( text[BELOW], pos + VECTOR2D( belowOffset, len / 2.0 ), M_PI / 2 );
|
||||
drawText( BELOW, pos + VECTOR2D( belowOffset, len / 2.0 ),
|
||||
GR_TEXT_H_ALIGN_CENTER, GR_TEXT_V_ALIGN_TOP, EDA_ANGLE::VERTICAL );
|
||||
}
|
||||
break;
|
||||
|
||||
case PIN_UP:
|
||||
if( size[INSIDE] )
|
||||
{
|
||||
setupDC( INSIDE );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_LEFT );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_CENTER );
|
||||
drawText( text[INSIDE], pos + VECTOR2D( 0, -insideOffset - len ), M_PI / 2 );
|
||||
drawText( INSIDE, pos + VECTOR2D( 0, -insideOffset - len ),
|
||||
GR_TEXT_H_ALIGN_LEFT, GR_TEXT_V_ALIGN_CENTER, EDA_ANGLE::VERTICAL );
|
||||
}
|
||||
if( size[OUTSIDE] )
|
||||
{
|
||||
setupDC( OUTSIDE );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_RIGHT );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_CENTER );
|
||||
drawText( text[OUTSIDE], pos + VECTOR2D( 0, outsideOffset ), M_PI / 2 );
|
||||
drawText( OUTSIDE, pos + VECTOR2D( 0, outsideOffset ),
|
||||
GR_TEXT_H_ALIGN_RIGHT, GR_TEXT_V_ALIGN_CENTER, EDA_ANGLE::VERTICAL );
|
||||
}
|
||||
if( size[ABOVE] )
|
||||
{
|
||||
setupDC( ABOVE );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_CENTER );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_BOTTOM );
|
||||
drawText( text[ABOVE], pos + VECTOR2D( -aboveOffset, -len / 2.0 ), M_PI / 2 );
|
||||
drawText( ABOVE, pos + VECTOR2D( -aboveOffset, -len / 2.0 ),
|
||||
GR_TEXT_H_ALIGN_CENTER, GR_TEXT_V_ALIGN_BOTTOM, EDA_ANGLE::VERTICAL );
|
||||
}
|
||||
if( size[BELOW] )
|
||||
{
|
||||
setupDC( BELOW );
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_CENTER );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_TOP );
|
||||
drawText( text[BELOW], pos + VECTOR2D( belowOffset, -len / 2.0 ), M_PI / 2 );
|
||||
drawText( BELOW, pos + VECTOR2D( belowOffset, -len / 2.0 ),
|
||||
GR_TEXT_H_ALIGN_CENTER, GR_TEXT_V_ALIGN_TOP, EDA_ANGLE::VERTICAL );
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1485,42 +1461,31 @@ void SCH_PAINTER::draw( const SCH_TEXT *aText, int aLayer )
|
|||
return;
|
||||
}
|
||||
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->SetLineWidth( getTextThickness( aText, drawingShadows ) );
|
||||
m_gal->SetStrokeColor( color );
|
||||
m_gal->SetIsFill( drawingShadows && eeconfig()->m_Selection.text_as_box );
|
||||
m_gal->SetFillColor( color );
|
||||
|
||||
VECTOR2D text_offset = aText->GetTextPos() + aText->GetSchematicTextOffset( &m_schSettings );
|
||||
VECTOR2D textPos( aText->GetTextPos() );
|
||||
VECTOR2D text_offset = aText->GetSchematicTextOffset( &m_schSettings );
|
||||
wxString shownText( aText->GetShownText() );
|
||||
|
||||
if( drawingShadows )
|
||||
{
|
||||
if( eeconfig()->m_Selection.text_as_box )
|
||||
if( drawingShadows && eeconfig()->m_Selection.text_as_box )
|
||||
{
|
||||
EDA_RECT bBox = aText->GetBoundingBox();
|
||||
bBox.Offset( text_offset.x, text_offset.y );
|
||||
bBox.RevertYAxis();
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->SetIsFill( true );
|
||||
m_gal->SetLineWidth( getTextThickness( aText, drawingShadows ) );
|
||||
m_gal->DrawRectangle( mapCoords( bBox.GetPosition() ), mapCoords( bBox.GetEnd() ) );
|
||||
return;
|
||||
}
|
||||
|
||||
float shadowWidth = getShadowWidth( aText->IsBrightened() );
|
||||
|
||||
switch( aText->GetLabelSpinStyle() )
|
||||
{
|
||||
case LABEL_SPIN_STYLE::LEFT: text_offset.x += shadowWidth / 2.0; break;
|
||||
case LABEL_SPIN_STYLE::UP: text_offset.y += shadowWidth / 2.0; break;
|
||||
case LABEL_SPIN_STYLE::RIGHT: text_offset.x -= shadowWidth / 2.0; break;
|
||||
case LABEL_SPIN_STYLE::BOTTOM: text_offset.y -= shadowWidth / 2.0; break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !shownText.IsEmpty() )
|
||||
{
|
||||
m_gal->SetTextAttributes( aText );
|
||||
m_gal->SetFontUnderlined( false );
|
||||
TEXT_ATTRIBUTES attrs = aText->GetAttributes();
|
||||
attrs.m_StrokeWidth = getTextThickness( aText, drawingShadows );
|
||||
|
||||
strokeText( shownText, text_offset, aText->GetTextAngle().AsRadians() );
|
||||
strokeText( shownText, textPos + text_offset, attrs );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1708,30 +1673,26 @@ void SCH_PAINTER::draw( const SCH_FIELD *aField, int aLayer )
|
|||
|
||||
VECTOR2I textpos = bbox.Centre();
|
||||
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->SetLineWidth( getTextThickness( aField, drawingShadows ) );
|
||||
m_gal->SetStrokeColor( color );
|
||||
m_gal->SetIsFill( drawingShadows && eeconfig()->m_Selection.text_as_box );
|
||||
m_gal->SetFillColor( color );
|
||||
|
||||
if( drawingShadows && eeconfig()->m_Selection.text_as_box )
|
||||
{
|
||||
bbox.RevertYAxis();
|
||||
m_gal->SetLineWidth( m_gal->GetLineWidth() / 2 );
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->SetIsFill( true );
|
||||
m_gal->SetLineWidth( getTextThickness( aField, drawingShadows ) );
|
||||
m_gal->DrawRectangle( mapCoords( bbox.GetPosition() ), mapCoords( bbox.GetEnd() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_CENTER );
|
||||
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_CENTER );
|
||||
m_gal->SetIsFill( false );
|
||||
m_gal->SetGlyphSize( VECTOR2D( aField->GetTextSize() ) );
|
||||
m_gal->SetFontBold( aField->IsBold() );
|
||||
m_gal->SetFontItalic( aField->IsItalic() );
|
||||
m_gal->SetFontUnderlined( underline );
|
||||
m_gal->SetTextMirrored( aField->IsMirrored() );
|
||||
TEXT_ATTRIBUTES attributes = aField->GetAttributes();
|
||||
attributes.m_Halign = GR_TEXT_H_ALIGN_CENTER;
|
||||
attributes.m_Valign = GR_TEXT_V_ALIGN_CENTER;
|
||||
attributes.m_StrokeWidth = getTextThickness( aField, drawingShadows );
|
||||
attributes.m_Angle = orient;
|
||||
|
||||
strokeText( aField->GetShownText(), textpos, orient.AsRadians() );
|
||||
strokeText( aField->GetShownText(), textpos, attributes );
|
||||
}
|
||||
|
||||
// Draw the umbilical line
|
||||
|
|
|
@ -193,8 +193,10 @@ private:
|
|||
bool setDeviceColors( const LIB_ITEM* aItem, int aLayer );
|
||||
|
||||
void triLine ( const VECTOR2D &a, const VECTOR2D &b, const VECTOR2D &c );
|
||||
void strokeText( const wxString& aText, const VECTOR2D& aPosition, double aRotationAngle );
|
||||
void boxText( const wxString& aText, const VECTOR2D& aPosition, double aAngle );
|
||||
void strokeText( const wxString& aText, const VECTOR2D& aPosition,
|
||||
const TEXT_ATTRIBUTES& aAttributes );
|
||||
void boxText( const wxString& aText, const VECTOR2D& aPosition,
|
||||
const TEXT_ATTRIBUTES& aAttrs );
|
||||
|
||||
private:
|
||||
SCH_RENDER_SETTINGS m_schSettings;
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include <sch_edit_frame.h>
|
||||
#include <plotters/plotter.h>
|
||||
#include <widgets/msgpanel.h>
|
||||
#include <gal/stroke_font.h>
|
||||
#include <bitmaps.h>
|
||||
#include <string_utils.h>
|
||||
#include <sch_text.h>
|
||||
|
@ -1682,7 +1681,7 @@ void SCH_GLOBALLABEL::CreateGraphicShape( const RENDER_SETTINGS* aRenderSettings
|
|||
int margin = GetLabelBoxExpansion( aRenderSettings );
|
||||
int halfSize = ( GetTextHeight() / 2 ) + margin;
|
||||
int linewidth = GetPenWidth();
|
||||
int symb_len = LenSize( GetShownText(), linewidth ) + 2 * margin;
|
||||
int symb_len = GetTextBox().GetWidth() + 2 * margin;
|
||||
|
||||
int x = symb_len + linewidth + 3;
|
||||
int y = halfSize + linewidth + 3;
|
||||
|
@ -1812,8 +1811,9 @@ const EDA_RECT SCH_HIERLABEL::GetBodyBoundingBox() const
|
|||
int y = GetTextPos().y;
|
||||
|
||||
int height = GetTextHeight() + penWidth + margin;
|
||||
int length = LenSize( GetShownText(), penWidth )
|
||||
+ height; // add height for triangular shapes
|
||||
int length = GetTextBox().GetWidth();
|
||||
|
||||
length += height; // add height for triangular shapes
|
||||
|
||||
int dx, dy;
|
||||
|
||||
|
|
|
@ -26,10 +26,7 @@
|
|||
#define BASIC_GAL_H
|
||||
|
||||
#include <eda_rect.h>
|
||||
|
||||
#include <gal/stroke_font.h>
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <newstroke_font.h>
|
||||
|
||||
class PLOTTER;
|
||||
|
||||
|
@ -62,12 +59,12 @@ class BASIC_GAL: public KIGFX::GAL
|
|||
public:
|
||||
BASIC_GAL( KIGFX::GAL_DISPLAY_OPTIONS& aDisplayOptions ) :
|
||||
GAL( aDisplayOptions ),
|
||||
m_callback( nullptr ),
|
||||
m_DC( nullptr ),
|
||||
m_Color( RED ),
|
||||
m_transform(),
|
||||
m_clipBox(),
|
||||
m_isClipped( false ),
|
||||
m_callback( nullptr ),
|
||||
m_callbackData( nullptr ),
|
||||
m_plotter( nullptr )
|
||||
{
|
||||
|
@ -96,12 +93,12 @@ public:
|
|||
}
|
||||
|
||||
/// Save the context.
|
||||
virtual void Save() override
|
||||
void Save() override
|
||||
{
|
||||
m_transformHistory.push( m_transform );
|
||||
}
|
||||
|
||||
virtual void Restore() override
|
||||
void Restore() override
|
||||
{
|
||||
m_transform = m_transformHistory.top();
|
||||
m_transformHistory.pop();
|
||||
|
@ -112,9 +109,9 @@ public:
|
|||
*
|
||||
* @param aPointList is a list of 2D-Vectors containing the polyline points.
|
||||
*/
|
||||
virtual void DrawPolyline( const std::deque<VECTOR2D>& aPointList ) override;
|
||||
|
||||
virtual void DrawPolyline( const VECTOR2D aPointList[], int aListSize ) override;
|
||||
void DrawPolyline( const std::deque<VECTOR2D>& aPointList ) override;
|
||||
void DrawPolyline( const std::vector<VECTOR2D>& aPointList ) override;
|
||||
void DrawPolyline( const VECTOR2D aPointList[], int aListSize ) override;
|
||||
|
||||
/**
|
||||
* Start and end points are defined as 2D-Vectors.
|
||||
|
@ -122,14 +119,19 @@ public:
|
|||
* @param aStartPoint is the start point of the line.
|
||||
* @param aEndPoint is the end point of the line.
|
||||
*/
|
||||
virtual void DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) override;
|
||||
void DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) override;
|
||||
|
||||
/**
|
||||
* Draw a polygon representing an outline font glyph.
|
||||
*/
|
||||
void DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTotal ) override;
|
||||
|
||||
/**
|
||||
* Translate the context.
|
||||
*
|
||||
* @param aTranslation is the translation vector.
|
||||
*/
|
||||
virtual void Translate( const VECTOR2D& aTranslation ) override
|
||||
void Translate( const VECTOR2D& aTranslation ) override
|
||||
{
|
||||
m_transform.m_moveOffset += aTranslation;
|
||||
}
|
||||
|
@ -139,7 +141,7 @@ public:
|
|||
*
|
||||
* @param aAngle is the rotation angle in radians.
|
||||
*/
|
||||
virtual void Rotate( double aAngle ) override
|
||||
void Rotate( double aAngle ) override
|
||||
{
|
||||
m_transform.m_rotAngle = aAngle;
|
||||
m_transform.m_rotCenter = m_transform.m_moveOffset;
|
||||
|
@ -151,9 +153,13 @@ private:
|
|||
// Apply the rotation/translation transform to aPoint
|
||||
const VECTOR2D transform( const VECTOR2D& aPoint ) const;
|
||||
|
||||
// When calling the draw functions outside a wxDC, to get the basic drawings lines /
|
||||
// polylines ..., a callback function (used in DRC) to store coordinates of each segment:
|
||||
void (* m_callback)( int x0, int y0, int xf, int yf, void* aData );
|
||||
|
||||
public:
|
||||
wxDC* m_DC;
|
||||
COLOR4D m_Color;
|
||||
KIGFX::COLOR4D m_Color;
|
||||
|
||||
private:
|
||||
TRANSFORM_PRM m_transform;
|
||||
|
@ -163,14 +169,10 @@ private:
|
|||
EDA_RECT m_clipBox; // The clip box
|
||||
bool m_isClipped; // Allows/disallows clipping
|
||||
|
||||
// When calling the draw functions outside a wxDC, to get the basic drawings
|
||||
// lines / polylines ..., a callback function (used in DRC) to store
|
||||
// coordinates of each segment:
|
||||
void (* m_callback)( int x0, int y0, int xf, int yf, void* aData );
|
||||
void* m_callbackData; // a optional parameter for m_callback
|
||||
|
||||
// When calling the draw functions for plot, the plotter acts as a wxDC to plot basic items.
|
||||
PLOTTER* m_plotter;
|
||||
PLOTTER* m_plotter; // When calling the draw functions for plot, the
|
||||
// plotter acts as a wxDC to plot basic items.
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -193,6 +193,8 @@ public:
|
|||
|
||||
void CopyText( const EDA_TEXT& aSrc );
|
||||
|
||||
const TEXT_ATTRIBUTES& GetAttributes() const { return m_attributes; }
|
||||
|
||||
/**
|
||||
* Helper function used in search and replace dialog.
|
||||
*
|
||||
|
@ -292,14 +294,6 @@ public:
|
|||
*/
|
||||
virtual bool TextHitTest( const EDA_RECT& aRect, bool aContains, int aAccuracy = 0 ) const;
|
||||
|
||||
/**
|
||||
* @return the text length in internal units.
|
||||
* @param aLine the line of text to consider. For single line text, this parameter
|
||||
* is always m_Text.
|
||||
* @param aThickness the stroke width of the text.
|
||||
*/
|
||||
int LenSize( const wxString& aLine, int aThickness ) const;
|
||||
|
||||
/**
|
||||
* Useful in multiline texts to calculate the full text or a line area (for zones filling,
|
||||
* locate functions....)
|
||||
|
|
|
@ -33,7 +33,9 @@
|
|||
#include <wx/string.h>
|
||||
|
||||
#include <utf8.h>
|
||||
#include <font/glyph.h>
|
||||
#include <font/text_attributes.h>
|
||||
#include <markup_parser.h>
|
||||
|
||||
namespace KIGFX
|
||||
{
|
||||
|
@ -105,17 +107,186 @@ public:
|
|||
virtual bool IsBold() const { return false; }
|
||||
virtual bool IsItalic() const { return false; }
|
||||
|
||||
static FONT* GetFont( const wxString& aFontName = "", bool aBold = false,
|
||||
bool aItalic = false );
|
||||
static bool IsStroke( const wxString& aFontName );
|
||||
|
||||
const wxString& Name() const;
|
||||
inline const char* NameAsToken() const { return Name().utf8_str().data(); }
|
||||
|
||||
/**
|
||||
* Draw a string.
|
||||
*
|
||||
* @param aGal is the graphics context.
|
||||
* @param aText is the text to be drawn.
|
||||
* @param aPosition is the text position in world coordinates.
|
||||
* @param aRotationAngle is the text rotation angle
|
||||
* @return bounding box
|
||||
*/
|
||||
VECTOR2D Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2D& aPosition,
|
||||
const VECTOR2D& aOrigin, const TEXT_ATTRIBUTES& aAttrs ) const;
|
||||
|
||||
VECTOR2D Draw( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2D& aPosition,
|
||||
const TEXT_ATTRIBUTES& aAttributes ) const
|
||||
{
|
||||
return Draw( aGal, aText, aPosition, VECTOR2D( 0, 0 ), aAttributes );
|
||||
}
|
||||
|
||||
virtual void DrawText( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2D& aPosition,
|
||||
const TEXT_ATTRIBUTES& aAttributes ) const;
|
||||
|
||||
/**
|
||||
* Draw a string.
|
||||
*
|
||||
* @param aGal is the graphics context
|
||||
* @param aText is the text string
|
||||
* @param aPosition is the text position in world coordinates
|
||||
* @param aParse is true is aText should first be parsed for variable substition etc.,
|
||||
* otherwise false (default is false)
|
||||
* @return bounding box
|
||||
*/
|
||||
VECTOR2D DrawString( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2D& aPosition,
|
||||
bool aParse, const TEXT_ATTRIBUTES& aAttributes ) const
|
||||
{
|
||||
return doDrawString( aGal, aText, aPosition, aParse, aAttributes );
|
||||
}
|
||||
|
||||
VECTOR2D DrawString( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2D& aPosition,
|
||||
bool aParse, const EDA_ANGLE& aAngle ) const
|
||||
{
|
||||
TEXT_ATTRIBUTES attributes;
|
||||
attributes.m_Angle = aAngle;
|
||||
return doDrawString( aGal, aText, aPosition, aParse, attributes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the boundary limits of aText (the bounding box of all shapes).
|
||||
*
|
||||
* @return a VECTOR2D giving the width and height of text.
|
||||
*/
|
||||
virtual VECTOR2D StringBoundaryLimits( const KIGFX::GAL* aGal, const UTF8& aText,
|
||||
const VECTOR2D& aGlyphSize,
|
||||
double aGlyphThickness ) const = 0;
|
||||
|
||||
VECTOR2D StringBoundaryLimits( const UTF8& aText, const VECTOR2D& aGlyphSize,
|
||||
double aGlyphThickness ) const
|
||||
{
|
||||
return StringBoundaryLimits( nullptr, aText, aGlyphSize, aGlyphThickness );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the vertical position of an overbar. This is the distance between the text
|
||||
* baseline and the overbar.
|
||||
*/
|
||||
virtual double ComputeOverbarVerticalPosition( double aGlyphHeight ) const = 0;
|
||||
|
||||
/**
|
||||
* Compute the distance (interline) between 2 lines of text (for multiline texts). This is
|
||||
* the distance between baselines, not the space between line bounding boxes.
|
||||
*/
|
||||
virtual double GetInterline( double aGlyphHeight, double aLineSpacing = 1.0 ) const = 0;
|
||||
|
||||
/**
|
||||
* Compute the X and Y size of a given text. The text is expected to be a single line.
|
||||
*/
|
||||
virtual VECTOR2D ComputeTextLineSize( const KIGFX::GAL* aGal, const UTF8& aText ) const = 0;
|
||||
|
||||
/**
|
||||
* Convert text string to polygon (outline font) or polyline (stroke font).
|
||||
*
|
||||
* @param aBoundingBox pointer to a BOX2I that will set to the bounding box, or nullptr
|
||||
* @param aText text to convert to polygon/polyline
|
||||
* @param aGlyphSize glyph size
|
||||
* @param aPosition position of text (cursor position before this text)
|
||||
* @param aAngle text angle
|
||||
* @param aTextStyle text style flags
|
||||
* @return text cursor position after this text
|
||||
*/
|
||||
virtual VECTOR2I GetTextAsPolygon( BOX2I* aBoundingBox, GLYPH_LIST& aGlyphs,
|
||||
const UTF8& aText, const VECTOR2D& aGlyphSize,
|
||||
const wxPoint& aPosition, const EDA_ANGLE& aAngle,
|
||||
TEXT_STYLE_FLAGS aTextStyle ) const = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Returns number of lines for a given text.
|
||||
*
|
||||
* @param aText is the text to be checked.
|
||||
* @return unsigned - The number of lines in aText.
|
||||
*/
|
||||
inline unsigned linesCount( const UTF8& aText ) const
|
||||
{
|
||||
if( aText.empty() )
|
||||
return 0; // std::count does not work well with empty strings
|
||||
else
|
||||
// aText.end() - 1 is to skip a newline character that is potentially at the end
|
||||
return std::count( aText.begin(), aText.end() - 1, '\n' ) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a single line of text. Multiline texts should be split before using the
|
||||
* function.
|
||||
*
|
||||
* @param aGal is a pointer to the graphics abstraction layer, or nullptr (nothing is drawn)
|
||||
* @param aBoundingBox is a pointer to a BOX2I variable which will be set to the bounding box,
|
||||
* or nullptr
|
||||
* @param aText is the text to be drawn.
|
||||
* @param aPosition is text position.
|
||||
* @param aAngle is text angle.
|
||||
* @param aIsMirrored is true if text should be drawn mirrored, false otherwise.
|
||||
* @return new cursor position
|
||||
*/
|
||||
VECTOR2D drawSingleLineText( KIGFX::GAL* aGal, BOX2I* aBoundingBox, const UTF8& aText,
|
||||
const VECTOR2D& aPosition, const VECTOR2D& aGlyphSize,
|
||||
const EDA_ANGLE& aAngle, bool aIsItalic, bool aIsMirrored ) const;
|
||||
|
||||
/**
|
||||
* Computes the bounding box for a single line of text.
|
||||
* Multiline texts should be split before using the function.
|
||||
*
|
||||
* @param aBoundingBox is a pointer to a BOX2I variable which will be set to the bounding box,
|
||||
* or nullptr
|
||||
* @param aText is the text to be drawn.
|
||||
* @param aPosition is text position.
|
||||
* @param aGlyphSize is glyph size.
|
||||
* @param aAngle is text angle.
|
||||
* @return new cursor position
|
||||
*/
|
||||
VECTOR2D boundingBoxSingleLine( BOX2I* aBoundingBox, const UTF8& aText,
|
||||
const VECTOR2D& aPosition, const VECTOR2D& aGlyphSize,
|
||||
const EDA_ANGLE& aAngle, bool aIsItalic ) const;
|
||||
|
||||
void getLinePositions( const UTF8& aText, const VECTOR2D& aPosition, wxArrayString& aStringList,
|
||||
std::vector<wxPoint>& aPositions, int& aLineCount,
|
||||
std::vector<VECTOR2D>& aBoundingBoxes,
|
||||
const TEXT_ATTRIBUTES& aAttributes ) const;
|
||||
|
||||
virtual VECTOR2D getBoundingBox( const UTF8& aString, const VECTOR2D& aGlyphSize,
|
||||
TEXT_STYLE_FLAGS aTextStyle = 0 ) const = 0;
|
||||
|
||||
VECTOR2D drawMarkup( BOX2I* aBoundingBox, GLYPH_LIST& aGlyphs,
|
||||
const std::unique_ptr<MARKUP::NODE>& aNode, const VECTOR2D& aPosition,
|
||||
const VECTOR2D& aGlyphSize, const EDA_ANGLE& aAngle,
|
||||
TEXT_STYLE_FLAGS aTextStyle, int aLevel = 0 ) const;
|
||||
|
||||
private:
|
||||
static FONT* getDefaultFont();
|
||||
|
||||
VECTOR2D doDrawString( KIGFX::GAL* aGal, const UTF8& aText, const VECTOR2D& aPosition,
|
||||
bool aParse, const TEXT_ATTRIBUTES& aAttrs ) const;
|
||||
VECTOR2D getBoundingBox( const UTF8& aText, TEXT_STYLE_FLAGS aTextStyle,
|
||||
const TEXT_ATTRIBUTES& aAttrs ) const;
|
||||
|
||||
protected:
|
||||
wxString m_fontName; ///< Font name
|
||||
wxString m_fontFileName; ///< Font file name
|
||||
|
||||
private:
|
||||
static FONT* s_defaultFont;
|
||||
static std::map<wxString, FONT*> s_fontMap;
|
||||
|
||||
static std::map< std::tuple<wxString, bool, bool>, FONT* > s_fontMap;
|
||||
};
|
||||
|
||||
} //namespace KIFONT
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* 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 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
|
||||
*/
|
||||
|
||||
#ifndef GLYPH_H
|
||||
#define GLYPH_H
|
||||
|
||||
#include <memory>
|
||||
#include <math/box2.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <wx/debug.h>
|
||||
|
||||
namespace KIFONT
|
||||
{
|
||||
class GLYPH
|
||||
{
|
||||
public:
|
||||
virtual ~GLYPH()
|
||||
{}
|
||||
|
||||
virtual void AddPoint( const VECTOR2D& aPoint ) = 0;
|
||||
|
||||
virtual void RaisePen() = 0;
|
||||
|
||||
virtual void Finalize() = 0;
|
||||
|
||||
virtual BOX2D BoundingBox() = 0;
|
||||
|
||||
virtual std::shared_ptr<GLYPH> Resize( const VECTOR2D& aGlyphSize ) const = 0;
|
||||
|
||||
virtual std::shared_ptr<GLYPH> Translate( const VECTOR2D& aOffset ) const = 0;
|
||||
|
||||
virtual std::shared_ptr<GLYPH> Mirror( bool aMirror,
|
||||
const VECTOR2D& aMirrorOrigin = { 0, 0 } ) const = 0;
|
||||
|
||||
virtual void Mirror( const VECTOR2D& aMirrorOrigin = { 0, 0 } ) = 0;
|
||||
|
||||
virtual const SHAPE_POLY_SET& GetPolylist() const = 0;
|
||||
|
||||
virtual const std::vector<std::vector<VECTOR2D>>& GetPoints() const = 0;
|
||||
|
||||
virtual bool IsOutline() const { return false; }
|
||||
virtual bool IsStroke() const { return false; }
|
||||
};
|
||||
|
||||
typedef std::vector<std::shared_ptr<GLYPH>> GLYPH_LIST;
|
||||
|
||||
|
||||
class OUTLINE_GLYPH : public GLYPH
|
||||
{
|
||||
public:
|
||||
OUTLINE_GLYPH( const SHAPE_POLY_SET& poly )
|
||||
{
|
||||
m_polySet = poly;
|
||||
}
|
||||
|
||||
const SHAPE_POLY_SET& GetPolylist() const override { return m_polySet; }
|
||||
|
||||
bool IsOutline() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
void AddPoint( const VECTOR2D& aPoint ) override
|
||||
{
|
||||
wxFAIL_MSG( "unimplemented" );
|
||||
}
|
||||
|
||||
void RaisePen() override
|
||||
{
|
||||
wxFAIL_MSG( "unimplemented" );
|
||||
}
|
||||
|
||||
void Finalize() override
|
||||
{
|
||||
wxFAIL_MSG( "unimplemented" );
|
||||
}
|
||||
|
||||
BOX2D BoundingBox() override
|
||||
{
|
||||
wxFAIL_MSG( "unimplemented" );
|
||||
return BOX2D();
|
||||
}
|
||||
|
||||
std::shared_ptr<GLYPH> Resize( const VECTOR2D& aGlyphSize ) const override
|
||||
{
|
||||
wxFAIL_MSG( "unimplemented" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<GLYPH> Translate( const VECTOR2D& aOffset ) const override
|
||||
{
|
||||
wxFAIL_MSG( "unimplemented" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<GLYPH> Mirror( bool aMirror,
|
||||
const VECTOR2D& aMirrorOrigin = { 0, 0 } ) const override
|
||||
{
|
||||
wxFAIL_MSG( "unimplemented" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Mirror( const VECTOR2D& aMirrorOrigin = VECTOR2D( 0, 0 ) ) override
|
||||
{
|
||||
wxFAIL_MSG( "unimplemented" );
|
||||
}
|
||||
|
||||
const std::vector<std::vector<VECTOR2D>>& GetPoints() const override
|
||||
{
|
||||
wxFAIL_MSG( "unimplemented" );
|
||||
return m_dummy;
|
||||
}
|
||||
|
||||
private:
|
||||
SHAPE_POLY_SET m_polySet;
|
||||
|
||||
// For unimplemented return values
|
||||
std::vector<std::vector<VECTOR2D>> m_dummy;
|
||||
};
|
||||
|
||||
|
||||
class STROKE_GLYPH : public GLYPH
|
||||
{
|
||||
public:
|
||||
STROKE_GLYPH()
|
||||
{}
|
||||
|
||||
STROKE_GLYPH( const STROKE_GLYPH& aGlyph );
|
||||
|
||||
void AddPoint( const VECTOR2D& aPoint ) override;
|
||||
|
||||
void RaisePen() override;
|
||||
|
||||
void Finalize() override;
|
||||
|
||||
BOX2D BoundingBox() override;
|
||||
|
||||
std::shared_ptr<GLYPH> Resize( const VECTOR2D& aGlyphSize ) const override;
|
||||
|
||||
std::shared_ptr<GLYPH> Translate( const VECTOR2D& aOffset ) const override;
|
||||
|
||||
std::shared_ptr<GLYPH> Transform( const VECTOR2D& aGlyphSize, const VECTOR2D& aOffset,
|
||||
double aTilt );
|
||||
|
||||
std::shared_ptr<GLYPH> Mirror( bool aMirror,
|
||||
const VECTOR2D& aMirrorOrigin = { 0, 0 } ) const override;
|
||||
|
||||
void Mirror( const VECTOR2D& aMirrorOrigin = { 0, 0 } ) override;
|
||||
|
||||
bool IsStroke() const override { return true; }
|
||||
|
||||
//
|
||||
const SHAPE_POLY_SET& GetPolylist() const override
|
||||
{
|
||||
wxFAIL_MSG( "unimplemented" );
|
||||
return m_dummy;
|
||||
}
|
||||
|
||||
const std::vector<std::vector<VECTOR2D>>& GetPoints() const override { return m_pointLists; }
|
||||
|
||||
private:
|
||||
void clearBoundingBox()
|
||||
{
|
||||
m_boundingBox.SetOrigin( 0, 0 );
|
||||
m_boundingBox.SetSize( 0, 0 );
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_penIsDown = false;
|
||||
std::vector<std::vector<VECTOR2D>> m_pointLists;
|
||||
BOX2D m_boundingBox;
|
||||
|
||||
// For unimplemented return values
|
||||
SHAPE_POLY_SET m_dummy;
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<VECTOR2D> GLYPH_POINTS;
|
||||
typedef std::vector<GLYPH_POINTS> GLYPH_POINTS_LIST;
|
||||
typedef std::vector<BOX2D> GLYPH_BOUNDING_BOX_LIST;
|
||||
|
||||
|
||||
} // namespace KIFONT
|
||||
|
||||
#endif // GLYPH_H
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
|
||||
* Copyright (C) 2013 CERN
|
||||
* Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
* Stroke font class
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef STROKE_FONT_H
|
||||
#define STROKE_FONT_H
|
||||
|
||||
#include <map>
|
||||
#include <deque>
|
||||
#include <algorithm>
|
||||
#include <utf8.h>
|
||||
#include <math/box2.h>
|
||||
#include <font/font.h>
|
||||
|
||||
namespace KIGFX
|
||||
{
|
||||
class GAL;
|
||||
}
|
||||
|
||||
namespace KIFONT
|
||||
{
|
||||
/**
|
||||
* Implement a stroke font drawing.
|
||||
*
|
||||
* A stroke font is composed of lines.
|
||||
*/
|
||||
class STROKE_FONT : public FONT
|
||||
{
|
||||
public:
|
||||
STROKE_FONT();
|
||||
|
||||
bool IsStroke() const override { return true; }
|
||||
|
||||
/**
|
||||
* Load a stroke font.
|
||||
*
|
||||
* @param aFontName is the name of the font. If empty, the standard KiCad stroke font is
|
||||
* loaded.
|
||||
*/
|
||||
static STROKE_FONT* LoadFont( const wxString& aFontName );
|
||||
|
||||
/**
|
||||
* Compute the boundary limits of aText (the bounding box of all shapes).
|
||||
*
|
||||
* @return a VECTOR2D giving the width and height of text.
|
||||
*/
|
||||
VECTOR2D StringBoundaryLimits( const KIGFX::GAL* aGal, const UTF8& aText,
|
||||
const VECTOR2D& aGlyphSize,
|
||||
double aGlyphThickness ) const override;
|
||||
|
||||
/**
|
||||
* Compute the vertical position of an overbar. This is the distance between the text
|
||||
* baseline and the overbar.
|
||||
*/
|
||||
double ComputeOverbarVerticalPosition( double aGlyphHeight ) const override;
|
||||
|
||||
/**
|
||||
* Compute the distance (interline) between 2 lines of text (for multiline texts). This is
|
||||
* the distance between baselines, not the space between line bounding boxes.
|
||||
*/
|
||||
double GetInterline( double aGlyphHeight, double aLineSpacing = 1.0 ) const override;
|
||||
|
||||
/**
|
||||
* Compute the X and Y size of a given text. The text is expected to be a single line.
|
||||
*/
|
||||
VECTOR2D ComputeTextLineSize( const KIGFX::GAL* aGal, const UTF8& aText ) const override;
|
||||
|
||||
VECTOR2I GetTextAsPolygon( BOX2I* aBoundingBox, GLYPH_LIST& aGlyphs, const UTF8& aText,
|
||||
const VECTOR2D& aGlyphSize, const wxPoint& aPosition,
|
||||
const EDA_ANGLE& aAngle, TEXT_STYLE_FLAGS aTextStyle ) const override;
|
||||
|
||||
protected:
|
||||
VECTOR2D getBoundingBox( const UTF8& aString, const VECTOR2D& aGlyphSize,
|
||||
TEXT_STYLE_FLAGS aTextStyle ) const override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Load the standard KiCad stroke font.
|
||||
*
|
||||
* @param aNewStrokeFont is the pointer to the font data.
|
||||
* @param aNewStrokeFontSize is the size of the font data.
|
||||
*/
|
||||
void loadNewStrokeFont( const char* const aNewStrokeFont[], int aNewStrokeFontSize );
|
||||
|
||||
private:
|
||||
const GLYPH_LIST* m_glyphs; ///< Glyph list
|
||||
const GLYPH_BOUNDING_BOX_LIST* m_glyphBoundingBoxes; ///< Bounding boxes of the glyphs
|
||||
double m_maxGlyphWidth;
|
||||
};
|
||||
|
||||
} //namespace KIFONT
|
||||
|
||||
#endif // STROKE_FONT_H
|
|
@ -109,6 +109,9 @@ public:
|
|||
void DrawPolygon( const SHAPE_POLY_SET& aPolySet, bool aStrokeTriangulation = false ) override;
|
||||
void DrawPolygon( const SHAPE_LINE_CHAIN& aPolySet ) override;
|
||||
|
||||
/// @copydoc GAL::DrawGlyph()
|
||||
void DrawGlyph( const KIFONT::GLYPH& aPolySet, int aNth, int aTotal ) override;
|
||||
|
||||
/// @copydoc GAL::DrawCurve()
|
||||
void DrawCurve( const VECTOR2D& startPoint, const VECTOR2D& controlPointA,
|
||||
const VECTOR2D& controlPointB, const VECTOR2D& endPoint,
|
||||
|
@ -272,6 +275,7 @@ protected:
|
|||
|
||||
/// Drawing polygons & polylines is the same in Cairo, so here is the common code
|
||||
void drawPoly( const std::deque<VECTOR2D>& aPointList );
|
||||
void drawPoly( const std::vector<VECTOR2D>& aPointList );
|
||||
void drawPoly( const VECTOR2D aPointList[], int aListSize );
|
||||
void drawPoly( const SHAPE_LINE_CHAIN& aLineChain );
|
||||
|
||||
|
|
|
@ -36,9 +36,9 @@
|
|||
#include <gal/color4d.h>
|
||||
#include <gal/cursors.h>
|
||||
#include <gal/definitions.h>
|
||||
#include <gal/stroke_font.h>
|
||||
#include <gal/gal_display_options.h>
|
||||
#include <newstroke_font.h>
|
||||
#include <font/stroke_font.h>
|
||||
#include <eda_rect.h>
|
||||
|
||||
class SHAPE_LINE_CHAIN;
|
||||
|
@ -171,6 +171,18 @@ public:
|
|||
DrawRectangle( aRect.GetOrigin(), aRect.GetEnd() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a polygon representing an outline font glyph.
|
||||
*/
|
||||
virtual void DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth = 0, int aTotal = 1 ) {};
|
||||
|
||||
void DrawGlyph( const std::shared_ptr<KIFONT::GLYPH>& aGlyph, int aNth = 0, int aTotal = 1 )
|
||||
{
|
||||
DrawGlyph( *aGlyph, aNth, aTotal );
|
||||
}
|
||||
|
||||
void DrawGlyphs( const KIFONT::GLYPH_LIST& aGlyphs );
|
||||
|
||||
/**
|
||||
* Draw a polygon.
|
||||
*
|
||||
|
@ -338,23 +350,18 @@ public:
|
|||
// Text
|
||||
// ----
|
||||
|
||||
const STROKE_FONT& GetStrokeFont() const
|
||||
{
|
||||
return m_strokeFont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a vector type text using preloaded Newstroke font.
|
||||
*
|
||||
* @param aText is the text to be drawn.
|
||||
* @param aPosition is the text position in world coordinates.
|
||||
* @param aRotationAngle is the text rotation angle.
|
||||
* @param aFont is the text font, or nullptr (defaults to newstroke)
|
||||
* @param aLineSpacing is the line spacing for multiline text (defaults to 1.0)
|
||||
*/
|
||||
virtual void StrokeText( const wxString& aText, const VECTOR2D& aPosition,
|
||||
double aRotationAngle )
|
||||
{
|
||||
m_strokeFont.Draw( aText, aPosition, aRotationAngle );
|
||||
}
|
||||
double aRotationAngle, KIFONT::FONT* aFont = nullptr,
|
||||
double aLineSpacing = 1.0 );
|
||||
|
||||
/**
|
||||
* Draw a text using a bitmap font. It should be faster than StrokeText(), but can be used
|
||||
|
@ -365,51 +372,18 @@ public:
|
|||
* @param aRotationAngle is the text rotation angle.
|
||||
*/
|
||||
virtual void BitmapText( const wxString& aText, const VECTOR2D& aPosition,
|
||||
double aRotationAngle )
|
||||
{
|
||||
// Fallback for implementations that don't implement bitmap text: use stroke font
|
||||
|
||||
// Handle flipped view
|
||||
if( m_globalFlipX )
|
||||
m_attributes.m_Mirrored = !m_attributes.m_Mirrored;
|
||||
|
||||
// Bitmap font is slightly smaller and slightly heavier than the stroke font so we
|
||||
// compensate a bit before stroking
|
||||
float saveLineWidth = m_lineWidth;
|
||||
VECTOR2D saveGlyphSize = m_attributes.m_Size;
|
||||
{
|
||||
m_lineWidth *= 1.2f;
|
||||
m_attributes.m_Size = m_attributes.m_Size * 0.8;
|
||||
|
||||
StrokeText( aText, aPosition, aRotationAngle );
|
||||
}
|
||||
m_lineWidth = saveLineWidth;
|
||||
m_attributes.m_Size = saveGlyphSize;
|
||||
|
||||
if( m_globalFlipX )
|
||||
m_attributes.m_Mirrored = !m_attributes.m_Mirrored;
|
||||
}
|
||||
double aRotationAngle );
|
||||
|
||||
/**
|
||||
* Compute the X and Y size of a given text. The text is expected to be a only one line text.
|
||||
*
|
||||
* @param aText is the text string (one line).
|
||||
* @return is the text size.
|
||||
* Loads attributes of the text (bold/italic/underline/mirrored and so on).
|
||||
*/
|
||||
VECTOR2D GetTextLineSize( const UTF8& aText ) const;
|
||||
|
||||
/**
|
||||
* Loads attributes of the given text (bold/italic/underline/mirrored and so on).
|
||||
*
|
||||
* @param aText is the text item.
|
||||
*/
|
||||
virtual void SetTextAttributes( const EDA_TEXT* aText );
|
||||
virtual void SetTextAttributes( const TEXT_ATTRIBUTES& aAttributes );
|
||||
|
||||
/**
|
||||
* Reset text attributes to default styling.
|
||||
*
|
||||
* Normally, custom attributes will be set individually after this,
|
||||
* otherwise you can use SetTextAttributes()
|
||||
* Normally, custom attributes will be set individually after this, otherwise you can use
|
||||
* SetTextAttributes()
|
||||
*/
|
||||
void ResetTextAttributes();
|
||||
|
||||
|
@ -1083,9 +1057,6 @@ protected:
|
|||
bool m_fullscreenCursor; ///< Shape of the cursor (fullscreen or small cross)
|
||||
VECTOR2D m_cursorPosition; ///< Current cursor position (world coordinates)
|
||||
|
||||
STROKE_FONT m_strokeFont; ///< Instance of object that stores information
|
||||
///< about how to draw texts
|
||||
|
||||
KICURSOR m_currentNativeCursor; ///< Current cursor
|
||||
|
||||
private:
|
||||
|
|
|
@ -140,6 +140,7 @@ public:
|
|||
|
||||
/// @copydoc GAL::DrawPolyline()
|
||||
void DrawPolyline( const std::deque<VECTOR2D>& aPointList ) override;
|
||||
void DrawPolyline( const std::vector<VECTOR2D>& aPointList ) override;
|
||||
void DrawPolyline( const VECTOR2D aPointList[], int aListSize ) override;
|
||||
void DrawPolyline( const SHAPE_LINE_CHAIN& aLineChain ) override;
|
||||
|
||||
|
@ -149,6 +150,9 @@ public:
|
|||
void DrawPolygon( const SHAPE_POLY_SET& aPolySet, bool aStrokeTriangulation = false ) override;
|
||||
void DrawPolygon( const SHAPE_LINE_CHAIN& aPolySet ) override;
|
||||
|
||||
/// @copydoc GAL::DrawGlyph()
|
||||
virtual void DrawGlyph( const KIFONT::GLYPH& aGlyph, int aNth, int aTotal ) override;
|
||||
|
||||
/// @copydoc GAL::DrawCurve()
|
||||
void DrawCurve( const VECTOR2D& startPoint, const VECTOR2D& controlPointA,
|
||||
const VECTOR2D& controlPointB, const VECTOR2D& endPoint,
|
||||
|
|
|
@ -1,191 +0,0 @@
|
|||
/*
|
||||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
|
||||
* Copyright (C) 2013 CERN
|
||||
* Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
* Stroke font class
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef STROKE_FONT_H_
|
||||
#define STROKE_FONT_H_
|
||||
|
||||
#include <deque>
|
||||
#include <algorithm>
|
||||
|
||||
#include <utf8.h>
|
||||
|
||||
#include <eda_text.h>
|
||||
|
||||
#include <math/box2.h>
|
||||
|
||||
namespace KIGFX
|
||||
{
|
||||
class GAL;
|
||||
|
||||
typedef std::vector<std::vector<VECTOR2D>*> GLYPH;
|
||||
typedef std::vector<GLYPH*> GLYPH_LIST;
|
||||
|
||||
/**
|
||||
* Implement a stroke font drawing.
|
||||
*
|
||||
* A stroke font is composed of lines.
|
||||
*/
|
||||
class STROKE_FONT
|
||||
{
|
||||
friend class GAL;
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
STROKE_FONT( GAL* aGal );
|
||||
|
||||
/**
|
||||
* Load the new stroke font.
|
||||
*
|
||||
* @param aNewStrokeFont is the pointer to the font data.
|
||||
* @param aNewStrokeFontSize is the size of the font data.
|
||||
* @return True, if the font was successfully loaded, else false.
|
||||
*/
|
||||
bool LoadNewStrokeFont( const char* const aNewStrokeFont[], int aNewStrokeFontSize );
|
||||
|
||||
/**
|
||||
* Draw a string.
|
||||
*
|
||||
* @param aText is the text to be drawn.
|
||||
* @param aPosition is the text position in world coordinates.
|
||||
* @param aRotationAngle is the text rotation angle in radians.
|
||||
*/
|
||||
void Draw( const UTF8& aText, const VECTOR2D& aPosition, double aRotationAngle );
|
||||
|
||||
/**
|
||||
* Changes Graphics Abstraction Layer used for drawing items for a new one.
|
||||
*
|
||||
* @param aGal is the new GAL instance.
|
||||
*/
|
||||
void SetGAL( GAL* aGal )
|
||||
{
|
||||
m_gal = aGal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the boundary limits of aText (the bounding box of all shapes).
|
||||
*
|
||||
* The overbar and alignment are not taken in account, '~' characters are skipped.
|
||||
*
|
||||
* @return a VECTOR2D giving the width and height of text.
|
||||
*/
|
||||
VECTOR2D ComputeStringBoundaryLimits( const UTF8& aText, const VECTOR2D& aGlyphSize,
|
||||
double aGlyphThickness ) const;
|
||||
|
||||
/**
|
||||
* Compute the vertical position of an overbar, sometimes used in texts.
|
||||
*
|
||||
* This is the distance between the text base line and the overbar.
|
||||
*
|
||||
* @param aGlyphHeight is the height (vertical size) of the text.
|
||||
* @return the relative position of the overbar axis.
|
||||
*/
|
||||
double ComputeOverbarVerticalPosition( double aGlyphHeight ) const;
|
||||
|
||||
/**
|
||||
* Compute the distance (interline) between 2 lines of text (for multiline texts).
|
||||
*
|
||||
* @param aGlyphHeight is the height (vertical size) of the text.
|
||||
* @return the interline.
|
||||
*/
|
||||
static double GetInterline( double aGlyphHeight );
|
||||
|
||||
private:
|
||||
/**
|
||||
* Compute the X and Y size of a given text. The text is expected to be
|
||||
* a only one line text.
|
||||
*
|
||||
* @param aText is the text string (one line).
|
||||
* @return the text size.
|
||||
*/
|
||||
VECTOR2D computeTextLineSize( const UTF8& aText ) const;
|
||||
|
||||
/**
|
||||
* Compute the vertical position of an overbar, sometimes used in texts.
|
||||
* This is the distance between the text base line and the overbar.
|
||||
* @return the relative position of the overbar axis.
|
||||
*/
|
||||
double computeOverbarVerticalPosition() const;
|
||||
double computeUnderlineVerticalPosition() const;
|
||||
|
||||
/**
|
||||
* Compute the bounding box of a given glyph.
|
||||
*
|
||||
* @param aGlyph is the glyph.
|
||||
* @param aGlyphWidth is the x-component of the bounding box size.
|
||||
* @return is the complete bounding box size.
|
||||
*/
|
||||
BOX2D computeBoundingBox( const GLYPH* aGlyph, double aGlyphWidth ) const;
|
||||
|
||||
/**
|
||||
* Draw a single line of text. Multiline texts should be split before using the
|
||||
* function.
|
||||
*
|
||||
* @param aText is the text to be drawn.
|
||||
*/
|
||||
void drawSingleLineText( const UTF8& aText );
|
||||
|
||||
/**
|
||||
* Returns number of lines for a given text.
|
||||
*
|
||||
* @param aText is the text to be checked.
|
||||
* @return unsigned - The number of lines in aText.
|
||||
*/
|
||||
inline unsigned linesCount( const UTF8& aText ) const
|
||||
{
|
||||
if( aText.empty() )
|
||||
return 0; // std::count does not work well with empty strings
|
||||
else
|
||||
// aText.end() - 1 is to skip a newline character that is potentially at the end
|
||||
return std::count( aText.begin(), aText.end() - 1, '\n' ) + 1;
|
||||
}
|
||||
|
||||
GAL* m_gal; ///< Pointer to the GAL
|
||||
const GLYPH_LIST* m_glyphs; ///< Glyph list
|
||||
const std::vector<BOX2D>* m_glyphBoundingBoxes; ///< Bounding boxes of the glyphs
|
||||
|
||||
///< Factor that determines relative vertical position of the overbar.
|
||||
static const double OVERBAR_POSITION_FACTOR;
|
||||
static const double UNDERLINE_POSITION_FACTOR;
|
||||
|
||||
///< Factor that determines relative line width for bold text.
|
||||
static const double BOLD_FACTOR;
|
||||
|
||||
///< Scale factor for a glyph
|
||||
static const double STROKE_FONT_SCALE;
|
||||
|
||||
///< Tilt factor for italic style (the is is the scaling factor
|
||||
///< on dY relative coordinates to give a tilt shape
|
||||
static const double ITALIC_TILT;
|
||||
|
||||
///< Factor that determines the pitch between 2 lines.
|
||||
static const double INTERLINE_PITCH_RATIO;
|
||||
};
|
||||
} // namespace KIGFX
|
||||
|
||||
#endif // STROKE_FONT_H_
|
|
@ -70,19 +70,22 @@ int Clamp_Text_PenSize( int aPenSize, const VECTOR2I& aSize, bool aBold = true )
|
|||
* @return the "best" value for a pen size to draw/plot a bold text.
|
||||
*/
|
||||
int GetPenSizeForBold( int aTextSize );
|
||||
int GetPenSizeForBold( const wxSize& aTextSize );
|
||||
|
||||
/**
|
||||
* @param aTextSize = the char size (height or width).
|
||||
* @return the "best" value for a pen size to draw/plot a non-bold text.
|
||||
*/
|
||||
int GetPenSizeForNormal( int aTextSize );
|
||||
int GetPenSizeForNormal( const wxSize& aTextSize );
|
||||
|
||||
/**
|
||||
* The full X size is GraphicTextWidth + the thickness of graphic lines.
|
||||
*
|
||||
* @return the X size of the graphic text.
|
||||
*/
|
||||
int GraphicTextWidth( const wxString& aText, const VECTOR2I& aSize, bool italic, bool bold );
|
||||
int GraphicTextWidth( const wxString& aText, KIFONT::FONT* aFont, const VECTOR2I& aSize,
|
||||
bool italic, bool bold );
|
||||
|
||||
/**
|
||||
* Draw a graphic text (like footprint text)
|
||||
|
|
|
@ -107,9 +107,6 @@ using selector = parse_tree::selector< Rule,
|
|||
subscript,
|
||||
overbar>>;
|
||||
|
||||
typedef std::unique_ptr<MARKUP::NODE, std::default_delete<MARKUP::NODE>> MARKUP_NODE;
|
||||
|
||||
|
||||
class MARKUP_PARSER
|
||||
{
|
||||
public:
|
||||
|
@ -117,7 +114,7 @@ public:
|
|||
in( source, "from_input" )
|
||||
{}
|
||||
|
||||
MARKUP_NODE Parse();
|
||||
std::unique_ptr<NODE> Parse();
|
||||
|
||||
private:
|
||||
string_input<> in;
|
||||
|
@ -125,6 +122,5 @@ private:
|
|||
|
||||
} // namespace MARKUP
|
||||
|
||||
std::ostream& operator<<( std::ostream& os, const MARKUP::MARKUP_NODE& node );
|
||||
|
||||
#endif //MARKUP_PARSER_H
|
||||
|
|
|
@ -57,25 +57,6 @@
|
|||
#define CELL_IS_ZONE 0x80 /* Area and auto-placement: cell available */
|
||||
|
||||
|
||||
/* Penalty (cost) for CntRot90 and CntRot180:
|
||||
* CntRot90 and CntRot180 are from 0 (rotation allowed) to 10 (rotation not allowed)
|
||||
*/
|
||||
static const double OrientationPenalty[11] =
|
||||
{
|
||||
2.0, // CntRot = 0 rotation prohibited
|
||||
1.9, // CntRot = 1
|
||||
1.8, // CntRot = 2
|
||||
1.7, // CntRot = 3
|
||||
1.6, // CntRot = 4
|
||||
1.5, // CntRot = 5
|
||||
1.4, // CntRot = 5
|
||||
1.3, // CntRot = 7
|
||||
1.2, // CntRot = 8
|
||||
1.1, // CntRot = 9
|
||||
1.0 // CntRot = 10 rotation authorized, no penalty
|
||||
};
|
||||
|
||||
|
||||
AR_AUTOPLACER::AR_AUTOPLACER( BOARD* aBoard )
|
||||
{
|
||||
m_board = aBoard;
|
||||
|
|
|
@ -1548,6 +1548,21 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
|
|||
}
|
||||
|
||||
|
||||
void PCB_PAINTER::strokeText( const wxString& aText, const VECTOR2D& aPosition,
|
||||
const TEXT_ATTRIBUTES& aAttrs )
|
||||
{
|
||||
KIFONT::FONT* font = aAttrs.m_Font;
|
||||
|
||||
if( !font )
|
||||
font = KIFONT::FONT::GetFont( wxEmptyString, aAttrs.m_Bold, aAttrs.m_Italic );
|
||||
|
||||
m_gal->SetIsFill( font->IsOutline() );
|
||||
m_gal->SetIsStroke( font->IsStroke() );
|
||||
|
||||
font->Draw( m_gal, aText, aPosition, aAttrs );
|
||||
}
|
||||
|
||||
|
||||
void PCB_PAINTER::draw( const PCB_TEXT* aText, int aLayer )
|
||||
{
|
||||
wxString shownText( aText->GetShownText() );
|
||||
|
@ -1556,19 +1571,19 @@ void PCB_PAINTER::draw( const PCB_TEXT* aText, int aLayer )
|
|||
return;
|
||||
|
||||
const COLOR4D& color = m_pcbSettings.GetColor( aText, aText->GetLayer() );
|
||||
VECTOR2D position( aText->GetTextPos().x, aText->GetTextPos().y );
|
||||
bool outline_mode = !pcbconfig()->m_Display.m_DisplayTextFill;
|
||||
|
||||
if( outline_mode )
|
||||
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
|
||||
else
|
||||
m_gal->SetLineWidth( getLineThickness( aText->GetEffectiveTextPenWidth() ) );
|
||||
|
||||
m_gal->SetStrokeColor( color );
|
||||
m_gal->SetIsFill( false );
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->SetTextAttributes( aText );
|
||||
m_gal->StrokeText( shownText, position, aText->GetTextAngle().AsRadians() );
|
||||
m_gal->SetFillColor( color );
|
||||
|
||||
TEXT_ATTRIBUTES attrs = aText->GetAttributes();
|
||||
|
||||
if( outline_mode )
|
||||
attrs.m_StrokeWidth = m_pcbSettings.m_outlineWidth;
|
||||
else
|
||||
attrs.m_StrokeWidth = getLineThickness( aText->GetEffectiveTextPenWidth() );
|
||||
|
||||
strokeText( shownText, aText->GetTextPos(), attrs );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1580,26 +1595,28 @@ void PCB_PAINTER::draw( const FP_TEXT* aText, int aLayer )
|
|||
return;
|
||||
|
||||
const COLOR4D& color = m_pcbSettings.GetColor( aText, aLayer );
|
||||
VECTOR2D position( aText->GetTextPos().x, aText->GetTextPos().y );
|
||||
bool outline_mode = !pcbconfig()->m_Display.m_DisplayTextFill;
|
||||
|
||||
if( outline_mode )
|
||||
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
|
||||
else
|
||||
m_gal->SetLineWidth( getLineThickness( aText->GetEffectiveTextPenWidth() ) );
|
||||
|
||||
m_gal->SetStrokeColor( color );
|
||||
m_gal->SetIsFill( false );
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->SetTextAttributes( aText );
|
||||
m_gal->StrokeText( shownText, position, aText->GetDrawRotation().AsRadians() );
|
||||
m_gal->SetFillColor( color );
|
||||
|
||||
TEXT_ATTRIBUTES attrs = aText->GetAttributes();
|
||||
|
||||
attrs.m_Angle = aText->GetDrawRotation();
|
||||
|
||||
if( outline_mode )
|
||||
attrs.m_StrokeWidth = m_pcbSettings.m_outlineWidth;
|
||||
else
|
||||
attrs.m_StrokeWidth = getLineThickness( aText->GetEffectiveTextPenWidth() );
|
||||
|
||||
strokeText( shownText, aText->GetTextPos(), attrs );
|
||||
|
||||
// Draw the umbilical line
|
||||
if( aText->IsSelected() )
|
||||
{
|
||||
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
|
||||
m_gal->SetStrokeColor( m_pcbSettings.GetColor( nullptr, LAYER_ANCHOR ) );
|
||||
m_gal->DrawLine( position, aText->GetParent()->GetPosition() );
|
||||
m_gal->DrawLine( aText->GetTextPos(), aText->GetParent()->GetPosition() );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1826,14 +1843,14 @@ void PCB_PAINTER::draw( const PCB_DIMENSION_BASE* aDimension, int aLayer )
|
|||
// Draw text
|
||||
const PCB_TEXT& text = aDimension->Text();
|
||||
VECTOR2D position( text.GetTextPos().x, text.GetTextPos().y );
|
||||
TEXT_ATTRIBUTES attrs = text.GetAttributes();
|
||||
|
||||
if( outline_mode )
|
||||
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
|
||||
attrs.m_StrokeWidth = m_pcbSettings.m_outlineWidth;
|
||||
else
|
||||
m_gal->SetLineWidth( getLineThickness( text.GetEffectiveTextPenWidth() ) );
|
||||
attrs.m_StrokeWidth = getLineThickness( text.GetEffectiveTextPenWidth() );
|
||||
|
||||
m_gal->SetTextAttributes( &text );
|
||||
m_gal->StrokeText( text.GetShownText(), position, text.GetTextAngle().AsRadians() );
|
||||
strokeText( text.GetShownText(), position, attrs );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ class PCB_TARGET;
|
|||
class PCB_MARKER;
|
||||
class NET_SETTINGS;
|
||||
class NETINFO_LIST;
|
||||
class TEXT_ATTRIBUTES;
|
||||
|
||||
namespace KIGFX
|
||||
{
|
||||
|
@ -200,6 +201,9 @@ protected:
|
|||
*/
|
||||
virtual int getDrillSize( const PCB_VIA* aVia ) const;
|
||||
|
||||
void strokeText( const wxString& aText, const VECTOR2D& aPosition,
|
||||
const TEXT_ATTRIBUTES& aAttrs );
|
||||
|
||||
protected:
|
||||
PCB_RENDER_SETTINGS m_pcbSettings;
|
||||
|
||||
|
|
|
@ -574,14 +574,19 @@ int DRAWING_TOOL::PlaceText( const TOOL_EVENT& aEvent )
|
|||
m_controls->ForceCursorPosition( true, m_controls->GetCursorPosition() );
|
||||
PCB_LAYER_ID layer = m_frame->GetActiveLayer();
|
||||
|
||||
wxSize textSize = dsnSettings.GetTextSize( layer );
|
||||
int thickness = dsnSettings.GetTextThickness( layer );
|
||||
|
||||
// Init the new item attributes
|
||||
if( m_isFootprintEditor )
|
||||
{
|
||||
FP_TEXT* fpText = new FP_TEXT( (FOOTPRINT*) m_frame->GetModel() );
|
||||
|
||||
fpText->SetLayer( layer );
|
||||
fpText->SetTextSize( dsnSettings.GetTextSize( layer ) );
|
||||
fpText->SetTextThickness( dsnSettings.GetTextThickness( layer ) );
|
||||
fpText->SetTextSize( textSize );
|
||||
fpText->SetTextThickness( thickness );
|
||||
fpText->SetBold( abs( thickness - GetPenSizeForBold( textSize ) ) <
|
||||
abs( thickness - GetPenSizeForNormal( textSize ) ) );
|
||||
fpText->SetItalic( dsnSettings.GetTextItalic( layer ) );
|
||||
fpText->SetKeepUpright( dsnSettings.GetTextUpright( layer ) );
|
||||
fpText->SetTextPos( (wxPoint) cursorPos );
|
||||
|
@ -619,8 +624,10 @@ int DRAWING_TOOL::PlaceText( const TOOL_EVENT& aEvent )
|
|||
if( IsBackLayer( layer ) )
|
||||
pcbText->SetMirrored( true );
|
||||
|
||||
pcbText->SetTextSize( dsnSettings.GetTextSize( layer ) );
|
||||
pcbText->SetTextThickness( dsnSettings.GetTextThickness( layer ) );
|
||||
pcbText->SetTextSize( textSize );
|
||||
pcbText->SetTextThickness( thickness );
|
||||
pcbText->SetBold( abs( thickness - GetPenSizeForBold( textSize ) ) <
|
||||
abs( thickness - GetPenSizeForNormal( textSize ) ) );
|
||||
pcbText->SetItalic( dsnSettings.GetTextItalic( layer ) );
|
||||
pcbText->SetTextPos( (wxPoint) cursorPos );
|
||||
|
||||
|
|
|
@ -67,7 +67,8 @@ void LABEL_MANAGER::Add( VECTOR2I target, std::string msg, COLOR4D color )
|
|||
lbl.m_color = color;
|
||||
m_gal->SetGlyphSize( VECTOR2D( m_textSize, m_textSize ) );
|
||||
|
||||
VECTOR2I textDims = m_gal->GetTextLineSize( msg );
|
||||
KIFONT::FONT* strokeFont = KIFONT::GetFont( wxEmptyString );
|
||||
VECTOR2I textDims = strokeFont->StringBoundaryLimits( m_gal, msg );
|
||||
|
||||
lbl.m_bbox.SetOrigin( lbl.m_target - textDims - VECTOR2I( m_textSize, m_textSize ) );
|
||||
lbl.m_bbox.SetSize( textDims );
|
||||
|
|
Loading…
Reference in New Issue