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;
147 const std::vector<wxString>* aEmbeddedFiles,
bool aForDrawingSheet )
152 std::tuple<wxString, bool, bool, bool> key = { aFontName, aBold, aItalic, aForDrawingSheet };
154 FONT* font =
nullptr;
180 wxArrayString& aTextLines, std::vector<VECTOR2I>& aPositions,
182 const METRICS& aFontMetrics )
const
185 int lineCount = aTextLines.Count();
186 aPositions.reserve( lineCount );
191 for(
int i = 0; i < lineCount; i++ )
193 VECTOR2I pos( aPosition.
x, aPosition.
y + i * interline );
198 aExtents.push_back( bBox );
201 height += ( aAttrs.
m_Size.
y * 1.17 );
222 wxFAIL_MSG( wxT(
"Indeterminate state legal only in dialogs." ) );
226 for(
int i = 0; i < lineCount; i++ )
228 VECTOR2I lineSize = aExtents.at( i );
231 lineOffset.
y += i * interline;
239 wxFAIL_MSG( wxT(
"Indeterminate state legal only in dialogs." ) );
243 aPositions.push_back( aPosition + lineOffset );
260 const METRICS& aFontMetrics )
const
262 if( !aGal || aText.empty() )
265 VECTOR2I position( aPosition - aCursor );
268 wxArrayString strings_list;
269 std::vector<VECTOR2I> positions;
270 std::vector<VECTOR2I> extents;
272 getLinePositions( aText, position, strings_list, positions, extents, aAttrs, aFontMetrics );
276 for(
size_t i = 0; i < strings_list.GetCount(); i++ )
295 bool drawUnderline =
false;
296 bool drawOverbar =
false;
302 if( !aNode->is_root() )
305 textStyle |= TEXT_STYLE::SUBSCRIPT;
307 textStyle |= TEXT_STYLE::SUPERSCRIPT;
312 if( aNode->has_content() )
317 nextPosition, aAngle, aMirror, aOrigin,
321 aBoundingBox->
Merge( bbox );
324 else if( aTextStyle & TEXT_STYLE::UNDERLINE )
326 drawUnderline =
true;
329 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
331 nextPosition =
drawMarkup( aBoundingBox, aGlyphs, child.get(), nextPosition, aFont,
332 aSize, aAngle, aMirror, aOrigin, textStyle, aFontMetrics );
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,
361 double barTrim = aSize.
x * 0.1;
364 VECTOR2D barStart( aPosition.
x + barTrim, aPosition.
y - barOffset );
365 VECTOR2D barEnd( nextPosition.
x - barTrim, nextPosition.
y - barOffset );
375 aGlyphs->push_back( barGlyph.
Transform( { 1.0, 1.0 }, { 0, 0 },
false, aAngle, aMirror,
393 if( !markup || !markup->
root )
403 wxASSERT( markup && markup->
root );
405 return ::drawMarkup( aBoundingBox, aGlyphs, markup->
root.get(), aPosition,
this, aSize, aAngle,
406 aMirror, aOrigin, aTextStyle, aFontMetrics );
413 bool aItalic,
bool aUnderline,
const METRICS& aFontMetrics )
const
421 textStyle |= TEXT_STYLE::ITALIC;
424 textStyle |= TEXT_STYLE::UNDERLINE;
426 std::vector<std::unique_ptr<GLYPH>> glyphs;
428 (void)
drawMarkup( aBoundingBox, &glyphs, aText, aPosition, aSize, aAngle, aMirror, aOrigin,
429 textStyle, aFontMetrics );
436 bool aBold,
bool aItalic,
const METRICS& aFontMetrics )
const
443 textStyle |= TEXT_STYLE::BOLD;
446 textStyle |= TEXT_STYLE::ITALIC;
449 textStyle, aFontMetrics );
467 bool aItalic,
const METRICS& aFontMetrics )
const
472 textStyle |= TEXT_STYLE::ITALIC;
475 VECTOR2I(), textStyle, aFontMetrics );
486 const std::unique_ptr<MARKUP::NODE>& aNode,
const KIFONT::FONT* aFont,
491 if( !aNode->is_root() )
493 wxChar escapeChar = 0;
495 if( aNode->isSubscript() )
498 textStyle = TEXT_STYLE::SUBSCRIPT;
500 else if( aNode->isSuperscript() )
503 textStyle = TEXT_STYLE::SUPERSCRIPT;
506 if( aNode->isOverbar() )
509 textStyle |= TEXT_STYLE::OVERBAR;
514 wxString word = wxString::Format( wxT(
"%c{" ), escapeChar );
517 if( aNode->has_content() )
520 aSize, { 0, 0 },
ANGLE_0,
false, { 0, 0 },
522 word += aNode->asWxString();
526 std::vector<std::pair<wxString, int>> childWords;
528 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
531 for(
const std::pair<wxString, int>& childWord : childWords )
533 word += childWord.first;
534 width += childWord.second;
538 aWords->emplace_back( std::make_pair( word, width ) );
543 wxString textRun = aNode->asWxString();
544 wxStringTokenizer tokenizer( textRun,
" ", wxTOKEN_RET_DELIMS );
545 std::vector<wxString> words;
547 while( tokenizer.HasMoreTokens() )
548 words.emplace_back( tokenizer.GetNextToken() );
550 for(
const wxString& word : words )
552 wxString chars = word;
555 int w = aFont->
GetTextAsGlyphs(
nullptr,
nullptr, chars, aSize, { 0, 0 },
556 ANGLE_0,
false, { 0, 0 }, textStyle ).x;
558 aWords->emplace_back( std::make_pair( word, w ) );
563 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
572 std::unique_ptr<MARKUP::NODE> root = markupParser.
Parse();
590 bool aBold,
bool aItalic )
const
595 textStyle |= TEXT_STYLE::BOLD;
598 textStyle |= TEXT_STYLE::ITALIC;
603 wxArrayString textLines;
606 aText = wxEmptyString;
608 for(
size_t ii = 0; ii < textLines.Count(); ++ii )
610 std::vector<std::pair<wxString, int>> markup;
611 std::vector<std::pair<wxString, int>> words;
615 for(
const auto& [ run, runWidth ] : markup )
617 if( !words.empty() && !words.back().first.EndsWith(
' ' ) )
619 words.back().first += run;
620 words.back().second += runWidth;
624 words.emplace_back( std::make_pair( run, runWidth ) );
628 bool buryMode =
false;
630 wxString pendingSpaces;
632 for(
const auto& [ word, wordWidth ] : words )
634 int pendingSpaceWidth = (int) pendingSpaces.Length() * spaceWidth;
635 bool overflow = lineWidth + pendingSpaceWidth + wordWidth > aColumnWidth - aThickness;
637 if( overflow && pendingSpaces.Length() > 0 )
641 pendingSpaces = wxEmptyString;
642 pendingSpaceWidth = 0;
646 if( word == wxS(
" " ) )
648 pendingSpaces += word;
658 aText += pendingSpaces;
659 lineWidth += pendingSpaceWidth;
662 if( word.EndsWith(
' ' ) )
664 aText += word.Left( word.Length() - 1 );
665 pendingSpaces = wxS(
" " );
670 pendingSpaces = wxEmptyString;
673 lineWidth += wordWidth;
678 if( ii != ( textLines.Count() - 1 ) )
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr const SizeVec & GetSize() const
FONT is an abstract base class for both outline and stroke fonts.
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.
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
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
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).
static std::map< std::tuple< wxString, bool, bool, bool >, FONT * > s_fontMap
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, const std::vector< wxString > *aEmbeddedFiles, bool aForDrawingSheet)
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, int aLayer)
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
VECTOR2< int32_t > VECTOR2I