2006-01-27 15:43:23 +00:00
|
|
|
/* ScummVM - Scumm Interpreter
|
|
|
|
* Copyright (C) 2006 The ScummVM project
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
2006-02-11 10:08:56 +00:00
|
|
|
* $URL$
|
|
|
|
* $Id$
|
2006-01-27 15:43:23 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gui/theme.h"
|
2006-10-08 10:57:48 +00:00
|
|
|
#include "gui/eval.h"
|
|
|
|
|
|
|
|
#define THEME_VERSION 1
|
2006-01-27 15:43:23 +00:00
|
|
|
|
|
|
|
namespace GUI {
|
2006-10-08 12:00:19 +00:00
|
|
|
ThemeClassic::ThemeClassic(OSystem *system, const Common::String &config, const Common::ConfigFile *cfg) : Theme() {
|
|
|
|
_stylefile = config;
|
2006-01-27 15:43:23 +00:00
|
|
|
_system = system;
|
|
|
|
_initOk = false;
|
2006-10-08 10:57:48 +00:00
|
|
|
_font = 0;
|
2006-10-08 11:03:46 +00:00
|
|
|
_fontName.clear();
|
2006-01-27 15:43:23 +00:00
|
|
|
memset(&_screen, 0, sizeof(_screen));
|
2006-05-29 13:12:04 +00:00
|
|
|
#ifndef CT_NO_TRANSPARENCY
|
2006-01-27 15:43:23 +00:00
|
|
|
memset(&_dialog, 0, sizeof(_dialog));
|
|
|
|
#endif
|
|
|
|
_font = 0;
|
2006-10-08 10:57:48 +00:00
|
|
|
|
2006-10-08 18:49:25 +00:00
|
|
|
// 'classic' is always the built in one, we force it and
|
|
|
|
// ignore all 'classic' named config files
|
2006-10-08 19:24:31 +00:00
|
|
|
if (config.compareToIgnoreCase("classic (builtin)") != 0) {
|
2006-10-08 18:49:25 +00:00
|
|
|
if (cfg)
|
|
|
|
_configFile = *cfg;
|
|
|
|
else
|
|
|
|
loadConfigFile(_stylefile);
|
|
|
|
}
|
2006-01-27 15:43:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ThemeClassic::~ThemeClassic() {
|
|
|
|
deinit();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ThemeClassic::init() {
|
|
|
|
deinit();
|
|
|
|
_screen.create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(OverlayColor));
|
|
|
|
if (_screen.pixels) {
|
|
|
|
_initOk = true;
|
|
|
|
clearAll();
|
2006-10-08 10:57:48 +00:00
|
|
|
resetDrawArea();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isThemeLoadingRequired()) {
|
|
|
|
loadTheme(_defaultConfig);
|
|
|
|
loadTheme(_configFile, false);
|
|
|
|
|
|
|
|
setupConfig();
|
|
|
|
}
|
|
|
|
|
|
|
|
_bgcolor = _system->RGBToColor(_colors[kBGColor][0], _colors[kBGColor][1], _colors[kBGColor][2]);
|
|
|
|
_color = _system->RGBToColor(_colors[kColor][0], _colors[kColor][1], _colors[kColor][2]);
|
|
|
|
_shadowcolor = _system->RGBToColor(_colors[kShadowColor][0], _colors[kShadowColor][1], _colors[kShadowColor][2]);
|
|
|
|
_textcolor = _system->RGBToColor(_colors[kTextColor][0], _colors[kTextColor][1], _colors[kTextColor][2]);
|
|
|
|
_textcolorhi = _system->RGBToColor(_colors[kTextColorHi][0], _colors[kTextColorHi][1], _colors[kTextColorHi][2]);
|
2006-10-08 11:03:46 +00:00
|
|
|
if (_fontName.empty()) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (_screen.w >= 400 && _screen.h >= 300) {
|
|
|
|
_font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
|
|
|
|
} else {
|
|
|
|
_font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
|
|
|
|
}
|
|
|
|
}
|
2006-03-07 03:31:31 +00:00
|
|
|
|
2006-01-27 15:43:23 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeClassic::deinit() {
|
|
|
|
if (_initOk) {
|
|
|
|
_system->hideOverlay();
|
|
|
|
_screen.free();
|
|
|
|
_initOk = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeClassic::refresh() {
|
|
|
|
init();
|
2006-04-19 06:22:15 +00:00
|
|
|
if (_enabled)
|
|
|
|
_system->showOverlay();
|
2006-01-27 15:43:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeClassic::enable() {
|
2006-01-27 23:13:51 +00:00
|
|
|
init();
|
|
|
|
resetDrawArea();
|
2006-01-27 15:43:23 +00:00
|
|
|
_system->showOverlay();
|
|
|
|
clearAll();
|
2006-04-19 06:22:15 +00:00
|
|
|
_enabled = true;
|
2006-01-27 15:43:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeClassic::disable() {
|
|
|
|
_system->hideOverlay();
|
2006-04-19 06:22:15 +00:00
|
|
|
_enabled = false;
|
2006-01-27 15:43:23 +00:00
|
|
|
}
|
|
|
|
|
2006-04-02 00:56:21 +00:00
|
|
|
void ThemeClassic::openDialog(bool topDialog) {
|
2006-05-29 13:12:04 +00:00
|
|
|
#ifndef CT_NO_TRANSPARENCY
|
2006-01-27 15:43:23 +00:00
|
|
|
if (!_dialog) {
|
|
|
|
_dialog = new DialogState;
|
|
|
|
assert(_dialog);
|
|
|
|
// first dialog
|
|
|
|
_dialog->screen.create(_screen.w, _screen.h, sizeof(OverlayColor));
|
|
|
|
}
|
|
|
|
memcpy(_dialog->screen.pixels, _screen.pixels, _screen.pitch*_screen.h);
|
|
|
|
blendScreenToDialog();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeClassic::closeDialog() {
|
2006-05-29 13:12:04 +00:00
|
|
|
#ifndef CT_NO_TRANSPARENCY
|
2006-01-27 15:43:23 +00:00
|
|
|
if (_dialog) {
|
|
|
|
_dialog->screen.free();
|
|
|
|
delete _dialog;
|
|
|
|
_dialog = 0;
|
|
|
|
}
|
2006-04-11 16:28:00 +00:00
|
|
|
_forceRedraw = true;
|
2006-01-27 15:43:23 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeClassic::clearAll() {
|
|
|
|
if (!_initOk)
|
|
|
|
return;
|
|
|
|
_system->clearOverlay();
|
|
|
|
// FIXME: problem with the 'pitch'
|
|
|
|
_system->grabOverlay((OverlayColor*)_screen.pixels, _screen.w);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeClassic::drawAll() {
|
2006-04-11 16:28:00 +00:00
|
|
|
_forceRedraw = false;
|
2006-01-27 15:43:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeClassic::resetDrawArea() {
|
|
|
|
if (_initOk) {
|
|
|
|
_drawArea = Common::Rect(0, 0, _screen.w, _screen.h);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-14 16:29:56 +00:00
|
|
|
int ThemeClassic::getTabSpacing() const {
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
int ThemeClassic::getTabPadding() const {
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
2006-06-05 12:22:51 +00:00
|
|
|
void ThemeClassic::drawDialogBackground(const Common::Rect &r, uint16 hints, State state) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (!_initOk)
|
|
|
|
return;
|
2006-01-31 20:19:47 +00:00
|
|
|
|
2006-01-27 15:43:23 +00:00
|
|
|
restoreBackground(r);
|
2006-05-29 13:12:04 +00:00
|
|
|
|
|
|
|
#ifndef CT_NO_TRANSPARENCY
|
2006-04-11 16:28:00 +00:00
|
|
|
if ((hints & THEME_HINT_SAVE_BACKGROUND) && !(hints & THEME_HINT_FIRST_DRAW) && !_forceRedraw) {
|
2006-01-31 20:19:47 +00:00
|
|
|
addDirtyRect(r);
|
|
|
|
return;
|
|
|
|
}
|
2006-05-29 13:12:04 +00:00
|
|
|
#endif
|
2006-01-31 20:19:47 +00:00
|
|
|
|
2006-01-27 15:43:23 +00:00
|
|
|
box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
|
2006-01-31 20:19:47 +00:00
|
|
|
addDirtyRect(r, (hints & THEME_HINT_SAVE_BACKGROUND) != 0);
|
2006-01-27 15:43:23 +00:00
|
|
|
}
|
|
|
|
|
2006-06-05 12:22:51 +00:00
|
|
|
void ThemeClassic::drawText(const Common::Rect &r, const Common::String &str, State state, TextAlign align, bool inverted, int deltax, bool useEllipsis, FontStyle font) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (!_initOk)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!inverted) {
|
|
|
|
restoreBackground(r);
|
|
|
|
_font->drawString(&_screen, str, r.left, r.top, r.width(), getColor(state), convertAligment(align), deltax, useEllipsis);
|
|
|
|
} else {
|
|
|
|
_screen.fillRect(r, getColor(state));
|
|
|
|
_font->drawString(&_screen, str, r.left, r.top, r.width(), _bgcolor, convertAligment(align), deltax, useEllipsis);
|
|
|
|
}
|
|
|
|
|
|
|
|
addDirtyRect(r);
|
|
|
|
}
|
|
|
|
|
2006-06-05 12:22:51 +00:00
|
|
|
void ThemeClassic::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, State state) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (!_initOk)
|
|
|
|
return;
|
|
|
|
restoreBackground(r);
|
|
|
|
font->drawChar(&_screen, ch, r.left, r.top, getColor(state));
|
|
|
|
addDirtyRect(r);
|
|
|
|
}
|
|
|
|
|
2006-06-05 12:22:51 +00:00
|
|
|
void ThemeClassic::drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background, State state) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (!_initOk || background == kWidgetBackgroundNo)
|
|
|
|
return;
|
|
|
|
|
2006-02-13 18:00:04 +00:00
|
|
|
restoreBackground(r);
|
2006-05-29 13:12:04 +00:00
|
|
|
|
|
|
|
#ifndef CT_NO_TRANSPARENCY
|
2006-04-11 16:28:00 +00:00
|
|
|
if ((hints & THEME_HINT_SAVE_BACKGROUND) && !(hints & THEME_HINT_FIRST_DRAW) && !_forceRedraw) {
|
2006-02-13 18:00:04 +00:00
|
|
|
addDirtyRect(r);
|
|
|
|
return;
|
|
|
|
}
|
2006-05-29 13:12:04 +00:00
|
|
|
#endif
|
2006-02-13 18:00:04 +00:00
|
|
|
|
2006-01-27 15:43:23 +00:00
|
|
|
switch (background) {
|
|
|
|
case kWidgetBackgroundBorder:
|
|
|
|
box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
|
|
|
|
break;
|
|
|
|
|
2006-05-29 13:06:28 +00:00
|
|
|
//case kWidgetBackgroundPlain:
|
|
|
|
//case kWidgetBackgroundBorderSmall:
|
2006-01-27 15:43:23 +00:00
|
|
|
default:
|
2006-05-29 13:06:28 +00:00
|
|
|
box(r.left, r.top, r.width(), r.height());
|
2006-01-27 15:43:23 +00:00
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
2006-02-13 18:00:04 +00:00
|
|
|
addDirtyRect(r, (hints & THEME_HINT_SAVE_BACKGROUND) != 0);
|
2006-01-27 15:43:23 +00:00
|
|
|
}
|
|
|
|
|
2006-06-15 02:14:40 +00:00
|
|
|
void ThemeClassic::drawButton(const Common::Rect &r, const Common::String &str, State state, uint16 hints) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (!_initOk)
|
|
|
|
return;
|
|
|
|
restoreBackground(r);
|
|
|
|
|
|
|
|
drawWidgetBackground(r, 0, kWidgetBackgroundBorder, state);
|
|
|
|
|
|
|
|
const int off = (r.height() - _font->getFontHeight()) / 2;
|
|
|
|
_font->drawString(&_screen, str, r.left, r.top+off, r.width(), getColor(state), Graphics::kTextAlignCenter, 0, false);
|
|
|
|
|
|
|
|
addDirtyRect(r);
|
|
|
|
}
|
|
|
|
|
2006-06-05 12:22:51 +00:00
|
|
|
void ThemeClassic::drawSurface(const Common::Rect &r, const Graphics::Surface &surface, State state, int alpha, bool themeTrans) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (!_initOk)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Common::Rect rect(r.left, r.top, r.left + surface.w, r.top + surface.h);
|
|
|
|
rect.clip(_screen.w, _screen.h);
|
|
|
|
|
|
|
|
if (!rect.isValidRect())
|
|
|
|
return;
|
|
|
|
|
|
|
|
assert(surface.bytesPerPixel == sizeof(OverlayColor));
|
|
|
|
|
|
|
|
OverlayColor *src = (OverlayColor *)surface.pixels;
|
|
|
|
OverlayColor *dst = (OverlayColor *)_screen.getBasePtr(rect.left, rect.top);
|
|
|
|
|
|
|
|
int w = rect.width();
|
|
|
|
int h = rect.height();
|
|
|
|
|
|
|
|
while (h--) {
|
|
|
|
memcpy(dst, src, surface.pitch);
|
|
|
|
src += w;
|
|
|
|
// FIXME: this should be pitch
|
|
|
|
dst += _screen.w;
|
|
|
|
}
|
|
|
|
addDirtyRect(r);
|
|
|
|
}
|
|
|
|
|
2006-06-05 12:22:51 +00:00
|
|
|
void ThemeClassic::drawSlider(const Common::Rect &r, int width, State state) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (!_initOk)
|
|
|
|
return;
|
|
|
|
Common::Rect r2 = r;
|
|
|
|
|
|
|
|
restoreBackground(r);
|
|
|
|
|
|
|
|
box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
|
|
|
|
r2.left = r.left + 2;
|
|
|
|
r2.top = r.top + 2;
|
|
|
|
r2.bottom = r.bottom - 2;
|
|
|
|
r2.right = r2.left + width;
|
|
|
|
if (r2.right > r.right - 2) {
|
|
|
|
r2.right = r.right - 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
_screen.fillRect(r2, getColor(state));
|
|
|
|
|
|
|
|
addDirtyRect(r);
|
|
|
|
}
|
|
|
|
|
2006-06-05 12:22:51 +00:00
|
|
|
void ThemeClassic::drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, State state, TextAlign align) {
|
2006-04-18 18:40:33 +00:00
|
|
|
if (!_initOk)
|
|
|
|
return;
|
|
|
|
|
|
|
|
restoreBackground(r);
|
|
|
|
|
|
|
|
box(r.left, r.top, r.width(), r.height());
|
|
|
|
|
|
|
|
Common::Point p0, p1;
|
|
|
|
|
|
|
|
p0 = Common::Point(r.right + 1 - r.height() / 2, r.top + 4);
|
|
|
|
p1 = Common::Point(r.right + 1 - r.height() / 2, r.bottom - 4);
|
|
|
|
|
|
|
|
OverlayColor color = getColor(state);
|
|
|
|
|
|
|
|
// Evil HACK to draw filled triangles
|
|
|
|
// FIXME: The "big" version is pretty ugly.
|
|
|
|
for (; p1.y - p0.y > 1; p0.y++, p0.x--, p1.y--, p1.x++) {
|
|
|
|
_screen.drawLine(p0.x, p0.y, p1.x, p0.y, color);
|
|
|
|
_screen.drawLine(p0.x, p1.y, p1.x, p1.y, color);
|
|
|
|
}
|
|
|
|
|
2006-07-23 15:08:48 +00:00
|
|
|
if (!sel.empty()) {
|
2006-04-18 18:40:33 +00:00
|
|
|
Common::Rect text(r.left + 2, r.top + 3, r.right - 4, r.top + 3 + _font->getFontHeight());
|
|
|
|
_font->drawString(&_screen, sel, text.left, text.top, text.width(), color, convertAligment(align), deltax, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
addDirtyRect(r);
|
|
|
|
}
|
|
|
|
|
2006-06-05 12:22:51 +00:00
|
|
|
void ThemeClassic::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, State state) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (!_initOk)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Common::Rect r2 = r;
|
|
|
|
int checkBoxSize = getFontHeight();
|
|
|
|
if (checkBoxSize > r.height()) {
|
|
|
|
checkBoxSize = r.height();
|
|
|
|
}
|
|
|
|
r2.bottom = r2.top + checkBoxSize;
|
|
|
|
|
|
|
|
restoreBackground(r2);
|
|
|
|
|
|
|
|
box(r.left, r.top, checkBoxSize, checkBoxSize, _color, _shadowcolor);
|
|
|
|
|
|
|
|
if (checked) {
|
2006-01-31 14:38:42 +00:00
|
|
|
r2.top += 3;
|
|
|
|
r2.bottom = r.top + checkBoxSize - 4;
|
|
|
|
r2.left += 3;
|
|
|
|
r2.right = r.left + checkBoxSize - 4;
|
|
|
|
|
|
|
|
OverlayColor c = getColor(state);
|
|
|
|
|
|
|
|
// Draw a cross
|
|
|
|
_screen.drawLine(r2.left, r2.top, r2.right, r2.bottom, c);
|
|
|
|
_screen.drawLine(r2.left, r2.bottom, r2.right, r2.top, c);
|
|
|
|
|
|
|
|
if (r2.height() > 5) {
|
|
|
|
// Thicken the lines
|
|
|
|
_screen.drawLine(r2.left, r2.top + 1, r2.right - 1, r2.bottom, c);
|
|
|
|
_screen.drawLine(r2.left + 1, r2.top, r2.right, r2.bottom - 1, c);
|
|
|
|
_screen.drawLine(r2.left, r2.bottom - 1, r2.right - 1, r2.top, c);
|
|
|
|
_screen.drawLine(r2.left + 1, r2.bottom, r2.right, r2.top + 1, c);
|
|
|
|
}
|
|
|
|
|
2006-01-27 15:43:23 +00:00
|
|
|
r2 = r;
|
|
|
|
}
|
|
|
|
|
|
|
|
r2.left += checkBoxSize + 10;
|
2006-03-24 17:39:13 +00:00
|
|
|
_font->drawString(&_screen, str, r2.left, r2.top, r2.width(), getColor(state), Graphics::kTextAlignLeft, 0, true);
|
2006-01-27 15:43:23 +00:00
|
|
|
|
|
|
|
addDirtyRect(r);
|
|
|
|
}
|
|
|
|
|
2006-06-15 02:14:40 +00:00
|
|
|
void ThemeClassic::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, int titleVPad, State state) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (!_initOk)
|
|
|
|
return;
|
|
|
|
restoreBackground(r);
|
2006-02-13 18:00:04 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < (int)tabs.size(); ++i) {
|
|
|
|
if (i == active)
|
|
|
|
continue;
|
|
|
|
box(r.left + i * tabWidth, r.top+2, tabWidth, tabHeight-2, _color, _shadowcolor);
|
|
|
|
_font->drawString(&_screen, tabs[i], r.left + i * tabWidth, r.top+4, tabWidth, getColor(state), Graphics::kTextAlignCenter, 0, true);
|
|
|
|
}
|
|
|
|
|
2006-06-15 02:14:40 +00:00
|
|
|
if (active >= 0) {
|
|
|
|
box(r.left + active * tabWidth, r.top, tabWidth, tabHeight, _color, _shadowcolor, true);
|
|
|
|
_font->drawString(&_screen, tabs[active], r.left + active * tabWidth, r.top+titleVPad, tabWidth, getColor(kStateHighlight), Graphics::kTextAlignCenter, 0, true);
|
|
|
|
|
|
|
|
_screen.hLine(r.left, r.top + tabHeight, r.left + active * tabWidth + 1, _color);
|
|
|
|
_screen.hLine(r.left + active * tabWidth + tabWidth - 2, r.top + tabHeight, r.right, _color);
|
|
|
|
_screen.hLine(r.left, r.bottom - 1, r.right - 1, _shadowcolor);
|
|
|
|
_screen.vLine(r.left, r.top + tabHeight, r.bottom - 1, _color);
|
|
|
|
_screen.vLine(r.right - 1, r.top + tabHeight, r.bottom - 1, _shadowcolor);
|
|
|
|
}
|
2006-02-13 18:00:04 +00:00
|
|
|
|
2006-01-27 15:43:23 +00:00
|
|
|
addDirtyRect(r);
|
|
|
|
}
|
|
|
|
|
2006-06-05 12:22:51 +00:00
|
|
|
void ThemeClassic::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState scroll, State state) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (!_initOk)
|
|
|
|
return;
|
|
|
|
restoreBackground(r);
|
|
|
|
Common::Rect r2 = r;
|
|
|
|
box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
|
|
|
|
|
|
|
|
const int UP_DOWN_BOX_HEIGHT = r.width() + 1;
|
|
|
|
const int B = 3;
|
|
|
|
const int arrowSize = (r.width() / 2 - B + 1);
|
|
|
|
|
|
|
|
OverlayColor color = 0;
|
|
|
|
if (scroll == kScrollbarStateSinglePage) {
|
|
|
|
color = _color;
|
|
|
|
} else if (scroll == kScrollbarStateUp && state == kStateHighlight) {
|
|
|
|
color = _textcolorhi;
|
|
|
|
} else {
|
|
|
|
color = _textcolor;
|
|
|
|
}
|
|
|
|
|
|
|
|
// draws the 'up' button
|
|
|
|
box(r.left, r.top, r.width(), UP_DOWN_BOX_HEIGHT, _color, _shadowcolor);
|
|
|
|
Common::Point p0 = Common::Point(r.left + r.width() / 2, r.top + (UP_DOWN_BOX_HEIGHT - arrowSize - 1) / 2);
|
|
|
|
Common::Point p1 = Common::Point(p0.x - arrowSize, p0.y + arrowSize);
|
|
|
|
Common::Point p2 = Common::Point(p0.x + arrowSize, p0.y + arrowSize);
|
|
|
|
for (; p1.x <= p2.x; ++p1.x)
|
|
|
|
_screen.drawLine(p0.x, p0.y, p1.x, p1.y, color);
|
|
|
|
|
|
|
|
if (scroll != kScrollbarStateSinglePage) {
|
|
|
|
r2.top += sliderY;
|
|
|
|
r2.left += 2;
|
|
|
|
r2.right -= 2;
|
|
|
|
r2.bottom = r2.top + sliderHeight;
|
|
|
|
_screen.fillRect(r2, (state == kStateHighlight && scroll == kScrollbarStateSlider) ? _textcolorhi : _textcolor);
|
|
|
|
box(r2.left, r2.top, r2.width(), r2.height());
|
|
|
|
int y = r2.top + sliderHeight / 2;
|
|
|
|
color = (state == kStateHighlight && scroll == kScrollbarStateSlider) ? _color : _bgcolor;
|
|
|
|
_screen.hLine(r2.left + 1, y - 2, r2.right - 2, color);
|
|
|
|
_screen.hLine(r2.left + 1, y, r2.right - 2, color);
|
|
|
|
_screen.hLine(r2.left + 1, y + 2, r2.right - 2, color);
|
|
|
|
r2 = r;
|
|
|
|
}
|
|
|
|
|
|
|
|
r2.top = r2.bottom - UP_DOWN_BOX_HEIGHT;
|
|
|
|
if (scroll == kScrollbarStateSinglePage) {
|
|
|
|
color = _color;
|
|
|
|
} else if (scroll == kScrollbarStateDown && state == kStateHighlight) {
|
|
|
|
color = _textcolorhi;
|
|
|
|
} else {
|
|
|
|
color = _textcolor;
|
|
|
|
}
|
|
|
|
|
|
|
|
// draws the 'down' button
|
|
|
|
box(r2.left, r2.top, r2.width(), UP_DOWN_BOX_HEIGHT, _color, _shadowcolor);
|
|
|
|
p0 = Common::Point(r2.left + r2.width() / 2, r2.top + (UP_DOWN_BOX_HEIGHT + arrowSize + 1) / 2);
|
|
|
|
p1 = Common::Point(p0.x - arrowSize, p0.y - arrowSize);
|
|
|
|
p2 = Common::Point(p0.x + arrowSize, p0.y - arrowSize);
|
|
|
|
for (; p1.x <= p2.x; ++p1.x)
|
|
|
|
_screen.drawLine(p0.x, p0.y, p1.x, p1.y, color);
|
|
|
|
|
|
|
|
addDirtyRect(r);
|
|
|
|
}
|
|
|
|
|
2006-06-05 12:22:51 +00:00
|
|
|
void ThemeClassic::drawCaret(const Common::Rect &r, bool erase, State state) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (!_initOk)
|
|
|
|
return;
|
|
|
|
|
|
|
|
OverlayColor color = 0;
|
|
|
|
if (erase) {
|
|
|
|
color = _bgcolor;
|
|
|
|
} else {
|
|
|
|
color = getColor(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
_screen.vLine(r.left, r.top, r.bottom - 2, color);
|
|
|
|
addDirtyRect(r);
|
|
|
|
}
|
|
|
|
|
2006-06-05 12:22:51 +00:00
|
|
|
void ThemeClassic::drawLineSeparator(const Common::Rect &r, State state) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (!_initOk)
|
|
|
|
return;
|
|
|
|
_screen.hLine(r.left - 1, r.top + r.height() / 2, r.right, _shadowcolor);
|
|
|
|
_screen.hLine(r.left, r.top + 1 + r.height() / 2, r.right, _color);
|
|
|
|
addDirtyRect(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
// intern drawing
|
|
|
|
|
2006-05-27 05:46:04 +00:00
|
|
|
void ThemeClassic::restoreBackground(Common::Rect r, bool special) {
|
2006-01-27 15:43:23 +00:00
|
|
|
r.clip(_screen.w, _screen.h);
|
2006-01-31 20:19:47 +00:00
|
|
|
r.clip(_drawArea);
|
2006-05-29 13:12:04 +00:00
|
|
|
#ifdef CT_NO_TRANSPARENCY
|
2006-01-27 15:43:23 +00:00
|
|
|
_screen.fillRect(r, _bgcolor);
|
|
|
|
#else
|
|
|
|
if (_dialog) {
|
|
|
|
if (!_dialog->screen.pixels) {
|
|
|
|
_screen.fillRect(r, _bgcolor);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const OverlayColor *src = (const OverlayColor*)_dialog->screen.getBasePtr(r.left, r.top);
|
|
|
|
OverlayColor *dst = (OverlayColor*)_screen.getBasePtr(r.left, r.top);
|
|
|
|
|
|
|
|
int h = r.height();
|
|
|
|
int w = r.width();
|
|
|
|
while (h--) {
|
|
|
|
memcpy(dst, src, w*sizeof(OverlayColor));
|
|
|
|
src += _dialog->screen.w;
|
|
|
|
dst += _screen.w;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
_screen.fillRect(r, _bgcolor);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2006-05-27 05:46:04 +00:00
|
|
|
bool ThemeClassic::addDirtyRect(Common::Rect r, bool save, bool special) {
|
2006-01-27 15:43:23 +00:00
|
|
|
// TODO: implement proper dirty rect handling
|
|
|
|
// FIXME: problem with the 'pitch'
|
|
|
|
r.clip(_screen.w, _screen.h);
|
|
|
|
r.clip(_drawArea);
|
|
|
|
_system->copyRectToOverlay((OverlayColor*)_screen.getBasePtr(r.left, r.top), _screen.w, r.left, r.top, r.width(), r.height());
|
2006-05-29 13:12:04 +00:00
|
|
|
#ifndef CT_NO_TRANSPARENCY
|
2006-01-31 20:19:47 +00:00
|
|
|
if (_dialog && save) {
|
|
|
|
if (_dialog->screen.pixels) {
|
|
|
|
OverlayColor *dst = (OverlayColor*)_dialog->screen.getBasePtr(r.left, r.top);
|
|
|
|
const OverlayColor *src = (const OverlayColor*)_screen.getBasePtr(r.left, r.top);
|
|
|
|
int h = r.height();
|
|
|
|
while (h--) {
|
|
|
|
memcpy(dst, src, r.width()*sizeof(OverlayColor));
|
|
|
|
dst += _dialog->screen.w;
|
|
|
|
src += _screen.w;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-04-11 14:16:15 +00:00
|
|
|
#endif
|
2006-01-27 15:43:23 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-02-13 18:00:04 +00:00
|
|
|
void ThemeClassic::box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB, bool skipLastRow) {
|
2006-01-27 15:43:23 +00:00
|
|
|
if (y >= 0) {
|
|
|
|
_screen.hLine(x + 1, y, x + width - 2, colorA);
|
|
|
|
_screen.hLine(x, y + 1, x + width - 1, colorA);
|
|
|
|
}
|
|
|
|
int drawY = y;
|
|
|
|
if (drawY < 0) {
|
|
|
|
height += drawY;
|
|
|
|
drawY = 0;
|
|
|
|
}
|
|
|
|
_screen.vLine(x, drawY + 1, drawY + height - 2, colorA);
|
|
|
|
_screen.vLine(x + 1, drawY, drawY + height - 1, colorA);
|
2006-02-13 18:00:04 +00:00
|
|
|
_screen.vLine(x + width - 1, drawY + 1, drawY + height - 2, colorB);
|
|
|
|
_screen.vLine(x + width - 2, drawY + 1, drawY + height - 1, colorB);
|
2006-01-27 15:43:23 +00:00
|
|
|
|
2006-02-13 18:00:04 +00:00
|
|
|
if (y + height >= 0 && !skipLastRow) {
|
2006-01-27 15:43:23 +00:00
|
|
|
_screen.hLine(x + 1, drawY + height - 2, x + width - 1, colorB);
|
|
|
|
_screen.hLine(x + 1, drawY + height - 1, x + width - 2, colorB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeClassic::box(int x, int y, int w, int h) {
|
|
|
|
_screen.hLine(x, y, x + w - 1, _color);
|
|
|
|
_screen.hLine(x, y + h - 1, x +w - 1, _shadowcolor);
|
|
|
|
_screen.vLine(x, y, y + h - 1, _color);
|
|
|
|
_screen.vLine(x + w - 1, y, y + h - 1, _shadowcolor);
|
|
|
|
}
|
|
|
|
|
2006-06-05 12:22:51 +00:00
|
|
|
OverlayColor ThemeClassic::getColor(State state) {
|
2006-01-27 15:43:23 +00:00
|
|
|
OverlayColor usedColor = _color;
|
|
|
|
switch (state) {
|
|
|
|
case kStateEnabled:
|
|
|
|
usedColor = _textcolor;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kStateHighlight:
|
|
|
|
usedColor = _textcolorhi;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return usedColor;
|
|
|
|
}
|
|
|
|
|
2006-05-29 13:12:04 +00:00
|
|
|
#ifndef CT_NO_TRANSPARENCY
|
2006-01-27 15:43:23 +00:00
|
|
|
void ThemeClassic::blendScreenToDialog() {
|
|
|
|
Common::Rect rect(0, 0, _screen.w, _screen.h);
|
|
|
|
|
|
|
|
if (!rect.isValidRect())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha)) {
|
|
|
|
int a, r, g, b;
|
|
|
|
uint8 aa, ar, ag, ab;
|
|
|
|
_system->colorToARGB(_bgcolor, aa, ar, ag, ab);
|
|
|
|
a = aa*3/(3+1);
|
|
|
|
if (a < 1)
|
|
|
|
return;
|
|
|
|
r = ar * a;
|
|
|
|
g = ag * a;
|
|
|
|
b = ab * a;
|
|
|
|
|
|
|
|
OverlayColor *ptr = (OverlayColor*)_dialog->screen.getBasePtr(rect.left, rect.top);
|
|
|
|
|
|
|
|
int h = rect.height();
|
|
|
|
int w = rect.width();
|
|
|
|
while (h--) {
|
|
|
|
for (int i = 0; i < w; i++) {
|
|
|
|
_system->colorToARGB(ptr[i], aa, ar, ag, ab);
|
|
|
|
int a2 = aa + a - (a*aa)/255;
|
|
|
|
ptr[i] = _system->ARGBToColor(a2,
|
|
|
|
((255-a)*aa*ar/255+r)/a2,
|
|
|
|
((255-a)*aa*ag/255+g)/a2,
|
|
|
|
((255-a)*aa*ab/255+b)/a2);
|
|
|
|
}
|
|
|
|
ptr += _screen.w;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int r, g, b;
|
|
|
|
uint8 ar, ag, ab;
|
|
|
|
_system->colorToRGB(_bgcolor, ar, ag, ab);
|
|
|
|
r = ar * 3;
|
|
|
|
g = ag * 3;
|
|
|
|
b = ab * 3;
|
|
|
|
|
|
|
|
OverlayColor *ptr = (OverlayColor*)_dialog->screen.getBasePtr(rect.left, rect.top);
|
|
|
|
|
|
|
|
int h = rect.height();
|
|
|
|
int w = rect.width();
|
|
|
|
|
|
|
|
while (h--) {
|
|
|
|
for (int i = 0; i < w; i++) {
|
|
|
|
_system->colorToRGB(ptr[i], ar, ag, ab);
|
|
|
|
ptr[i] = _system->RGBToColor((ar + r) / (3+1),
|
|
|
|
(ag + g) / (3+1),
|
|
|
|
(ab + b) / (3+1));
|
|
|
|
}
|
|
|
|
ptr += _screen.w;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2006-10-08 10:57:48 +00:00
|
|
|
|
|
|
|
void ThemeClassic::setupConfig() {
|
|
|
|
if (_configFile.hasSection("theme")) {
|
2006-10-08 12:00:19 +00:00
|
|
|
if (loadConfig())
|
|
|
|
return;
|
2006-10-08 10:57:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const uint8 colors[][3] = {
|
|
|
|
{ 104, 104, 104 },
|
|
|
|
{ 64, 64, 64 },
|
|
|
|
{ 0, 0, 0, },
|
|
|
|
{ 32, 160, 32 },
|
|
|
|
{ 0, 255, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
memcpy(_colors, colors, sizeof(colors));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ThemeClassic::loadConfig() {
|
|
|
|
Common::String temp;
|
|
|
|
_configFile.getKey("version", "theme", temp);
|
|
|
|
if (atoi(temp.c_str()) != THEME_VERSION) {
|
|
|
|
// TODO: improve this detection and handle it nicer
|
|
|
|
warning("Theme config uses a different version (you have: '%s', needed is: '%d')", temp.c_str(), THEME_VERSION);
|
2006-10-08 12:00:19 +00:00
|
|
|
_configFile.clear();
|
|
|
|
|
|
|
|
// force a theme reload here
|
|
|
|
loadTheme(_defaultConfig);
|
2006-10-08 10:57:48 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
temp.clear();
|
|
|
|
_configFile.getKey("type", "theme", temp);
|
|
|
|
if (0 != temp.compareToIgnoreCase("classic")) {
|
|
|
|
warning("Theme config is not for the classic style theme");
|
2006-10-08 12:00:19 +00:00
|
|
|
_configFile.clear();
|
|
|
|
|
|
|
|
// force a theme reload here
|
|
|
|
loadTheme(_defaultConfig);
|
2006-10-08 10:57:48 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
getColorFromConfig("color", _colors[kColor][0], _colors[kColor][1], _colors[kColor][2]);
|
|
|
|
getColorFromConfig("shadowcolor", _colors[kShadowColor][0], _colors[kShadowColor][1], _colors[kShadowColor][2]);
|
|
|
|
getColorFromConfig("bgcolor", _colors[kBGColor][0], _colors[kBGColor][1], _colors[kBGColor][2]);
|
|
|
|
getColorFromConfig("textcolor", _colors[kTextColor][0], _colors[kTextColor][1], _colors[kTextColor][2]);
|
|
|
|
getColorFromConfig("textcolorhi", _colors[kTextColorHi][0], _colors[kTextColorHi][1], _colors[kTextColorHi][2]);
|
|
|
|
|
|
|
|
temp.clear();
|
|
|
|
temp = _evaluator->getStringVar("font");
|
2006-10-08 11:03:46 +00:00
|
|
|
if (temp.empty() || 0 == temp.compareToIgnoreCase("builtin")) {
|
|
|
|
if (!_fontName.empty())
|
2006-10-08 10:57:48 +00:00
|
|
|
delete _font;
|
2006-10-08 11:03:46 +00:00
|
|
|
_fontName.clear();
|
2006-10-08 10:57:48 +00:00
|
|
|
} else if (temp != _fontName) {
|
2006-10-08 11:03:46 +00:00
|
|
|
if (!_fontName.empty())
|
2006-10-08 10:57:48 +00:00
|
|
|
delete _font;
|
|
|
|
_font = loadFont(temp.c_str());
|
|
|
|
_fontName = temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-01-27 15:43:23 +00:00
|
|
|
} // end of namespace GUI
|
|
|
|
|