GA::kit v0.3
G&A's in-house C++ application framework
Loading...
Searching...
No Matches
paragraph_component.h
Go to the documentation of this file.
1#pragma once
2#include "ga/color.h"
3#include "ga/fbo.h"
4#include "ga/font.h"
6#include "ga/math.h"
7
8namespace ga {
9
11{
12public:
13 enum class HorzAlignment
14 {
15 LEFT,
16 CENTER,
17 RIGHT
18 };
19 enum class VertAlignment
20 {
21 TOP,
22 MIDDLE,
23 BOTTOM
24 };
25
26 Paragraph();
27
28 Paragraph& setFont( std::shared_ptr<Font> font, bool resetLeadingAndSpacing = true );
29 std::shared_ptr<Font> getFont() { return m_font; }
30
31 Paragraph& setBoldFont( std::shared_ptr<Font> font );
32 std::shared_ptr<Font> getBoldFont() { return m_boldFont; }
33
34 Paragraph& setItalicFont( std::shared_ptr<Font> font );
35 std::shared_ptr<Font> getItalicFont() { return m_italicFont; }
36
37 Paragraph& setBoldItalicFont( std::shared_ptr<Font> font );
38 std::shared_ptr<Font> getBoldItalicFont() { return m_boldItalicFont; }
39
40 Paragraph& setText( std::string text );
41 std::string getText() { return m_text; }
42
47
48 // position offset from 0,0,0
49 Paragraph& setTextOffset( ga::vec3 textOffset );
50 Paragraph& setTextOffset( ga::vec2 textOffset ) { return setTextOffset( ga::vec3( textOffset, 0 ) ); }
51
52 ga::vec3 getTextOffset() { return m_offset; }
53
54 // text box size
55 Paragraph& setSize( ga::vec2 size );
56 ga::vec2 getSize() { return m_size; }
57
58 Paragraph& setTextColor( const ga::Color textColor );
60
61 // spacing between lines
62 Paragraph& setLeading( float px );
63 float getLeading() { return m_leading; }
64
65 // spacing between words
66 Paragraph& setWordSpacing( float px );
67 float getWordSpacing() { return m_spacing; }
68
69 // toggle markdown (bold and italic) parsing
70 Paragraph& setIsMarkdownText( bool isMarkdown );
72
73 // enable/disable fbo cache
74 Paragraph& setFboCacheEnabled( bool enable );
76
77 void draw();
78
79 std::vector<ga::Rect> getWordBounds();
81 int getNumberOfLines();
82
83 void cleanLayout();
84
85protected:
86 enum class FontStyle
87 {
88 REGULAR,
89 BOLD,
90 ITALIC,
92 };
93
95 {
96 std::string text;
97 std::vector<FontStyle> styles; // char-by-char styles
98 };
99
101 {
102 std::string text;
105 };
106
107 struct Word
108 {
109 std::string text;
110 float x, y, w, h;
111 std::vector<FontStyle> style; // char-by-char style
112 std::vector<StyledToken> styledTokens; // bounds per styled part of text
113 };
114
115 std::vector<Word> m_words;
116 std::vector<std::vector<Word*>> m_lines;
117
118 std::shared_ptr<Font> fontForStyle( FontStyle style )
119 {
120 switch ( style ) {
121 case FontStyle::BOLD:
122 return m_boldFont ? m_boldFont : m_font;
126 if ( m_boldItalicFont )
127 return m_boldItalicFont;
128 if ( m_italicFont )
129 return m_italicFont;
130 if ( m_boldFont )
131 return m_boldFont;
132 return m_font;
133 }
134 default:
135 return m_font;
136 }
137 }
138
139 void calcWordRect( Word& word );
140
141 void drawParagraph( bool forceRedraw = false )
142 {
143 if ( m_font == nullptr || m_text.empty() ) {
144 return;
145 }
146 if ( !m_cacheToFbo || forceRedraw ) {
147 for ( auto& word : m_words ) {
148 // m_font->draw( word.text, word.x, word.y );
149 for ( auto& token : word.styledTokens ) {
150 fontForStyle( token.style )->drawString( token.text, word.x + token.bounds.x, word.y );
151 }
152 }
153 } else {
154 if ( m_fbo.isAllocated() ) {
155 m_fbo.draw( m_fboRect.x, m_fboRect.y, m_fbo.getWidth(), m_fbo.getHeight() );
156 }
157 }
158 }
159
160 StyledText parseMarkdownStyles( const std::string& text );
161
162 std::string m_text; // raw text, could contain **bold** and *italics*
163 StyledText m_styledText; // styled text, parsed for **bold** and *italics*
165
166 glm::vec3 m_offset;
167 glm::vec2 m_size;
168
174 bool m_isMarkdownFormatted; // bold and italic formatting
175
176 ga::Fbo m_fbo;
178
179 bool m_isLayoutDirty = true;
180 bool m_cacheToFbo = false;
181
182 // --- below methods are adapted from ofxParagraph ---
183 /*
184 Copyright (C) 2014 Stephen Braitsch [http://braitsch.io]
185
186 Permission is hereby granted, free of charge, to any person obtaining a copy
187 of this software and associated documentation files (the "Software"), to deal
188 in the Software without restriction, including without limitation the rights
189 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
190 copies of the Software, and to permit persons to whom the Software is
191 furnished to do so, subject to the following conditions:
192
193 The above copyright notice and this permission notice shall be included in all
194 copies or substantial portions of the Software.
195
196 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
197 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
198 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
199 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
200 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
201 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
202 SOFTWARE.
203 */
204
206 {
207 if ( !m_font )
208 return;
209 m_words.clear();
210 float lineHeight = m_font->getSize();
211 std::string str = m_styledText.text;
212
213 // break paragraph into words //
214 auto spPosition = str.find( " " );
215 auto nlPosition = str.find( "\n" );
216 auto position = spPosition < nlPosition ? spPosition : nlPosition;
217 size_t textPos = 0;
218
219 while ( position != std::string::npos ) {
220 std::string s = str.substr( 0, position );
221 //auto rect = m_font->rect( s );
222 Word word = { s }; //, rect.getLeft(), rect.getTop(), rect.getWidth(), rect.getHeight() };
223 word.style.insert( word.style.end(), m_styledText.styles.begin() + textPos, m_styledText.styles.begin() + textPos + position );
224 calcWordRect( word );
225 m_words.push_back( word );
226 str.erase( 0, position + 1 );
227 textPos += position + 1;
228
229 if ( position == nlPosition ) {
230 word = { "\n", 0.f, 0.f, 0.f, 0.f, { FontStyle::REGULAR } };
231 m_words.push_back( word ); // add new line "word"
232 }
233
234 spPosition = str.find( " " );
235 nlPosition = str.find( "\n" );
236 position = spPosition < nlPosition ? spPosition : nlPosition;
237 }
238 // append the last word //
239 //auto rect = m_font->rect( str );
240 Word word = { str }; //, rect.getLeft(), rect.getTop(), rect.getWidth(), rect.getHeight() };
241 word.style.insert( word.style.end(), m_styledText.styles.begin() + textPos, m_styledText.styles.end() );
242 calcWordRect( word );
243 m_words.push_back( word );
244
245 // assign words to lines //
246 float x = 0;
247 float y = lineHeight * .85; // origin is top of the text, but ofTTF draws from baseline
248
249 m_lines.clear();
250 std::vector<Word*> line;
251 for ( auto& word : m_words ) {
252
253 if ( word.text == "\n" ) {
254 // new line character forces new line
255
256 x = 0;
257 y += m_leading;
258 word.x = x;
259 word.y = y;
260 if ( line.size() > 0 ) {
261 m_lines.push_back( line );
262 }
263 line.clear();
264
265 } else if ( x + word.w < m_size.x ) {
266 // append word to current line
267
268 word.x = x;
269 word.y = y;
270 x += word.w + m_spacing;
271 line.push_back( &word );
272
273 } else {
274 // create new line starting with this word
275
276 if ( line.size() > 0 )
277 y += m_leading;
278 word.x = 0;
279 word.y = y; // account for descender - todo: fix
280 x = word.w + m_spacing;
281 if ( line.size() > 0 )
282 m_lines.push_back( line );
283 line.clear();
284 line.push_back( &word );
285 }
286 }
287 // append the last line //
288 m_lines.push_back( line );
289 // mHeight = mLines.size() * ( lineHeight + leading );
290
291 // reposition words for right & center aligned paragraphs //
293 for ( auto& line : m_lines ) {
294 int lineWidth = 0;
295 for ( auto* word : line ) {
296 lineWidth += word->w;
297 }
298 lineWidth += m_spacing * ( line.size() - 1 );
299 // calculate the amount each word should move over //
300 float offset = ( m_size.x - lineWidth ) / 2;
301 for ( auto* word : line ) {
302 word->x += offset;
303 }
304 }
305 } else if ( m_hAlignment == HorzAlignment::RIGHT ) {
306 for ( auto& line : m_lines ) {
307 auto* lword = line.back();
308 // calculate the distance the last word in each line is from the right boundary //
309 int offset = m_size.x - ( lword->x + lword->w );
310 for ( auto* word : line ) {
311 word->x += offset;
312 }
313 }
314 }
315
317 float pHeight = lineHeight + ( m_lines.size() - 1 ) * m_leading;
318 float yOffset = ( m_size.y - pHeight ) * .5;
319 for ( auto& word : m_words ) {
320 word.y += yOffset;
321 }
322 } else if ( m_vAlignment == VertAlignment::BOTTOM ) {
323 float pHeight = lineHeight + ( m_lines.size() - 1 ) * m_leading;
324 float yOffset = ( m_size.y - pHeight );
325 for ( auto& word : m_words ) {
326 word.y += yOffset;
327 }
328 }
329 }
330};
331} // namespace ga
Definition: component.h:11
Definition: paragraph_component.h:11
ga::Color getTextColor()
Definition: paragraph_component.h:59
bool m_isMarkdownFormatted
Definition: paragraph_component.h:174
ga::vec2 getSize()
Definition: paragraph_component.h:56
void calcWordRect(Word &word)
Definition: paragraph_component.cpp:224
Paragraph & setBoldItalicFont(std::shared_ptr< Font > font)
Definition: paragraph_component.cpp:48
Paragraph & setTextOffset(ga::vec2 textOffset)
Definition: paragraph_component.h:50
Paragraph & setFont(std::shared_ptr< Font > font, bool resetLeadingAndSpacing=true)
Definition: paragraph_component.cpp:21
VertAlignment
Definition: paragraph_component.h:20
ga::Fbo m_fbo
Definition: paragraph_component.h:176
bool getIsFboCacheEnabled()
Definition: paragraph_component.h:75
void cleanLayout()
Definition: paragraph_component.cpp:193
ga::Color m_textColor
Definition: paragraph_component.h:169
std::shared_ptr< Font > getBoldItalicFont()
Definition: paragraph_component.h:38
glm::vec3 m_offset
Definition: paragraph_component.h:166
std::shared_ptr< Font > getItalicFont()
Definition: paragraph_component.h:35
HorzAlignment
Definition: paragraph_component.h:14
float m_spacing
Definition: paragraph_component.h:173
std::string getText()
Definition: paragraph_component.h:41
FontStyle
Definition: paragraph_component.h:87
Paragraph()
Definition: paragraph_component.cpp:7
std::shared_ptr< Font > getBoldFont()
Definition: paragraph_component.h:32
int getNumberOfLines()
Definition: paragraph_component.cpp:187
Paragraph & setTextOffset(ga::vec3 textOffset)
Definition: paragraph_component.cpp:83
Paragraph & setVerticalAlignment(VertAlignment alignment)
Definition: paragraph_component.cpp:73
std::shared_ptr< Font > m_font
Definition: paragraph_component.h:164
std::shared_ptr< Font > m_boldItalicFont
Definition: paragraph_component.h:164
Paragraph & setText(std::string text)
Definition: paragraph_component.cpp:55
VertAlignment m_vAlignment
Definition: paragraph_component.h:171
ga::Rect m_fboRect
Definition: paragraph_component.h:177
Paragraph & setWordSpacing(float px)
Definition: paragraph_component.cpp:119
StyledText parseMarkdownStyles(const std::string &text)
Definition: paragraph_component.cpp:286
void calculateTextFlow()
Definition: paragraph_component.h:205
bool m_cacheToFbo
Definition: paragraph_component.h:180
HorzAlignment m_hAlignment
Definition: paragraph_component.h:170
Paragraph & setTextColor(const ga::Color textColor)
Definition: paragraph_component.cpp:100
std::vector< Word > m_words
Definition: paragraph_component.h:115
void drawParagraph(bool forceRedraw=false)
Definition: paragraph_component.h:141
HorzAlignment getHorizontalAlignment()
Definition: paragraph_component.h:45
float m_leading
Definition: paragraph_component.h:172
Paragraph & setLeading(float px)
Definition: paragraph_component.cpp:108
std::vector< std::vector< Word * > > m_lines
Definition: paragraph_component.h:116
std::vector< ga::Rect > getWordBounds()
Definition: paragraph_component.cpp:154
std::shared_ptr< Font > fontForStyle(FontStyle style)
Definition: paragraph_component.h:118
VertAlignment getVerticalAlignment()
Definition: paragraph_component.h:46
Paragraph & setFboCacheEnabled(bool enable)
Definition: paragraph_component.cpp:134
std::shared_ptr< Font > m_italicFont
Definition: paragraph_component.h:164
float getWordSpacing()
Definition: paragraph_component.h:67
Paragraph & setIsMarkdownText(bool isMarkdown)
Definition: paragraph_component.cpp:128
StyledText m_styledText
Definition: paragraph_component.h:163
Paragraph & setHorizontalAlignment(HorzAlignment alignment)
Definition: paragraph_component.cpp:64
std::string m_text
Definition: paragraph_component.h:162
std::shared_ptr< Font > m_boldFont
Definition: paragraph_component.h:164
Paragraph & setItalicFont(std::shared_ptr< Font > font)
Definition: paragraph_component.cpp:41
ga::vec3 getTextOffset()
Definition: paragraph_component.h:52
ga::Rect getParagraphBounds()
Definition: paragraph_component.cpp:171
glm::vec2 m_size
Definition: paragraph_component.h:167
Paragraph & setSize(ga::vec2 size)
Definition: paragraph_component.cpp:91
std::shared_ptr< Font > getFont()
Definition: paragraph_component.h:29
bool m_isLayoutDirty
Definition: paragraph_component.h:179
Paragraph & setBoldFont(std::shared_ptr< Font > font)
Definition: paragraph_component.cpp:34
void draw()
Definition: paragraph_component.cpp:140
bool getIsMarkdownText() const
Definition: paragraph_component.h:71
float getLeading()
Definition: paragraph_component.h:63
Definition: color.h:9
ga::vec4 Color
Definition: color.h:12
Definition: paragraph_component.h:95
std::string text
Definition: paragraph_component.h:96
std::vector< FontStyle > styles
Definition: paragraph_component.h:97
Definition: paragraph_component.h:101
std::string text
Definition: paragraph_component.h:102
ga::Rect bounds
Definition: paragraph_component.h:104
FontStyle style
Definition: paragraph_component.h:103
Definition: paragraph_component.h:108
std::vector< FontStyle > style
Definition: paragraph_component.h:111
std::string text
Definition: paragraph_component.h:109
float w
Definition: paragraph_component.h:110
std::vector< StyledToken > styledTokens
Definition: paragraph_component.h:112
float h
Definition: paragraph_component.h:110
float x
Definition: paragraph_component.h:110
float y
Definition: paragraph_component.h:110
A 2D axis-aligned rectangle, with x,y (float) position and w,h (float) size components.
Definition: math.h:64
float y
Definition: math.h:91
float x
Definition: math.h:91