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 );
221 wxFAIL_MSG( wxT(
"Indeterminate state legal only in dialogs." ) );
225 for(
int i = 0; i < lineCount; i++ )
227 VECTOR2I lineSize = aExtents.at( i );
230 lineOffset.
y += i * interline;
238 wxFAIL_MSG( wxT(
"Indeterminate state legal only in dialogs." ) );
242 aPositions.push_back( aPosition + lineOffset );
259 const METRICS& aFontMetrics )
const
261 if( !aGal || aText.empty() )
264 VECTOR2I position( aPosition - aCursor );
267 wxArrayString strings_list;
268 std::vector<VECTOR2I> positions;
269 std::vector<VECTOR2I> extents;
271 getLinePositions( aText, position, strings_list, positions, extents, aAttrs, aFontMetrics );
275 for(
size_t i = 0; i < strings_list.GetCount(); i++ )
294 bool drawUnderline =
false;
295 bool drawOverbar =
false;
301 if( !aNode->is_root() )
304 textStyle |= TEXT_STYLE::SUBSCRIPT;
306 textStyle |= TEXT_STYLE::SUPERSCRIPT;
311 if( aNode->has_content() )
316 nextPosition, aAngle, aMirror, aOrigin,
320 aBoundingBox->
Merge( bbox );
323 else if( aTextStyle & TEXT_STYLE::UNDERLINE )
325 drawUnderline =
true;
328 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
330 nextPosition =
drawMarkup( aBoundingBox, aGlyphs, child.get(), nextPosition, aFont,
331 aSize, aAngle, aMirror, aOrigin, textStyle, aFontMetrics );
338 double barTrim = aSize.
x * 0.1;
341 VECTOR2D barStart( aPosition.
x + barTrim, aPosition.
y - barOffset );
342 VECTOR2D barEnd( nextPosition.
x - barTrim, nextPosition.
y - barOffset );
352 aGlyphs->push_back( barGlyph.
Transform( { 1.0, 1.0 }, { 0, 0 },
false, aAngle, aMirror,
360 double barTrim = aSize.
x * 0.1;
363 VECTOR2D barStart( aPosition.
x + barTrim, aPosition.
y - barOffset );
364 VECTOR2D barEnd( nextPosition.
x - barTrim, nextPosition.
y - barOffset );
374 aGlyphs->push_back( barGlyph.
Transform( { 1.0, 1.0 }, { 0, 0 },
false, aAngle, aMirror,
392 if( !markup || !markup->
root )
402 wxASSERT( markup && markup->
root );
404 return ::drawMarkup( aBoundingBox, aGlyphs, markup->
root.get(), aPosition,
this, aSize, aAngle,
405 aMirror, aOrigin, aTextStyle, aFontMetrics );
412 bool aItalic,
bool aUnderline,
const METRICS& aFontMetrics )
const
420 textStyle |= TEXT_STYLE::ITALIC;
423 textStyle |= TEXT_STYLE::UNDERLINE;
425 std::vector<std::unique_ptr<GLYPH>> glyphs;
427 (void)
drawMarkup( aBoundingBox, &glyphs, aText, aPosition, aSize, aAngle, aMirror, aOrigin,
428 textStyle, aFontMetrics );
435 bool aBold,
bool aItalic,
const METRICS& aFontMetrics )
const
442 textStyle |= TEXT_STYLE::BOLD;
445 textStyle |= TEXT_STYLE::ITALIC;
448 textStyle, aFontMetrics );
466 bool aItalic,
const METRICS& aFontMetrics )
const
471 textStyle |= TEXT_STYLE::ITALIC;
474 VECTOR2I(), textStyle, aFontMetrics );
485 const std::unique_ptr<MARKUP::NODE>& aNode,
const KIFONT::FONT* aFont,
490 if( !aNode->is_root() )
492 wxChar escapeChar = 0;
494 if( aNode->isSubscript() )
497 textStyle = TEXT_STYLE::SUBSCRIPT;
499 else if( aNode->isSuperscript() )
502 textStyle = TEXT_STYLE::SUPERSCRIPT;
505 if( aNode->isOverbar() )
508 textStyle |= TEXT_STYLE::OVERBAR;
513 wxString word = wxString::Format( wxT(
"%c{" ), escapeChar );
516 if( aNode->has_content() )
519 aSize, { 0, 0 },
ANGLE_0,
false, { 0, 0 },
521 word += aNode->asWxString();
525 std::vector<std::pair<wxString, int>> childWords;
527 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
530 for(
const std::pair<wxString, int>& childWord : childWords )
532 word += childWord.first;
533 width += childWord.second;
537 aWords->emplace_back( std::make_pair( word, width ) );
542 wxString textRun = aNode->asWxString();
543 wxStringTokenizer tokenizer( textRun,
" ", wxTOKEN_RET_DELIMS );
544 std::vector<wxString> words;
546 while( tokenizer.HasMoreTokens() )
547 words.emplace_back( tokenizer.GetNextToken() );
549 for(
const wxString& word : words )
551 wxString chars = word;
554 int w = aFont->
GetTextAsGlyphs(
nullptr,
nullptr, chars, aSize, { 0, 0 },
555 ANGLE_0,
false, { 0, 0 }, textStyle ).x;
557 aWords->emplace_back( std::make_pair( word, w ) );
562 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
571 std::unique_ptr<MARKUP::NODE> root = markupParser.
Parse();
589 bool aBold,
bool aItalic )
const
594 textStyle |= TEXT_STYLE::BOLD;
597 textStyle |= TEXT_STYLE::ITALIC;
602 wxArrayString textLines;
605 aText = wxEmptyString;
607 for(
size_t ii = 0; ii < textLines.Count(); ++ii )
609 std::vector<std::pair<wxString, int>> markup;
610 std::vector<std::pair<wxString, int>> words;
614 for(
const auto& [ run, runWidth ] : markup )
616 if( !words.empty() && !words.back().first.EndsWith(
' ' ) )
618 words.back().first += run;
619 words.back().second += runWidth;
623 words.emplace_back( std::make_pair( run, runWidth ) );
627 bool buryMode =
false;
629 wxString pendingSpaces;
631 for(
const auto& [ word, wordWidth ] : words )
633 int pendingSpaceWidth = (int) pendingSpaces.Length() * spaceWidth;
634 bool overflow = lineWidth + pendingSpaceWidth + wordWidth > aColumnWidth - aThickness;
636 if( overflow && pendingSpaces.Length() > 0 )
640 pendingSpaces = wxEmptyString;
641 pendingSpaceWidth = 0;
645 if( word == wxS(
" " ) )
647 pendingSpaces += word;
657 aText += pendingSpaces;
658 lineWidth += pendingSpaceWidth;
661 if( word.EndsWith(
' ' ) )
663 aText += word.Left( word.Length() - 1 );
664 pendingSpaces = wxS(
" " );
669 pendingSpaces = wxEmptyString;
672 lineWidth += wordWidth;
677 if( ii != ( textLines.Count() - 1 ) )
const SizeVec & GetSize() const
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
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
@ GR_TEXT_H_ALIGN_INDETERMINATE
@ GR_TEXT_V_ALIGN_INDETERMINATE
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".