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;
181 wxArrayString& aTextLines, std::vector<VECTOR2I>& aPositions,
183 const METRICS& aFontMetrics )
const
186 int lineCount = aTextLines.Count();
187 aPositions.reserve( lineCount );
192 for(
int i = 0; i < lineCount; i++ )
194 VECTOR2I pos( aPosition.
x, aPosition.
y + i * interline );
199 aExtents.push_back( bBox );
202 height += ( aAttrs.
m_Size.
y * 1.17 );
223 wxFAIL_MSG( wxT(
"Indeterminate state legal only in dialogs." ) );
227 for(
int i = 0; i < lineCount; i++ )
229 VECTOR2I lineSize = aExtents.at( i );
232 lineOffset.
y += i * interline;
240 wxFAIL_MSG( wxT(
"Indeterminate state legal only in dialogs." ) );
244 aPositions.push_back( aPosition + lineOffset );
251 const METRICS& aFontMetrics )
const
253 if( !aGal || aText.empty() )
256 VECTOR2I position( aPosition - aCursor );
259 wxArrayString strings_list;
260 std::vector<VECTOR2I> positions;
261 std::vector<VECTOR2I> extents;
263 getLinePositions( aText, position, strings_list, positions, extents, aAttrs, aFontMetrics );
267 for(
size_t i = 0; i < strings_list.GetCount(); i++ )
286 bool drawUnderline =
false;
287 bool drawOverbar =
false;
293 if( !aNode->is_root() )
296 textStyle |= TEXT_STYLE::SUBSCRIPT;
298 textStyle |= TEXT_STYLE::SUPERSCRIPT;
303 if( aNode->has_content() )
308 nextPosition, aAngle, aMirror, aOrigin,
312 aBoundingBox->
Merge( bbox );
315 else if( aTextStyle & TEXT_STYLE::UNDERLINE )
317 drawUnderline =
true;
320 for(
const std::unique_ptr<MARKUP::NODE>& child : aNode->children )
322 nextPosition =
drawMarkup( aBoundingBox, aGlyphs, child.get(), nextPosition, aFont,
323 aSize, aAngle, aMirror, aOrigin, textStyle, aFontMetrics );
330 double barTrim = aSize.
x * 0.1;
333 VECTOR2D barStart( aPosition.
x + barTrim, aPosition.
y - barOffset );
334 VECTOR2D barEnd( nextPosition.
x - barTrim, nextPosition.
y - barOffset );
344 aGlyphs->push_back( barGlyph.
Transform( { 1.0, 1.0 }, { 0, 0 },
false, aAngle, aMirror,
352 double barTrim = aSize.
x * 0.1;
355 VECTOR2D barStart( aPosition.
x + barTrim, aPosition.
y - barOffset );
356 VECTOR2D barEnd( nextPosition.
x - barTrim, nextPosition.
y - barOffset );
366 aGlyphs->push_back( barGlyph.
Transform( { 1.0, 1.0 }, { 0, 0 },
false, aAngle, aMirror,
384 if( !markup || !markup->
root )
394 wxASSERT( markup && markup->
root );
396 return ::drawMarkup( aBoundingBox, aGlyphs, markup->
root.get(), aPosition,
this, aSize, aAngle,
397 aMirror, aOrigin, aTextStyle, aFontMetrics );
404 bool aItalic,
bool aUnderline,
const METRICS& aFontMetrics )
const
412 textStyle |= TEXT_STYLE::ITALIC;
415 textStyle |= TEXT_STYLE::UNDERLINE;
417 std::vector<std::unique_ptr<GLYPH>> glyphs;
419 (void)
drawMarkup( aBoundingBox, &glyphs, aText, aPosition, aSize, aAngle, aMirror, aOrigin,
420 textStyle, aFontMetrics );
427 bool aBold,
bool aItalic,
const METRICS& aFontMetrics )
const
434 textStyle |= TEXT_STYLE::BOLD;
437 textStyle |= TEXT_STYLE::ITALIC;
440 textStyle, aFontMetrics );
458 bool aItalic,
const METRICS& aFontMetrics )
const
463 textStyle |= TEXT_STYLE::ITALIC;
466 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();
572 bool aBold,
bool aItalic )
const
577 textStyle |= TEXT_STYLE::BOLD;
580 textStyle |= TEXT_STYLE::ITALIC;
585 wxArrayString textLines;
588 aText = wxEmptyString;
590 for(
size_t ii = 0; ii < textLines.Count(); ++ii )
592 std::vector<std::pair<wxString, int>> markup;
593 std::vector<std::pair<wxString, int>> words;
597 for(
const auto& [ run, runWidth ] : markup )
599 if( !words.empty() && !words.back().first.EndsWith(
' ' ) )
601 words.back().first += run;
602 words.back().second += runWidth;
606 words.emplace_back( std::make_pair( run, runWidth ) );
610 bool buryMode =
false;
612 wxString pendingSpaces;
614 for(
const auto& [ word, wordWidth ] : words )
616 int pendingSpaceWidth = (int) pendingSpaces.Length() * spaceWidth;
617 bool overflow = lineWidth + pendingSpaceWidth + wordWidth > aColumnWidth - aThickness;
619 if( overflow && pendingSpaces.Length() > 0 )
623 pendingSpaces = wxEmptyString;
624 pendingSpaceWidth = 0;
628 if( word == wxS(
" " ) )
630 pendingSpaces += word;
640 aText += pendingSpaces;
641 lineWidth += pendingSpaceWidth;
644 if( word.EndsWith(
' ' ) )
646 aText += word.Left( word.Length() - 1 );
647 pendingSpaces = wxS(
" " );
652 pendingSpaces = wxEmptyString;
655 lineWidth += wordWidth;
660 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()
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)
Break marked-up text into "words".
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