29#include <unordered_map>
41#include <wx/tokenzr.h>
59 std::unique_ptr<MARKUP::NODE>
root;
71 auto it =
m_cache.find( aQuery );
94 ENTRY*
Get(
const CACHE_ENTRY::first_type& aQuery )
96 auto it =
m_cache.find( aQuery );
115 std::unordered_map<wxString, std::list<CACHE_ENTRY>::iterator>
m_cache;
142 std::tuple<wxString, bool, bool> key = { aFontName, aBold, aItalic };
167 wxArrayString& aTextLines, std::vector<VECTOR2I>& aPositions,
171 int lineCount = aTextLines.Count();
172 aPositions.reserve( lineCount );
177 for(
int i = 0; i < lineCount; i++ )
179 VECTOR2I pos( aPosition.
x, aPosition.
y + i * interline );
184 aExtents.push_back( bBox );
187 height += ( aAttrs.
m_Size.
y * 1.17 );
209 for(
int i = 0; i < lineCount; i++ )
211 VECTOR2I lineSize = aExtents.at( i );
214 lineOffset.
y += i * interline;
223 aPositions.push_back( aPosition + lineOffset );
241 if( !aGal || aText.empty() )
244 VECTOR2I position( aPosition - aCursor );
247 wxArrayString strings_list;
248 std::vector<VECTOR2I> positions;
249 std::vector<VECTOR2I> extents;
251 getLinePositions( aText, position, strings_list, positions, extents, aAttrs );
255 for(
size_t i = 0; i < strings_list.GetCount(); i++ )
273 bool drawUnderline =
false;
274 bool drawOverbar =
false;
280 if( !aNode->is_root() )
283 textStyle |= TEXT_STYLE::SUBSCRIPT;
285 textStyle |= TEXT_STYLE::SUPERSCRIPT;
290 if( aNode->has_content() )
295 nextPosition, aAngle, aMirror, aOrigin,
299 aBoundingBox->
Merge( bbox );
302 else if( aTextStyle & TEXT_STYLE::UNDERLINE )
304 drawUnderline =
true;
307 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
309 nextPosition =
drawMarkup( aBoundingBox, aGlyphs, child.get(), nextPosition, aFont,
310 aSize, aAngle, aMirror, aOrigin, textStyle );
317 double barTrim = aSize.
x * 0.1;
320 VECTOR2D barStart( aPosition.
x + barTrim, aPosition.
y - barOffset );
321 VECTOR2D barEnd( nextPosition.
x - barTrim, nextPosition.
y - barOffset );
331 aGlyphs->push_back( barGlyph.
Transform( { 1.0, 1.0 }, { 0, 0 },
false, aAngle, aMirror,
339 double barTrim = aSize.
x * 0.1;
342 VECTOR2D barStart( aPosition.
x + barTrim, aPosition.
y - barOffset );
343 VECTOR2D barEnd( nextPosition.
x - barTrim, nextPosition.
y - barOffset );
353 aGlyphs->push_back( barGlyph.
Transform( { 1.0, 1.0 }, { 0, 0 },
false, aAngle, aMirror,
371 if( !markup || !markup->
root )
381 wxASSERT( markup && markup->
root );
383 return ::drawMarkup( aBoundingBox, aGlyphs, markup->
root.get(), aPosition,
this, aSize, aAngle,
384 aMirror, aOrigin, aTextStyle );
391 bool aItalic,
bool aUnderline )
const
399 textStyle |= TEXT_STYLE::ITALIC;
402 textStyle |= TEXT_STYLE::UNDERLINE;
404 std::vector<std::unique_ptr<GLYPH>> glyphs;
406 (void)
drawMarkup( aBoundingBox, &glyphs, aText, aPosition, aSize, aAngle, aMirror, aOrigin,
414 bool aBold,
bool aItalic )
const
421 textStyle |= TEXT_STYLE::BOLD;
424 textStyle |= TEXT_STYLE::ITALIC;
450 textStyle |= TEXT_STYLE::ITALIC;
464 const std::unique_ptr<MARKUP::NODE>& aNode,
const KIFONT::FONT* aFont,
469 if( !aNode->is_root() )
471 wxChar escapeChar = 0;
473 if( aNode->isSubscript() )
476 textStyle = TEXT_STYLE::SUBSCRIPT;
478 else if( aNode->isSuperscript() )
481 textStyle = TEXT_STYLE::SUPERSCRIPT;
484 if( aNode->isOverbar() )
487 textStyle |= TEXT_STYLE::OVERBAR;
492 wxString word = wxString::Format( wxT(
"%c{" ), escapeChar );
495 if( aNode->has_content() )
498 aSize, { 0, 0 },
ANGLE_0,
false, { 0, 0 },
500 word += aNode->asWxString();
504 std::vector<std::pair<wxString, int>> childWords;
506 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
509 for(
const std::pair<wxString, int>& childWord : childWords )
511 word += childWord.first;
512 width += childWord.second;
516 aWords->emplace_back( std::make_pair( word, width ) );
521 wxString textRun = aNode->asWxString();
522 wxStringTokenizer tokenizer( textRun,
" ", wxTOKEN_RET_DELIMS );
523 std::vector<wxString> words;
525 while( tokenizer.HasMoreTokens() )
526 words.emplace_back( tokenizer.GetNextToken() );
528 for(
const wxString& word : words )
530 wxString chars = word;
533 int w = aFont->
GetTextAsGlyphs(
nullptr,
nullptr, chars, aSize, { 0, 0 },
534 ANGLE_0,
false, { 0, 0 }, textStyle ).x;
536 aWords->emplace_back( std::make_pair( word, w ) );
541 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
550 std::unique_ptr<MARKUP::NODE> root = markupParser.
Parse();
568 bool aBold,
bool aItalic )
const
573 textStyle |= TEXT_STYLE::BOLD;
576 textStyle |= TEXT_STYLE::ITALIC;
581 wxArrayString textLines;
584 aText = wxEmptyString;
586 for(
size_t ii = 0; ii < textLines.Count(); ++ii )
588 std::vector<std::pair<wxString, int>> markup;
589 std::vector<std::pair<wxString, int>> words;
593 for(
const auto& [ run, runWidth ] : markup )
595 if( !words.empty() && !words.back().first.EndsWith(
' ' ) )
597 words.back().first += run;
598 words.back().second += runWidth;
602 words.emplace_back( std::make_pair( run, runWidth ) );
606 bool buryMode =
false;
608 wxString pendingSpaces;
610 for(
const auto& [ word, wordWidth ] : words )
612 int pendingSpaceWidth = (int) pendingSpaces.Length() * spaceWidth;
613 bool overflow = lineWidth + pendingSpaceWidth + wordWidth > aColumnWidth - aThickness;
615 if( overflow && pendingSpaces.Length() > 0 )
619 pendingSpaces = wxEmptyString;
620 pendingSpaceWidth = 0;
624 if( word == wxS(
" " ) )
626 pendingSpaces += word;
636 aText += pendingSpaces;
637 lineWidth += pendingSpaceWidth;
640 if( word.EndsWith(
' ' ) )
642 aText += word.Left( word.Length() - 1 );
643 pendingSpaces = wxS(
" " );
648 pendingSpaces = wxEmptyString;
651 lineWidth += wordWidth;
656 if( ii != ( textLines.Count() - 1 ) )
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
const Vec & GetSize() const
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
FONT is an abstract base class for both outline and stroke fonts.
virtual double ComputeUnderlineVerticalPosition(double aGlyphHeight) const =0
Compute the vertical position of an underline.
virtual double GetInterline(double aGlyphHeight, double aLineSpacing=1.0) const =0
Compute the distance (interline) between 2 lines of text (for multiline texts).
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false)
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttrs) const
Draw a string.
virtual double ComputeOverbarVerticalPosition(double aGlyphHeight) const =0
Compute the vertical position of an overbar.
void drawSingleLineText(KIGFX::GAL *aGal, BOX2I *aBoundingBox, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin, bool aItalic, bool aUnderline) const
Draws a single line of text.
virtual bool IsStroke() const
static FONT * s_defaultFont
void getLinePositions(const wxString &aText, const VECTOR2I &aPosition, wxArrayString &aTextLines, std::vector< VECTOR2I > &aPositions, std::vector< VECTOR2I > &aExtents, const TEXT_ATTRIBUTES &aAttrs) const
VECTOR2I boundingBoxSingleLine(BOX2I *aBBox, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aSize, bool aItalic) const
Computes the bounding box for a single line of text.
void wordbreakMarkup(std::vector< std::pair< wxString, int > > *aWords, const wxString &aText, const VECTOR2I &aSize, TEXT_STYLE_FLAGS aTextStyle) const
Factor that determines the pitch between 2 lines.
virtual bool IsOutline() const
VECTOR2I drawMarkup(BOX2I *aBoundingBox, std::vector< std::unique_ptr< GLYPH > > *aGlyphs, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aSize, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin, TEXT_STYLE_FLAGS aTextStyle) const
static std::map< std::tuple< wxString, bool, bool >, FONT * > s_fontMap
VECTOR2I StringBoundaryLimits(const wxString &aText, const VECTOR2I &aSize, int aThickness, bool aBold, bool aItalic) const
Compute the boundary limits of aText (the bounding box of all shapes).
virtual VECTOR2I GetTextAsGlyphs(BOX2I *aBBox, std::vector< std::unique_ptr< GLYPH > > *aGlyphs, const wxString &aText, const VECTOR2I &aSize, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin, TEXT_STYLE_FLAGS aTextStyle) const =0
Convert text string to an array of GLYPHs.
static FONT * getDefaultFont()
void LinebreakText(wxString &aText, int aColumnWidth, const VECTOR2I &aGlyphSize, int aThickness, bool aBold, bool aItalic) const
Insert characters into text to ensure that no lines are wider than aColumnWidth.
static OUTLINE_FONT * LoadFont(const wxString &aFontFileName, bool aBold, bool aItalic)
Load an outline font.
static STROKE_FONT * LoadFont(const wxString &aFontName)
Load a stroke font.
void AddPoint(const VECTOR2D &aPoint)
std::unique_ptr< GLYPH > Transform(const VECTOR2D &aGlyphSize, const VECTOR2I &aOffset, double aTilt, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin)
Abstract interface for drawing on a 2D-surface.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
virtual void DrawGlyphs(const std::vector< std::unique_ptr< KIFONT::GLYPH > > &aGlyphs)
Draw polygons representing font glyphs.
std::unique_ptr< NODE > Parse()
MARKUP_CACHE(size_t aMaxSize)
std::unordered_map< wxString, std::list< CACHE_ENTRY >::iterator > m_cache
ENTRY & Put(const CACHE_ENTRY::first_type &aQuery, ENTRY &&aResult)
std::pair< wxString, ENTRY > CACHE_ENTRY
std::list< CACHE_ENTRY > m_cacheMru
ENTRY * Get(const CACHE_ENTRY::first_type &aQuery)
GR_TEXT_H_ALIGN_T m_Halign
GR_TEXT_V_ALIGN_T m_Valign
static constexpr EDA_ANGLE & ANGLE_0
static std::mutex s_markupCacheMutex
void wordbreakMarkup(std::vector< std::pair< wxString, int > > *aWords, const std::unique_ptr< MARKUP::NODE > &aNode, const KIFONT::FONT *aFont, const VECTOR2I &aSize, TEXT_STYLE_FLAGS aTextStyle)
static MARKUP_CACHE s_markupCache(1024)
VECTOR2I drawMarkup(BOX2I *aBoundingBox, std::vector< std::unique_ptr< GLYPH > > *aGlyphs, const MARKUP::NODE *aNode, const VECTOR2I &aPosition, const KIFONT::FONT *aFont, const VECTOR2I &aSize, const EDA_ANGLE &aAngle, bool aMirror, const VECTOR2I &aOrigin, TEXT_STYLE_FLAGS aTextStyle)
unsigned int TEXT_STYLE_FLAGS
This file contains miscellaneous commonly used macros and functions.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
BOX2I boundingBox(T aObject)
Used by SHAPE_INDEX to get the bounding box of a generic T object.
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
bool isSuperscript() const
wxString asWxString() const
std::unique_ptr< MARKUP::NODE > root
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".