2017-10-29 10:28:14 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Copyright (C) 2015 Dimok
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
****************************************************************************/
|
2018-06-21 20:44:58 +02:00
|
|
|
#include <gui/GuiText.h>
|
|
|
|
#include <gui/FreeTypeGX.h>
|
2019-08-14 23:24:55 +02:00
|
|
|
#include <gui/video/CVideo.h>
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
FreeTypeGX *GuiText::presentFont = NULL;
|
2020-08-13 13:26:45 +02:00
|
|
|
int32_t GuiText::presetSSAA = 2;
|
2018-06-21 20:44:58 +02:00
|
|
|
int32_t GuiText::presetSize = 28;
|
|
|
|
int32_t GuiText::presetMaxWidth = 0xFFFF;
|
|
|
|
int32_t GuiText::presetAlignment = ALIGN_CENTER | ALIGN_MIDDLE;
|
|
|
|
GX2ColorF32 GuiText::presetColor = (GX2ColorF32) {
|
2020-08-13 12:38:07 +02:00
|
|
|
1.0f, 1.0f, 1.0f, 1.0f
|
2018-06-21 20:44:58 +02:00
|
|
|
};
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
#define TEXT_SCROLL_DELAY 6
|
|
|
|
#define TEXT_SCROLL_INITIAL_DELAY 10
|
|
|
|
#define MAX_LINES_TO_DRAW 10
|
2017-10-29 10:28:14 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor for the GuiText class.
|
|
|
|
*/
|
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
GuiText::GuiText() {
|
|
|
|
text = NULL;
|
2020-08-13 13:41:03 +02:00
|
|
|
currentSize = presetSize;
|
2018-06-21 20:44:58 +02:00
|
|
|
color = glm::vec4(presetColor.r, presetColor.g, presetColor.b, presetColor.a);
|
|
|
|
alpha = presetColor.a;
|
|
|
|
alignment = presetAlignment;
|
|
|
|
maxWidth = presetMaxWidth;
|
2020-08-13 13:26:45 +02:00
|
|
|
internalSSAA = presetSSAA;
|
2018-06-21 20:44:58 +02:00
|
|
|
wrapMode = 0;
|
|
|
|
font = presentFont;
|
|
|
|
linestodraw = MAX_LINES_TO_DRAW;
|
|
|
|
textScrollPos = 0;
|
|
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
|
|
|
textScrollDelay = TEXT_SCROLL_DELAY;
|
|
|
|
defaultBlur = 4.0f;
|
|
|
|
blurGlowIntensity = 0.0f;
|
|
|
|
blurAlpha = 0.0f;
|
|
|
|
blurGlowColor = glm::vec4(0.0f);
|
2020-08-13 14:12:08 +02:00
|
|
|
width = 0;
|
|
|
|
height = 0;
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
GuiText::GuiText(const char *t, int32_t s, const glm::vec4 &c) {
|
2018-06-21 20:44:58 +02:00
|
|
|
text = NULL;
|
2020-08-13 13:41:03 +02:00
|
|
|
currentSize = s;
|
2018-06-21 20:44:58 +02:00
|
|
|
color = c;
|
|
|
|
alpha = c[3];
|
|
|
|
alignment = ALIGN_CENTER | ALIGN_MIDDLE;
|
|
|
|
maxWidth = presetMaxWidth;
|
2020-08-13 13:26:45 +02:00
|
|
|
internalSSAA = presetSSAA;
|
2018-06-21 20:44:58 +02:00
|
|
|
wrapMode = 0;
|
|
|
|
font = presentFont;
|
|
|
|
linestodraw = MAX_LINES_TO_DRAW;
|
|
|
|
textScrollPos = 0;
|
|
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
|
|
|
textScrollDelay = TEXT_SCROLL_DELAY;
|
|
|
|
defaultBlur = 4.0f;
|
|
|
|
blurGlowIntensity = 0.0f;
|
|
|
|
blurAlpha = 0.0f;
|
|
|
|
blurGlowColor = glm::vec4(0.0f);
|
2020-08-13 14:12:08 +02:00
|
|
|
width = 0;
|
|
|
|
height = 0;
|
2018-06-21 20:44:58 +02:00
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
if (t) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
2018-06-21 20:44:58 +02:00
|
|
|
text = FreeTypeGX::charToWideChar(t);
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
GuiText::GuiText(const wchar_t *t, int32_t s, const glm::vec4 &c) {
|
2018-06-21 20:44:58 +02:00
|
|
|
text = NULL;
|
2020-08-13 13:41:03 +02:00
|
|
|
currentSize = s;
|
2018-06-21 20:44:58 +02:00
|
|
|
color = c;
|
|
|
|
alpha = c[3];
|
|
|
|
alignment = ALIGN_CENTER | ALIGN_MIDDLE;
|
|
|
|
maxWidth = presetMaxWidth;
|
2020-08-13 13:26:45 +02:00
|
|
|
internalSSAA = presetSSAA;
|
2018-06-21 20:44:58 +02:00
|
|
|
wrapMode = 0;
|
|
|
|
font = presentFont;
|
|
|
|
linestodraw = MAX_LINES_TO_DRAW;
|
|
|
|
textScrollPos = 0;
|
|
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
|
|
|
textScrollDelay = TEXT_SCROLL_DELAY;
|
|
|
|
defaultBlur = 4.0f;
|
|
|
|
blurGlowIntensity = 0.0f;
|
|
|
|
blurAlpha = 0.0f;
|
|
|
|
blurGlowColor = glm::vec4(0.0f);
|
2020-08-13 14:12:08 +02:00
|
|
|
width = 0;
|
|
|
|
height = 0;
|
2018-06-21 20:44:58 +02:00
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
if (t) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
2020-08-13 12:38:07 +02:00
|
|
|
text = new(std::nothrow) wchar_t[wcslen(t) + 1];
|
2020-08-13 12:58:19 +02:00
|
|
|
if (!text) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
return;
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2018-06-21 20:44:58 +02:00
|
|
|
|
|
|
|
wcscpy(text, t);
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor for the GuiText class, uses presets
|
|
|
|
*/
|
2020-08-13 12:38:07 +02:00
|
|
|
GuiText::GuiText(const char *t) {
|
2018-06-21 20:44:58 +02:00
|
|
|
text = NULL;
|
2020-08-13 13:41:03 +02:00
|
|
|
currentSize = presetSize;
|
2018-06-21 20:44:58 +02:00
|
|
|
color = glm::vec4(presetColor.r, presetColor.g, presetColor.b, presetColor.a);
|
|
|
|
alpha = presetColor.a;
|
|
|
|
alignment = presetAlignment;
|
|
|
|
maxWidth = presetMaxWidth;
|
2020-08-13 13:26:45 +02:00
|
|
|
internalSSAA = presetSSAA;
|
2018-06-21 20:44:58 +02:00
|
|
|
wrapMode = 0;
|
|
|
|
font = presentFont;
|
|
|
|
linestodraw = MAX_LINES_TO_DRAW;
|
|
|
|
textScrollPos = 0;
|
|
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
|
|
|
textScrollDelay = TEXT_SCROLL_DELAY;
|
|
|
|
defaultBlur = 4.0f;
|
|
|
|
blurGlowIntensity = 0.0f;
|
|
|
|
blurAlpha = 0.0f;
|
|
|
|
blurGlowColor = glm::vec4(0.0f);
|
2020-08-13 14:12:08 +02:00
|
|
|
width = 0;
|
|
|
|
height = 0;
|
2018-06-21 20:44:58 +02:00
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
if (t) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
2018-06-21 20:44:58 +02:00
|
|
|
text = FreeTypeGX::charToWideChar(t);
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destructor for the GuiText class.
|
|
|
|
*/
|
2018-06-21 20:44:58 +02:00
|
|
|
GuiText::~GuiText() {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
2020-08-13 12:58:19 +02:00
|
|
|
if (text) {
|
2020-08-13 12:38:07 +02:00
|
|
|
delete[] text;
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2018-06-21 20:44:58 +02:00
|
|
|
text = NULL;
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
clearDynamicText();
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
void GuiText::setText(const char *t) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
2020-08-13 12:58:19 +02:00
|
|
|
if (text) {
|
2020-08-13 12:38:07 +02:00
|
|
|
delete[] text;
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2018-06-21 20:44:58 +02:00
|
|
|
text = NULL;
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
clearDynamicText();
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
textScrollPos = 0;
|
|
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
if (t) {
|
2018-06-21 20:44:58 +02:00
|
|
|
text = FreeTypeGX::charToWideChar(t);
|
|
|
|
}
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
void GuiText::setTextf(const char *format, ...) {
|
2020-08-13 12:38:07 +02:00
|
|
|
if (!format) {
|
2018-06-21 20:44:58 +02:00
|
|
|
setText((char *) NULL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t max_len = strlen(format) + 8192;
|
2020-08-16 14:14:00 +02:00
|
|
|
char *tmp = new(std::nothrow) char[max_len];
|
2018-06-21 20:44:58 +02:00
|
|
|
va_list va;
|
|
|
|
va_start(va, format);
|
2020-08-13 12:38:07 +02:00
|
|
|
if ((vsnprintf(tmp, max_len, format, va) >= 0) && tmp) {
|
2018-06-21 20:44:58 +02:00
|
|
|
setText(tmp);
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
2018-06-21 20:44:58 +02:00
|
|
|
va_end(va);
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 12:58:19 +02:00
|
|
|
if (tmp) {
|
2020-08-13 12:38:07 +02:00
|
|
|
delete[] tmp;
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
void GuiText::setText(const wchar_t *t) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
2020-08-13 12:58:19 +02:00
|
|
|
if (text) {
|
2020-08-13 12:38:07 +02:00
|
|
|
delete[] text;
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2018-06-21 20:44:58 +02:00
|
|
|
text = NULL;
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
clearDynamicText();
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
textScrollPos = 0;
|
|
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
if (t) {
|
|
|
|
text = new(std::nothrow) wchar_t[wcslen(t) + 1];
|
2020-08-13 12:58:19 +02:00
|
|
|
if (!text) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
return;
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
wcscpy(text, t);
|
|
|
|
}
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
void GuiText::clearDynamicText() {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
2020-08-13 12:38:07 +02:00
|
|
|
for (uint32_t i = 0; i < textDyn.size(); i++) {
|
2020-08-13 12:58:19 +02:00
|
|
|
if (textDyn[i]) {
|
2020-08-13 12:38:07 +02:00
|
|
|
delete[] textDyn[i];
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2018-06-21 20:44:58 +02:00
|
|
|
}
|
|
|
|
textDyn.clear();
|
|
|
|
textDynWidth.clear();
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
void GuiText::setPresets(int32_t sz, const glm::vec4 &c, int32_t w, int32_t a) {
|
2018-06-21 20:44:58 +02:00
|
|
|
presetSize = sz;
|
|
|
|
presetColor = (GX2ColorF32) {
|
2020-08-13 12:38:07 +02:00
|
|
|
(float) c.r / 255.0f, (float) c.g / 255.0f, (float) c.b / 255.0f, (float) c.a / 255.0f
|
2018-06-21 20:44:58 +02:00
|
|
|
};
|
|
|
|
presetMaxWidth = w;
|
|
|
|
presetAlignment = a;
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
void GuiText::setPresetFont(FreeTypeGX *f) {
|
|
|
|
presentFont = f;
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
void GuiText::setFontSize(int32_t s) {
|
2020-08-13 13:41:03 +02:00
|
|
|
currentSize = s;
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
void GuiText::setMaxWidth(int32_t width, int32_t w) {
|
|
|
|
maxWidth = width;
|
|
|
|
wrapMode = w;
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
if (w == SCROLL_HORIZONTAL) {
|
2018-06-21 20:44:58 +02:00
|
|
|
textScrollPos = 0;
|
|
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
|
|
|
textScrollDelay = TEXT_SCROLL_DELAY;
|
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
clearDynamicText();
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
void GuiText::setColor(const glm::vec4 &c) {
|
2018-06-21 20:44:58 +02:00
|
|
|
color = c;
|
|
|
|
alpha = c[3];
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
void GuiText::setBlurGlowColor(float blur, const glm::vec4 &c) {
|
2018-06-21 20:44:58 +02:00
|
|
|
blurGlowColor = c;
|
|
|
|
blurGlowIntensity = blur;
|
|
|
|
blurAlpha = c[3];
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
int32_t GuiText::getTextWidth(int32_t ind) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
|
|
|
int32_t res;
|
2020-08-13 12:58:19 +02:00
|
|
|
if (ind < 0 || ind >= (int32_t) textDyn.size()) {
|
2020-08-13 14:05:28 +02:00
|
|
|
res = this->getTextWidth();
|
|
|
|
} else {
|
|
|
|
res = font->getWidth(textDyn[ind], currentSize);
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
|
|
|
return res;
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2020-08-13 13:39:17 +02:00
|
|
|
//!Get the Horizontal Size of Text
|
|
|
|
int32_t GuiText::getTextWidth() {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
2020-08-13 13:39:17 +02:00
|
|
|
auto res = font->getWidth(text, currentSize);
|
|
|
|
res = res > maxWidth && maxWidth > 0 ? maxWidth : res;
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
|
|
|
return res;
|
2020-08-13 14:08:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
float GuiText::getTextHeight() {
|
|
|
|
textMutex.lock();
|
|
|
|
if (wrapMode == GuiText::WRAP && textDyn.empty()) {
|
|
|
|
if (maxWidth > 0 && font->getWidth(text, currentSize)) {
|
|
|
|
wrapText();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto res = textDyn.empty() ? getLineHeight() : getLineHeight() * textDyn.size();
|
|
|
|
textMutex.unlock();
|
2020-08-13 13:39:17 +02:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
const wchar_t *GuiText::getDynText(int32_t ind) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
|
|
|
const wchar_t *result;
|
2020-08-13 12:58:19 +02:00
|
|
|
if (ind < 0 || ind >= (int32_t) textDyn.size()) {
|
2020-08-13 14:05:28 +02:00
|
|
|
result = text;
|
|
|
|
} else {
|
|
|
|
result = textDyn[ind];
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
|
|
|
return result;
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Change font
|
|
|
|
*/
|
2018-06-21 20:44:58 +02:00
|
|
|
bool GuiText::setFont(FreeTypeGX *f) {
|
2020-08-13 12:58:19 +02:00
|
|
|
if (!f) {
|
2018-06-21 20:44:58 +02:00
|
|
|
return false;
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2018-06-21 20:44:58 +02:00
|
|
|
|
|
|
|
font = f;
|
|
|
|
return true;
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
std::string GuiText::toUTF8(void) const {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
2020-08-13 12:58:19 +02:00
|
|
|
if (!text) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
return std::string();
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
|
|
|
|
char *pUtf8 = FreeTypeGX::wideCharToUTF8(text);
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2020-08-13 12:58:19 +02:00
|
|
|
if (!pUtf8) {
|
2018-06-21 20:44:58 +02:00
|
|
|
return std::string();
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
|
|
|
|
std::string strOutput(pUtf8);
|
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
delete[] pUtf8;
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
return strOutput;
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
void GuiText::makeDottedText() {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
2018-06-21 20:44:58 +02:00
|
|
|
int32_t pos = textDyn.size();
|
|
|
|
textDyn.resize(pos + 1);
|
|
|
|
|
|
|
|
int32_t i = 0, currentWidth = 0;
|
2020-08-13 12:38:07 +02:00
|
|
|
textDyn[pos] = new(std::nothrow) wchar_t[maxWidth];
|
|
|
|
if (!textDyn[pos]) {
|
2018-06-21 20:44:58 +02:00
|
|
|
textDyn.resize(pos);
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (text[i]) {
|
|
|
|
currentWidth += font->getCharWidth(text[i], currentSize, i > 0 ? text[i - 1] : 0);
|
|
|
|
if (currentWidth >= maxWidth && i > 2) {
|
|
|
|
textDyn[pos][i - 2] = '.';
|
|
|
|
textDyn[pos][i - 1] = '.';
|
|
|
|
textDyn[pos][i] = '.';
|
|
|
|
i++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
textDyn[pos][i] = text[i];
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
textDyn[pos][i] = 0;
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
void GuiText::scrollText(uint32_t frameCount) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
2018-06-21 20:44:58 +02:00
|
|
|
if (textDyn.size() == 0) {
|
|
|
|
int32_t pos = textDyn.size();
|
|
|
|
int32_t i = 0, currentWidth = 0;
|
|
|
|
textDyn.resize(pos + 1);
|
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
textDyn[pos] = new(std::nothrow) wchar_t[maxWidth];
|
|
|
|
if (!textDyn[pos]) {
|
2018-06-21 20:44:58 +02:00
|
|
|
textDyn.resize(pos);
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (text[i] && currentWidth < maxWidth) {
|
|
|
|
textDyn[pos][i] = text[i];
|
|
|
|
|
|
|
|
currentWidth += font->getCharWidth(text[i], currentSize, i > 0 ? text[i - 1] : 0);
|
|
|
|
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
textDyn[pos][i] = 0;
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (frameCount % textScrollDelay != 0) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (textScrollInitialDelay) {
|
|
|
|
--textScrollInitialDelay;
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t stringlen = wcslen(text);
|
|
|
|
|
|
|
|
++textScrollPos;
|
|
|
|
if (textScrollPos > stringlen) {
|
|
|
|
textScrollPos = 0;
|
|
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t ch = textScrollPos;
|
|
|
|
int32_t pos = textDyn.size() - 1;
|
|
|
|
|
2020-08-13 12:58:19 +02:00
|
|
|
if (!textDyn[pos]) {
|
2020-08-13 12:38:07 +02:00
|
|
|
textDyn[pos] = new(std::nothrow) wchar_t[maxWidth];
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2018-06-21 20:44:58 +02:00
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
if (!textDyn[pos]) {
|
2018-06-21 20:44:58 +02:00
|
|
|
textDyn.resize(pos);
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t i = 0, currentWidth = 0;
|
|
|
|
|
|
|
|
while (currentWidth < maxWidth) {
|
|
|
|
if (ch > stringlen - 1) {
|
|
|
|
textDyn[pos][i++] = ' ';
|
|
|
|
currentWidth += font->getCharWidth(L' ', currentSize, ch > 0 ? text[ch - 1] : 0);
|
|
|
|
textDyn[pos][i++] = ' ';
|
|
|
|
currentWidth += font->getCharWidth(L' ', currentSize, L' ');
|
|
|
|
textDyn[pos][i++] = ' ';
|
|
|
|
currentWidth += font->getCharWidth(L' ', currentSize, L' ');
|
|
|
|
ch = 0;
|
|
|
|
|
2020-08-13 12:58:19 +02:00
|
|
|
if (currentWidth >= maxWidth) {
|
2018-06-21 20:44:58 +02:00
|
|
|
break;
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2018-06-21 20:44:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
textDyn[pos][i] = text[ch];
|
|
|
|
currentWidth += font->getCharWidth(text[ch], currentSize, ch > 0 ? text[ch - 1] : 0);
|
|
|
|
++ch;
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
textDyn[pos][i] = 0;
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
void GuiText::wrapText() {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
2020-08-16 14:14:00 +02:00
|
|
|
if (!text || textDyn.size() > 0) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
|
|
|
return;
|
|
|
|
}
|
2018-06-21 20:44:58 +02:00
|
|
|
|
|
|
|
int32_t i = 0;
|
|
|
|
int32_t ch = 0;
|
|
|
|
int32_t linenum = 0;
|
|
|
|
int32_t lastSpace = -1;
|
|
|
|
int32_t lastSpaceIndex = -1;
|
|
|
|
int32_t currentWidth = 0;
|
|
|
|
|
|
|
|
while (text[ch] && linenum < linestodraw) {
|
|
|
|
if (linenum >= (int32_t) textDyn.size()) {
|
|
|
|
textDyn.resize(linenum + 1);
|
2020-08-13 12:38:07 +02:00
|
|
|
textDyn[linenum] = new(std::nothrow) wchar_t[maxWidth];
|
|
|
|
if (!textDyn[linenum]) {
|
2018-06-21 20:44:58 +02:00
|
|
|
textDyn.resize(linenum);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
textDyn[linenum][i] = text[ch];
|
|
|
|
textDyn[linenum][i + 1] = 0;
|
|
|
|
|
|
|
|
currentWidth += font->getCharWidth(text[ch], currentSize, ch > 0 ? text[ch - 1] : 0x0000);
|
|
|
|
|
|
|
|
if (currentWidth >= maxWidth || (text[ch] == '\n')) {
|
2020-08-13 12:38:07 +02:00
|
|
|
if (text[ch] == '\n') {
|
2018-06-21 20:44:58 +02:00
|
|
|
lastSpace = -1;
|
|
|
|
lastSpaceIndex = -1;
|
|
|
|
} else if (lastSpace >= 0) {
|
|
|
|
textDyn[linenum][lastSpaceIndex] = 0; // discard space, and everything after
|
|
|
|
ch = lastSpace; // go backwards to the last space
|
|
|
|
lastSpace = -1; // we have used this space
|
|
|
|
lastSpaceIndex = -1;
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
2018-06-21 20:44:58 +02:00
|
|
|
|
|
|
|
if (linenum + 1 == linestodraw && text[ch + 1] != 0x0000) {
|
2020-08-13 12:58:19 +02:00
|
|
|
if (i < 2) {
|
2017-10-29 10:28:14 +01:00
|
|
|
i = 2;
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2018-06-21 20:44:58 +02:00
|
|
|
textDyn[linenum][i - 2] = '.';
|
|
|
|
textDyn[linenum][i - 1] = '.';
|
|
|
|
textDyn[linenum][i] = '.';
|
|
|
|
textDyn[linenum][i + 1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
currentWidth = 0;
|
|
|
|
++linenum;
|
|
|
|
i = -1;
|
|
|
|
}
|
|
|
|
if (text[ch] == ' ' && i >= 0) {
|
|
|
|
lastSpace = ch;
|
|
|
|
lastSpaceIndex = i;
|
|
|
|
}
|
|
|
|
++ch;
|
|
|
|
++i;
|
|
|
|
}
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2020-08-13 14:12:08 +02:00
|
|
|
/**
|
|
|
|
* We need to redefine this, because we don't want to use our width.
|
|
|
|
*/
|
|
|
|
float GuiText::getCenterX(void) {
|
|
|
|
float pCenterX = 0.0f;
|
|
|
|
|
|
|
|
if (parentElement) {
|
|
|
|
pCenterX = parentElement->getCenterX();
|
|
|
|
}
|
|
|
|
|
|
|
|
pCenterX += xoffset + xoffsetDyn;
|
|
|
|
|
|
|
|
if (alignment & ALIGN_LEFT) {
|
|
|
|
float pWidth = 0.0f;
|
|
|
|
float pScale = 0.0f;
|
|
|
|
|
|
|
|
if (parentElement) {
|
|
|
|
pWidth = parentElement->getWidth();
|
|
|
|
pScale = parentElement->getScaleX();
|
|
|
|
}
|
|
|
|
|
|
|
|
pCenterX -= pWidth * 0.5f * pScale;
|
|
|
|
} else if (alignment & ALIGN_RIGHT) {
|
|
|
|
float pWidth = 0.0f;
|
|
|
|
float pScale = 0.0f;
|
|
|
|
|
|
|
|
if (parentElement) {
|
|
|
|
pWidth = parentElement->getWidth();
|
|
|
|
pScale = parentElement->getScaleX();
|
|
|
|
}
|
|
|
|
|
|
|
|
pCenterX += pWidth * 0.5f * pScale;
|
|
|
|
}
|
|
|
|
return pCenterX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* We need to redefine this, because we don't want to use our height.
|
|
|
|
*/
|
|
|
|
float GuiText::getCenterY(void) {
|
|
|
|
float pCenterY = 0.0f;
|
|
|
|
|
|
|
|
if (parentElement) {
|
|
|
|
pCenterY = parentElement->getCenterY();
|
|
|
|
}
|
|
|
|
|
|
|
|
pCenterY += yoffset + yoffsetDyn;
|
|
|
|
|
|
|
|
if (alignment & ALIGN_TOP) {
|
|
|
|
float pHeight = 0.0f;
|
|
|
|
float pScale = 0.0f;
|
|
|
|
|
|
|
|
if (parentElement) {
|
|
|
|
pHeight = parentElement->getHeight();
|
|
|
|
pScale = parentElement->getScaleY();
|
|
|
|
}
|
|
|
|
|
|
|
|
pCenterY += pHeight * 0.5f * pScale;
|
|
|
|
} else if (alignment & ALIGN_BOTTOM) {
|
|
|
|
float pHeight = 0.0f;
|
|
|
|
float pScale = 0.0f;
|
|
|
|
|
|
|
|
if (parentElement) {
|
|
|
|
pHeight = parentElement->getHeight();
|
|
|
|
pScale = parentElement->getScaleY();
|
|
|
|
}
|
|
|
|
|
|
|
|
pCenterY -= pHeight * 0.5f * pScale;
|
|
|
|
}
|
|
|
|
return pCenterY;
|
|
|
|
}
|
|
|
|
|
2017-10-29 10:28:14 +01:00
|
|
|
/**
|
|
|
|
* Draw the text on screen
|
|
|
|
*/
|
2018-06-21 20:44:58 +02:00
|
|
|
void GuiText::draw(CVideo *pVideo) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.lock();
|
2020-08-13 12:58:19 +02:00
|
|
|
if (!text) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
return;
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 12:58:19 +02:00
|
|
|
if (!isVisible()) {
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2018-06-21 20:44:58 +02:00
|
|
|
return;
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
|
|
|
|
color[3] = getAlpha();
|
|
|
|
blurGlowColor[3] = blurAlpha * getAlpha();
|
|
|
|
|
2020-08-13 13:26:45 +02:00
|
|
|
auto internalRenderingScale = internalSSAA == 0 ? 1 : internalSSAA << 1;
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 13:26:45 +02:00
|
|
|
int32_t normal_size = currentSize * getScale();
|
|
|
|
int32_t internalRenderingSize = normal_size * internalRenderingScale;
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 13:26:45 +02:00
|
|
|
auto textWidth = font->getWidth(text, normal_size);
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 13:26:45 +02:00
|
|
|
float x_pos = getCenterX() * internalRenderingScale;
|
|
|
|
float y_pos = getCenterY() * internalRenderingScale;
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 14:12:26 +02:00
|
|
|
if (alignment & ALIGN_TOP) {
|
|
|
|
y_pos -= getLineHeight() * getScale() * internalRenderingScale;
|
|
|
|
} else if (alignment & ALIGN_BOTTOM) {
|
|
|
|
y_pos += getLineHeight() * getScale() * internalRenderingScale;
|
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
if (maxWidth > 0 && maxWidth <= textWidth) {
|
|
|
|
if (wrapMode == DOTTED) { // text dotted
|
2020-08-13 12:58:19 +02:00
|
|
|
if (textDyn.size() == 0) {
|
2018-06-21 20:44:58 +02:00
|
|
|
makeDottedText();
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
if (textDynWidth.size() != textDyn.size()) {
|
2017-10-29 10:28:14 +01:00
|
|
|
textDynWidth.resize(textDyn.size());
|
|
|
|
|
2020-08-13 12:58:19 +02:00
|
|
|
for (uint32_t i = 0; i < textDynWidth.size(); i++) {
|
2020-08-13 13:26:45 +02:00
|
|
|
textDynWidth[i] = font->getWidth(textDyn[i], internalRenderingSize);
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-08-13 12:58:19 +02:00
|
|
|
if (textDyn.size() > 0) {
|
2020-08-13 13:26:45 +02:00
|
|
|
font->drawText(pVideo, x_pos, y_pos, getDepth(), textDyn[textDyn.size() - 1], internalRenderingSize, color, alignment, textDynWidth[textDyn.size() - 1], defaultBlur, blurGlowIntensity, blurGlowColor, internalRenderingScale);
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2020-08-13 13:26:45 +02:00
|
|
|
return;
|
2020-08-13 12:38:07 +02:00
|
|
|
} else if (wrapMode == SCROLL_HORIZONTAL) {
|
2018-06-21 20:44:58 +02:00
|
|
|
scrollText(pVideo->getFrameCount());
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 12:58:19 +02:00
|
|
|
if (textDyn.size() > 0) {
|
2020-08-13 13:26:45 +02:00
|
|
|
font->drawText(pVideo, x_pos, y_pos, getDepth(), textDyn[textDyn.size() - 1], internalRenderingSize, color, alignment, maxWidth * internalRenderingScale * getScale(), defaultBlur, blurGlowIntensity, blurGlowColor,
|
|
|
|
internalRenderingScale);
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2020-08-13 13:26:45 +02:00
|
|
|
return;
|
2020-08-13 12:38:07 +02:00
|
|
|
} else if (wrapMode == WRAP) {
|
2020-08-13 12:58:19 +02:00
|
|
|
if (textDyn.size() == 0) {
|
2018-06-21 20:44:58 +02:00
|
|
|
wrapText();
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
|
2020-08-13 12:38:07 +02:00
|
|
|
if (textDynWidth.size() != textDyn.size()) {
|
2017-10-29 10:28:14 +01:00
|
|
|
textDynWidth.resize(textDyn.size());
|
|
|
|
|
2020-08-13 12:58:19 +02:00
|
|
|
for (uint32_t i = 0; i < textDynWidth.size(); i++) {
|
2020-08-13 13:26:45 +02:00
|
|
|
textDynWidth[i] = font->getWidth(textDyn[i], internalRenderingSize);
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|
|
|
|
|
2020-08-13 14:11:18 +02:00
|
|
|
float voffset = 0.0f;
|
2020-08-13 12:58:19 +02:00
|
|
|
if (alignment & ALIGN_MIDDLE) {
|
2020-08-13 14:11:18 +02:00
|
|
|
voffset = (float) (((int32_t) getLineHeight() * (textDyn.size() - 1)) >> 1) * internalRenderingScale;
|
2020-08-13 12:58:19 +02:00
|
|
|
}
|
2020-08-13 14:11:18 +02:00
|
|
|
float y_offset = 0.0f;
|
2020-08-13 12:38:07 +02:00
|
|
|
for (uint32_t i = 0; i < textDyn.size(); i++) {
|
2020-08-13 13:26:45 +02:00
|
|
|
font->drawText(pVideo, x_pos, y_pos + y_offset + voffset, getDepth(), textDyn[i], internalRenderingSize, color, alignment, textDynWidth[i], defaultBlur, blurGlowIntensity, blurGlowColor, internalRenderingScale);
|
2020-08-13 14:11:18 +02:00
|
|
|
y_offset -= getLineHeight() * getScale() * internalRenderingScale;
|
2018-06-21 20:44:58 +02:00
|
|
|
}
|
2020-08-13 14:05:28 +02:00
|
|
|
textMutex.unlock();
|
2020-08-13 13:26:45 +02:00
|
|
|
return;
|
2018-06-21 20:44:58 +02:00
|
|
|
}
|
|
|
|
}
|
2020-08-13 13:26:45 +02:00
|
|
|
auto newTextWidth = font->getWidth(text, internalRenderingSize);
|
|
|
|
font->drawText(pVideo, x_pos, y_pos, getDepth(), text, internalRenderingSize, color, alignment, newTextWidth, defaultBlur, blurGlowIntensity, blurGlowColor, internalRenderingScale);
|
|
|
|
textMutex.unlock();
|
2017-10-29 10:28:14 +01:00
|
|
|
}
|