/* * Copyright 2010 OpenXcom Developers. * * This file is part of OpenXcom. * * OpenXcom 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. * * OpenXcom 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 OpenXcom. If not, see . */ #include "Text.h" #include #include "../Engine/Font.h" namespace OpenXcom { /** * Sets up a blank text with the specified size and position. * @param width Width in pixels. * @param height Height in pixels. * @param x X position in pixels. * @param y Y position in pixels. */ Text::Text(int width, int height, int x, int y) : Surface(width, height, x, y), _big(0), _small(0), _font(0), _text(L""), _wrap(false), _invert(false), _align(ALIGN_LEFT), _valign(ALIGN_TOP), _color(0) { } /** * */ Text::~Text() { } /** * Takes an integer value and formats it as currency, * spacing the thousands and adding a $ sign to the front. * @param funds The funding value. * @return The formatted string. */ std::wstring Text::formatFunding(int funds) { std::wstringstream ss; ss << funds; std::wstring s = ss.str(); size_t spacer = s.size() - 3; while (spacer > 0 && spacer < s.size()) { s.insert(spacer, L" "); spacer -= 3; } s.insert(0, L"$"); return s; } /** * Changes the text to use the big-size font. */ void Text::setBig() { _font = _big; } /** * Changes the text to use the small-size font. */ void Text::setSmall() { _font = _small; } /** * Returns the font currently used by the text. * @return Pointer to font. */ Font *const Text::getFont() const { return _font; } /** * Changes the various fonts for the text to use. * The different fonts need to be passed in advance since the * text size can change mid-text. * @param big Pointer to large-size font. * @param small Pointer to small-size font. */ void Text::setFonts(Font *big, Font *small) { _big = big; _small = small; _font = _small; } /** * Changes the string displayed on screen. * @param text Text string. */ void Text::setText(const std::wstring &text) { _text = text; processText(); } /** * Returns the string displayed on screen. * @return Text string. */ std::wstring Text::getText() const { return _text; } /** * Enables/disables text wordwrapping. When enabled, lines of * text are automatically split to ensure they stay within the * drawing area, otherwise they simply go off the edge. * @param wrap Wordwrapping setting. */ void Text::setWordWrap(bool wrap) { if (wrap != _wrap) { _wrap = wrap; processText(); } } /** * Enables/disables color inverting. Mostly used to make * button text look pressed along with the button. * @param invert Invert setting. */ void Text::setInvert(bool invert) { _invert = invert; draw(); } /** * Changes the way the text is aligned horizontally * relative to the drawing area. * @param align Horizontal alignment. */ void Text::setAlign(TextHAlign align) { _align = align; draw(); } /** * Changes the way the text is aligned vertically * relative to the drawing area. * @param valign Vertical alignment. */ void Text::setVerticalAlign(TextVAlign valign) { _valign = valign; draw(); } /** * Changes the color used to render the text. Unlike regular graphics, * fonts are greyscale so they need to be assigned a specific position * in the palette to be displayed. * @param color Color value. */ void Text::setColor(Uint8 color) { _color = color; draw(); } /** * Returns the color used to render the text. * @return Color value. */ Uint8 Text::getColor() const { return _color; } /** * Returns the rendered text's height. Useful to check if wordwrap applies. * @return height value. */ int Text::getTextHeight() { int height = 0; for (std::vector::iterator i = _lineHeight.begin(); i != _lineHeight.end(); i++) { height += *i; } return height; } /** * Takes care of any text post-processing like calculating * line metrics for alignment and wordwrapping if necessary. */ void Text::processText() { if (_font == 0) { return; } std::wstring *s = &_text; // Use a separate string for wordwrapping text if (_wrap) { _wrappedText = _text; s = &_wrappedText; } _lineWidth.clear(); _lineHeight.clear(); int width = 0, word = 0; std::wstring::iterator space = s->begin(); Font *font = _font; // Go through the text character by character for (std::wstring::iterator c = s->begin(); c <= s->end(); c++) { // End of the line if (c == s->end() || *c == '\n' || *c == 2) { // Add line measurements for alignment later _lineWidth.push_back(width); _lineHeight.push_back(font->getHeight() + font->getSpacing()); width = 0; word = 0; if (c == s->end()) break; else if (*c == 2) font = _small; } // Keep track of spaces for wordwrapping else if (*c == ' ') { space = c; width += font->getWidth() / 2; word = 0; } // Keep track of the width of the last line and word else { width += font->getChar(*c)->getCrop()->w + font->getSpacing(); word += font->getChar(*c)->getCrop()->w + font->getSpacing(); } // Wordwrap if the last word doesn't fit the line if (_wrap && width > getWidth()) { // Go back to the last space and put a linebreak there *space = '\n'; c = space - 1; width -= word + font->getWidth() / 2; } } draw(); } /** * Draws all the characters in the text with a really * nasty complex gritty text rendering algorithm logic stuff. */ void Text::draw() { clear(); if (_text.empty() || _font == 0) { return; } int x = 0, y = 0, line = 0, height = 0, pos = 0; Font *font = _font; std::wstring *s = &_text; for (std::vector::iterator i = _lineHeight.begin(); i != _lineHeight.end(); i++) { height += *i; } switch (_valign) { case ALIGN_TOP: y = 0; break; case ALIGN_MIDDLE: y = (getHeight() - height) / 2; break; case ALIGN_BOTTOM: y = getHeight() - height; break; } switch (_align) { case ALIGN_LEFT: x = 0; break; case ALIGN_CENTER: x = (getWidth() - _lineWidth[line]) / 2; break; case ALIGN_RIGHT: x = getWidth() - _lineWidth[line]; break; } if (_wrap) s = &_wrappedText; // Draw each letter one by one for (std::wstring::iterator c = s->begin(); c != s->end(); c++) { if (*c == ' ') { // panther: trim spaces on line begins if (pos>0) { x += font->getWidth() / 2; } } else if (*c == '\n' || *c == 2) { line++; pos = 0; y += font->getHeight() + font->getSpacing(); switch (_align) { case ALIGN_LEFT: x = 0; break; case ALIGN_CENTER: x = (getWidth() - _lineWidth[line]) / 2; break; case ALIGN_RIGHT: x = getWidth() - _lineWidth[line]; break; } if (*c == 2) font = _small; } else { Surface* chr = font->getChar(*c); chr->setX(x); chr->setY(y); chr->blit(this); x += chr->getCrop()->w + font->getSpacing(); pos += 1; } } this->offset(_color); if (_invert) { this->invert(_color + 3); } } }