aboutsummaryrefslogtreecommitdiff
path: root/gui/ThemeNew.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gui/ThemeNew.cpp')
-rw-r--r--gui/ThemeNew.cpp801
1 files changed, 801 insertions, 0 deletions
diff --git a/gui/ThemeNew.cpp b/gui/ThemeNew.cpp
new file mode 100644
index 0000000000..c707134d8a
--- /dev/null
+++ b/gui/ThemeNew.cpp
@@ -0,0 +1,801 @@
+/* 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"
+
+#include "graphics/imageman.h"
+#include "graphics/imagedec.h"
+
+#include "common/config-manager.h"
+#include "common/file.h"
+
+#include "common/unzip.h"
+
+using Graphics::Surface;
+
+/** Specifies the currently active 16bit pixel format, 555 or 565. */
+extern int gBitFormat;
+
+static void getColorFromConfig(const Common::ConfigFile &cfg, const Common::String &value, OverlayColor &color) {
+ Common::String temp;
+ cfg.getKey(value, "colors", temp);
+ int r, g, b;
+ sscanf(temp.c_str(), "%d %d %d", &r, &g, &b);
+ color = OSystem::instance().RGBToColor(r, g, b);
+}
+
+namespace GUI {
+ThemeNew::ThemeNew(OSystem *system, Common::String stylefile) : Theme(), _system(system), _screen(), _initOk(false),
+_forceRedraw(false), _font(0), _imageHandles(0), _images(0), _colors() {
+ _initOk = false;
+ memset(&_screen, 0, sizeof(_screen));
+ memset(&_dialog, 0, sizeof(_dialog));
+ memset(&_colors, 0, sizeof(_colors));
+
+ _screen.create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(OverlayColor));
+ if (_screen.pixels) {
+ _initOk = true;
+ clearAll();
+ if (_screen.w >= 400 && _screen.h >= 300) {
+ _font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
+ } else {
+ _font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
+ }
+ }
+
+ if (ConfMan.hasKey("extrapath")) {
+ Common::File::addDefaultDirectory(ConfMan.get("extrapath"));
+ }
+ if (ConfMan.hasKey("themepath")) {
+ Common::File::addDefaultDirectory(ConfMan.get("themepath"));
+ }
+ ImageMan.addArchive(stylefile + ".zip");
+
+ if (!_configFile.loadFromFile(stylefile + ".ini")) {
+#ifdef USE_ZLIB
+ // Maybe find a nicer solution to this
+ unzFile zipFile = unzOpen((stylefile + ".zip").c_str());
+ if (zipFile == NULL) return;
+ if (unzLocateFile(zipFile, (stylefile + ".ini").c_str(), 2) == UNZ_OK) {
+ unz_file_info fileInfo;
+ unzOpenCurrentFile(zipFile);
+ unzGetCurrentFileInfo(zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
+ uint8 *buffer = new uint8[fileInfo.uncompressed_size];
+ assert(buffer);
+ unzReadCurrentFile(zipFile, buffer, fileInfo.uncompressed_size);
+ unzCloseCurrentFile(zipFile);
+ Common::MemoryReadStream stream(buffer, fileInfo.uncompressed_size);
+ if (!_configFile.loadFromStream(stream)) {
+ warning("Can not find theme config file '%s'", (stylefile + ".ini").c_str());
+ unzClose(zipFile);
+ return;
+ }
+ delete [] buffer;
+ buffer = 0;
+ } else {
+ warning("Can not find theme config file '%s'", (stylefile + ".ini").c_str());
+ return;
+ }
+ unzClose(zipFile);
+#else
+ warning("Can not find theme config file '%s'", (stylefile + ".ini").c_str());
+ return;
+#endif
+ }
+
+ Common::String temp = "";
+ _configFile.getKey("version", "theme", temp);
+ if (temp != "1") {
+ // TODO: improve this detection and handle it nicer
+ warning("Theme config uses a different version");
+ return;
+ }
+
+ static Common::String imageHandlesTable[kImageHandlesMax];
+ _configFile.getKey("dialog_corner", "pixmaps", imageHandlesTable[kDialogBkgdCorner]);
+ _configFile.getKey("dialog_top", "pixmaps", imageHandlesTable[kDialogBkgdTop]);
+ _configFile.getKey("dialog_left", "pixmaps", imageHandlesTable[kDialogBkgdLeft]);
+ _configFile.getKey("dialog_bkgd", "pixmaps", imageHandlesTable[kDialogBkgd]);
+ _configFile.getKey("widget_corner", "pixmaps", imageHandlesTable[kWidgetBkgdCorner]);
+ _configFile.getKey("widget_top", "pixmaps", imageHandlesTable[kWidgetBkgdTop]);
+ _configFile.getKey("widget_left", "pixmaps", imageHandlesTable[kWidgetBkgdLeft]);
+ _configFile.getKey("widget_bkgd", "pixmaps", imageHandlesTable[kWidgetBkgd]);
+ _configFile.getKey("checkbox_empty", "pixmaps", imageHandlesTable[kCheckboxEmpty]);
+ _configFile.getKey("checkbox_checked", "pixmaps", imageHandlesTable[kCheckboxChecked]);
+ _configFile.getKey("widget_arrow", "pixmaps", imageHandlesTable[kWidgetArrow]);
+
+ getColorFromConfig(_configFile, "main_dialog_start", _colors[kMainDialogStart]);
+ getColorFromConfig(_configFile, "main_dialog_end", _colors[kMainDialogEnd]);
+
+ getColorFromConfig(_configFile, "dialog_start", _colors[kDialogStart]);
+ getColorFromConfig(_configFile, "dialog_end", _colors[kDialogEnd]);
+
+ getColorFromConfig(_configFile, "color_state_disabled", _colors[kColorStateDisabled]);
+ getColorFromConfig(_configFile, "color_state_highlight", _colors[kColorStateHighlight]);
+ getColorFromConfig(_configFile, "color_state_enabled", _colors[kColorStateEnabled]);
+ getColorFromConfig(_configFile, "color_transparency", _colors[kColorTransparency]);
+
+ getColorFromConfig(_configFile, "text_inverted_background", _colors[kTextInvertedBackground]);
+ getColorFromConfig(_configFile, "text_inverted_color", _colors[kTextInvertedColor]);
+
+ getColorFromConfig(_configFile, "widget_bkgd_start", _colors[kWidgetBackgroundStart]);
+ getColorFromConfig(_configFile, "widget_bkgd_end", _colors[kWidgetBackgroundEnd]);
+ getColorFromConfig(_configFile, "widget_bkgd_small_start", _colors[kWidgetBackgroundSmallStart]);
+ getColorFromConfig(_configFile, "widget_bkgd_small_end", _colors[kWidgetBackgroundSmallEnd]);
+
+ getColorFromConfig(_configFile, "button_bkgd_start", _colors[kButtonBackgroundStart]);
+ getColorFromConfig(_configFile, "button_bkgd_end", _colors[kButtonBackgroundEnd]);
+ getColorFromConfig(_configFile, "button_text_enabled", _colors[kButtonTextEnabled]);
+ getColorFromConfig(_configFile, "button_text_disabled", _colors[kButtonTextDisabled]);
+ getColorFromConfig(_configFile, "button_text_highlight", _colors[kButtonTextHighlight]);
+
+ getColorFromConfig(_configFile, "slider_background_start", _colors[kSliderBackgroundStart]);
+ getColorFromConfig(_configFile, "slider_background_end", _colors[kSliderBackgroundEnd]);
+ getColorFromConfig(_configFile, "slider_start", _colors[kSliderStart]);
+ getColorFromConfig(_configFile, "slider_end", _colors[kSliderEnd]);
+
+ getColorFromConfig(_configFile, "tab_background_start", _colors[kTabBackgroundStart]);
+ getColorFromConfig(_configFile, "tab_background_end", _colors[kTabBackgroundEnd]);
+
+ getColorFromConfig(_configFile, "scrollbar_background_start", _colors[kScrollbarBackgroundStart]);
+ getColorFromConfig(_configFile, "scrollbar_background_end", _colors[kScrollbarBackgroundEnd]);
+ getColorFromConfig(_configFile, "scrollbar_button_start", _colors[kScrollbarButtonStart]);
+ getColorFromConfig(_configFile, "scrollbar_button_end", _colors[kScrollbarButtonEnd]);
+ getColorFromConfig(_configFile, "scrollbar_slider_start", _colors[kScrollbarSliderStart]);
+ getColorFromConfig(_configFile, "scrollbar_slider_end", _colors[kScrollbarSliderEnd]);
+
+ getColorFromConfig(_configFile, "caret_color", _colors[kCaretColor]);
+
+ _imageHandles = imageHandlesTable;
+
+ _images = new const Graphics::Surface*[ARRAYSIZE(imageHandlesTable)];
+ assert(_images);
+
+ for (int i = 0; _imageHandles[i] != "\0"; ++i) {
+ ImageMan.registerSurface(_imageHandles[i], 0);
+ _images[i] = ImageMan.getSurface(_imageHandles[i]);
+ }
+}
+
+ThemeNew::~ThemeNew() {
+ deinit();
+ delete [] _images;
+ _images = 0;
+ if (_imageHandles) {
+ for (int i = 0; i < kImageHandlesMax; ++i) {
+ ImageMan.unregisterSurface(_imageHandles[i]);
+ }
+ }
+}
+
+bool ThemeNew::init() {
+ if (!_images)
+ return false;
+ for (int i = 0; i < kImageHandlesMax; ++i) {
+ if (!_images[i]) {
+ return false;
+ }
+ }
+
+ deinit();
+ _screen.create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(OverlayColor));
+ if (_screen.pixels) {
+ _initOk = true;
+ clearAll();
+ if (_screen.w >= 400 && _screen.h >= 300) {
+ _font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
+ } else {
+ _font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
+ }
+ }
+
+ return true;
+}
+
+void ThemeNew::deinit() {
+ if (_initOk) {
+ _system->hideOverlay();
+ _screen.free();
+ _initOk = false;
+ }
+}
+
+void ThemeNew::refresh() {
+ init();
+ _system->showOverlay();
+}
+
+void ThemeNew::enable() {
+ _system->showOverlay();
+ clearAll();
+}
+
+void ThemeNew::disable() {
+ _system->hideOverlay();
+}
+
+void ThemeNew::openDialog() {
+ 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);
+}
+
+void ThemeNew::closeDialog() {
+ if (_dialog) {
+ _dialog->screen.free();
+ delete _dialog;
+ _dialog = 0;
+ }
+ _forceRedraw = true;
+}
+
+void ThemeNew::clearAll() {
+ if (!_initOk)
+ return;
+ _system->clearOverlay();
+ // FIXME: problem with the 'pitch'
+ _system->grabOverlay((OverlayColor*)_screen.pixels, _screen.w);
+}
+
+void ThemeNew::drawAll() {
+ // TODO: see ThemeNew::addDirtyRect
+ _forceRedraw = false;
+}
+
+void ThemeNew::resetDrawArea() {
+ if (_initOk) {
+ _drawArea = Common::Rect(0, 0, _screen.w, _screen.h);
+ }
+}
+
+#define surface(x) (_images[x])
+
+void ThemeNew::drawDialogBackground(const Common::Rect &r, kState state, bool mainDialog) {
+ if (!_initOk)
+ return;
+
+ if (mainDialog) {
+ colorFade(r, _colors[kMainDialogStart], _colors[kMainDialogEnd]);
+ } else {
+ drawRectMasked(r, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd),
+ 255, _colors[kDialogStart], _colors[kDialogEnd]);
+ }
+
+ addDirtyRect(r, true);
+}
+
+void ThemeNew::drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis) {
+ if (!_initOk)
+ return;
+ Common::Rect r2(r.left, r.top, r.right, r.top+_font->getFontHeight());
+
+ restoreBackground(r2);
+
+ if (inverted) {
+ _screen.fillRect(r, _colors[kTextInvertedBackground]);
+ _font->drawString(&_screen, str, r.left, r.top, r.width(), _colors[kTextInvertedColor], convertAligment(align), deltax, useEllipsis);
+ addDirtyRect(r2);
+ return;
+ } else {
+ _font->drawString(&_screen, str, r.left, r.top, r.width(), getColor(state), convertAligment(align), deltax, useEllipsis);
+ }
+
+ addDirtyRect(r2);
+}
+
+void ThemeNew::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 ThemeNew::drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background, kState state) {
+ if (!_initOk)
+ return;
+
+ if ((hints & THEME_HINT_SAVE_BACKGROUND) && !(hints & THEME_HINT_FIRST_DRAW) && !_forceRedraw) {
+ restoreBackground(r);
+ return;
+ }
+
+ if (background == kWidgetBackgroundBorderSmall) {
+ drawRectMasked(r, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd),
+ (state == kStateDisabled) ? 128 : 256, _colors[kWidgetBackgroundSmallStart], _colors[kWidgetBackgroundSmallEnd]);
+ } else {
+ drawRectMasked(r, surface(kWidgetBkgdCorner), surface(kWidgetBkgdTop), surface(kWidgetBkgdLeft), surface(kWidgetBkgd),
+ (state == kStateDisabled) ? 128 : 256, _colors[kWidgetBackgroundStart], _colors[kWidgetBackgroundEnd], 2);
+ }
+
+ addDirtyRect(r, (hints & THEME_HINT_SAVE_BACKGROUND));
+}
+
+void ThemeNew::drawButton(const Common::Rect &r, const Common::String &str, kState state) {
+ if (!_initOk)
+ return;
+
+ drawRectMasked(r, surface(kWidgetBkgdCorner), surface(kWidgetBkgdTop), surface(kWidgetBkgdLeft), surface(kWidgetBkgd),
+ 255, _colors[kButtonBackgroundStart], _colors[kButtonBackgroundEnd], 2);
+
+ const int off = (r.height() - _font->getFontHeight()) / 2;
+
+ OverlayColor col = 0;
+ switch (state) {
+ case kStateEnabled:
+ col = _colors[kButtonTextEnabled];
+ break;
+
+ case kStateHighlight:
+ col = _colors[kButtonTextHighlight];
+ break;
+
+ default:
+ col = _colors[kButtonTextDisabled];
+ break;
+ };
+
+ _font->drawString(&_screen, str, r.left, r.top + off, r.width(), col, Graphics::kTextAlignCenter, 0, true);
+
+ addDirtyRect(r);
+}
+
+void ThemeNew::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 ThemeNew::drawSlider(const Common::Rect &r, int width, kState state) {
+ if (!_initOk)
+ return;
+
+ drawRectMasked(r, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd), 255,
+ _colors[kSliderBackgroundStart], _colors[kSliderBackgroundEnd]);
+
+ Common::Rect r2 = r;
+ 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;
+ }
+
+ drawRectMasked(r2, surface(kWidgetBkgdCorner), surface(kWidgetBkgdTop), surface(kWidgetBkgdLeft), surface(kWidgetBkgd),
+ (state == kStateDisabled) ? 128 : 256, _colors[kSliderStart], _colors[kSliderEnd], 2);
+
+ addDirtyRect(r);
+}
+
+void ThemeNew::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, kState state) {
+ if (!_initOk)
+ return;
+ Common::Rect r2 = r;
+
+ const Graphics::Surface *checkBox = surface(checked ? kCheckboxChecked : kCheckboxEmpty);
+ int checkBoxSize = checkBox->w;
+
+ drawSurface(Common::Rect(r.left, r.top, r.left+checkBox->w, r.top+checkBox->h), checkBox, false, false, (state == kStateDisabled) ? 128 : 256);
+ r2.left += checkBoxSize + 5;
+ _font->drawString(&_screen, str, r2.left, r2.top, r2.width(), getColor(state), Graphics::kTextAlignCenter, 0, false);
+
+ addDirtyRect(r);
+}
+
+void ThemeNew::drawTab(const Common::Rect &r, const Common::String &str, bool active, kState state) {
+ if (!_initOk)
+ return;
+ if (active) {
+ _font->drawString(&_screen, str, r.left, r.top+2, r.width(), getColor(kStateHighlight), Graphics::kTextAlignCenter, 0, true);
+ } else {
+ drawRectMasked(r, surface(kWidgetBkgdCorner), surface(kWidgetBkgdTop), surface(kWidgetBkgdLeft), surface(kWidgetBkgd),
+ (state == kStateDisabled) ? 128 : 256, _colors[kTabBackgroundStart], _colors[kTabBackgroundEnd], 2);
+ _font->drawString(&_screen, str, r.left, r.top+2, r.width(), getColor(state), Graphics::kTextAlignCenter, 0, true);
+ }
+ addDirtyRect(r);
+}
+
+void ThemeNew::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, kScrollbarState, kState state) {
+ if (!_initOk)
+ return;
+ const int UP_DOWN_BOX_HEIGHT = r.width() + 1;
+ Common::Rect r2 = r;
+
+ // draws the scrollbar background
+ drawRectMasked(r2, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd), 255,
+ _colors[kScrollbarBackgroundStart], _colors[kScrollbarBackgroundEnd]);
+
+ // draws the 'up' button
+ r2.bottom = r2.top + UP_DOWN_BOX_HEIGHT;
+ drawRectMasked(r2, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd), 255,
+ _colors[kScrollbarButtonStart], _colors[kScrollbarButtonEnd]);
+
+ const Graphics::Surface *arrow = surface(kWidgetArrow);
+ r2.left += 1 + (r2.width() - arrow->w) / 2;
+ r2.right = r2.left + arrow->w;
+ r2.top += (r2.height() - arrow->h) / 2;
+ r2.bottom = r2.top + arrow->h;
+ drawSurface(r2, arrow, false, false, 255);
+
+ // draws the slider
+ r2 = r;
+ r2.left += 2;
+ r2.right -= 2;
+ r2.top += sliderY;
+ r2.bottom = r2.top + sliderHeight / 2 + surface(kWidgetBkgdCorner)->h + 4;
+ drawRectMasked(r2, surface(kWidgetBkgdCorner), surface(kWidgetBkgdTop), surface(kWidgetBkgdLeft), surface(kWidgetBkgd), 255,
+ _colors[kScrollbarSliderStart], _colors[kScrollbarSliderEnd]);
+ r2.top += sliderHeight / 2;
+ r2.bottom += sliderHeight / 2 - surface(kWidgetBkgdCorner)->h - 4;
+ drawRectMasked(r2, surface(kWidgetBkgdCorner), surface(kWidgetBkgdTop), surface(kWidgetBkgdLeft), surface(kWidgetBkgd), 255,
+ _colors[kScrollbarSliderEnd], _colors[kScrollbarSliderStart]);
+
+ // draws the 'down' button
+ r2 = r;
+ r2.top = r2.bottom - UP_DOWN_BOX_HEIGHT;
+ drawRectMasked(r2, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd), 255,
+ _colors[kScrollbarButtonStart], _colors[kScrollbarButtonEnd]);
+
+ r2.left += 1 + (r2.width() - arrow->w) / 2;
+ r2.right = r2.left + arrow->w;
+ r2.top += (r2.height() - arrow->h) / 2;
+ r2.bottom = r2.top + arrow->h;
+ drawSurface(r2, arrow, true, false, 255);
+
+ addDirtyRect(r);
+}
+
+void ThemeNew::drawCaret(const Common::Rect &r, bool erase, kState state) {
+ if (!_initOk)
+ return;
+
+ restoreBackground(Common::Rect(r.left, r.top, r.left+1, r.bottom));
+ if (!erase) {
+ _screen.vLine(r.left, r.top, r.bottom, _colors[kCaretColor]);
+ } else {
+ // FIXME: hack to restore the caret background correctly
+ const OverlayColor search = _colors[kTextInvertedBackground];
+ const OverlayColor *src = (const OverlayColor*)_screen.getBasePtr(r.left-1, r.top-1);
+ int height = r.height() + 2;
+ if (r.top + height > _screen.h) {
+ height = _screen.h - r.top;
+ }
+ bool drawInvBackground = false;
+ while (height--) {
+ if (src[0] == search || src[1] == search || src[2] == search) {
+ drawInvBackground = true;
+ }
+ src += _screen.w;
+ }
+ if (drawInvBackground) {
+ _screen.vLine(r.left, r.top, r.bottom, search);
+ }
+ }
+ addDirtyRect(r);
+}
+
+void ThemeNew::drawLineSeparator(const Common::Rect &r, kState state) {
+ if (!_initOk)
+ return;
+ _screen.hLine(r.left - 1, r.top + r.height() / 2, r.right, _system->RGBToColor(0, 0, 0));
+ addDirtyRect(r);
+}
+
+#pragma mark - intern drawing
+
+void ThemeNew::restoreBackground(Common::Rect r) {
+ r.clip(_screen.w, _screen.h);
+ r.clip(_drawArea);
+ if (_dialog) {
+ if (!_dialog->screen.pixels) {
+ 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;
+ }
+ }
+}
+
+bool ThemeNew::addDirtyRect(Common::Rect r, bool backup) {
+ // 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());
+ if (_dialog && backup) {
+ 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;
+ }
+ }
+ }
+ return true;
+}
+
+inline uint8 calcColor(uint8 start, uint8 end, int pos, int max) {
+ int diff = ((int)end - (int)start) * pos / max;
+ return start + diff;
+}
+
+OverlayColor calcColor(OverlayColor start, OverlayColor end, int pos, int max, uint factor = 1) {
+ pos *= factor;
+ if (pos > max) {
+ pos = max;
+ }
+ OverlayColor result = 0;
+ uint8 sr = 0, sg = 0, sb = 0;
+ uint8 er = 0, eg = 0, eb = 0;
+ if (gBitFormat == 565) {
+ sr = (start >> 11) & 0x1F;
+ sg = (start >> 5) & 0x3F;
+ sb = (start >> 0) & 0x1F;
+
+ er = (end >> 11) & 0x1F;
+ eg = (end >> 5) & 0x3F;
+ eb = (end >> 0) & 0x1F;
+ } else {
+ sr = (start >> 10) & 0x1F;
+ sg = (start >> 5) & 0x1F;
+ sb = (start >> 0) & 0x1F;
+
+ er = (end >> 10) & 0x1F;
+ eg = (end >> 5) & 0x1F;
+ eb = (end >> 0) & 0x1F;
+ }
+ uint8 cr = calcColor(sr, er, pos, max);
+ uint8 cg = calcColor(sg, eg, pos, max);
+ uint8 cb = calcColor(sb, eb, pos, max);
+ if (gBitFormat == 565) {
+ result = ((int)(cr & 0x1F) << 11) | ((int)(cg & 0x3F) << 5) | (int)(cb & 0x1F);
+ } else {
+ result = ((int)(cr & 0x1F) << 10) | ((int)(cg & 0x1F) << 5) | (int)(cb & 0x1F);
+ }
+ return result;
+}
+
+void ThemeNew::colorFade(const Common::Rect &r, OverlayColor start, OverlayColor end) {
+ OverlayColor *ptr = (OverlayColor*)_screen.getBasePtr(r.left, r.top);
+ int h = r.height();
+ while (h--) {
+ OverlayColor col = calcColor(start, end, r.height()-h, r.height());
+ for (int i = 0; i < r.width(); ++i) {
+ ptr[i] = col;
+ }
+ ptr += _screen.w;
+ }
+}
+
+void ThemeNew::drawRect(const Common::Rect &r, const Surface *corner, const Surface *top, const Surface *left, const Surface *fill, int alpha) {
+ // top left
+ drawRectMasked(r, corner, top, left, fill, alpha, _system->RGBToColor(255, 255, 255), _system->RGBToColor(255, 255, 255));
+}
+
+void ThemeNew::drawRectMasked(const Common::Rect &r, const Graphics::Surface *corner, const Graphics::Surface *top,
+ const Graphics::Surface *left, const Graphics::Surface *fill, int alpha,
+ OverlayColor start, OverlayColor end, uint factor) {
+ int drawWidth = MIN(corner->w, MIN(top->w, MIN(left->w, fill->w)));
+ int drawHeight = MIN(corner->h, MIN(top->h, MIN(left->h, fill->h)));
+ int partsH = r.height() / drawHeight;
+ int partsW = r.width() / drawWidth;
+ int yPos = r.top;
+
+ int specialHeight = 0;
+ int specialWidth = 0;
+
+ if (drawHeight*2 > r.height()) {
+ drawHeight = r.height() / 2;
+ partsH = 2;
+ } else {
+ specialHeight = r.height() % drawHeight;
+ if (specialHeight != 0)
+ ++partsH;
+ }
+
+ if (drawWidth*2 > r.width()) {
+ drawWidth = r.width() / 2;
+ partsW = 2;
+ } else {
+ specialWidth = r.width() % drawWidth;
+ if (specialWidth != 0)
+ ++partsW;
+ }
+
+ for (int y = 0; y < partsH; ++y) {
+ int xPos = r.left;
+ bool upDown = false;
+ if (y == partsH - 1)
+ upDown = true;
+
+ // calculate the correct drawing height
+ int usedHeight = drawHeight;
+ if (specialHeight && y == 1) {
+ usedHeight = specialHeight;
+ }
+
+ OverlayColor startCol = calcColor(start, end, yPos-r.top, r.height(), factor);
+ OverlayColor endCol = calcColor(start, end, yPos-r.top+usedHeight, r.height(), factor);
+
+ for (int i = 0; i < partsW; ++i) {
+
+ // calculate the correct drawing width
+ int usedWidth = drawWidth;
+ if (specialWidth && i == 1) {
+ usedWidth = specialWidth;
+ }
+
+ // draw the right surface
+ if (!i) {
+ if (!y || y == partsH - 1) {
+ drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), corner, upDown, false, alpha, startCol, endCol);
+ } else {
+ drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), left, upDown, false, alpha, startCol, endCol);
+ }
+ } else if (i == partsW - 1) {
+ if (!y || y == partsH - 1) {
+ drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), corner, upDown, true, alpha, startCol, endCol);
+ } else {
+ drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), left, upDown, true, alpha, startCol, endCol);
+ }
+ } else if (!y || y == partsH - 1) {
+ drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), top, upDown, false, alpha, startCol, endCol);
+ } else {
+ drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), fill, upDown, false, alpha, startCol, endCol);
+ }
+ xPos += usedWidth;
+ }
+ yPos += usedHeight;
+ }
+}
+
+void ThemeNew::drawSurface(const Common::Rect &r, const Surface *surf, bool upDown, bool leftRight, int alpha) {
+ drawSurfaceMasked(r, surf, upDown, leftRight, alpha, _system->RGBToColor(255, 255, 255), _system->RGBToColor(255, 255, 255));
+}
+
+inline OverlayColor getColorAlpha(OverlayColor col1, OverlayColor col2, int alpha) {
+ if (alpha == 256) {
+ return col1;
+ }
+ uint8 r1, g1, b1;
+ uint8 r2, g2, b2;
+ OSystem::instance().colorToRGB(col1, r1, g1, b1);
+ OSystem::instance().colorToRGB(col2, r2, g2, b2);
+ uint8 r, g, b;
+ r = (alpha * (r1 - r2) >> 8) + r2;
+ g = (alpha * (g1 - g2) >> 8) + g2;
+ b = (alpha * (b1 - b2) >> 8) + b2;
+ return OSystem::instance().RGBToColor(r, g, b);
+}
+
+void ThemeNew::drawSurfaceMasked(const Common::Rect &r, const Graphics::Surface *surf, bool upDown, bool leftRight,
+ int alpha, OverlayColor start, OverlayColor end, uint factor) {
+ OverlayColor *dst = (OverlayColor*)_screen.getBasePtr(r.left, r.top);
+ const OverlayColor *src = 0;
+
+ const OverlayColor transparency = _colors[kColorTransparency];
+
+ if (upDown && !leftRight) { // upsidedown
+ src = (const OverlayColor*)surf->pixels + (surf->h - 1) * surf->w;
+ int drawWidth = (r.width() < surf->w) ? r.width() : surf->w;
+ for (int i = 0; i < r.height(); ++i) {
+ OverlayColor rowColor = calcColor(start, end, i, r.height(), factor);
+ for (int x = 0; x < drawWidth; ++x) {
+ if (src[x] != transparency && dst >= _screen.pixels) {
+ dst[x] = getColorAlpha(src[x], dst[x], alpha) & rowColor;
+ }
+ }
+ dst += _screen.w;
+ src -= surf->w;
+ }
+ } else if (upDown && leftRight) { // upsidedown + left right inverse
+ src = (const OverlayColor*)surf->pixels + (surf->h - 1) * surf->w;
+ int drawWidth = (r.width() < surf->w) ? r.width() : surf->w;
+ for (int i = 0; i < r.height(); ++i) {
+ OverlayColor rowColor = calcColor(start, end, i, r.height(), factor);
+ for (int x = 0; x < drawWidth; ++x) {
+ if (src[drawWidth-x-1] != transparency && dst >= _screen.pixels) {
+ dst[x] = getColorAlpha(src[drawWidth-x-1], dst[x], alpha) & rowColor;
+ }
+ }
+ dst += _screen.w;
+ src -= surf->w;
+ }
+ } else if (!upDown && leftRight) { // left right inverse
+ src = (const OverlayColor*)surf->pixels;
+ int drawWidth = (r.width() < surf->w) ? r.width() : surf->w;
+ for (int i = 0; i < r.height(); ++i) {
+ OverlayColor rowColor = calcColor(start, end, i, r.height(), factor);
+ for (int x = 0; x < drawWidth; ++x) {
+ if (src[drawWidth-x-1] != transparency && dst >= _screen.pixels) {
+ dst[x] = getColorAlpha(src[drawWidth-x-1], dst[x], alpha) & rowColor;
+ }
+ }
+ dst += _screen.w;
+ src += surf->w;
+ }
+ } else { // normal
+ src = (const OverlayColor*)surf->pixels;
+ int drawWidth = (r.width() < surf->w) ? r.width() : surf->w;
+ for (int i = 0; i < r.height(); ++i) {
+ OverlayColor rowColor = calcColor(start, end, i, r.height(), factor);
+ for (int x = 0; x < drawWidth; ++x) {
+ if (src[x] != transparency && dst >= _screen.pixels) {
+ dst[x] = getColorAlpha(src[x], dst[x], alpha) & rowColor;
+ }
+ }
+ dst += _screen.w;
+ src += surf->w;
+ }
+ }
+}
+
+OverlayColor ThemeNew::getColor(kState state) {
+ switch (state) {
+ case kStateDisabled:
+ return _colors[kColorStateDisabled];
+ break;
+
+ case kStateHighlight:
+ return _colors[kColorStateHighlight];
+ break;
+
+ default:
+ break;
+ };
+ return _colors[kColorStateEnabled];
+}
+
+} // end of namespace GUI