aboutsummaryrefslogtreecommitdiff
path: root/gui/theme.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gui/theme.cpp')
-rw-r--r--gui/theme.cpp516
1 files changed, 516 insertions, 0 deletions
diff --git a/gui/theme.cpp b/gui/theme.cpp
new file mode 100644
index 0000000000..dfb8dcbebb
--- /dev/null
+++ b/gui/theme.cpp
@@ -0,0 +1,516 @@
+/* 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.
+ *
+ * $Header $
+ */
+
+#include "gui/theme.h"
+
+namespace GUI {
+ThemeClassic::ThemeClassic(OSystem *system) : Theme() {
+ _system = system;
+ _initOk = false;
+ memset(&_screen, 0, sizeof(_screen));
+#ifdef OLDGUI_TRANSPARENCY
+ memset(&_dialog, 0, sizeof(_dialog));
+#endif
+ _font = 0;
+
+ // Maybe change this filename
+ _configFile.loadFromFile("classic.ini");
+}
+
+ThemeClassic::~ThemeClassic() {
+ deinit();
+}
+
+bool ThemeClassic::init() {
+ deinit();
+ _screen.create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(OverlayColor));
+ if (_screen.pixels) {
+ _initOk = true;
+ clearAll();
+ _bgcolor = _system->RGBToColor(0, 0, 0);
+ _color = _system->RGBToColor(104, 104, 104);
+ _shadowcolor = _system->RGBToColor(64, 64, 64);
+ _textcolor = _system->RGBToColor(32, 160, 32);
+ _textcolorhi = _system->RGBToColor(0, 255, 0);
+ if (_screen.w >= 400 && _screen.h >= 300) {
+ _font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
+ } else {
+ _font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
+ }
+ }
+ return true;
+}
+
+void ThemeClassic::deinit() {
+ if (_initOk) {
+ _system->hideOverlay();
+ _screen.free();
+ _initOk = false;
+ }
+}
+
+void ThemeClassic::refresh() {
+ init();
+ _bgcolor = _system->RGBToColor(0, 0, 0);
+ _color = _system->RGBToColor(104, 104, 104);
+ _shadowcolor = _system->RGBToColor(64, 64, 64);
+ _textcolor = _system->RGBToColor(32, 160, 32);
+ _textcolorhi = _system->RGBToColor(0, 255, 0);
+ _system->showOverlay();
+}
+
+void ThemeClassic::enable() {
+ _system->showOverlay();
+ clearAll();
+}
+
+void ThemeClassic::disable() {
+ _system->hideOverlay();
+}
+
+void ThemeClassic::openDialog() {
+#ifdef OLDGUI_TRANSPARENCY
+ 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() {
+#ifdef OLDGUI_TRANSPARENCY
+ if (_dialog) {
+ _dialog->screen.free();
+ delete _dialog;
+ _dialog = 0;
+ }
+#endif
+}
+
+void ThemeClassic::clearAll() {
+ if (!_initOk)
+ return;
+ _system->clearOverlay();
+ // FIXME: problem with the 'pitch'
+ _system->grabOverlay((OverlayColor*)_screen.pixels, _screen.w);
+}
+
+void ThemeClassic::drawAll() {
+ if (!_initOk)
+ return;
+}
+
+void ThemeClassic::resetDrawArea() {
+ if (_initOk) {
+ _drawArea = Common::Rect(0, 0, _screen.w, _screen.h);
+ }
+}
+
+void ThemeClassic::drawDialogBackground(const Common::Rect &r, kState state, bool mainDialog) {
+ if (!_initOk)
+ return;
+
+ restoreBackground(r);
+ box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
+ addDirtyRect(r);
+}
+
+void ThemeClassic::drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis) {
+ 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);
+}
+
+void ThemeClassic::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state) {
+ if (!_initOk)
+ return;
+ restoreBackground(r);
+ font->drawChar(&_screen, ch, r.left, r.top, getColor(state));
+ addDirtyRect(r);
+}
+
+void ThemeClassic::drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background, kState state) {
+ if (!_initOk || background == kWidgetBackgroundNo)
+ return;
+
+ switch (background) {
+ case kWidgetBackgroundBorder:
+ restoreBackground(r);
+ box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
+ break;
+
+ case kWidgetBackgroundBorderSmall:
+ restoreBackground(r);
+ box(r.left, r.top, r.width(), r.height());
+ break;
+
+ case kWidgetBackgroundPlain:
+ restoreBackground(r);
+ break;
+
+ default:
+ break;
+ };
+
+ addDirtyRect(r);
+}
+
+void ThemeClassic::drawButton(const Common::Rect &r, const Common::String &str, kState state) {
+ 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);
+}
+
+void ThemeClassic::drawSurface(const Common::Rect &r, const Graphics::Surface &surface, kState state) {
+ 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);
+}
+
+void ThemeClassic::drawSlider(const Common::Rect &r, int width, kState state) {
+ 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);
+}
+
+void ThemeClassic::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, kState state) {
+ 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) {
+ // TODO: implement old style
+ r2.top += 2;
+ r2.bottom = r.top + checkBoxSize - 2;
+ r2.left += 2;
+ r2.right = r.left + checkBoxSize - 2;
+ _screen.fillRect(r2, getColor(state));
+ r2 = r;
+ }
+
+ r2.left += checkBoxSize + 10;
+ _font->drawString(&_screen, str, r2.left, r2.top, r2.width(), getColor(state), Graphics::kTextAlignCenter, 0, true);
+
+ addDirtyRect(r);
+}
+
+void ThemeClassic::drawTab(const Common::Rect &r, const Common::String &str, bool active, kState state) {
+ if (!_initOk)
+ return;
+ restoreBackground(r);
+ box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
+ _font->drawString(&_screen, str, r.left, r.top+2, r.width(), getColor(state), Graphics::kTextAlignCenter, 0, true);
+ addDirtyRect(r);
+}
+
+void ThemeClassic::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, kScrollbarState scroll, kState state) {
+ 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);
+}
+
+void ThemeClassic::drawCaret(const Common::Rect &r, bool erase, kState state) {
+ 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);
+}
+
+void ThemeClassic::drawLineSeparator(const Common::Rect &r, kState state) {
+ 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
+
+void ThemeClassic::restoreBackground(Common::Rect r) {
+ r.clip(_screen.w, _screen.h);
+#ifndef OLDGUI_TRANSPARENCY
+ _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
+}
+
+bool ThemeClassic::addDirtyRect(Common::Rect r) {
+ // 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());
+ return true;
+}
+
+void ThemeClassic::box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB) {
+ 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);
+
+ if (y + height >= 0) {
+ _screen.hLine(x + 1, drawY + height - 2, x + width - 1, colorB);
+ _screen.hLine(x + 1, drawY + height - 1, x + width - 2, colorB);
+ _screen.vLine(x + width - 1, drawY + 1, drawY + height - 2, colorB);
+ _screen.vLine(x + width - 2, drawY + 1, drawY + height - 1, 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);
+}
+
+OverlayColor ThemeClassic::getColor(kState state) {
+ OverlayColor usedColor = _color;
+ switch (state) {
+ case kStateEnabled:
+ usedColor = _textcolor;
+ break;
+
+ case kStateHighlight:
+ usedColor = _textcolorhi;
+ break;
+
+ default:
+ break;
+ }
+ return usedColor;
+}
+
+#ifdef OLDGUI_TRANSPARENCY
+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
+} // end of namespace GUI
+