mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-12-28 20:51:51 +01:00
87755f2543
*Fixed clock alignment *Restrict text scrolling to the right pixel size
578 lines
12 KiB
C++
578 lines
12 KiB
C++
/****************************************************************************
|
|
* libwiigui
|
|
*
|
|
* Tantric 2009
|
|
*
|
|
* gui_text.cpp
|
|
*
|
|
* GUI class definitions
|
|
***************************************************************************/
|
|
|
|
#include "gui.h"
|
|
#include "wstring.hpp"
|
|
|
|
#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();
|
|
|
|
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();
|
|
}
|