/**************************************************************************** * libwiigui * * Tantric 2009 * * gui_text.cpp * * GUI class definitions ***************************************************************************/ #include "gui.h" #include "../utils/gettext.h" static GXColor presetColor = (GXColor){255, 255, 255, 255}; static int currentSize = 0; static int presetSize = 0; static int presetMaxWidth = 0; static int presetAlignmentHor = 0; static int presetAlignmentVert = 0; static u16 presetStyle = 0; #define TEXT_SCROLL_DELAY 8 #define TEXT_SCROLL_INITIAL_DELAY 6 /** * Constructor for the GuiText class. */ GuiText::GuiText(const char * t, int s, GXColor c) { origText = NULL; text = NULL; size = s; color = c; alpha = c.a; style = FTGX_JUSTIFY_CENTER | FTGX_ALIGN_MIDDLE; maxWidth = 0; wrap = false; textDynNum = 0; textScroll = SCROLL_NONE; textScrollPos = 0; textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; textScrollDelay = TEXT_SCROLL_DELAY; alignmentHor = ALIGN_CENTRE; alignmentVert = ALIGN_MIDDLE; if(t) { origText = strdup(t); text = charToWideChar(gettext(t)); } } /** * Constructor for the GuiText class, uses presets */ GuiText::GuiText(const char * t) { origText = NULL; text = NULL; size = presetSize; color = presetColor; alpha = presetColor.a; style = presetStyle; maxWidth = presetMaxWidth; wrap = false; textDynNum = 0; textScroll = SCROLL_NONE; textScrollPos = 0; textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; textScrollDelay = TEXT_SCROLL_DELAY; alignmentHor = presetAlignmentHor; alignmentVert = presetAlignmentVert; if(t) { origText = strdup(t); text = charToWideChar(gettext(t)); } } /** * Destructor for the GuiText class. */ GuiText::~GuiText() { if(origText) free(origText); if(text) delete[] text; if(textDynNum > 0) { for(int i=0; i < textDynNum; i++) delete[] textDyn[i]; } } void GuiText::SetText(const char * t) { if(origText) free(origText); if(text) delete[] text; if(textDynNum > 0) { for(int i=0; i < textDynNum; i++) delete[] textDyn[i]; } origText = NULL; text = NULL; textDynNum = 0; textScrollPos = 0; textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; if(t) { origText = strdup(t); text = charToWideChar(gettext(t)); } } 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) { size = s; } void GuiText::SetMaxWidth(int width) { maxWidth = width; if(textDynNum > 0) { for(int i=0; i < textDynNum; i++) delete[] textDyn[i]; } textDynNum = 0; } void GuiText::SetWrap(bool w, int width) { wrap = w; maxWidth = width; if(textDynNum > 0) { for(int i=0; i < textDynNum; i++) delete[] textDyn[i]; } textDynNum = 0; } void GuiText::SetScroll(int s) { if(textScroll == s) return; if(textDynNum > 0) { for(int i=0; i < textDynNum; i++) delete[] textDyn[i]; } textDynNum = 0; textScroll = s; textScrollPos = 0; textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; textScrollDelay = TEXT_SCROLL_DELAY; } void GuiText::SetColor(GXColor c) { color = c; alpha = c.a; } void GuiText::SetStyle(u16 s) { style = s; } void GuiText::SetAlignment(int hor, int vert) { 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::ResetText() { if(!origText) return; if(text) delete[] text; text = charToWideChar(gettext(origText)); if(textDynNum > 0) { for(int i=0; i < textDynNum; i++) delete[] textDyn[i]; } textDynNum = 0; } /** * Draw the text on screen */ void GuiText::Draw() { if(!text) return; if(!this->IsVisible()) return; GXColor c = color; c.a = this->GetAlpha(); int newSize = size*this->GetScale(); if(newSize > MAX_FONT_SIZE) newSize = MAX_FONT_SIZE; if(newSize != currentSize) { ChangeFontSize(newSize); if(!fontSystem[newSize]) fontSystem[newSize] = new FreeTypeGX(newSize); currentSize = newSize; } if(maxWidth == 0) { fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), text, c, style); this->UpdateEffects(); return; } u32 maxChar = maxWidth*2.5 / (float)newSize; // approximate u32 textlen = wcslen(text); if(wrap) { if(textDynNum == 0) { u32 n = 0, ch = 0; int linenum = 0; int lastSpace = -1; int lastSpaceIndex = -1; while(ch < textlen && linenum < 20) { if(n == 0) textDyn[linenum] = new wchar_t[textlen + 1]; textDyn[linenum][n] = text[ch]; textDyn[linenum][n+1] = 0; if(text[ch] == ' ' || ch == textlen-1) { if(wcslen(textDyn[linenum]) >= maxChar) { 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; } ++linenum; n = -1; } else if(ch == textlen-1) { ++linenum; } } if(text[ch] == ' ' && n >= 0) { lastSpace = ch; lastSpaceIndex = n; } ++ch; ++n; } textDynNum = linenum; } int lineheight = newSize + 6; int voffset = 0; if(alignmentVert == ALIGN_MIDDLE) voffset = (lineheight >> 1) * (1-textDynNum); int left = this->GetLeft(); int top = this->GetTop() + voffset; for(int i=0; i < textDynNum; ++i) fontSystem[currentSize]->drawText(left, top+i*lineheight, textDyn[i], c, style); } else { if(textDynNum == 0) { textDynNum = 1; textDyn[0] = wcsdup(text); if(textlen > maxChar) textDyn[0][maxChar] = 0; } if(textScroll == SCROLL_HORIZONTAL) { if(textlen > maxChar && (FrameTimer % textScrollDelay == 0)) { if(textScrollInitialDelay) { --textScrollInitialDelay; } else { ++textScrollPos; if((u32)textScrollPos > textlen-1) { textScrollPos = 0; textScrollInitialDelay = TEXT_SCROLL_INITIAL_DELAY; } wcsncpy(textDyn[0], &text[textScrollPos], maxChar-1); u32 dynlen = wcslen(textDyn[0]); if(dynlen+2 < maxChar) { textDyn[0][dynlen] = ' '; textDyn[0][dynlen+1] = ' '; wcsncat(&textDyn[0][dynlen+2], text, maxChar - dynlen - 2); } } } } fontSystem[currentSize]->drawText(this->GetLeft(), this->GetTop(), textDyn[0], c, style); } this->UpdateEffects(); }