mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-05 02:55:07 +01:00
6d6f0f2243
*Added a font scale factor to the settings. This font scale resizes the overall font sizes. Only full integer font sizes are supported. The font scale factor is multiplied to the font size of a text and the result is rounded and used as the font size. It's a good quick fix for too big fonts. *Fixed GAMEID_GAMETITLE folder game layout
577 lines
12 KiB
C++
577 lines
12 KiB
C++
/****************************************************************************
|
|
* libwiigui
|
|
*
|
|
* Tantric 2009
|
|
*
|
|
* gui_text.cpp
|
|
*
|
|
* GUI class definitions
|
|
***************************************************************************/
|
|
|
|
#include "gui.h"
|
|
#include "wstring.hpp"
|
|
#include "settings/CSettings.h"
|
|
|
|
#define MAX_LINES_TO_DRAW 9
|
|
|
|
static int presetSize = 18;
|
|
static int presetMaxWidth = 0;
|
|
static int presetAlignmentHor = 0;
|
|
static int presetAlignmentVert = 0;
|
|
static u16 presetStyle = 0;
|
|
static GXColor presetColor = (GXColor) {255, 255, 255, 255};
|
|
|
|
#define TEXT_SCROLL_DELAY 5
|
|
#define TEXT_SCROLL_INITIAL_DELAY 8
|
|
|
|
/**
|
|
* Constructor for the GuiText class.
|
|
*/
|
|
|
|
GuiText::GuiText(const char * t, int s, GXColor c)
|
|
{
|
|
text = NULL;
|
|
size = s;
|
|
currentSize = size;
|
|
color = c;
|
|
alpha = c.a;
|
|
style = FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE;
|
|
maxWidth = 0;
|
|
wrapMode = 0;
|
|
passChar = 0;
|
|
font = NULL;
|
|
linestodraw = MAX_LINES_TO_DRAW;
|
|
textScrollPos = 0;
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
|
textScrollDelay = TEXT_SCROLL_DELAY;
|
|
|
|
alignmentHor = ALIGN_CENTRE;
|
|
alignmentVert = ALIGN_MIDDLE;
|
|
|
|
if (t)
|
|
{
|
|
text = charToWideChar(t);
|
|
if (!text) return;
|
|
|
|
textWidth = fontSystem->getWidth(text, currentSize);
|
|
}
|
|
}
|
|
|
|
GuiText::GuiText(const wchar_t * t, int s, GXColor c)
|
|
{
|
|
text = NULL;
|
|
size = s;
|
|
currentSize = size;
|
|
color = c;
|
|
alpha = c.a;
|
|
style = FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE;
|
|
maxWidth = 0;
|
|
wrapMode = 0;
|
|
passChar = 0;
|
|
font = NULL;
|
|
linestodraw = MAX_LINES_TO_DRAW;
|
|
textScrollPos = 0;
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
|
textScrollDelay = TEXT_SCROLL_DELAY;
|
|
|
|
alignmentHor = ALIGN_CENTRE;
|
|
alignmentVert = ALIGN_MIDDLE;
|
|
|
|
if (t)
|
|
{
|
|
text = new (std::nothrow) wchar_t[wcslen(t) + 1];
|
|
if (!text) return;
|
|
|
|
wcscpy(text, t);
|
|
|
|
textWidth = fontSystem->getWidth(text, currentSize);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Constructor for the GuiText class, uses presets
|
|
*/
|
|
GuiText::GuiText(const char * t)
|
|
{
|
|
text = NULL;
|
|
size = presetSize;
|
|
currentSize = size;
|
|
color = presetColor;
|
|
alpha = presetColor.a;
|
|
style = presetStyle;
|
|
maxWidth = presetMaxWidth;
|
|
wrapMode = 0;
|
|
passChar = 0;
|
|
font = NULL;
|
|
linestodraw = MAX_LINES_TO_DRAW;
|
|
textScrollPos = 0;
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
|
textScrollDelay = TEXT_SCROLL_DELAY;
|
|
|
|
alignmentHor = presetAlignmentHor;
|
|
alignmentVert = presetAlignmentVert;
|
|
|
|
if (t)
|
|
{
|
|
text = charToWideChar(t);
|
|
if (!text) return;
|
|
|
|
textWidth = fontSystem->getWidth(text, currentSize);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Destructor for the GuiText class.
|
|
*/
|
|
GuiText::~GuiText()
|
|
{
|
|
if (text) delete[] text;
|
|
text = NULL;
|
|
|
|
if (font)
|
|
{
|
|
delete font;
|
|
font = NULL;
|
|
}
|
|
|
|
ClearDynamicText();
|
|
}
|
|
|
|
void GuiText::SetText(const char * t)
|
|
{
|
|
LOCK( this );
|
|
|
|
if (text) delete[] text;
|
|
text = NULL;
|
|
|
|
ClearDynamicText();
|
|
|
|
textScrollPos = 0;
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
|
|
|
if (t)
|
|
{
|
|
text = charToWideChar(t);
|
|
if (!text) return;
|
|
|
|
if (passChar != 0)
|
|
{
|
|
for (u8 i = 0; i < wcslen(text); i++)
|
|
text[i] = passChar;
|
|
}
|
|
|
|
textWidth = fontSystem->getWidth(text, currentSize);
|
|
}
|
|
}
|
|
|
|
void GuiText::SetTextf(const char *format, ...)
|
|
{
|
|
if (!format) SetText((char *) NULL);
|
|
|
|
char *tmp = 0;
|
|
va_list va;
|
|
va_start( va, format );
|
|
if ((vasprintf(&tmp, format, va) >= 0) && tmp)
|
|
{
|
|
SetText(tmp);
|
|
}
|
|
va_end( va );
|
|
|
|
if (tmp) free(tmp);
|
|
}
|
|
|
|
void GuiText::SetText(const wchar_t * t)
|
|
{
|
|
LOCK( this );
|
|
|
|
if (text) delete[] text;
|
|
text = NULL;
|
|
|
|
ClearDynamicText();
|
|
|
|
textScrollPos = 0;
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
|
|
|
if (t)
|
|
{
|
|
text = new (std::nothrow) wchar_t[wcslen(t) + 1];
|
|
if (!text) return;
|
|
|
|
wcscpy(text, t);
|
|
|
|
if (passChar != 0)
|
|
{
|
|
for (u8 i = 0; i < wcslen(text); i++)
|
|
text[i] = passChar;
|
|
}
|
|
|
|
textWidth = fontSystem->getWidth(text, currentSize);
|
|
}
|
|
}
|
|
|
|
void GuiText::ClearDynamicText()
|
|
{
|
|
for (u32 i = 0; i < textDyn.size(); i++)
|
|
{
|
|
if (textDyn[i]) delete[] textDyn[i];
|
|
}
|
|
textDyn.clear();
|
|
}
|
|
|
|
void GuiText::SetPresets(int sz, GXColor c, int w, u16 s, int h, int v)
|
|
{
|
|
presetSize = sz;
|
|
presetColor = c;
|
|
presetStyle = s;
|
|
presetMaxWidth = w;
|
|
presetAlignmentHor = h;
|
|
presetAlignmentVert = v;
|
|
}
|
|
|
|
void GuiText::SetFontSize(int s)
|
|
{
|
|
LOCK( this );
|
|
|
|
size = s;
|
|
}
|
|
|
|
void GuiText::SetMaxWidth(int width, int w)
|
|
{
|
|
LOCK( this );
|
|
|
|
maxWidth = width;
|
|
wrapMode = w;
|
|
|
|
if (w == SCROLL_HORIZONTAL)
|
|
{
|
|
textScrollPos = 0;
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
|
textScrollDelay = TEXT_SCROLL_DELAY;
|
|
}
|
|
|
|
ClearDynamicText();
|
|
}
|
|
|
|
void GuiText::SetPassChar(wchar_t p)
|
|
{
|
|
LOCK( this );
|
|
passChar = p;
|
|
}
|
|
|
|
void GuiText::SetColor(GXColor c)
|
|
{
|
|
LOCK( this );
|
|
color = c;
|
|
alpha = c.a;
|
|
}
|
|
|
|
void GuiText::SetStyle(u16 s)
|
|
{
|
|
LOCK( this );
|
|
style = s;
|
|
}
|
|
|
|
void GuiText::SetAlignment(int hor, int vert)
|
|
{
|
|
LOCK( this );
|
|
style = 0;
|
|
|
|
switch (hor)
|
|
{
|
|
case ALIGN_LEFT:
|
|
style |= FTGX_JUSTIFY_LEFT;
|
|
break;
|
|
case ALIGN_RIGHT:
|
|
style |= FTGX_JUSTIFY_RIGHT;
|
|
break;
|
|
default:
|
|
style |= FTGX_JUSTIFY_CENTER;
|
|
break;
|
|
}
|
|
switch (vert)
|
|
{
|
|
case ALIGN_TOP:
|
|
style |= FTGX_ALIGN_TOP;
|
|
break;
|
|
case ALIGN_BOTTOM:
|
|
style |= FTGX_ALIGN_BOTTOM;
|
|
break;
|
|
default:
|
|
style |= FTGX_ALIGN_MIDDLE;
|
|
break;
|
|
}
|
|
|
|
alignmentHor = hor;
|
|
alignmentVert = vert;
|
|
}
|
|
|
|
void GuiText::SetLinesToDraw(int l)
|
|
{
|
|
linestodraw = l;
|
|
}
|
|
|
|
int GuiText::GetTextWidth()
|
|
{
|
|
if (!text) return 0;
|
|
|
|
return fontSystem->getWidth(text, currentSize);
|
|
}
|
|
|
|
int GuiText::GetTextWidth(int ind)
|
|
{
|
|
if (ind < 0 || ind >= (int) textDyn.size()) return this->GetTextWidth();
|
|
|
|
return fontSystem->getWidth(textDyn[ind], currentSize);
|
|
}
|
|
|
|
int GuiText::GetTextMaxWidth()
|
|
{
|
|
return maxWidth;
|
|
}
|
|
|
|
const wchar_t * GuiText::GetDynText(int ind)
|
|
{
|
|
if (ind < 0 || ind >= (int) textDyn.size()) return text;
|
|
|
|
return textDyn[ind];
|
|
}
|
|
|
|
const wchar_t * GuiText::GetText()
|
|
{
|
|
return text;
|
|
}
|
|
|
|
/**
|
|
* Change font
|
|
*/
|
|
bool GuiText::SetFont(const u8 *fontbuffer, const u32 filesize)
|
|
{
|
|
if (!fontbuffer || !filesize) return false;
|
|
LOCK( this );
|
|
if (font)
|
|
{
|
|
delete font;
|
|
font = NULL;
|
|
}
|
|
font = new FreeTypeGX(fontbuffer, filesize);
|
|
textWidth = font->getWidth(text, currentSize);
|
|
|
|
return true;
|
|
}
|
|
|
|
void GuiText::MakeDottedText()
|
|
{
|
|
int pos = textDyn.size();
|
|
textDyn.resize(pos + 1);
|
|
|
|
int i = 0, currentWidth = 0;
|
|
textDyn[pos] = new wchar_t[maxWidth];
|
|
|
|
while (text[i])
|
|
{
|
|
currentWidth += (font ? font : fontSystem)->getCharWidth(text[i], currentSize, i > 0 ? text[i - 1] : 0x0000);
|
|
if (currentWidth >= maxWidth)
|
|
{
|
|
if (i > 3)
|
|
{
|
|
textDyn[pos][i - 3] = '.';
|
|
textDyn[pos][i - 2] = '.';
|
|
textDyn[pos][i - 1] = '.';
|
|
}
|
|
break;
|
|
}
|
|
|
|
textDyn[pos][i] = text[i];
|
|
|
|
i++;
|
|
}
|
|
textDyn[pos][i] = 0;
|
|
}
|
|
|
|
void GuiText::ScrollText()
|
|
{
|
|
if (textDyn.size() == 0)
|
|
{
|
|
int pos = textDyn.size();
|
|
int i = 0, currentWidth = 0;
|
|
textDyn.resize(pos + 1);
|
|
|
|
textDyn[pos] = new wchar_t[maxWidth];
|
|
|
|
while (text[i] && currentWidth < maxWidth-40)
|
|
{
|
|
textDyn[pos][i] = text[i];
|
|
|
|
currentWidth += (font ? font : fontSystem)->getCharWidth(text[i], currentSize, i > 0 ? text[i - 1] : 0x0000);
|
|
|
|
++i;
|
|
}
|
|
textDyn[pos][i] = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
if (frameCount % textScrollDelay != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (textScrollInitialDelay)
|
|
{
|
|
--textScrollInitialDelay;
|
|
return;
|
|
}
|
|
|
|
int strlen = wcslen(text);
|
|
|
|
++textScrollPos;
|
|
if (textScrollPos > strlen)
|
|
{
|
|
textScrollPos = 0;
|
|
textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY;
|
|
}
|
|
|
|
int ch = textScrollPos;
|
|
int pos = textDyn.size() - 1;
|
|
|
|
if (textDyn[pos]) delete[] textDyn[pos];
|
|
|
|
textDyn[pos] = new wchar_t[maxWidth];
|
|
|
|
int i = 0, currentWidth = 0;
|
|
|
|
while (currentWidth < maxWidth-40)
|
|
{
|
|
if (ch > strlen - 1)
|
|
{
|
|
textDyn[pos][i++] = ' ';
|
|
textDyn[pos][i++] = ' ';
|
|
textDyn[pos][i++] = ' ';
|
|
ch = 0;
|
|
}
|
|
|
|
textDyn[pos][i] = text[ch];
|
|
++ch;
|
|
++i;
|
|
|
|
currentWidth += (font ? font : fontSystem)->getCharWidth(text[ch], currentSize, ch > 0 ? text[ch - 1] : 0x0000);
|
|
}
|
|
textDyn[pos][i] = 0;
|
|
}
|
|
|
|
void GuiText::WrapText()
|
|
{
|
|
if (textDyn.size() > 0) return;
|
|
|
|
int i = 0;
|
|
int ch = 0;
|
|
int linenum = 0;
|
|
int lastSpace = -1;
|
|
int lastSpaceIndex = -1;
|
|
int currentWidth = 0;
|
|
|
|
while (text[ch] && linenum < linestodraw)
|
|
{
|
|
if (linenum >= (int) textDyn.size())
|
|
{
|
|
textDyn.resize(linenum + 1);
|
|
textDyn[linenum] = new wchar_t[maxWidth];
|
|
}
|
|
|
|
textDyn[linenum][i] = text[ch];
|
|
textDyn[linenum][i + 1] = 0;
|
|
|
|
currentWidth += (font ? font : fontSystem)->getCharWidth(text[ch], currentSize, ch > 0 ? text[ch - 1] : 0x0000);
|
|
|
|
if (currentWidth >= maxWidth)
|
|
{
|
|
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;
|
|
}
|
|
|
|
if (linenum + 1 == linestodraw && text[ch + 1] != 0x0000)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Draw the text on screen
|
|
*/
|
|
void GuiText::Draw()
|
|
{
|
|
if (!text) return;
|
|
|
|
if (!IsVisible()) return;
|
|
|
|
GXColor c = color;
|
|
c.a = GetAlpha();
|
|
|
|
int newSize = size * GetScale() * Settings.FontScaleFactor;
|
|
|
|
if (newSize != currentSize)
|
|
{
|
|
currentSize = newSize;
|
|
|
|
if (text) textWidth = (font ? font : fontSystem)->getWidth(text, currentSize);
|
|
}
|
|
|
|
if (maxWidth > 0 && maxWidth <= textWidth)
|
|
{
|
|
if (wrapMode == DOTTED) // text dotted
|
|
{
|
|
if (textDyn.size() == 0)
|
|
MakeDottedText();
|
|
|
|
if (textDyn.size() > 0)
|
|
(font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop(), 0, textDyn[textDyn.size() - 1], currentSize, c, style);
|
|
}
|
|
|
|
else if (wrapMode == SCROLL_HORIZONTAL)
|
|
{
|
|
ScrollText();
|
|
|
|
if (textDyn.size() > 0)
|
|
(font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop(), 0, textDyn[textDyn.size() - 1], currentSize, c, style);
|
|
}
|
|
else if (wrapMode == WRAP)
|
|
{
|
|
int lineheight = currentSize + 6;
|
|
int voffset = 0;
|
|
if (alignmentVert == ALIGN_MIDDLE) voffset = -(lineheight * textDyn.size()) / 2 + lineheight / 2;
|
|
|
|
if (textDyn.size() == 0) WrapText();
|
|
|
|
for (u32 i = 0; i < textDyn.size(); i++)
|
|
{
|
|
(font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop() + voffset + i * lineheight, 0, textDyn[i], currentSize, c, style);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(font ? font : fontSystem)->drawText(this->GetLeft(), this->GetTop(), 0, text, currentSize, c, style, textWidth);
|
|
}
|
|
this->UpdateEffects();
|
|
}
|