29#include <unordered_map>
41#include <wx/tokenzr.h>
68 std::unique_ptr<MARKUP::NODE>
root;
80 auto it = m_cache.find( aQuery );
82 m_cacheMru.emplace_front(
CACHE_ENTRY( aQuery, std::move( aResult ) ) );
84 if( it != m_cache.end() )
86 m_cacheMru.erase( it->second );
90 m_cache[aQuery] = m_cacheMru.begin();
92 if( m_cache.size() > m_maxSize )
94 auto last = m_cacheMru.end();
96 m_cache.erase( last->first );
97 m_cacheMru.pop_back();
100 return m_cacheMru.begin()->second;
103 ENTRY*
Get(
const CACHE_ENTRY::first_type& aQuery )
105 auto it = m_cache.find( aQuery );
107 if( it == m_cache.end() )
110 m_cacheMru.splice( m_cacheMru.begin(), m_cacheMru, it->second );
112 return &m_cacheMru.begin()->second;
124 std::unordered_map<wxString, std::list<CACHE_ENTRY>::iterator>
m_cache;
151 std::tuple<wxString, bool, bool> key = { aFontName, aBold, aItalic };
153 FONT* font =
nullptr;
179 wxArrayString& aTextLines, std::vector<VECTOR2I>& aPositions,
181 const METRICS& aFontMetrics )
const
184 int lineCount = aTextLines.Count();
185 aPositions.reserve( lineCount );
190 for(
int i = 0; i < lineCount; i++ )
192 VECTOR2I pos( aPosition.
x, aPosition.
y + i * interline );
197 aExtents.push_back( bBox );
200 height += ( aAttrs.
m_Size.
y * 1.17 );
222 for(
int i = 0; i < lineCount; i++ )
224 VECTOR2I lineSize = aExtents.at( i );
227 lineOffset.
y += i * interline;
236 aPositions.push_back( aPosition + lineOffset );
253 const METRICS& aFontMetrics )
const
255 if( !aGal || aText.empty() )
258 VECTOR2I position( aPosition - aCursor );
261 wxArrayString strings_list;
262 std::vector<VECTOR2I> positions;
263 std::vector<VECTOR2I> extents;
265 getLinePositions( aText, position, strings_list, positions, extents, aAttrs, aFontMetrics );
269 for(
size_t i = 0; i < strings_list.GetCount(); i++ )
288 bool drawUnderline =
false;
289 bool drawOverbar =
false;
295 if( !aNode->is_root() )
298 textStyle |= TEXT_STYLE::SUBSCRIPT;
300 textStyle |= TEXT_STYLE::SUPERSCRIPT;
305 if( aNode->has_content() )
310 nextPosition, aAngle, aMirror, aOrigin,
314 aBoundingBox->
Merge( bbox );
317 else if( aTextStyle & TEXT_STYLE::UNDERLINE )
319 drawUnderline =
true;
322 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
324 nextPosition =
drawMarkup( aBoundingBox, aGlyphs, child.get(), nextPosition, aFont,
325 aSize, aAngle, aMirror, aOrigin, textStyle, aFontMetrics );
332 double barTrim = aSize.
x * 0.1;
335 VECTOR2D barStart( aPosition.
x + barTrim, aPosition.
y - barOffset );
336 VECTOR2D barEnd( nextPosition.
x - barTrim, nextPosition.
y - barOffset );
346 aGlyphs->push_back( barGlyph.
Transform( { 1.0, 1.0 }, { 0, 0 },
false, aAngle, aMirror,
354 double barTrim = aSize.
x * 0.1;
357 VECTOR2D barStart( aPosition.
x + barTrim, aPosition.
y - barOffset );
358 VECTOR2D barEnd( nextPosition.
x - barTrim, nextPosition.
y - barOffset );
368 aGlyphs->push_back( barGlyph.
Transform( { 1.0, 1.0 }, { 0, 0 },
false, aAngle, aMirror,
386 if( !markup || !markup->
root )
396 wxASSERT( markup && markup->
root );
398 return ::drawMarkup( aBoundingBox, aGlyphs, markup->
root.get(), aPosition,
this, aSize, aAngle,
399 aMirror, aOrigin, aTextStyle, aFontMetrics );
406 bool aItalic,
bool aUnderline,
const METRICS& aFontMetrics )
const
414 textStyle |= TEXT_STYLE::ITALIC;
417 textStyle |= TEXT_STYLE::UNDERLINE;
419 std::vector<std::unique_ptr<GLYPH>> glyphs;
421 (void)
drawMarkup( aBoundingBox, &glyphs, aText, aPosition, aSize, aAngle, aMirror, aOrigin,
422 textStyle, aFontMetrics );
429 bool aBold,
bool aItalic,
const METRICS& aFontMetrics )
const
436 textStyle |= TEXT_STYLE::BOLD;
439 textStyle |= TEXT_STYLE::ITALIC;
442 textStyle, aFontMetrics );
460 bool aItalic,
const METRICS& aFontMetrics )
const
465 textStyle |= TEXT_STYLE::ITALIC;
468 VECTOR2I(), textStyle, aFontMetrics );
479 const std::unique_ptr<MARKUP::NODE>& aNode,
const KIFONT::FONT* aFont,
484 if( !aNode->is_root() )
486 wxChar escapeChar = 0;
488 if( aNode->isSubscript() )
491 textStyle = TEXT_STYLE::SUBSCRIPT;
493 else if( aNode->isSuperscript() )
496 textStyle = TEXT_STYLE::SUPERSCRIPT;
499 if( aNode->isOverbar() )
502 textStyle |= TEXT_STYLE::OVERBAR;
507 wxString word = wxString::Format( wxT(
"%c{" ), escapeChar );
510 if( aNode->has_content() )
513 aSize, { 0, 0 },
ANGLE_0,
false, { 0, 0 },
515 word += aNode->asWxString();
519 std::vector<std::pair<wxString, int>> childWords;
521 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
524 for(
const std::pair<wxString, int>& childWord : childWords )
526 word += childWord.first;
527 width += childWord.second;
531 aWords->emplace_back( std::make_pair( word, width ) );
536 wxString textRun = aNode->asWxString();
537 wxStringTokenizer tokenizer( textRun,
" ", wxTOKEN_RET_DELIMS );
538 std::vector<wxString> words;
540 while( tokenizer.HasMoreTokens() )
541 words.emplace_back( tokenizer.GetNextToken() );
543 for(
const wxString& word : words )
545 wxString chars = word;
548 int w = aFont->
GetTextAsGlyphs(
nullptr,
nullptr, chars, aSize, { 0, 0 },
549 ANGLE_0,
false, { 0, 0 }, textStyle ).x;
551 aWords->emplace_back( std::make_pair( word, w ) );
556 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
565 std::unique_ptr<MARKUP::NODE> root = markupParser.
Parse();
583 bool aBold,
bool aItalic )
const
588 textStyle |= TEXT_STYLE::BOLD;
591 textStyle |= TEXT_STYLE::ITALIC;
596 wxArrayString textLines;
599 aText = wxEmptyString;
601 for(
size_t ii = 0; ii < textLines.Count(); ++ii )
603 std::vector<std::pair<wxString, int>> markup;
604 std::vector<std::pair<wxString, int>> words;
608 for(
const auto& [ run, runWidth ] : markup )
610 if( !words.empty() && !words.back().first.EndsWith(
' ' ) )
612 words.back().first += run;
613 words.back().second += runWidth;
617 words.emplace_back( std::make_pair( run, runWidth ) );
621 bool buryMode =
false;
623 wxString pendingSpaces;
625 for(
const auto& [ word, wordWidth ] : words )
627 int pendingSpaceWidth = (int) pendingSpaces.Length() * spaceWidth;
628 bool overflow = lineWidth + pendingSpaceWidth + wordWidth > aColumnWidth - aThickness;
630 if( overflow && pendingSpaces.Length() > 0 )
634 pendingSpaces = wxEmptyString;
635 pendingSpaceWidth = 0;
639 if( word == wxS(
" " ) )
641 pendingSpaces += word;
651 aText += pendingSpaces;
652 lineWidth += pendingSpaceWidth;
655 if( word.EndsWith(
' ' ) )
657 aText += word.Left( word.Length() - 1 );
658 pendingSpaces = wxS(
" " );
663 pendingSpaces = wxEmptyString;
666 lineWidth += wordWidth;
671 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.
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false)
VECTOR2I boundingBoxSingleLine(BOX2I *aBBox, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aSize, bool aItalic, const METRICS &aFontMetrics) const
Computes the bounding box for a single line of text.
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 METRICS &aFontMetrics) 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 METRICS &aFontMetrics) const
void wordbreakMarkup(std::vector< std::pair< wxString, int > > *aWords, const wxString &aText, const VECTOR2I &aSize, TEXT_STYLE_FLAGS aTextStyle) const
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttributes, const METRICS &aFontMetrics) const
Draw a string.
virtual bool IsOutline() const
static std::map< std::tuple< wxString, bool, bool >, FONT * > s_fontMap
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 METRICS &aFontMetrics) const
VECTOR2I StringBoundaryLimits(const wxString &aText, const VECTOR2I &aSize, int aThickness, bool aBold, bool aItalic, const METRICS &aFontMetrics) const
Compute the boundary limits of aText (the bounding box of all shapes).
virtual double GetInterline(double aGlyphHeight, const METRICS &aFontMetrics) const =0
Compute the distance (interline) between 2 lines of text (for multiline texts).
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.
double GetUnderlineVerticalPosition(double aGlyphHeight) const
Compute the vertical position of an underline.
double GetOverbarVerticalPosition(double aGlyphHeight) const
Compute the vertical position of an overbar.
static const METRICS & Default()
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, const METRICS &aFontMetrics)
unsigned int TEXT_STYLE_FLAGS
This file contains miscellaneous commonly used macros and functions.
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.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
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".