GRAPHICS: Implement rendering of rich MacText

This commit is contained in:
Eugene Sandulenko 2017-01-31 23:14:03 +01:00
parent c15e063bbd
commit d4e4a20cc5
2 changed files with 79 additions and 26 deletions

View file

@ -45,19 +45,22 @@ MacText::MacText(Common::String s, MacWindowManager *wm, const Font *font, int f
_bgcolor = bgcolor; _bgcolor = bgcolor;
_maxWidth = maxWidth; _maxWidth = maxWidth;
_textMaxWidth = 0; _textMaxWidth = 0;
_textMaxHeight = 0;
_surface = nullptr; _surface = nullptr;
_textAlignment = textAlignment; _textAlignment = textAlignment;
_interLinear = 0; // 0 pixels between the lines by default _interLinear = 0; // 0 pixels between the lines by default
splitString(_str);
_fullRefresh = true;
_defaultFormatting.font = font; _defaultFormatting.font = font;
_defaultFormatting.wm = wm; _defaultFormatting.wm = wm;
_currentFormatting = _defaultFormatting; _currentFormatting = _defaultFormatting;
splitString(_str);
recalcDims();
_fullRefresh = true;
} }
void MacText::splitString(Common::String &str) { void MacText::splitString(Common::String &str) {
@ -118,7 +121,7 @@ void MacText::splitString(Common::String &str) {
if (*s == '\r' || *s == '\n' || nextChunk) { if (*s == '\r' || *s == '\n' || nextChunk) {
Common::Array<Common::String> text; Common::Array<Common::String> text;
_textMaxWidth = MAX(_font->wordWrapText(tmp, _maxWidth, text), _textMaxWidth); _font->wordWrapText(tmp, _maxWidth, text);
tmp.clear(); tmp.clear();
if (text.size()) { if (text.size()) {
@ -163,7 +166,7 @@ void MacText::splitString(Common::String &str) {
if (tmp.size()) { if (tmp.size()) {
Common::Array<Common::String> text; Common::Array<Common::String> text;
_textMaxWidth = MAX(_font->wordWrapText(tmp, _maxWidth, text), _textMaxWidth); _font->wordWrapText(tmp, _maxWidth, text);
_textLines[curLine].chunks[curChunk].text = text[0]; _textLines[curLine].chunks[curChunk].text = text[0];
@ -183,22 +186,19 @@ void MacText::splitString(Common::String &str) {
} }
void MacText::reallocSurface() { void MacText::reallocSurface() {
int lineH = _font->getFontHeight() + _interLinear;
// round to closest 10 // round to closest 10
//TODO: work out why this rounding doesn't correctly fill the entire width //TODO: work out why this rounding doesn't correctly fill the entire width
//int requiredH = (_text.size() + (_text.size() * 10 + 9) / 10) * lineH //int requiredH = (_text.size() + (_text.size() * 10 + 9) / 10) * lineH
int requiredH = _text.size() * lineH;
int surfW = _textMaxWidth;
if (!_surface) { if (!_surface) {
_surface = new ManagedSurface(surfW, requiredH); _surface = new ManagedSurface(_textMaxWidth, _textMaxHeight);
return; return;
} }
if (_surface->h < requiredH) { if (_surface->h < _textMaxWidth) {
// realloc surface and copy old content // realloc surface and copy old content
ManagedSurface *n = new ManagedSurface(surfW, requiredH); ManagedSurface *n = new ManagedSurface(_textMaxWidth, _textMaxHeight);
n->blitFrom(*_surface, Common::Point(0, 0)); n->blitFrom(*_surface, Common::Point(0, 0));
delete _surface; delete _surface;
@ -208,7 +208,7 @@ void MacText::reallocSurface() {
void MacText::render() { void MacText::render() {
if (_fullRefresh) { if (_fullRefresh) {
render(0, _text.size()); render(0, _textLines.size());
_fullRefresh = false; _fullRefresh = false;
} }
@ -218,25 +218,23 @@ void MacText::render(int from, int to) {
reallocSurface(); reallocSurface();
from = MAX<int>(0, from); from = MAX<int>(0, from);
to = MIN<int>(to, _text.size()); to = MIN<int>(to, _textLines.size() - 1);
int lineH = _font->getFontHeight() + _interLinear;
int y = from * lineH;
// Clear the screen // Clear the screen
_surface->fillRect(Common::Rect(0, y, _surface->w, to * lineH), _bgcolor); _surface->fillRect(Common::Rect(0, _textLines[from].y, _surface->w, _textLines[to].y + getLineHeight(to)), _bgcolor);
for (int i = from; i < to; i++) { for (int i = from; i <= to; i++) {
int xOffset = 0; int xOffset = 0;
if (_textAlignment == kTextAlignRight) if (_textAlignment == kTextAlignRight)
xOffset = _textMaxWidth - _font->getStringWidth(_text[i]); xOffset = _textMaxWidth - getLineWidth(i);
else if (_textAlignment == kTextAlignCenter) else if (_textAlignment == kTextAlignCenter)
xOffset = (_textMaxWidth / 2) - (_font->getStringWidth(_text[i]) / 2); xOffset = (_textMaxWidth / 2) - (getLineWidth(i) / 2);
// TODO: _textMaxWidth, when -1, was not rendering ANY text. // TODO: _textMaxWidth, when -1, was not rendering ANY text.
_font->drawString(_surface, _text[i], xOffset, y, _maxWidth, _fgcolor); 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);
y += _font->getFontHeight() + _interLinear; xOffset += _textLines[i].chunks[j].getFont()->getStringWidth(_textLines[i].chunks[j].text);
}
} }
for (uint i = 0; i < _textLines.size(); i++) { for (uint i = 0; i < _textLines.size(); i++) {
@ -249,6 +247,50 @@ void MacText::render(int from, int to) {
} }
} }
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;
}
void MacText::draw(ManagedSurface *g, int x, int y, int w, int h, int xoff, int yoff) { void MacText::draw(ManagedSurface *g, int x, int y, int w, int h, int xoff, int yoff) {
render(); render();
@ -264,7 +306,10 @@ void MacText::draw(ManagedSurface *g, int x, int y, int w, int h, int xoff, int
void MacText::appendText(Common::String str) { void MacText::appendText(Common::String str) {
int oldLen = _text.size(); int oldLen = _text.size();
// TODO: Recalc length
splitString(str); splitString(str);
recalcDims();
render(oldLen + 1, _text.size()); render(oldLen + 1, _text.size());
} }
@ -272,10 +317,13 @@ void MacText::appendText(Common::String str) {
void MacText::replaceLastLine(Common::String str) { void MacText::replaceLastLine(Common::String str) {
int oldLen = MAX<int>(0, _text.size() - 1); int oldLen = MAX<int>(0, _text.size() - 1);
// TODO: Recalc length, adapt to _textLines
if (_text.size()) if (_text.size())
_text.pop_back(); _text.pop_back();
splitString(str); splitString(str);
recalcDims();
render(oldLen, _text.size()); render(oldLen, _text.size());
} }

View file

@ -76,11 +76,13 @@ struct MacFontRun {
struct MacTextLine { struct MacTextLine {
int width; int width;
int height; int height;
int y;
Common::Array<MacFontRun> chunks; Common::Array<MacFontRun> chunks;
MacTextLine() { MacTextLine() {
width = height = -1; width = height = -1;
y = 0;
} }
}; };
@ -101,8 +103,10 @@ public:
private: private:
void splitString(Common::String &s); void splitString(Common::String &s);
void render(int from, int to); void render(int from, int to);
void calcMaxWidth(); void recalcDims();
void reallocSurface(); void reallocSurface();
int getLineWidth(int line);
int getLineHeight(int line);
private: private:
MacWindowManager *_wm; MacWindowManager *_wm;
@ -117,6 +121,7 @@ private:
Common::Array<Common::String> _text; Common::Array<Common::String> _text;
int _textMaxWidth; int _textMaxWidth;
int _textMaxHeight;
Graphics::ManagedSurface *_surface; Graphics::ManagedSurface *_surface;
bool _fullRefresh; bool _fullRefresh;