/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program 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. * * This program 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 this program. If not, see . * */ #include "common/util.h" #include "qdengine/system/graphics/gr_dispatcher.h" #include "qdengine/system/graphics/UI_TextParser.h" namespace QDEngine { UI_TextParser::UI_TextParser(const grFont *font) : _font(font) { _outNodes.reserve(8); init(); } UI_TextParser::UI_TextParser(const UI_TextParser &src) { (*this) = src; } void UI_TextParser::operator= (const UI_TextParser &src) { _font = src._font; _outNodes.reserve(8); init(); } void UI_TextParser::init() { _tagWidth = 0; _lineWidth = 0; _lineBegin = 0; _pstr = 0; _fitIn = -1; _lastSpace = 0; _lastTagWidth = 0; _outNodes.clear(); _outNodes.push_back(OutNode()); _prevLineIndex = _outNodes.size() - 1; _size.set(0, fontHeight()); _lineCount = 1; } void UI_TextParser::setFont(const grFont *font) { _font = font; init(); } OutNodes::const_iterator UI_TextParser::getLineBegin(int lineNum) const { assert(lineNum >= 0); if (!lineNum) return _outNodes.begin(); if (lineNum >= _lineCount) return _outNodes.end(); for (auto it = _outNodes.begin(); it != _outNodes.end(); it++) { if (it->type == OutNode::NEW_LINE) if (lineNum-- == 0) return it; } assert(lineNum == 0); return _outNodes.end(); } bool UI_TextParser::testWidth(int width) { if (_fitIn < 0) return true; if (_lineWidth + _tagWidth + width > _fitIn) { if (_lastSpace != _lineBegin) { _outNodes.push_back(OutNode(_lineBegin, _lastSpace, _lastTagWidth)); _lineWidth += _lastTagWidth; endLine(); _lineBegin = _lastSpace + 1; _lastSpace = _lineBegin; _tagWidth -= _lastTagWidth; _lastTagWidth = 0; } else if (_lineWidth > 0) { assert(_lastTagWidth == 0); endLine(); testWidth(width); } else if (_tagWidth > 0) { putText(); endLine(); skipNode(); } return false; } return true; } void UI_TextParser::parseString(const char *text, int color, int fitIn) { if (!_font) setFont(grDispatcher::get_default_font()); assert(_font); init(); _fitIn = fitIn > 2 * fontHeight() ? fitIn : -1; _pstr = text; _lineBegin = text; _lastSpace = _lineBegin; while (byte cc = *_pstr) { if (cc == '\n') { putText(); ++_pstr; endLine(); skipNode(); continue; } if (cc < 32) { ++_pstr; continue; } if (cc == ' ') { _lastTagWidth = _tagWidth; _lastSpace = _pstr; } //if(useWildChars) if (cc == '&') { if (_pstr[1] != '&') { putText(); ++_pstr; getColor(color); continue; } else { addChar('&'); putText(); ++_pstr; skipNode(); continue; } } else if (cc == '<') { if (_pstr[1] != '<') { putText(); ++_pstr; _lineWidth += getToken(); continue; } else { addChar('<'); putText(); ++_pstr; skipNode(); continue; } } addChar((byte)cc); } putText(); _size.x = MAX(_size.x, _lineWidth); _outNodes[_prevLineIndex].width = _lineWidth; _size.y = fontHeight() * _lineCount; } int UI_TextParser::getToken() { char cc; while ((cc = *_pstr) && cc != '=' && cc != '>') ++_pstr; if (cc != '>') { while ((cc = *_pstr) && cc != ';' && cc != '>') ++_pstr; if (cc == ';') { while ((cc = *_pstr) && cc != '>') ++_pstr; } } if (!cc) { skipNode(); return 0; } /* switch(tag_len){ case 3: if(!strncmp(begin_tag, "img=", 4)){ string img_name(begin_tag + 4, begin_style ? begin_style : _pstr); if(const UI_Sprite* sprite = UI_SpriteReference(img_name.c_str())) if(!sprite->isEmpty()){ OutNode node; node.type = OutNode::SPRITE; node.sprite = sprite; node.style = getStyle(begin_style, _pstr); if((node.style & 0x03) != 2) node.width = sprite->size().xi(); else{ Vect2f size = sprite->size(); node.width = round(size.x / size.y * fontHeight()); } ++_pstr; testWidth(node.width); putNode(node); return node.width; } } break; }*/ ++_pstr; skipNode(); return 0; } int UI_TextParser::getStyle(const char *styleptr, const char *end) { if (!styleptr || *end != '>') return 0; char cc; while ((cc = *(++styleptr)) && cc != '=' && cc != '>'); if (cc != '=') return 0; int style = 0; while ((cc = *(++styleptr)) >= '0' && cc <= '9') style = style * 10 + (int)(cc - '0'); return style; } void UI_TextParser::getColor(int defColor) { int color = defColor; if (*_pstr != '>') { int s = 0; int i = 0; for (; i < 6; ++i, ++_pstr) if (char k = *_pstr) { int a = fromHex(k); if (a < 0) break; s |= a << (i * 4); } else break; if (i > 5) { color &= 0xFF000000; color |= s; } else { skipNode(); return; } } else ++_pstr; OutNode node(color); putNode(node); } } // namespace QDEngine