2016-12-14 19:20:26 +01:00
|
|
|
/* 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 2
|
|
|
|
* 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2017-01-30 10:10:22 +01:00
|
|
|
#include "graphics/macgui/macfontmanager.h"
|
2016-12-14 19:20:26 +01:00
|
|
|
#include "graphics/macgui/mactext.h"
|
2017-01-30 10:10:22 +01:00
|
|
|
#include "graphics/macgui/macwindowmanager.h"
|
2016-12-14 19:37:45 +01:00
|
|
|
#include "graphics/font.h"
|
2016-12-14 19:20:26 +01:00
|
|
|
|
|
|
|
namespace Graphics {
|
|
|
|
|
2017-01-30 10:10:22 +01:00
|
|
|
const Font *MacFontRun::getFont() {
|
|
|
|
if (font)
|
|
|
|
return font;
|
|
|
|
|
|
|
|
MacFont macFont = MacFont(fontId, fontSize, textSlant);
|
|
|
|
|
|
|
|
font = wm->_fontMan->getFont(macFont);
|
|
|
|
|
|
|
|
return font;
|
|
|
|
}
|
|
|
|
|
|
|
|
MacText::MacText(Common::String s, MacWindowManager *wm, const Font *font, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment) {
|
2016-12-14 19:20:26 +01:00
|
|
|
_str = s;
|
2017-01-29 14:19:28 +01:00
|
|
|
_wm = wm;
|
2016-12-14 19:20:26 +01:00
|
|
|
_font = font;
|
2016-12-14 20:09:08 +01:00
|
|
|
_fgcolor = fgcolor;
|
|
|
|
_bgcolor = bgcolor;
|
2017-02-01 01:06:01 +01:00
|
|
|
_maxWidth = maxWidth - 1; // This seems to be correct. TODO: More testing is required
|
2017-01-17 22:15:43 +11:00
|
|
|
_textMaxWidth = 0;
|
2017-01-31 23:14:03 +01:00
|
|
|
_textMaxHeight = 0;
|
2016-12-20 21:18:15 +01:00
|
|
|
_surface = nullptr;
|
2017-01-17 22:15:43 +11:00
|
|
|
_textAlignment = textAlignment;
|
2016-12-14 20:09:08 +01:00
|
|
|
|
2017-01-28 12:14:49 +01:00
|
|
|
_interLinear = 0; // 0 pixels between the lines by default
|
2016-12-14 19:37:45 +01:00
|
|
|
|
2017-01-30 10:10:22 +01:00
|
|
|
_defaultFormatting.font = font;
|
|
|
|
_defaultFormatting.wm = wm;
|
2017-01-30 22:58:02 +01:00
|
|
|
|
|
|
|
_currentFormatting = _defaultFormatting;
|
2017-01-31 23:14:03 +01:00
|
|
|
|
|
|
|
splitString(_str);
|
|
|
|
|
|
|
|
recalcDims();
|
|
|
|
|
|
|
|
_fullRefresh = true;
|
2016-12-14 19:37:45 +01:00
|
|
|
}
|
|
|
|
|
2016-12-16 19:37:33 +01:00
|
|
|
void MacText::splitString(Common::String &str) {
|
|
|
|
const char *s = str.c_str();
|
2016-12-14 19:37:45 +01:00
|
|
|
|
|
|
|
Common::String tmp;
|
2016-12-19 09:26:56 +01:00
|
|
|
bool prevCR = false;
|
2016-12-14 19:37:45 +01:00
|
|
|
|
2017-01-31 09:52:51 +01:00
|
|
|
if (_textLines.empty()) {
|
|
|
|
_textLines.resize(1);
|
2017-01-31 22:35:06 +01:00
|
|
|
_textLines[0].chunks.push_back(_defaultFormatting);
|
2017-01-31 09:52:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int curLine = _textLines.size() - 1;
|
2017-01-31 22:35:06 +01:00
|
|
|
int curChunk = _textLines[curLine].chunks.size() - 1;
|
2017-01-31 09:52:51 +01:00
|
|
|
bool nextChunk = false;
|
2017-01-30 22:58:02 +01:00
|
|
|
|
2016-12-14 19:37:45 +01:00
|
|
|
while (*s) {
|
2017-01-29 00:53:41 +01:00
|
|
|
if (*s == '\001') {
|
|
|
|
s++;
|
|
|
|
if (*s == '\001') {
|
|
|
|
// Copy it verbatim
|
|
|
|
} else {
|
|
|
|
if (*s++ != '\015')
|
|
|
|
error("MacText: formatting error");
|
|
|
|
|
|
|
|
uint16 fontId = *s++; fontId = (fontId << 8) | *s++;
|
|
|
|
byte textSlant = *s++;
|
|
|
|
byte unk3f = *s++;
|
|
|
|
uint16 fontSize = *s++; fontSize = (fontSize << 8) | *s++;
|
|
|
|
uint16 palinfo1 = *s++; palinfo1 = (palinfo1 << 8) | *s++;
|
|
|
|
uint16 palinfo2 = *s++; palinfo2 = (palinfo2 << 8) | *s++;
|
|
|
|
uint16 palinfo3 = *s++; palinfo3 = (palinfo3 << 8) | *s++;
|
|
|
|
|
|
|
|
debug(8, "******** splitString: fontId: %d, textSlant: %d, unk3: %d, fontSize: %d, p0: %x p1: %x p2: %x",
|
|
|
|
fontId, textSlant, unk3f, fontSize, palinfo1, palinfo2, palinfo3);
|
|
|
|
|
2017-01-30 22:58:02 +01:00
|
|
|
_currentFormatting.setValues(_wm, fontId, textSlant, unk3f, fontSize, palinfo1, palinfo2, palinfo3);
|
|
|
|
|
2017-01-31 22:35:06 +01:00
|
|
|
if (_textLines[curLine].chunks[curChunk].text.empty()) {
|
|
|
|
_textLines[curLine].chunks[curChunk] = _currentFormatting;
|
2017-01-31 18:44:18 +01:00
|
|
|
continue;
|
|
|
|
} else {
|
2017-01-31 22:35:06 +01:00
|
|
|
_textLines[curLine].chunks.push_back(_currentFormatting);
|
2017-01-31 18:44:18 +01:00
|
|
|
}
|
2017-01-30 22:58:02 +01:00
|
|
|
|
2017-01-31 09:52:51 +01:00
|
|
|
nextChunk = true;
|
2017-01-29 00:53:41 +01:00
|
|
|
}
|
2017-01-31 09:52:51 +01:00
|
|
|
} else if (*s == '\n' && prevCR) { // trean \r\n as one
|
2016-12-14 19:37:45 +01:00
|
|
|
prevCR = false;
|
2017-01-15 18:42:50 +11:00
|
|
|
|
|
|
|
s++;
|
2016-12-14 19:37:45 +01:00
|
|
|
continue;
|
2017-01-31 09:52:51 +01:00
|
|
|
} else if (*s == '\r') {
|
|
|
|
prevCR = true;
|
2016-12-14 19:37:45 +01:00
|
|
|
}
|
|
|
|
|
2017-01-31 09:52:51 +01:00
|
|
|
if (*s == '\r' || *s == '\n' || nextChunk) {
|
|
|
|
Common::Array<Common::String> text;
|
2016-12-14 19:37:45 +01:00
|
|
|
|
2017-01-31 23:14:03 +01:00
|
|
|
_font->wordWrapText(tmp, _maxWidth, text);
|
2017-01-31 19:02:15 +01:00
|
|
|
tmp.clear();
|
2017-01-31 09:52:51 +01:00
|
|
|
|
2017-01-31 18:44:18 +01:00
|
|
|
if (text.size()) {
|
|
|
|
if (nextChunk) {
|
2017-01-31 22:35:06 +01:00
|
|
|
_textLines[curLine].chunks[curChunk].text += text[0];
|
2017-01-31 18:44:18 +01:00
|
|
|
curChunk++;
|
2017-01-31 09:52:51 +01:00
|
|
|
|
2017-01-31 18:44:18 +01:00
|
|
|
_text[curLine] += text[0];
|
2017-01-31 19:02:15 +01:00
|
|
|
|
2017-01-31 19:06:27 +01:00
|
|
|
nextChunk = false;
|
|
|
|
|
2017-01-31 19:02:15 +01:00
|
|
|
continue;
|
2017-01-31 18:44:18 +01:00
|
|
|
}
|
2017-01-31 09:52:51 +01:00
|
|
|
|
2017-01-31 19:02:15 +01:00
|
|
|
for (uint i = 0; i < text.size(); i++) {
|
2017-01-31 09:52:51 +01:00
|
|
|
_text.push_back(text[i]);
|
|
|
|
|
2017-01-31 22:35:06 +01:00
|
|
|
_textLines[curLine].chunks[curChunk].text = text[i];
|
2017-01-31 22:16:50 +01:00
|
|
|
|
2017-01-31 18:44:18 +01:00
|
|
|
curLine++;
|
|
|
|
_textLines.resize(curLine + 1);
|
2017-01-31 22:35:06 +01:00
|
|
|
_textLines[curLine].chunks.push_back(_currentFormatting);
|
2017-01-31 18:44:18 +01:00
|
|
|
curChunk = 0;
|
2017-01-31 09:52:51 +01:00
|
|
|
}
|
2017-01-31 19:06:27 +01:00
|
|
|
} else {
|
|
|
|
if (nextChunk) { // No text, replacing formatting
|
2017-01-31 22:35:06 +01:00
|
|
|
_textLines[curLine].chunks[curChunk] = _currentFormatting;
|
2017-01-31 19:06:27 +01:00
|
|
|
}
|
2017-01-31 09:52:51 +01:00
|
|
|
}
|
2016-12-14 19:37:45 +01:00
|
|
|
|
2017-01-31 18:44:18 +01:00
|
|
|
if (!nextChunk) // Don't skip next character
|
|
|
|
s++;
|
|
|
|
|
|
|
|
nextChunk = false;
|
2016-12-14 19:37:45 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp += *s;
|
2017-01-15 18:42:50 +11:00
|
|
|
s++;
|
2016-12-14 19:37:45 +01:00
|
|
|
}
|
|
|
|
|
2017-01-31 18:44:18 +01:00
|
|
|
if (tmp.size()) {
|
|
|
|
Common::Array<Common::String> text;
|
|
|
|
|
2017-01-31 23:14:03 +01:00
|
|
|
_font->wordWrapText(tmp, _maxWidth, text);
|
2017-01-31 18:44:18 +01:00
|
|
|
|
2017-01-31 22:35:06 +01:00
|
|
|
_textLines[curLine].chunks[curChunk].text = text[0];
|
2017-01-31 18:44:18 +01:00
|
|
|
|
|
|
|
_text.push_back(text[0]);
|
|
|
|
|
|
|
|
if (text.size() > 1) {
|
|
|
|
for (uint i = 1; i < text.size(); i++) {
|
|
|
|
_text.push_back(text[i]);
|
|
|
|
|
|
|
|
curLine++;
|
|
|
|
_textLines.resize(curLine + 1);
|
2017-01-31 22:35:06 +01:00
|
|
|
_textLines[curLine].chunks.push_back(_currentFormatting);
|
|
|
|
_textLines[curLine].chunks[0].text = text[i];
|
2017-01-31 18:44:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-14 19:37:45 +01:00
|
|
|
}
|
|
|
|
|
2016-12-16 19:37:33 +01:00
|
|
|
void MacText::reallocSurface() {
|
2016-12-20 21:18:15 +01:00
|
|
|
// round to closest 10
|
2017-01-15 18:42:50 +11:00
|
|
|
//TODO: work out why this rounding doesn't correctly fill the entire width
|
|
|
|
//int requiredH = (_text.size() + (_text.size() * 10 + 9) / 10) * lineH
|
2016-12-16 19:37:33 +01:00
|
|
|
|
2016-12-20 21:18:15 +01:00
|
|
|
if (!_surface) {
|
2017-01-31 23:14:03 +01:00
|
|
|
_surface = new ManagedSurface(_textMaxWidth, _textMaxHeight);
|
2016-12-20 21:18:15 +01:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-31 23:14:03 +01:00
|
|
|
if (_surface->h < _textMaxWidth) {
|
2016-12-20 21:18:15 +01:00
|
|
|
// realloc surface and copy old content
|
2017-01-31 23:14:03 +01:00
|
|
|
ManagedSurface *n = new ManagedSurface(_textMaxWidth, _textMaxHeight);
|
2016-12-20 21:18:15 +01:00
|
|
|
n->blitFrom(*_surface, Common::Point(0, 0));
|
|
|
|
|
|
|
|
delete _surface;
|
|
|
|
_surface = n;
|
2016-12-16 19:37:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 19:37:45 +01:00
|
|
|
void MacText::render() {
|
2016-12-14 20:09:08 +01:00
|
|
|
if (_fullRefresh) {
|
2017-01-31 23:14:03 +01:00
|
|
|
render(0, _textLines.size());
|
2016-12-14 20:09:08 +01:00
|
|
|
|
2016-12-20 21:07:54 +01:00
|
|
|
_fullRefresh = false;
|
|
|
|
}
|
|
|
|
}
|
2016-12-14 20:09:08 +01:00
|
|
|
|
2016-12-20 21:07:54 +01:00
|
|
|
void MacText::render(int from, int to) {
|
2016-12-20 21:19:13 +01:00
|
|
|
reallocSurface();
|
|
|
|
|
2016-12-20 21:07:54 +01:00
|
|
|
from = MAX<int>(0, from);
|
2017-01-31 23:14:03 +01:00
|
|
|
to = MIN<int>(to, _textLines.size() - 1);
|
2016-12-20 21:07:54 +01:00
|
|
|
|
|
|
|
// Clear the screen
|
2017-01-31 23:14:03 +01:00
|
|
|
_surface->fillRect(Common::Rect(0, _textLines[from].y, _surface->w, _textLines[to].y + getLineHeight(to)), _bgcolor);
|
2016-12-20 21:07:54 +01:00
|
|
|
|
2017-01-31 23:14:03 +01:00
|
|
|
for (int i = from; i <= to; i++) {
|
2017-01-17 22:15:43 +11:00
|
|
|
int xOffset = 0;
|
2017-01-28 12:14:49 +01:00
|
|
|
if (_textAlignment == kTextAlignRight)
|
2017-01-31 23:14:03 +01:00
|
|
|
xOffset = _textMaxWidth - getLineWidth(i);
|
2017-01-28 12:14:49 +01:00
|
|
|
else if (_textAlignment == kTextAlignCenter)
|
2017-01-31 23:14:03 +01:00
|
|
|
xOffset = (_textMaxWidth / 2) - (getLineWidth(i) / 2);
|
2016-12-20 21:07:54 +01:00
|
|
|
|
2017-01-31 23:14:03 +01:00
|
|
|
// TODO: _textMaxWidth, when -1, was not rendering ANY text.
|
|
|
|
for (uint j = 0; j < _textLines[i].chunks.size(); j++) {
|
|
|
|
_textLines[i].chunks[j].getFont()->drawString(_surface, _textLines[i].chunks[j].text, xOffset, _textLines[i].y, _maxWidth, _fgcolor);
|
|
|
|
xOffset += _textLines[i].chunks[j].getFont()->getStringWidth(_textLines[i].chunks[j].text);
|
|
|
|
}
|
2016-12-14 20:09:08 +01:00
|
|
|
}
|
2016-12-20 21:07:54 +01:00
|
|
|
|
2017-01-31 19:02:15 +01:00
|
|
|
for (uint i = 0; i < _textLines.size(); i++) {
|
|
|
|
debugN(4, "%2d ", i);
|
|
|
|
|
2017-01-31 22:35:06 +01:00
|
|
|
for (uint j = 0; j < _textLines[i].chunks.size(); j++)
|
|
|
|
debugN(4, "[%d] \"%s\"", _textLines[i].chunks[j].fontId, _textLines[i].chunks[j].text.c_str());
|
2017-01-31 19:02:15 +01:00
|
|
|
|
|
|
|
debug(4, "");
|
|
|
|
}
|
2016-12-14 19:20:26 +01:00
|
|
|
}
|
|
|
|
|
2017-01-31 23:14:03 +01:00
|
|
|
int MacText::getLineWidth(int line) {
|
|
|
|
if (line >= _textLines.size())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (_textLines[line].width != -1)
|
|
|
|
return _textLines[line].width;
|
|
|
|
|
|
|
|
int width = 0;
|
|
|
|
int height = 0;
|
|
|
|
|
|
|
|
for (uint i = 0; i < _textLines[line].chunks.size(); i++) {
|
|
|
|
width += _textLines[line].chunks[i].getFont()->getStringWidth(_textLines[line].chunks[i].text);
|
|
|
|
height = MAX(height, _textLines[line].chunks[i].getFont()->getFontHeight());
|
|
|
|
}
|
|
|
|
|
|
|
|
_textLines[line].width = width;
|
|
|
|
_textLines[line].height = height;
|
|
|
|
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int MacText::getLineHeight(int line) {
|
|
|
|
if (line >= _textLines.size())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
getLineWidth(line); // This calculates height also
|
|
|
|
|
|
|
|
return _textLines[line].height;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MacText::recalcDims() {
|
|
|
|
int y = 0;
|
|
|
|
_textMaxWidth = 0;
|
|
|
|
|
|
|
|
for (uint i = 0; i < _textLines.size(); i++) {
|
|
|
|
_textLines[i].y = y;
|
|
|
|
|
|
|
|
y += getLineHeight(i) + _interLinear;
|
|
|
|
_textMaxWidth = MAX(_textMaxWidth, getLineWidth(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
_textMaxHeight = y;
|
|
|
|
}
|
|
|
|
|
2016-12-15 18:18:12 +01:00
|
|
|
void MacText::draw(ManagedSurface *g, int x, int y, int w, int h, int xoff, int yoff) {
|
|
|
|
render();
|
|
|
|
|
2016-12-20 21:18:15 +01:00
|
|
|
if (x + w < _surface->w || y + h < _surface->h) {
|
2016-12-15 18:18:12 +01:00
|
|
|
g->fillRect(Common::Rect(x, y, x + w, y + w), _bgcolor);
|
|
|
|
}
|
|
|
|
|
2016-12-20 21:19:13 +01:00
|
|
|
g->blitFrom(*_surface, Common::Rect(MIN<int>(_surface->w, x), MIN<int>(_surface->h, y),
|
|
|
|
MIN<int>(_surface->w, x + w), MIN<int>(_surface->w, y + w)),
|
|
|
|
Common::Point(xoff, yoff));
|
2016-12-15 18:18:12 +01:00
|
|
|
}
|
|
|
|
|
2016-12-16 19:37:33 +01:00
|
|
|
void MacText::appendText(Common::String str) {
|
2016-12-20 21:18:15 +01:00
|
|
|
int oldLen = _text.size();
|
2016-12-16 19:37:33 +01:00
|
|
|
|
2017-01-31 23:14:03 +01:00
|
|
|
// TODO: Recalc length
|
|
|
|
|
2016-12-16 19:37:33 +01:00
|
|
|
splitString(str);
|
2017-01-31 23:14:03 +01:00
|
|
|
recalcDims();
|
2016-12-16 19:37:33 +01:00
|
|
|
|
2016-12-20 21:18:15 +01:00
|
|
|
render(oldLen + 1, _text.size());
|
2016-12-16 19:37:33 +01:00
|
|
|
}
|
|
|
|
|
2016-12-22 18:15:43 +01:00
|
|
|
void MacText::replaceLastLine(Common::String str) {
|
|
|
|
int oldLen = MAX<int>(0, _text.size() - 1);
|
|
|
|
|
2017-01-31 23:14:03 +01:00
|
|
|
// TODO: Recalc length, adapt to _textLines
|
|
|
|
|
2016-12-22 18:15:43 +01:00
|
|
|
if (_text.size())
|
|
|
|
_text.pop_back();
|
|
|
|
|
|
|
|
splitString(str);
|
2017-01-31 23:14:03 +01:00
|
|
|
recalcDims();
|
2016-12-22 18:15:43 +01:00
|
|
|
|
|
|
|
render(oldLen, _text.size());
|
|
|
|
}
|
|
|
|
|
2016-12-14 19:20:26 +01:00
|
|
|
} // End of namespace Graphics
|