usbloadergx/source/libwiigui/gui_text.cpp

601 lines
11 KiB
C++
Raw Normal View History

/****************************************************************************
* 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)
{
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)
{
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();
}