libgui 2.01
libgui is a GUI library for the GameCube, Wii, and Wii U
 
Loading...
Searching...
No Matches
GuiText.cpp
1/****************************************************************************
2 * libgui
3 * Daryl Borth 2009-2026
4 * GuiText.cpp
5 ***************************************************************************/
6
7#include "Gui.h"
8
9GuiTextTranslator* textTranslator = new GuiTextTranslator();
10static PixelColor presetColor = (PixelColor){255, 255, 255, 255};
11static int currentSize = 0;
12static int presetSize = 0;
13static int presetMaxWidth = 0;
14static ALIGN_H presetAlignmentHor = ALIGN_H::LEFT;
15static ALIGN_V presetAlignmentVert = ALIGN_V::TOP;
16static uint16_t presetStyle = 0;
17
18#define TEXT_SCROLL_DELAY 8
19#define TEXT_SCROLL_INITIAL_DELAY 6
20
24GuiText::GuiText(const char * t, int s, PixelColor c)
25{
26 origText = nullptr;
27 text = nullptr;
28 size = s;
29 color = c;
30 alpha = c.a;
31 style = GUI_TEXT_JUSTIFY_CENTER | GUI_TEXT_ALIGN_MIDDLE;
32 maxWidth = 0;
33 wrap = false;
34 textDynNum = 0;
35 textScroll = SCROLL::NONE;
36 textScrollPos = 0;
37 textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
38 textScrollDelay = TEXT_SCROLL_DELAY;
39
40 alignmentHor = ALIGN_H::CENTRE;
41 alignmentVert = ALIGN_V::MIDDLE;
42
43 if(t)
44 {
45 origText = strdup(t);
46 text = getText(t);
47 }
48
49 for(int i=0; i < 20; i++)
50 textDyn[i] = nullptr;
51}
52
56GuiText::GuiText(const char * t)
57{
58 origText = nullptr;
59 text = nullptr;
60 size = presetSize;
61 color = presetColor;
62 alpha = presetColor.a;
63 style = presetStyle;
64 maxWidth = presetMaxWidth;
65 wrap = false;
66 textDynNum = 0;
67 textScroll = SCROLL::NONE;
68 textScrollPos = 0;
69 textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
70 textScrollDelay = TEXT_SCROLL_DELAY;
71
72 alignmentHor = presetAlignmentHor;
73 alignmentVert = presetAlignmentVert;
74
75 if(t)
76 {
77 origText = strdup(t);
78 text = getText(t);
79 }
80
81 for(int i=0; i < 20; i++)
82 textDyn[i] = nullptr;
83}
84
89{
90 if(origText)
91 free(origText);
92 if(text)
93 delete[] text;
94
95 if(textDynNum > 0)
96 {
97 for(int i=0; i < textDynNum; i++)
98 if(textDyn[i])
99 delete[] textDyn[i];
100 }
101}
102
103wchar_t* GuiText::getText(const char *t) const {
104 return GuiTextRenderer::charToWideChar(textTranslator->getText(t));
105}
106
107void GuiText::setText(const char * t)
108{
109 if(origText)
110 free(origText);
111 if(text)
112 delete[] text;
113
114 if(textDynNum > 0)
115 {
116 for(int i=0; i < textDynNum; i++)
117 if(textDyn[i])
118 delete[] textDyn[i];
119 }
120
121 origText = nullptr;
122 text = nullptr;
123 textDynNum = 0;
124 textScrollPos = 0;
125 textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
126
127 if(t)
128 {
129 origText = strdup(t);
130 text = getText(t);
131 }
132}
133
134void GuiText::setWText(wchar_t * t)
135{
136 if(origText)
137 free(origText);
138 if(text)
139 delete[] text;
140
141 if(textDynNum > 0)
142 {
143 for(int i=0; i < textDynNum; i++)
144 if(textDyn[i])
145 delete[] textDyn[i];
146 }
147
148 origText = nullptr;
149 text = nullptr;
150 textDynNum = 0;
151 textScrollPos = 0;
152 textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
153
154 if(t)
155 text = wcsdup(t);
156}
157
159{
160 if(!text)
161 return 0;
162
163 return wcslen(text);
164}
165
166void GuiText::setPresets(int sz, PixelColor c, int w, uint16_t s, ALIGN_H h, ALIGN_V v)
167{
168 presetSize = sz;
169 presetColor = c;
170 presetStyle = s;
171 presetMaxWidth = w;
172 presetAlignmentHor = h;
173 presetAlignmentVert = v;
174}
175
177{
178 size = s;
179}
180
182{
183 maxWidth = width;
184
185 for(int i=0; i < textDynNum; i++)
186 {
187 if(textDyn[i])
188 {
189 delete[] textDyn[i];
190 textDyn[i] = nullptr;
191 }
192 }
193
194 textDynNum = 0;
195}
196
198{
199 if(!text)
200 return 0;
201
202 fontSystem->setPixelSize(size);
203 return fontSystem->getWidth(text);
204}
205
206void GuiText::setWrap(bool w, int width)
207{
208 wrap = w;
209 maxWidth = width;
210
211 for(int i=0; i < textDynNum; i++)
212 {
213 if(textDyn[i])
214 {
215 delete[] textDyn[i];
216 textDyn[i] = nullptr;
217 }
218 }
219
220 textDynNum = 0;
221}
222
224{
225 if(textScroll == s)
226 return;
227
228 for(int i=0; i < textDynNum; i++)
229 {
230 if(textDyn[i])
231 {
232 delete[] textDyn[i];
233 textDyn[i] = nullptr;
234 }
235 }
236
237 textDynNum = 0;
238
239 textScroll = s;
240 textScrollPos = 0;
241 textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
242 textScrollDelay = TEXT_SCROLL_DELAY;
243}
244
246{
247 color = c;
248 alpha = c.a;
249}
250
251void GuiText::setStyle(uint16_t s)
252{
253 style = s;
254}
255
257{
258 style = 0;
259
260 switch(hor)
261 {
262 case ALIGN_H::LEFT:
263 style |= GUI_TEXT_JUSTIFY_LEFT;
264 break;
265 case ALIGN_H::RIGHT:
266 style |= GUI_TEXT_JUSTIFY_RIGHT;
267 break;
268 default:
269 style |= GUI_TEXT_JUSTIFY_CENTER;
270 break;
271 }
272 switch(vert)
273 {
274 case ALIGN_V::TOP:
275 style |= GUI_TEXT_ALIGN_TOP;
276 break;
277 case ALIGN_V::BOTTOM:
278 style |= GUI_TEXT_ALIGN_BOTTOM;
279 break;
280 default:
281 style |= GUI_TEXT_ALIGN_MIDDLE;
282 break;
283 }
284
285 alignmentHor = hor;
286 alignmentVert = vert;
287}
288
290{
291 if(!origText)
292 return;
293 if(text)
294 delete[] text;
295
296 text = getText(origText);
297
298 for(int i=0; i < textDynNum; i++)
299 {
300 if(textDyn[i])
301 {
302 delete[] textDyn[i];
303 textDyn[i] = nullptr;
304 }
305 }
306
307 textDynNum = 0;
308 currentSize = 0;
309}
310
314bool GuiText::scrollStepDue()
315{
316 const uint32_t now = platform->getVideo()->getFrameTimer();
317
318 // Timer was reset: resync instead of stalling
319 if(now < textScrollLastTick)
320 textScrollLastTick = now;
321
322 if(now - textScrollLastTick < (uint32_t)textScrollDelay)
323 return false;
324
325 textScrollLastTick = now;
326 return true;
327}
328
333{
334 if(!text)
335 return;
336
337 if(!this->isVisible())
338 return;
339
340 PixelColor c = color;
341 c.a = this->getAlpha();
342
343 int newSize = size*this->getScale();
344
345 fontSystem->setPixelSize(newSize);
346
347 if(maxWidth == 0)
348 {
349 fontSystem->drawText(this->getLeft(), this->getTop(), text, c, style);
350 this->updateEffects();
351 return;
352 }
353
354 uint32_t textlen = wcslen(text);
355
356 if(wrap)
357 {
358 if(textDynNum == 0)
359 {
360 int n = 0;
361 uint32_t ch = 0;
362 int linenum = 0;
363 int lastSpace = -1;
364 int lastSpaceIndex = -1;
365
366 while(ch < textlen && linenum < 20)
367 {
368 if(n == 0)
369 textDyn[linenum] = new wchar_t[textlen + 1];
370
371 textDyn[linenum][n] = text[ch];
372 textDyn[linenum][n+1] = 0;
373
374 if(text[ch] == ' ' || ch == textlen-1)
375 {
376 if(fontSystem->getWidth(textDyn[linenum]) > maxWidth)
377 {
378 if(lastSpace >= 0)
379 {
380 textDyn[linenum][lastSpaceIndex] = 0; // discard space, and everything after
381 ch = lastSpace; // go backwards to the last space
382 lastSpace = -1; // we have used this space
383 lastSpaceIndex = -1;
384 }
385 ++linenum;
386 n = -1;
387 }
388 else if(ch == textlen-1)
389 {
390 ++linenum;
391 }
392 }
393 if(text[ch] == ' ' && n >= 0)
394 {
395 lastSpace = ch;
396 lastSpaceIndex = n;
397 }
398 ++ch;
399 ++n;
400 }
401 textDynNum = linenum;
402 }
403
404 int lineheight = newSize + 6;
405 int voffset = 0;
406
407 if(alignmentVert == ALIGN_V::MIDDLE)
408 voffset = (lineheight >> 1) * (1-textDynNum);
409
410 int left = this->getLeft();
411 int top = this->getTop() + voffset;
412
413 for(int i=0; i < textDynNum; ++i)
414 fontSystem->drawText(left, top+i*lineheight, textDyn[i], c, style);
415 }
416 else
417 {
418 if(textDynNum == 0)
419 {
420 textDynNum = 1;
421 textDyn[0] = wcsdup(text);
422 int len = wcslen(textDyn[0]);
423
424 while(fontSystem->getWidth(textDyn[0]) > maxWidth)
425 textDyn[0][--len] = 0;
426 }
427
428 if(textScroll == SCROLL::HORIZONTAL)
429 {
430 if(fontSystem->getWidth(text) > maxWidth && scrollStepDue())
431 {
432 if(textScrollInitialDelay)
433 {
434 --textScrollInitialDelay;
435 }
436 else
437 {
438 ++textScrollPos;
439 if((uint32_t)textScrollPos > textlen-1)
440 {
441 textScrollPos = 0;
442 textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
443 }
444
445 wcscpy(textDyn[0], &text[textScrollPos]);
446 uint32_t dynlen = wcslen(textDyn[0]);
447
448 if(dynlen+2 < textlen)
449 {
450 textDyn[0][dynlen] = ' ';
451 textDyn[0][dynlen+1] = ' ';
452 textDyn[0][dynlen+2] = 0;
453 dynlen += 2;
454 }
455
456 if(fontSystem->getWidth(textDyn[0]) > maxWidth)
457 {
458 while(fontSystem->getWidth(textDyn[0]) > maxWidth)
459 textDyn[0][--dynlen] = 0;
460 }
461 else
462 {
463 int i = 0;
464
465 while(fontSystem->getWidth(textDyn[0]) < maxWidth && dynlen+1 < textlen)
466 {
467 textDyn[0][dynlen] = text[i++];
468 textDyn[0][++dynlen] = 0;
469 }
470
471 if(fontSystem->getWidth(textDyn[0]) > maxWidth)
472 textDyn[0][dynlen-2] = 0;
473 else
474 textDyn[0][dynlen-1] = 0;
475 }
476 }
477 }
478 }
479 fontSystem->drawText(this->getLeft(), this->getTop(), textDyn[0], c, style);
480 }
481 this->updateEffects();
482}
483
484void GuiText::getNaturalSize(int& w, int& h)
485{
486 if(!text)
487 {
488 w = 0;
489 h = 0;
490 return;
491 }
492
493 fontSystem->setPixelSize(size);
494 w = fontSystem->getWidth(text);
495 h = fontSystem->getHeight(text);
496 if(maxWidth > 0 && w > maxWidth)
497 w = maxWidth;
498}
Umbrella header for the platform-agnostic libgui core.
bool isVisible()
Checks whether or not the element is visible.
int getTop()
Gets the current topmost coordinate of the element Considers vertical alignment, y offset,...
int alpha
Element alpha value (0-255)
Definition GuiElement.h:278
int width
Element width.
Definition GuiElement.h:268
ALIGN_H alignmentHor
Horizontal element alignment, respective to parent element (LEFT, RIGHT, CENTRE)
Definition GuiElement.h:289
void updateEffects()
Updates the element's effects (dynamic values) Called by Draw(), used for animation purposes.
int getLeft()
Gets the current leftmost coordinate of the element Considers horizontal alignment,...
ALIGN_V alignmentVert
Horizontal element alignment, respective to parent element (TOP, BOTTOM, MIDDLE)
Definition GuiElement.h:290
float getScale()
Gets the element's current scale Considers scale, scaleDyn, and the parent element's GetScale() value...
int getAlpha()
Gets the element's alpha value Considers alpha, alphaDyn, and the parent element's GetAlpha() value.
static wchar_t * charToWideChar(const char *p)
Hashed msgid -> UTF-8 string table loaded from a single binary .lang blob (see loadLanguage()).
void setWrap(bool w, int width=0)
Enables/disables text wrapping.
Definition GuiText.cpp:206
void setColor(PixelColor c)
Sets the font color.
Definition GuiText.cpp:245
void resetText()
Updates the text to the selected language.
Definition GuiText.cpp:289
GuiText(const char *t, int s, PixelColor c)
Constructor.
Definition GuiText.cpp:24
~GuiText()
Destructor.
Definition GuiText.cpp:88
void setScroll(SCROLL s)
Enables/disables text scrolling.
Definition GuiText.cpp:223
static void setPresets(int sz, PixelColor c, int w, uint16_t s, ALIGN_H h, ALIGN_V v)
Sets up preset values to be used by GuiText(t) Useful when printing multiple text elements,...
Definition GuiText.cpp:166
void getNaturalSize(int &w, int &h) override
Gets the text's size for layout: its rendered width and height on one line (at most the maximum width...
Definition GuiText.cpp:484
void setFontSize(int s)
Sets the font size.
Definition GuiText.cpp:176
void setText(const char *t)
Sets the text of the GuiText element.
Definition GuiText.cpp:107
int getTextWidth()
Gets the width of the text when rendered.
Definition GuiText.cpp:197
void draw() override
Constantly called to draw the text.
Definition GuiText.cpp:332
void setWText(wchar_t *t)
Sets the text of the GuiText element.
Definition GuiText.cpp:134
void setMaxWidth(int w)
Sets the maximum width of the drawn texture image.
Definition GuiText.cpp:181
int getLength()
Gets the translated text length of the GuiText element.
Definition GuiText.cpp:158
void setStyle(uint16_t s)
Sets the GuiTextRenderer style attributes.
Definition GuiText.cpp:251
void setAlignment(ALIGN_H hor, ALIGN_V vert)
Sets the text alignment.
Definition GuiText.cpp:256
SCROLL
Scrolling mode of a GuiText (none or horizontal).
Definition Gui.h:41
ALIGN_V
Vertical alignment of a GuiElement relative to its parent.
Definition GuiElement.h:20
ALIGN_H
Horizontal alignment of a GuiElement relative to its parent.
Definition GuiElement.h:28
8-bit-per-channel RGBA color used by the video interfaces.
Definition Mesh.h:16
uint8_t a
Alpha component.
Definition Mesh.h:20