29#include <unordered_map>
41#include <wx/tokenzr.h>
68 std::unique_ptr<MARKUP::NODE>
root;
78 auto it = m_cache.find( aQuery );
80 m_cacheMru.emplace_front( std::make_pair( aQuery, std::move( aResult ) ) );
82 if( it != m_cache.end() )
84 m_cacheMru.erase( it->second );
88 m_cache[aQuery] = m_cacheMru.begin();
90 if( m_cache.size() > m_maxSize )
92 auto last = m_cacheMru.end();
94 m_cache.erase( last->first );
95 m_cacheMru.pop_back();
98 return m_cacheMru.begin()->second;
103 auto it = m_cache.find( aQuery );
105 if( it == m_cache.end() )
108 m_cacheMru.splice( m_cacheMru.begin(), m_cacheMru, it->second );
110 return &m_cacheMru.begin()->second;
122 std::unordered_map<wxString, std::list<std::pair<wxString, ENTRY>>::iterator>
m_cache;
148 const std::vector<wxString>* aEmbeddedFiles,
bool aForDrawingSheet )
153 std::tuple<wxString, bool, bool, bool> key = { aFontName, aBold, aItalic, aForDrawingSheet };
155 FONT* font =
nullptr;
182 wxArrayString& aTextLines, std::vector<VECTOR2I>& aPositions,
184 const METRICS& aFontMetrics )
const
187 int lineCount = aTextLines.Count();
188 aPositions.reserve( lineCount );
193 for(
int i = 0; i < lineCount; i++ )
195 VECTOR2I pos( aPosition.
x, aPosition.
y + i * interline );
200 aExtents.push_back( bBox );
203 height += ( aAttrs.
m_Size.
y * 1.17 );
224 wxFAIL_MSG( wxT(
"Indeterminate state legal only in dialogs." ) );
228 for(
int i = 0; i < lineCount; i++ )
230 VECTOR2I lineSize = aExtents.at( i );
233 lineOffset.
y += i * interline;
241 wxFAIL_MSG( wxT(
"Indeterminate state legal only in dialogs." ) );
245 aPositions.push_back( aPosition + lineOffset );
252 const METRICS& aFontMetrics )
const
254 if( !aGal || aText.empty() )
257 VECTOR2I position( aPosition - aCursor );
260 wxArrayString strings_list;
261 std::vector<VECTOR2I> positions;
262 std::vector<VECTOR2I> extents;
264 getLinePositions( aText, position, strings_list, positions, extents, aAttrs, aFontMetrics );
268 for(
size_t i = 0; i < strings_list.GetCount(); i++ )
287 bool drawUnderline =
false;
288 bool drawOverbar =
false;
294 if( !aNode->is_root() )
297 textStyle |= TEXT_STYLE::SUBSCRIPT;
299 textStyle |= TEXT_STYLE::SUPERSCRIPT;
304 if( aNode->has_content() )
309 nextPosition, aAngle, aMirror, aOrigin,
313 aBoundingBox->
Merge( bbox );
316 else if( aTextStyle & TEXT_STYLE::UNDERLINE )
318 drawUnderline =
true;
321 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
323 nextPosition =
drawMarkup( aBoundingBox, aGlyphs, child.get(), nextPosition, aFont,
324 aSize, aAngle, aMirror, aOrigin, textStyle, aFontMetrics );
331 double barTrim = aSize.
x * 0.1;
334 VECTOR2D barStart( aPosition.
x + barTrim, aPosition.
y - barOffset );
335 VECTOR2D barEnd( nextPosition.
x - barTrim, nextPosition.
y - barOffset );
345 aGlyphs->push_back( barGlyph.
Transform( { 1.0, 1.0 }, { 0, 0 },
false, aAngle, aMirror,
353 double barTrim = aSize.
x * 0.1;
356 VECTOR2D barStart( aPosition.
x + barTrim, aPosition.
y - barOffset );
357 VECTOR2D barEnd( nextPosition.
x - barTrim, nextPosition.
y - barOffset );
367 aGlyphs->push_back( barGlyph.
Transform( { 1.0, 1.0 }, { 0, 0 },
false, aAngle, aMirror,
385 if( !markup || !markup->
root )
395 wxASSERT( markup && markup->
root );
397 return ::drawMarkup( aBoundingBox, aGlyphs, markup->
root.get(), aPosition,
this, aSize, aAngle,
398 aMirror, aOrigin, aTextStyle, aFontMetrics );
405 bool aItalic,
bool aUnderline,
const METRICS& aFontMetrics )
const
413 textStyle |= TEXT_STYLE::ITALIC;
416 textStyle |= TEXT_STYLE::UNDERLINE;
418 std::vector<std::unique_ptr<GLYPH>> glyphs;
420 (void)
drawMarkup( aBoundingBox, &glyphs, aText, aPosition, aSize, aAngle, aMirror, aOrigin,
421 textStyle, aFontMetrics );
428 bool aBold,
bool aItalic,
const METRICS& aFontMetrics )
const
435 textStyle |= TEXT_STYLE::BOLD;
438 textStyle |= TEXT_STYLE::ITALIC;
441 textStyle, aFontMetrics );
459 bool aItalic,
const METRICS& aFontMetrics )
const
464 textStyle |= TEXT_STYLE::ITALIC;
467 VECTOR2I(), textStyle, aFontMetrics );
480 const std::unique_ptr<MARKUP::NODE>& aNode,
const KIFONT::FONT* aFont,
485 if( !aNode->is_root() )
487 wxChar escapeChar = 0;
489 if( aNode->isSubscript() )
492 textStyle = TEXT_STYLE::SUBSCRIPT;
494 else if( aNode->isSuperscript() )
497 textStyle = TEXT_STYLE::SUPERSCRIPT;
500 if( aNode->isOverbar() )
503 textStyle |= TEXT_STYLE::OVERBAR;
508 wxString word = wxString::Format( wxT(
"%c{" ), escapeChar );
511 if( aNode->has_content() )
514 aSize, { 0, 0 },
ANGLE_0,
false, { 0, 0 },
516 word += aNode->asWxString();
520 std::vector<std::pair<wxString, int>> childWords;
522 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
525 for(
const std::pair<wxString, int>& childWord : childWords )
527 word += childWord.first;
528 width += childWord.second;
532 aWords->emplace_back( std::make_pair( word, width ) );
537 wxString textRun = aNode->asWxString();
538 wxStringTokenizer tokenizer( textRun,
" ", wxTOKEN_RET_DELIMS );
539 std::vector<wxString> words;
541 while( tokenizer.HasMoreTokens() )
542 words.emplace_back( tokenizer.GetNextToken() );
544 for(
const wxString& word : words )
546 wxString chars = word;
549 int w = aFont->
GetTextAsGlyphs(
nullptr,
nullptr, chars, aSize, { 0, 0 },
550 ANGLE_0,
false, { 0, 0 }, textStyle ).x;
552 aWords->emplace_back( std::make_pair( word, w ) );
557 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
566 std::unique_ptr<MARKUP::NODE> root = markupParser.
Parse();
573 bool aBold,
bool aItalic )
const
578 textStyle |= TEXT_STYLE::BOLD;
581 textStyle |= TEXT_STYLE::ITALIC;
586 wxArrayString textLines;
589 aText = wxEmptyString;
591 for(
size_t ii = 0; ii < textLines.Count(); ++ii )
593 std::vector<std::pair<wxString, int>> markup;
594 std::vector<std::pair<wxString, int>> words;
598 for(
const auto& [ run, runWidth ] : markup )
600 if( !words.empty() && !words.back().first.EndsWith(
' ' ) )
602 words.back().first += run;
603 words.back().second += runWidth;
607 words.emplace_back( std::make_pair( run, runWidth ) );
611 bool buryMode =
false;
613 wxString pendingSpaces;
615 for(
const auto& [ word, wordWidth ] : words )
617 int pendingSpaceWidth = (int) pendingSpaces.Length() * spaceWidth;
618 bool overflow = lineWidth + pendingSpaceWidth + wordWidth > aColumnWidth - aThickness;
620 if( overflow && pendingSpaces.Length() > 0 )
624 pendingSpaces = wxEmptyString;
625 pendingSpaceWidth = 0;
629 if( word == wxS(
" " ) )
631 pendingSpaces += word;
641 aText += pendingSpaces;
642 lineWidth += pendingSpaceWidth;
645 if( word.EndsWith(
' ' ) )
647 aText += word.Left( word.Length() - 1 );
648 pendingSpaces = wxS(
" " );
653 pendingSpaces = wxEmptyString;
656 lineWidth += wordWidth;
661 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
Compute 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
Draw 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()
std::list< std::pair< wxString, ENTRY > > m_cacheMru
MARKUP_CACHE(size_t aMaxSize)
ENTRY & Put(const wxString &aQuery, ENTRY &&aResult)
ENTRY * Get(const wxString &aQuery)
std::unordered_map< wxString, std::list< std::pair< wxString, ENTRY > >::iterator > m_cache
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)
Break marked-up text into "words".
static std::mutex s_defaultFontMutex
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