aboutsummaryrefslogtreecommitdiff
path: root/gui
diff options
context:
space:
mode:
authorJohannes Schickel2006-01-27 15:43:23 +0000
committerJohannes Schickel2006-01-27 15:43:23 +0000
commit5051b080a2cfefef81907be0324e229f284ae355 (patch)
treeaf2b67affe5aaf357c3278e3befdbd412dea5545 /gui
parent901645cb0f28ef0278e5b5e3a7347a85f9142b8b (diff)
downloadscummvm-rg350-5051b080a2cfefef81907be0324e229f284ae355.tar.gz
scummvm-rg350-5051b080a2cfefef81907be0324e229f284ae355.tar.bz2
scummvm-rg350-5051b080a2cfefef81907be0324e229f284ae355.zip
- adds the new gui renderer also a new implementation for the classic gui
- adds a ImageMan and ImageDec class for loading and managing image files - adds a loader for zip files which is used by the new theme and the image manager - changes the widgets to use the new gui code - changes the scumm dialogs to use the new gui code - fixes a #include problem in the sky debugger with the new gui code To use the new gui copy gui/themes/default-theme.zip to your extrapath. If the theme zip can not be found the gui will fallback to the classic theme. If you want to change the gui styles use "gui_theme=classic" for the classic theme and "gui_theme=default-theme" for the new theme. Thanks to eriktorbjorn for testing and help with the new theme and to sev for reviewing this patch. svn-id: r20227
Diffstat (limited to 'gui')
-rw-r--r--gui/EditTextWidget.cpp8
-rw-r--r--gui/ListWidget.cpp19
-rw-r--r--gui/PopUpWidget.cpp44
-rw-r--r--gui/ScrollBarWidget.cpp75
-rw-r--r--gui/TabWidget.cpp26
-rw-r--r--gui/ThemeNew.cpp801
-rw-r--r--gui/about.cpp71
-rw-r--r--gui/about.h2
-rw-r--r--gui/console.cpp54
-rw-r--r--gui/console.h1
-rw-r--r--gui/dialog.cpp20
-rw-r--r--gui/dialog.h3
-rw-r--r--gui/editable.cpp6
-rw-r--r--gui/launcher.cpp1
-rw-r--r--gui/module.mk4
-rw-r--r--gui/newgui.cpp285
-rw-r--r--gui/newgui.h62
-rw-r--r--gui/theme.cpp516
-rw-r--r--gui/theme.h361
-rw-r--r--gui/themes/default-theme.zipbin0 -> 3612 bytes
-rw-r--r--gui/widget.cpp86
-rw-r--r--gui/widget.h6
22 files changed, 1842 insertions, 609 deletions
diff --git a/gui/EditTextWidget.cpp b/gui/EditTextWidget.cpp
index c43c385a5f..d2e9f4da27 100644
--- a/gui/EditTextWidget.cpp
+++ b/gui/EditTextWidget.cpp
@@ -59,15 +59,11 @@ void EditTextWidget::handleMouseDown(int x, int y, int button, int clickCount) {
void EditTextWidget::drawWidget(bool hilite) {
- // Draw a thin frame around us.
- g_gui.hLine(_x, _y, _x + _w - 1, g_gui._color);
- g_gui.hLine(_x, _y + _h - 1, _x +_w - 1, g_gui._shadowcolor);
- g_gui.vLine(_x, _y, _y + _h - 1, g_gui._color);
- g_gui.vLine(_x + _w - 1, _y, _y + _h - 1, g_gui._shadowcolor);
+ g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), _hints, Theme::kWidgetBackgroundBorderSmall);
// Draw the text
adjustOffset();
- g_gui.drawString(_editString, _x + 2, _y + 2, getEditRect().width(), g_gui._textcolor, kTextAlignLeft, -_editScrollOffset, false);
+ g_gui.theme()->drawText(Common::Rect(_x+2,_y+2, _x+getEditRect().width()-2, _y+_h-2), _editString, Theme::kStateEnabled, Theme::kTextAlignLeft, false, -_editScrollOffset, false);
}
Common::Rect EditTextWidget::getEditRect() const {
diff --git a/gui/ListWidget.cpp b/gui/ListWidget.cpp
index 4e4af1ad12..9f3797af15 100644
--- a/gui/ListWidget.cpp
+++ b/gui/ListWidget.cpp
@@ -37,6 +37,7 @@ ListWidget::ListWidget(GuiObject *boss, int x, int y, int w, int h, WidgetSize w
}
_flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_WANT_TICKLE;
+ setHints(THEME_HINT_SAVE_BACKGROUND);
_type = kListWidget;
_editMode = false;
_numberingMode = kListNumberingOne;
@@ -297,27 +298,25 @@ void ListWidget::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
}
void ListWidget::drawWidget(bool hilite) {
- NewGui *gui = &g_gui;
int i, pos, len = _list.size();
Common::String buffer;
int deltax;
// Draw a thin frame around the list.
- gui->hLine(_x, _y, _x + _w - 1, gui->_color);
- gui->hLine(_x, _y + _h - 1, _x + _w - 1, gui->_shadowcolor);
- gui->vLine(_x, _y, _y + _h - 1, gui->_color);
+ g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), _hints, Theme::kWidgetBackgroundBorderSmall);
// Draw the list items
for (i = 0, pos = _currentPos; i < _entriesPerPage && pos < len; i++, pos++) {
- const OverlayColor textColor = (_selectedItem == pos && _hasFocus) ? gui->_bgcolor : gui->_textcolor;
const int y = _y + 2 + kLineHeight * i;
+ const int fontHeight = kLineHeight;
+ bool inverted = false;
// Draw the selected item inverted, on a highlighted background.
if (_selectedItem == pos) {
if (_hasFocus)
- gui->fillRect(_x + 1, _y + 1 + kLineHeight * i, _w - 1, kLineHeight, gui->_textcolorhi);
+ inverted = true;
else
- gui->frameRect(_x + 1, _y + 1 + kLineHeight * i, _w - 1, kLineHeight, gui->_textcolorhi);
+ g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y + 1 + kLineHeight * i, _x+_w-1, y+fontHeight-1), _hints, Theme::kWidgetBackgroundBorderSmall);
}
// If in numbering mode, we first print a number prefix
@@ -325,7 +324,7 @@ void ListWidget::drawWidget(bool hilite) {
char temp[10];
sprintf(temp, "%2d. ", (pos + _numberingMode));
buffer = temp;
- gui->drawString(buffer, _x + 2, y, _w - 4, textColor);
+ g_gui.theme()->drawText(Common::Rect(_x+2, y, _x+_w-2, y+fontHeight-1), buffer, Theme::kStateEnabled, Theme::kTextAlignLeft, inverted);
}
Common::Rect r(getEditRect());
@@ -335,11 +334,11 @@ void ListWidget::drawWidget(bool hilite) {
adjustOffset();
deltax = -_editScrollOffset;
- gui->drawString(buffer, _x + r.left, y, r.width(), textColor, kTextAlignLeft, deltax, false);
+ g_gui.theme()->drawText(Common::Rect(_x + r.left - deltax, y, _x+_w-2, y+fontHeight-1), buffer, Theme::kStateEnabled, Theme::kTextAlignLeft, inverted);
} else {
buffer = _list[pos];
deltax = 0;
- gui->drawString(buffer, _x + r.left, y, r.width(), textColor);
+ g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x+_w-2, y+fontHeight-1), buffer, Theme::kStateEnabled, Theme::kTextAlignLeft, inverted);
}
}
}
diff --git a/gui/PopUpWidget.cpp b/gui/PopUpWidget.cpp
index e09680f308..6edff1f927 100644
--- a/gui/PopUpWidget.cpp
+++ b/gui/PopUpWidget.cpp
@@ -140,13 +140,10 @@ PopUpDialog::PopUpDialog(PopUpWidget *boss, int clickX, int clickY, WidgetSize w
void PopUpDialog::drawDialog() {
// Draw the menu border
- g_gui.hLine(_x, _y, _x+_w - 1, g_gui._color);
- g_gui.hLine(_x, _y + _h - 1, _x + _w - 1, g_gui._shadowcolor);
- g_gui.vLine(_x, _y, _y+_h - 1, g_gui._color);
- g_gui.vLine(_x + _w - 1, _y, _y + _h - 1, g_gui._shadowcolor);
+ g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), THEME_HINT_FIRST_DRAW | THEME_HINT_SAVE_BACKGROUND, Theme::kWidgetBackgroundBorderSmall);
- if (_twoColumns)
- g_gui.vLine(_x + _w / 2, _y, _y + _h - 2, g_gui._color);
+ /*if (_twoColumns)
+ g_gui.vLine(_x + _w / 2, _y, _y + _h - 2, g_gui._color);*/
// Draw the entries
int count = _popUpBoss->_entries.size();
@@ -155,11 +152,9 @@ void PopUpDialog::drawDialog() {
}
// The last entry may be empty. Fill it with black.
- if (_twoColumns && (count & 1)) {
+ /*if (_twoColumns && (count & 1)) {
g_gui.fillRect(_x + 1 + _w / 2, _y + 1 + kLineHeight * (_entriesPerColumn - 1), _w / 2 - 1, kLineHeight, g_gui._bgcolor);
- }
-
- g_gui.addDirtyRect(_x, _y, _w, _h);
+ }*/
}
void PopUpDialog::handleMouseUp(int x, int y, int button, int clickCount) {
@@ -322,15 +317,13 @@ void PopUpDialog::drawMenuEntry(int entry, bool hilite) {
Common::String &name = _popUpBoss->_entries[entry].name;
- g_gui.fillRect(x, y, w, kLineHeight, hilite ? g_gui._textcolorhi : g_gui._bgcolor);
if (name.size() == 0) {
// Draw a separator
- g_gui.hLine(x - 1, y + kLineHeight / 2, x + w, g_gui._shadowcolor);
- g_gui.hLine(x, y + 1 + kLineHeight / 2, x + w, g_gui._color);
+ g_gui.theme()->drawLineSeparator(Common::Rect(x, y, x+w, y+kLineHeight));
} else {
- g_gui.drawString(name, x + 1, y + 2, w - 2, hilite ? g_gui._bgcolor : g_gui._textcolor);
+ g_gui.theme()->drawText(Common::Rect(x+1, y+2, x+w-1, y+kLineHeight), name, hilite ? Theme::kStateHighlight : Theme::kStateEnabled,
+ Theme::kTextAlignLeft);
}
- g_gui.addDirtyRect(x, y, w, kLineHeight);
}
@@ -343,6 +336,7 @@ void PopUpDialog::drawMenuEntry(int entry, bool hilite) {
PopUpWidget::PopUpWidget(GuiObject *boss, int x, int y, int w, int h, const String &label, uint labelWidth, WidgetSize ws)
: Widget(boss, x, y - 1, w, h + 2), CommandSender(boss), _ws(ws), _label(label), _labelWidth(labelWidth) {
_flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS;
+ setHints(THEME_HINT_SAVE_BACKGROUND);
_type = kPopUpWidget;
_selectedItem = -1;
@@ -397,22 +391,19 @@ void PopUpWidget::setSelectedTag(uint32 tag) {
}
void PopUpWidget::drawWidget(bool hilite) {
- NewGui *gui = &g_gui;
int x = _x + _labelWidth;
int w = _w - _labelWidth;
+ // Draw a thin frame around us.
+ g_gui.theme()->drawWidgetBackground(Common::Rect(x, _y, x+w, _y+_h), _hints, Theme::kWidgetBackgroundBorderSmall);
+
// Draw the label, if any
if (_labelWidth > 0)
- gui->drawString(_label, _x, _y + 3, _labelWidth, isEnabled() ? gui->_textcolor : gui->_color, kTextAlignRight);
-
- // Draw a thin frame around us.
- gui->hLine(x, _y, x + w - 1, gui->_color);
- gui->hLine(x, _y +_h-1, x + w - 1, gui->_shadowcolor);
- gui->vLine(x, _y, _y+_h-1, gui->_color);
- gui->vLine(x + w - 1, _y, _y +_h - 1, gui->_shadowcolor);
+ g_gui.theme()->drawText(Common::Rect(_x+2,_y+3,_x+_labelWidth, _y+g_gui.theme()->getFontHeight()), _label,
+ isEnabled() ? Theme::kStateEnabled : Theme::kStateDisabled, Theme::kTextAlignRight);
// Draw a set of arrows at the right end to signal this is a dropdown/popup
- Common::Point p0, p1;
+ /*Common::Point p0, p1;
p0 = Common::Point(x + w + 1 - _h / 2, _y + 4);
p1 = Common::Point(x + w + 1 - _h / 2, _y + _h - 4);
@@ -425,12 +416,13 @@ void PopUpWidget::drawWidget(bool hilite) {
for (; p1.y - p0.y > 1; p0.y++, p0.x--, p1.y--, p1.x++) {
surf.drawLine(p0.x, p0.y, p1.x, p0.y, color);
surf.drawLine(p0.x, p1.y, p1.x, p1.y, color);
- }
+ }*/
// Draw the selected entry, if any
if (_selectedItem >= 0) {
TextAlignment align = (g_gui.getStringWidth(_entries[_selectedItem].name) > w-6) ? kTextAlignRight : kTextAlignLeft;
- gui->drawString(_entries[_selectedItem].name, x+2, _y+3, w-6, !isEnabled() ? gui->_color : gui->_textcolor, align);
+ g_gui.theme()->drawText(Common::Rect(x+2, _y+3, _x+w-6, _y+g_gui.theme()->getFontHeight()), _entries[_selectedItem].name,
+ isEnabled() ? Theme::kStateEnabled : Theme::kStateDisabled, g_gui.theme()->convertAligment(align));
}
}
diff --git a/gui/ScrollBarWidget.cpp b/gui/ScrollBarWidget.cpp
index e373f04a1e..03182b35c0 100644
--- a/gui/ScrollBarWidget.cpp
+++ b/gui/ScrollBarWidget.cpp
@@ -179,73 +179,22 @@ void ScrollBarWidget::recalc() {
}
void ScrollBarWidget::drawWidget(bool hilite) {
- NewGui *gui = &g_gui;
- int bottomY = _y + _h - UP_DOWN_BOX_HEIGHT;
- bool isSinglePage = (_numEntries <= _entriesPerPage);
- OverlayColor color;
- Graphics::Surface &surf = g_gui.getScreen();
- const int B = 3;
- Common::Point p0, p1, p2;
-
- gui->frameRect(_x, _y, _w, _h, gui->_shadowcolor);
-
if (_draggingPart != kNoPart)
_part = _draggingPart;
- const int arrowSize = (_w / 2 - B + 1);
-
- //
- // Up arrow
- //
- color = isSinglePage ? gui->_color :
- (hilite && _part == kUpArrowPart) ? gui->_textcolorhi : gui->_textcolor;
- gui->frameRect(_x, _y, _w, UP_DOWN_BOX_HEIGHT, gui->_color);
- p0 = Common::Point(_x + _w / 2, _y + (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);
-#if 0
- surf.drawLine(p0.x, p0.y, p1.x, p1.y, color);
- surf.drawLine(p0.x, p0.y, p2.x, p2.y, color);
-// surf.drawLine(p1.x, p1.y, p2.x, p2.y, color);
-#else
- // Evil HACK to draw filled triangle
- for (; p1.x <= p2.x; ++p1.x)
- surf.drawLine(p0.x, p0.y, p1.x, p1.y, color);
-#endif
-
- //
- // Down arrow
- //
- color = isSinglePage ? gui->_color :
- (hilite && _part == kDownArrowPart) ? gui->_textcolorhi : gui->_textcolor;
- gui->frameRect(_x, bottomY, _w, UP_DOWN_BOX_HEIGHT, gui->_color);
- p0 = Common::Point(_x + _w / 2, bottomY + (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);
-
-#if 0
- surf.drawLine(p0.x, p0.y, p1.x, p1.y, color);
- surf.drawLine(p0.x, p0.y, p2.x, p2.y, color);
-// surf.drawLine(p1.x, p1.y, p2.x, p2.y, color);
-#else
- // Evil HACK to draw filled triangle
- for (; p1.x <= p2.x; ++p1.x)
- surf.drawLine(p0.x, p0.y, p1.x, p1.y, color);
-#endif
-
- //
- // Slider
- //
- if (!isSinglePage) {
- gui->fillRect(_x, _y + _sliderPos, _w, _sliderHeight,
- (hilite && _part == kSliderPart) ? gui->_textcolorhi : gui->_textcolor);
- gui->frameRect(_x, _y + _sliderPos, _w, _sliderHeight, gui->_color);
- int y = _y + _sliderPos + _sliderHeight / 2;
- color = (hilite && _part == kSliderPart) ? gui->_color : gui->_shadowcolor;
- gui->hLine(_x + 2, y - 2, _x + _w - 3, color);
- gui->hLine(_x + 2, y, _x + _w - 3, color);
- gui->hLine(_x + 2, y + 2, _x + _w-3, color);
+ Theme::kScrollbarState state = Theme::kScrollbarStateNo;
+ if (_numEntries <= _entriesPerPage) {
+ state = Theme::kScrollbarStateSinglePage;
+ } else if (_part == kUpArrowPart) {
+ state = Theme::kScrollbarStateUp;
+ } else if (_part == kDownArrowPart) {
+ state = Theme::kScrollbarStateDown;
+ } else if (_part == kSliderPart) {
+ state = Theme::kScrollbarStateSlider;
}
+
+ g_gui.theme()->drawScrollbar(Common::Rect(_x, _y, _x+_w, _y+_h), _sliderPos, _sliderHeight, state,
+ isEnabled() ? (hilite ? Theme::kStateHighlight : Theme::kStateEnabled) : Theme::kStateDisabled);
}
} // End of namespace GUI
diff --git a/gui/TabWidget.cpp b/gui/TabWidget.cpp
index 48b519938b..346a1d9c5d 100644
--- a/gui/TabWidget.cpp
+++ b/gui/TabWidget.cpp
@@ -127,7 +127,7 @@ bool TabWidget::handleKeyDown(uint16 ascii, int keycode, int modifiers) {
return Widget::handleKeyDown(ascii, keycode, modifiers);
}
-static void box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB, bool omitBottom) {
+/*static void box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB, bool omitBottom) {
NewGui &gui = g_gui;
gui.hLine(x + 1, y, x + width - 2, colorA);
@@ -141,36 +141,18 @@ static void box(int x, int y, int width, int height, OverlayColor colorA, Overla
}
gui.vLine(x + width - 1, y + 1, y + height - (omitBottom ? 1 : 2), colorB);
gui.vLine(x + width - 2, y + 1, y + height - (omitBottom ? 2 : 1), colorB);
-}
+}*/
void TabWidget::drawWidget(bool hilite) {
- NewGui *gui = &g_gui;
-
- const int left1 = _x + 1;
- const int right1 = _x + kTabLeftOffset + _activeTab * (_tabWidth + kTabSpacing);
- const int left2 = right1 + _tabWidth;
- const int right2 = _x + _w - 2;
-
- // Draw horizontal line
- gui->hLine(left1, _y + _tabHeight - 2, right1, gui->_shadowcolor);
- gui->hLine(left2, _y + _tabHeight - 2, right2, gui->_shadowcolor);
-
// Iterate over all tabs and draw them
int i, x = _x + kTabLeftOffset;
for (i = 0; i < (int)_tabs.size(); ++i) {
- OverlayColor color = (i == _activeTab) ? gui->_color : gui->_shadowcolor;
int yOffset = (i == _activeTab) ? 0 : 2;
- box(x, _y + yOffset, _tabWidth, _tabHeight - yOffset, color, color, (i == _activeTab));
- gui->drawString(_tabs[i].title, x + kTabPadding, _y + yOffset / 2 + (_tabHeight - gui->getFontHeight() - 3), _tabWidth - 2 * kTabPadding, gui->_textcolor, kTextAlignCenter);
+ g_gui.theme()->drawTab(Common::Rect(x, _y+yOffset, x+_tabWidth, _y+_tabHeight), _tabs[i].title, (i == _activeTab));
x += _tabWidth + kTabSpacing;
}
-
- // Draw more horizontal lines
- gui->hLine(left1, _y + _tabHeight - 1, right1, gui->_color);
- gui->hLine(left2, _y + _tabHeight - 1, right2, gui->_color);
- gui->hLine(_x+1, _y + _h - 2, _x + _w - 2, gui->_shadowcolor);
- gui->hLine(_x+1, _y + _h - 1, _x + _w - 2, gui->_color);
+ g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y+_tabHeight-2, _x+_w, _y+_h), _hints, Theme::kWidgetBackgroundBorderSmall);
}
Widget *TabWidget::findWidget(int x, int y) {
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
diff --git a/gui/about.cpp b/gui/about.cpp
index 372ffa5484..0043bd8518 100644
--- a/gui/about.cpp
+++ b/gui/about.cpp
@@ -73,7 +73,6 @@ static const char *credits_intro[] = {
#include "gui/credits.h"
-
AboutDialog::AboutDialog()
: Dialog(10, 20, 300, 174),
_scrollPos(0), _scrollTime(0), _modifiers(0), _willClose(false) {
@@ -111,7 +110,6 @@ AboutDialog::AboutDialog()
}
_w += 2*xOff;
-
for (i = 0; i < 1; i++)
_lines.push_back("");
@@ -166,7 +164,7 @@ void AboutDialog::addLine(const char *str) {
_lines.push_back(format);
} else {
Common::StringList wrappedLines;
- g_gui.getFont().wordWrapText(str, _w - 2*xOff, wrappedLines);
+ g_gui.getFont().wordWrapText(str, _w - 2 * xOff, wrappedLines);
for (Common::StringList::const_iterator i = wrappedLines.begin(); i != wrappedLines.end(); ++i) {
_lines.push_back(format + *i);
@@ -180,27 +178,17 @@ void AboutDialog::open() {
_scrollPos = 0;
_modifiers = 0;
_willClose = false;
- _canvas.pixels = NULL;
Dialog::open();
}
void AboutDialog::close() {
- free(_canvas.pixels);
Dialog::close();
}
void AboutDialog::drawDialog() {
- if (!_canvas.pixels) {
- // Blend over the background. Since we can't afford to do that
- // every time the text is updated (it's horribly CPU intensive)
- // we do it just once and then use a copy of the result as our
- // static background for the remainder of the credits.
- g_gui.blendRect(_x, _y, _w, _h, g_gui._bgcolor);
- g_gui.copyToSurface(&_canvas, _x, _y, _w, _h);
- }
-
- g_gui.drawSurface(_canvas, _x, _y);
+ g_gui.theme()->setDrawArea(Common::Rect(_x, _y, _x+_w, _y+_h));
+ Dialog::drawDialog();
// Draw text
// TODO: Add a "fade" effect for the top/bottom text lines
@@ -213,35 +201,37 @@ void AboutDialog::drawDialog() {
for (int line = firstLine; line < lastLine; line++) {
const char *str = _lines[line].c_str();
- Graphics::TextAlignment align = Graphics::kTextAlignCenter;
- OverlayColor color = g_gui._textcolor;
+ Theme::kTextAlign align = Theme::kTextAlignCenter;
+ Theme::kState state = Theme::kStateEnabled;
while (str[0] == '\\') {
switch (str[1]) {
case 'C':
- align = Graphics::kTextAlignCenter;
+ align = Theme::kTextAlignCenter;
break;
case 'L':
- align = Graphics::kTextAlignLeft;
+ align = Theme::kTextAlignLeft;
break;
case 'R':
- align = Graphics::kTextAlignRight;
+ align = Theme::kTextAlignRight;
break;
case 'c':
switch (str[2]) {
case '0':
- color = g_gui._textcolor;
+ state = Theme::kStateEnabled;
break;
case '1':
- color = g_gui._textcolorhi;
+ state = Theme::kStateHighlight;
break;
case '2':
- color = g_gui._color;
+ state = Theme::kStateDisabled;
break;
case '3':
- color = g_gui._shadowcolor;
+ warning("Need state for color 3");
+ // color = g_gui._shadowcolor;
break;
case '4':
- color = g_gui._bgcolor;
+ warning("Need state for color 4");
+ // color = g_gui._bgcolor;
break;
default:
error("Unknown color type '%c'", str[2]);
@@ -255,31 +245,17 @@ void AboutDialog::drawDialog() {
str += 2;
}
// Trim leading whitespaces if center mode is on
- if (align == Graphics::kTextAlignCenter)
+ if (align == Theme::kTextAlignCenter)
while (*str && *str == ' ')
str++;
- g_gui.drawString(str, _x + xOff, y, _w - 2 * xOff, color, align, 0, false);
+ g_gui.theme()->drawText(Common::Rect(_x + xOff, y, _x + _w - xOff, y + g_gui.theme()->getFontHeight() + 4), str, state, align, false, 0, false);
y += _lineHeight;
}
-
- // Draw a border
- g_gui.box(_x, _y, _w, _h, g_gui._color, g_gui._shadowcolor);
-
- // Finally blit it all to the screen
- g_gui.addDirtyRect(_x, _y, _w, _h);
+ g_gui.theme()->resetDrawArea();
}
-
void AboutDialog::handleTickle() {
- // We're in the process of doing a full redraw to re-create the
- // background image for the text. That means we need to wait for the
- // GUI itself to clear the overlay and call drawDialog() in all of the
- // dialogs, otherwise we'll only redraw this one and it'll still have
- // the remains of the old image, including the text that was on it.
- if (!_canvas.pixels)
- return;
-
const uint32 t = getMillis();
int scrollOffset = ((int)t - (int)_scrollTime) / kScrollMillisPerPixel;
if (scrollOffset > 0) {
@@ -302,16 +278,6 @@ void AboutDialog::handleTickle() {
}
}
-void AboutDialog::handleScreenChanged() {
- // The screen has changed. That means the overlay colors in the canvas
- // may no longer be correct. Reset it, and issue a full redraw.
- // TODO: We could check if the bit format has changed, like we do in
- // the MPEG player.
- free(_canvas.pixels);
- _canvas.pixels = NULL;
- draw();
-}
-
void AboutDialog::handleMouseUp(int x, int y, int button, int clickCount) {
// Close upon any mouse click
close();
@@ -329,5 +295,4 @@ void AboutDialog::handleKeyUp(uint16 ascii, int keycode, int modifiers) {
close();
}
-
} // End of namespace GUI
diff --git a/gui/about.h b/gui/about.h
index a4c1977691..6f0900ea28 100644
--- a/gui/about.h
+++ b/gui/about.h
@@ -36,7 +36,6 @@ protected:
uint32 _lineHeight;
byte _modifiers;
bool _willClose;
- Graphics::Surface _canvas;
int xOff, yOff;
@@ -49,7 +48,6 @@ public:
void close();
void drawDialog();
void handleTickle();
- void handleScreenChanged();
void handleMouseUp(int x, int y, int button, int clickCount);
void handleKeyDown(uint16 ascii, int keycode, int modifiers);
void handleKeyUp(uint16 ascii, int keycode, int modifiers);
diff --git a/gui/console.cpp b/gui/console.cpp
index 4f43b5a6df..57c374ddef 100644
--- a/gui/console.cpp
+++ b/gui/console.cpp
@@ -114,10 +114,7 @@ void ConsoleDialog::slideUpAndClose() {
}
void ConsoleDialog::open() {
- // This dialog will be redrawn a lot, so we store a copy of the blended
- // background in a separate "canvas", just like in the About dialog.
- _canvas.pixels = NULL;
-
+ // TODO: find a new way to do this
// Initiate sliding the console down. We do a very simple trick to achieve
// this effect: we simply move the console dialog just above (outside) the
// visible screen area, then shift it down in handleTickle() over a
@@ -135,36 +132,16 @@ void ConsoleDialog::open() {
}
void ConsoleDialog::close() {
- free(_canvas.pixels);
Dialog::close();
}
void ConsoleDialog::drawDialog() {
- if (!_canvas.pixels) {
- // Blend over the background. Don't count the time used for
- // this when timing the slide action.
-
- uint32 now = g_system->getMillis();
- uint32 delta;
-
- g_gui.blendRect(0, 0, _w, _h, g_gui._bgcolor, 2);
- g_gui.copyToSurface(&_canvas, 0, 0, _w, _h);
-
- delta = g_system->getMillis() - now;
-
- if (_slideTime)
- _slideTime += delta;
- }
-
- g_gui.drawSurface(_canvas, 0, 0);
-
- // Draw a border
- g_gui.hLine(_x, _y + _h - 1, _x + _w - 1, g_gui._color);
-
// Draw text
int start = _scrollLine - _linesPerPage + 1;
int y = _y + 2;
+ g_gui.theme()->drawDialogBackground(Common::Rect(_x, _y, _x+_w, _y+_h));
+
for (int line = 0; line < _linesPerPage; line++) {
int x = _x + 1;
for (int column = 0; column < _lineWidth; column++) {
@@ -174,7 +151,7 @@ void ConsoleDialog::drawDialog() {
#else
byte c = buffer((start + line) * _lineWidth + column);
#endif
- g_gui.drawChar(c, x, y, g_gui._textcolor, _font);
+ g_gui.theme()->drawChar(Common::Rect(x, y, x+kConsoleCharWidth, y+kConsoleLineHeight), c, _font);
x += kConsoleCharWidth;
}
y += kConsoleLineHeight;
@@ -182,21 +159,14 @@ void ConsoleDialog::drawDialog() {
// Draw the scrollbar
_scrollBar->draw();
-
- // Finally blit it all to the screen
- g_gui.addDirtyRect(_x, _y, _w, _h);
}
void ConsoleDialog::handleScreenChanged() {
- free(_canvas.pixels);
- _canvas.pixels = NULL;
+ Dialog::handleScreenChanged();
draw();
}
void ConsoleDialog::handleTickle() {
- if (!_canvas.pixels)
- return;
-
uint32 time = g_system->getMillis();
if (_caretTime < time) {
_caretTime = time + kCaretBlinkTime;
@@ -219,7 +189,7 @@ void ConsoleDialog::handleTickle() {
draw();
} else if (_slideMode == kUpSlideMode && _y <= -_h) {
// End the slide
- _slideMode = kNoSlideMode;
+ //_slideMode = kNoSlideMode;
close();
} else
draw();
@@ -614,6 +584,7 @@ void ConsoleDialog::print(const char *str) {
}
void ConsoleDialog::drawCaret(bool erase) {
+ // TODO: use code from EditableWidget::drawCaret here
int line = _currentPos / _lineWidth;
int displayLine = line - _scrollLine + _linesPerPage - 1;
@@ -626,17 +597,8 @@ void ConsoleDialog::drawCaret(bool erase) {
int x = _x + 1 + (_currentPos % _lineWidth) * kConsoleCharWidth;
int y = _y + displayLine * kConsoleLineHeight;
- char c = buffer(_currentPos);
- if (erase) {
- g_gui.fillRect(x, y, kConsoleCharWidth, kConsoleLineHeight, g_gui._bgcolor);
- g_gui.drawChar(c, x, y + 2, g_gui._textcolor, _font);
- } else {
- g_gui.fillRect(x, y, kConsoleCharWidth, kConsoleLineHeight, g_gui._textcolor);
- g_gui.drawChar(c, x, y + 2, g_gui._bgcolor, _font);
- }
- g_gui.addDirtyRect(x, y, kConsoleCharWidth, kConsoleLineHeight);
-
_caretVisible = !erase;
+ g_gui.theme()->drawCaret(Common::Rect(x, y, x+kConsoleCharWidth, y+kConsoleLineHeight), erase);
}
void ConsoleDialog::scrollToCurrent() {
diff --git a/gui/console.h b/gui/console.h
index 0bd0cb88d1..257ec95b4b 100644
--- a/gui/console.h
+++ b/gui/console.h
@@ -43,7 +43,6 @@ public:
typedef bool (*CompletionCallbackProc)(ConsoleDialog* console, const char *input, char*& completion, void *refCon);
protected:
- Graphics::Surface _canvas;
const Graphics::Font *_font;
char _buffer[kBufferSize];
diff --git a/gui/dialog.cpp b/gui/dialog.cpp
index fd8cec6a87..c6be54248d 100644
--- a/gui/dialog.cpp
+++ b/gui/dialog.cpp
@@ -40,7 +40,7 @@ namespace GUI {
Dialog::Dialog(int x, int y, int w, int h)
: GuiObject(x, y, w, h),
- _mouseWidget(0), _focusedWidget(0), _dragWidget(0), _visible(false) {
+ _mouseWidget(0), _focusedWidget(0), _dragWidget(0), _visible(false), _mainDialog(false) {
}
Dialog::~Dialog() {
@@ -88,6 +88,18 @@ void Dialog::close() {
releaseFocus();
}
+void Dialog::handleScreenChanged() {
+ // The screen has changed. That means the screen visual may also have
+ // changed, so any cached image may be invalid. The subsequent redraw
+ // should be treated as the very first draw.
+
+ Widget *w = _firstWidget;
+ while (w) {
+ w->setHints(THEME_HINT_FIRST_DRAW);
+ w = w->_next;
+ }
+}
+
void Dialog::releaseFocus() {
if (_focusedWidget) {
_focusedWidget->lostFocus();
@@ -104,8 +116,7 @@ void Dialog::drawDialog() {
if (!isVisible())
return;
- g_gui.blendRect(_x, _y, _w, _h, g_gui._bgcolor);
- g_gui.box(_x, _y, _w, _h, g_gui._color, g_gui._shadowcolor);
+ g_gui.theme()->drawDialogBackground(Common::Rect(_x, _y, _x+_w, _y+_h), Theme::kStateEnabled, _mainDialog);
// Draw all children
Widget *w = _firstWidget;
@@ -113,9 +124,6 @@ void Dialog::drawDialog() {
w->draw();
w = w->_next;
}
-
- // Flag the draw area as dirty
- g_gui.addDirtyRect(_x, _y, _w, _h);
}
void Dialog::handleMouseDown(int x, int y, int button, int clickCount) {
diff --git a/gui/dialog.h b/gui/dialog.h
index 69d851f78a..5170e7c9b2 100644
--- a/gui/dialog.h
+++ b/gui/dialog.h
@@ -44,6 +44,7 @@ protected:
Widget *_focusedWidget;
Widget *_dragWidget;
bool _visible;
+ bool _mainDialog; // FIXME: find a better solution for this and change the Theme class to handle it then
private:
int _result;
@@ -73,7 +74,7 @@ protected:
virtual void handleKeyUp(uint16 ascii, int keycode, int modifiers);
virtual void handleMouseMoved(int x, int y, int button);
virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
- virtual void handleScreenChanged() {}
+ void handleScreenChanged();
Widget *findWidget(int x, int y); // Find the widget at pos x,y if any
diff --git a/gui/editable.cpp b/gui/editable.cpp
index 07007583b5..3909acb423 100644
--- a/gui/editable.cpp
+++ b/gui/editable.cpp
@@ -143,7 +143,6 @@ void EditableWidget::drawCaret(bool erase) {
Common::Rect editRect = getEditRect();
- int16 color = (erase ^ _caretInverse) ? g_gui._bgcolor : g_gui._textcolorhi;
int x = editRect.left;
int y = editRect.top + 1;
@@ -155,9 +154,8 @@ void EditableWidget::drawCaret(bool erase) {
x += getAbsX();
y += getAbsY();
- g_gui.vLine(x, y, y + editRect.height() - 2, color);
- g_gui.addDirtyRect(x, y, 2, editRect.height() - 2);
-
+ g_gui.theme()->drawCaret(Common::Rect(x, y, x+editRect.width(), y+editRect.height()-2), erase);
+
_caretVisible = !erase;
}
diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index 7d9cc18dea..68d5bdb7f2 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -490,6 +490,7 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
LauncherDialog::LauncherDialog(GameDetector &detector)
: Dialog(0, 0, 320, 200), _detector(detector) {
+ _mainDialog = true;
const int screenW = g_system->getOverlayWidth();
const int screenH = g_system->getOverlayHeight();
diff --git a/gui/module.mk b/gui/module.mk
index e3b2af7727..9c6eb8faac 100644
--- a/gui/module.mk
+++ b/gui/module.mk
@@ -16,7 +16,9 @@ MODULE_OBJS := \
gui/PopUpWidget.o \
gui/ScrollBarWidget.o \
gui/TabWidget.o \
- gui/widget.o
+ gui/widget.o \
+ gui/theme.o \
+ gui/ThemeNew.o
MODULE_DIRS += \
gui
diff --git a/gui/newgui.cpp b/gui/newgui.cpp
index 11f57fb167..91e7249d36 100644
--- a/gui/newgui.cpp
+++ b/gui/newgui.cpp
@@ -24,6 +24,8 @@
#include "gui/newgui.h"
#include "gui/dialog.h"
+#include "common/config-manager.h"
+
DECLARE_SINGLETON(GUI::NewGui);
namespace GUI {
@@ -55,7 +57,7 @@ enum {
// Constructor
NewGui::NewGui() : _needRedraw(false),
- _stateIsSaved(false), _font(0), _cursorAnimateCounter(0), _cursorAnimateTimer(0) {
+ _stateIsSaved(false), _cursorAnimateCounter(0), _cursorAnimateTimer(0) {
_system = &OSystem::instance();
@@ -65,32 +67,26 @@ NewGui::NewGui() : _needRedraw(false),
// Reset key repeat
_currentKeyDown.keycode = 0;
- // updates the scaling factor
- updateScaleFactor();
-}
-
-void NewGui::updateColors() {
- // Setup some default GUI colors.
- _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);
-}
-
-void NewGui::updateScaleFactor() {
- const int screenW = g_system->getOverlayWidth();
- const int screenH = g_system->getOverlayHeight();
-
- // TODO: Perhaps we should also set the widget size here. That'd allow
- // us to remove much of the screen size checking from the individual
- // widgets.
-
- if (screenW >= 400 && screenH >= 300) {
- _font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
+ ConfMan.registerDefault("gui_theme", "default-theme");
+ Common::String style = ConfMan.get("gui_theme");
+ if (scumm_stricmp(style.c_str(), "classic") == 0) {
+ _theme = new ThemeClassic(_system);
} else {
- _font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
+ _theme = new ThemeNew(_system, style.c_str());
+ }
+ assert(_theme);
+
+ // Init the theme
+ if (!_theme->init()) {
+ warning("Could not initialize your preferred theme, falling back to classic style");
+ delete _theme;
+ _theme = new ThemeClassic(_system);
+ assert(_theme);
+ if (!_theme->init()) {
+ error("Couldn't initialize classic theme");
+ }
}
+ _theme->resetDrawArea();
}
void NewGui::runLoop() {
@@ -101,36 +97,34 @@ void NewGui::runLoop() {
if (activeDialog == 0)
return;
- // Setup some default GUI colors. Normally this will be done whenever an
- // EVENT_SCREEN_CHANGED is received. However, not yet all backends support
- // that event, so we also do it "manually" whenever a run loop is entered.
- updateColors();
- updateScaleFactor();
-
if (!_stateIsSaved) {
saveState();
+ _theme->enable();
didSaveState = true;
}
+ _theme->openDialog();
+
while (!_dialogStack.empty() && activeDialog == _dialogStack.top()) {
activeDialog->handleTickle();
if (_needRedraw) {
// Restore the overlay to its initial state, then draw all dialogs.
// This is necessary to get the blending right.
- _system->clearOverlay();
- _system->grabOverlay((OverlayColor *)_screen.pixels, _screenPitch);
+ _theme->clearAll();
+ for (int i = 0; i < _dialogStack.size(); ++i) {
+ _theme->closeDialog();
+ }
for (int i = 0; i < _dialogStack.size(); i++) {
- // For each dialog we draw we have to ensure the correct
- // scaling mode is active.
- updateScaleFactor();
+ _theme->openDialog();
_dialogStack[i]->drawDialog();
}
_needRedraw = false;
}
animateCursor();
+ _theme->drawAll();
_system->updateScreen();
OSystem::Event event;
@@ -191,8 +185,9 @@ void NewGui::runLoop() {
_system->quit();
return;
case OSystem::EVENT_SCREEN_CHANGED:
- updateColors();
- updateScaleFactor();
+ // reinit the whole theme
+ _theme->refresh();
+ _needRedraw = true;
activeDialog->handleScreenChanged();
break;
}
@@ -211,8 +206,12 @@ void NewGui::runLoop() {
_system->delayMillis(10);
}
- if (didSaveState)
+ _theme->closeDialog();
+
+ if (didSaveState) {
restoreState();
+ _theme->disable();
+ }
}
#pragma mark -
@@ -221,20 +220,6 @@ void NewGui::saveState() {
// Backup old cursor
_oldCursorMode = _system->showMouse(true);
- // Enable the overlay
- _system->showOverlay();
-
- // Create a screen buffer for the overlay data, and fill it with
- // whatever is visible on the screen rught now.
- _screen.h = _system->getOverlayHeight();
- _screen.w = _system->getOverlayWidth();
- _screen.bytesPerPixel = sizeof(OverlayColor);
- _screen.pitch = _screen.w * _screen.bytesPerPixel;
- _screenPitch = _screen.w;
- _screen.pixels = (OverlayColor*)calloc(_screen.w * _screen.h, sizeof(OverlayColor));
-
- _system->grabOverlay((OverlayColor *)_screen.pixels, _screenPitch);
-
_currentKeyDown.keycode = 0;
_lastClick.x = _lastClick.y = 0;
_lastClick.time = 0;
@@ -246,12 +231,6 @@ void NewGui::saveState() {
void NewGui::restoreState() {
_system->showMouse(_oldCursorMode);
- _system->hideOverlay();
- if (_screen.pixels) {
- free(_screen.pixels);
- _screen.pixels = 0;
- }
-
_system->updateScreen();
_stateIsSaved = false;
@@ -272,194 +251,6 @@ void NewGui::closeTopDialog() {
_needRedraw = true;
}
-#pragma mark -
-
-const Graphics::Font &NewGui::getFont() const {
- return *_font;
-}
-
-OverlayColor *NewGui::getBasePtr(int x, int y) {
- return (OverlayColor *)_screen.getBasePtr(x, y);
-}
-
-void NewGui::box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB) {
- hLine(x + 1, y, x + width - 2, colorA);
- hLine(x, y + 1, x + width - 1, colorA);
- vLine(x, y + 1, y + height - 2, colorA);
- vLine(x + 1, y, y + height - 1, colorA);
-
- hLine(x + 1, y + height - 2, x + width - 1, colorB);
- hLine(x + 1, y + height - 1, x + width - 2, colorB);
- vLine(x + width - 1, y + 1, y + height - 2, colorB);
- vLine(x + width - 2, y + 1, y + height - 1, colorB);
-}
-
-void NewGui::hLine(int x, int y, int x2, OverlayColor color) {
- _screen.hLine(x, y, x2, color);
-}
-
-void NewGui::vLine(int x, int y, int y2, OverlayColor color) {
- _screen.vLine(x, y, y2, color);
-}
-
-void NewGui::copyToSurface(Graphics::Surface *s, int x, int y, int w, int h) {
- Common::Rect rect(x, y, x + w, y + h);
- rect.clip(_screen.w, _screen.h);
-
- if (!rect.isValidRect())
- return;
-
- s->w = rect.width();
- s->h = rect.height();
- s->bytesPerPixel = sizeof(OverlayColor);
- s->pitch = s->w * s->bytesPerPixel;
- s->pixels = (OverlayColor *)malloc(s->pitch * s->h);
-
- w = s->w;
- h = s->h;
-
- OverlayColor *dst = (OverlayColor *)s->pixels;
- OverlayColor *src = getBasePtr(rect.left, rect.top);
-
- while (h--) {
- memcpy(dst, src, s->pitch);
- src += _screenPitch;
- dst += s->w;
- }
-}
-
-void NewGui::drawSurface(const Graphics::Surface &s, int x, int y) {
- Common::Rect rect(x, y, x + s.w, y + s.h);
- rect.clip(_screen.w, _screen.h);
-
- if (!rect.isValidRect())
- return;
-
- assert(s.bytesPerPixel == sizeof(OverlayColor));
-
- OverlayColor *src = (OverlayColor *)s.pixels;
- OverlayColor *dst = getBasePtr(rect.left, rect.top);
-
- int w = rect.width();
- int h = rect.height();
-
- while (h--) {
- memcpy(dst, src, s.pitch);
- src += w;
- dst += _screenPitch;
- }
-}
-
-void NewGui::blendRect(int x, int y, int w, int h, OverlayColor color, int level) {
-#ifdef NEWGUI_256
- fillRect(x, y, w, h, color);
-#else
- Common::Rect rect(x, y, x + w, y + h);
- rect.clip(_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(color, aa, ar, ag, ab);
- a = aa*level/(level+1);
- if (a < 1)
- return;
- r = ar * a;
- g = ag * a;
- b = ab * a;
-
- OverlayColor *ptr = getBasePtr(rect.left, rect.top);
-
- h = rect.height();
- 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 += _screenPitch;
- }
-
- } else {
-
- int r, g, b;
- uint8 ar, ag, ab;
- _system->colorToRGB(color, ar, ag, ab);
- r = ar * level;
- g = ag * level;
- b = ab * level;
-
- OverlayColor *ptr = getBasePtr(rect.left, rect.top);
-
- h = rect.height();
- 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) / (level+1),
- (ag + g) / (level+1),
- (ab + b) / (level+1));
- }
- ptr += _screenPitch;
- }
-
- }
-#endif
-}
-
-void NewGui::fillRect(int x, int y, int w, int h, OverlayColor color) {
- _screen.fillRect(Common::Rect(x, y, x + w, y + h), color);
-}
-
-void NewGui::frameRect(int x, int y, int w, int h, OverlayColor color) {
- _screen.frameRect(Common::Rect(x, y, x + w, y + h), color);
-}
-
-void NewGui::addDirtyRect(int x, int y, int w, int h) {
- Common::Rect rect(x, y, x + w, y + h);
- rect.clip(_screen.w, _screen.h);
-
- if (!rect.isValidRect())
- return;
-
- // For now we don't keep yet another list of dirty rects but simply
- // blit the affected area directly to the overlay. At least for our current
- // GUI/widget/dialog code that is just fine.
- OverlayColor *buf = getBasePtr(rect.left, rect.top);
- _system->copyRectToOverlay(buf, _screenPitch, rect.left, rect.top, rect.width(), rect.height());
-}
-
-void NewGui::drawChar(byte chr, int xx, int yy, OverlayColor color, const Graphics::Font *font) {
- if (font == 0)
- font = &getFont();
- font->drawChar(&_screen, chr, xx, yy, color);
-}
-
-int NewGui::getStringWidth(const String &str) const {
- return getFont().getStringWidth(str);
-}
-
-int NewGui::getCharWidth(byte c) const {
- return getFont().getCharWidth(c);
-}
-
-int NewGui::getFontHeight() const {
- return getFont().getFontHeight();
-}
-
-void NewGui::drawString(const String &s, int x, int y, int w, OverlayColor color, TextAlignment align, int deltax, bool useEllipsis) {
- getFont().drawString(&_screen, s, x, y, w, color, align, deltax, useEllipsis);
-}
-
//
// Draw the mouse cursor (animated). This is mostly ripped from the cursor code in gfx.cpp
// We could plug in a different cursor here if we like to.
diff --git a/gui/newgui.h b/gui/newgui.h
index 51cc2af2ce..2307f90fc5 100644
--- a/gui/newgui.h
+++ b/gui/newgui.h
@@ -26,6 +26,7 @@
#include "common/stack.h"
#include "common/str.h"
#include "graphics/fontman.h"
+#include "gui/theme.h"
class OSystem;
@@ -67,18 +68,23 @@ public:
bool isActive() const { return ! _dialogStack.empty(); }
+ Theme *theme() { return _theme; }
+
+ const Graphics::Font &getFont() const { return *(_theme->getFont()); }
+ int getFontHeight() const { return _theme->getFontHeight(); }
+ int getStringWidth(const Common::String &str) const { return _theme->getStringWidth(str); }
+ int getCharWidth(byte c) const { return _theme->getCharWidth(c); }
+
protected:
OSystem *_system;
- Graphics::Surface _screen;
- int _screenPitch;
+
+ Theme *_theme;
bool _needRedraw;
DialogStack _dialogStack;
bool _stateIsSaved;
- const Graphics::Font *_font;
-
// for continuous events (keyDown)
struct {
uint16 ascii;
@@ -109,54 +115,6 @@ protected:
void loop();
void animateCursor();
- void updateColors();
-
- void updateScaleFactor();
-
- OverlayColor *getBasePtr(int x, int y);
-
-public:
- // Theme colors
- OverlayColor _color, _shadowcolor;
- OverlayColor _bgcolor;
- OverlayColor _textcolor;
- OverlayColor _textcolorhi;
-
- // Font
- const Graphics::Font &getFont() const;
-
- // Screen surface
- Graphics::Surface &getScreen() { return _screen; }
-
- // Drawing primitives
- void box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB);
- void hLine(int x, int y, int x2, OverlayColor color);
- void vLine(int x, int y, int y2, OverlayColor color);
-
- /**
- * Copy the specified screen rectangle into a new graphics surfaces.
- * New memory for the GFX data is allocated via malloc; it is the
- * callers responsibilty to free that data.
- */
- void copyToSurface(Graphics::Surface *s, int x, int y, int w, int h);
-
- /**
- * Draw the graphics contained in the given surface at the specified coordinates.
- */
- void drawSurface(const Graphics::Surface &s, int x, int y);
-
- void blendRect(int x, int y, int w, int h, OverlayColor color, int level = 3);
- void fillRect(int x, int y, int w, int h, OverlayColor color);
- void frameRect(int x, int y, int w, int h, OverlayColor color);
-
- void drawChar(byte c, int x, int y, OverlayColor color, const Graphics::Font *font = 0);
- void drawString(const String &str, int x, int y, int w, OverlayColor color, Graphics::TextAlignment align = Graphics::kTextAlignLeft, int deltax = 0, bool useEllipsis = true);
-
- int getStringWidth(const String &str) const;
- int getCharWidth(byte c) const;
- int getFontHeight() const;
-
- void addDirtyRect(int x, int y, int w, int h);
};
} // End of namespace GUI
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
+
diff --git a/gui/theme.h b/gui/theme.h
new file mode 100644
index 0000000000..b6730199ef
--- /dev/null
+++ b/gui/theme.h
@@ -0,0 +1,361 @@
+/* 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 $
+ */
+
+#ifndef GUI_THEME_H
+#define GUI_THEME_H
+
+#include "common/stdafx.h"
+#include "common/system.h"
+#include "common/rect.h"
+#include "common/str.h"
+#include "common/config-file.h"
+
+#include "graphics/surface.h"
+#include "graphics/fontman.h"
+
+namespace GUI {
+
+// Hints to the theme engine that the widget is used in a non-standard way.
+
+enum {
+ // Indicates that this is the first time the widget is drawn.
+ THEME_HINT_FIRST_DRAW = 1 << 0,
+
+ // Indicates that the widget will be redrawn often, e.g. list widgets.
+ // It may therefore be a good idea to save the background so that it
+ // can be redrawn quickly.
+ THEME_HINT_SAVE_BACKGROUND = 1 << 1
+};
+
+class Theme {
+public:
+ Theme() : _drawArea(), _configFile() {}
+ virtual ~Theme() {}
+
+ enum kTextAlign {
+ kTextAlignLeft,
+ kTextAlignCenter,
+ kTextAlignRight
+ };
+
+ enum kWidgetBackground {
+ kWidgetBackgroundNo,
+ kWidgetBackgroundPlain,
+ kWidgetBackgroundBorder,
+ kWidgetBackgroundBorderSmall
+ };
+
+ enum kState {
+ kStateDisabled,
+ kStateEnabled,
+ kStateHighlight
+ };
+
+ enum kScrollbarState {
+ kScrollbarStateNo,
+ kScrollbarStateUp,
+ kScrollbarStateDown,
+ kScrollbarStateSlider,
+ kScrollbarStateSinglePage
+ };
+
+ virtual bool init() = 0;
+ virtual void deinit() = 0;
+
+ virtual void refresh() = 0;
+
+ virtual void enable() = 0;
+ virtual void disable() = 0;
+
+ virtual void openDialog() = 0;
+ virtual void closeDialog() = 0;
+
+ virtual void clearAll() = 0;
+ virtual void drawAll() = 0;
+
+ virtual void setDrawArea(const Common::Rect &r) { _drawArea = r; }
+ // resets the draw area to the screen size
+ virtual void resetDrawArea() = 0;
+
+ virtual const Common::ConfigFile &getConfigFile() { return _configFile; }
+
+ virtual const Graphics::Font *getFont() const = 0;
+ virtual int getFontHeight() const = 0;
+ virtual int getStringWidth(const Common::String &str) const = 0;
+ virtual int getCharWidth(byte c) const = 0;
+
+ virtual void drawDialogBackground(const Common::Rect &r, kState state = kStateEnabled, bool mainDialog = false) = 0;
+ virtual void drawText(const Common::Rect &r, const Common::String &str, kState state = kStateEnabled, kTextAlign align = kTextAlignCenter, bool inverted = false, int deltax = 0, bool useEllipsis = true) = 0;
+ // this should ONLY be used by the debugger until we get a nicer solution
+ virtual void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state = kStateEnabled) = 0;
+
+ virtual void drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background = kWidgetBackgroundPlain, kState state = kStateEnabled) = 0;
+ virtual void drawButton(const Common::Rect &r, const Common::String &str, kState state = kStateEnabled) = 0;
+ virtual void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, kState state = kStateEnabled) = 0;
+ virtual void drawSlider(const Common::Rect &r, int width, kState state = kStateEnabled) = 0;
+ virtual void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, kState state = kStateEnabled) = 0;
+ virtual void drawTab(const Common::Rect &r, const Common::String &str, bool active, kState state = kStateEnabled) = 0;
+ virtual void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, kScrollbarState, kState state = kStateEnabled) = 0;
+ virtual void drawCaret(const Common::Rect &r, bool erase, kState state = kStateEnabled) = 0;
+ virtual void drawLineSeparator(const Common::Rect &r, kState state = kStateEnabled) = 0;
+
+ Graphics::TextAlignment convertAligment(kTextAlign align) const {
+ switch (align) {
+ case kTextAlignLeft:
+ return Graphics::kTextAlignLeft;
+ break;
+
+ case kTextAlignRight:
+ return Graphics::kTextAlignRight;
+ break;
+
+ default:
+ break;
+ };
+ return Graphics::kTextAlignCenter;
+ };
+
+ kTextAlign convertAligment(Graphics::TextAlignment align) const {
+ switch (align) {
+ case Graphics::kTextAlignLeft:
+ return kTextAlignLeft;
+ break;
+
+ case Graphics::kTextAlignRight:
+ return kTextAlignRight;
+ break;
+
+ default:
+ break;
+ }
+ return kTextAlignCenter;
+ }
+
+protected:
+ Common::Rect _drawArea;
+ Common::ConfigFile _configFile;
+};
+
+#define OLDGUI_TRANSPARENCY
+
+class ThemeClassic : public Theme {
+public:
+ ThemeClassic(OSystem *system);
+ virtual ~ThemeClassic();
+
+ bool init();
+ void deinit();
+
+ void refresh();
+
+ void enable();
+ void disable();
+
+ void openDialog();
+ void closeDialog();
+
+ void clearAll();
+ void drawAll();
+
+ void resetDrawArea();
+
+ const Graphics::Font *getFont() const { return _font; }
+ int getFontHeight() const { if (_initOk) return _font->getFontHeight(); return 0; }
+ int getStringWidth(const Common::String &str) const { if (_initOk) return _font->getStringWidth(str); return 0; }
+ int getCharWidth(byte c) const { if (_initOk) return _font->getCharWidth(c); return 0; }
+
+ void drawDialogBackground(const Common::Rect &r, kState state, bool mainDialog);
+ void drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis);
+ void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state);
+
+ void drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background, kState state);
+ void drawButton(const Common::Rect &r, const Common::String &str, kState state);
+ void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, kState state);
+ void drawSlider(const Common::Rect &r, int width, kState state);
+ void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, kState state);
+ void drawTab(const Common::Rect &r, const Common::String &str, bool active, kState state);
+ void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, kScrollbarState, kState state);
+ void drawCaret(const Common::Rect &r, bool erase, kState state);
+ void drawLineSeparator(const Common::Rect &r, kState state);
+private:
+ void restoreBackground(Common::Rect r);
+ bool addDirtyRect(Common::Rect r);
+
+ void box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB);
+ void box(int x, int y, int width, int height);
+
+ OverlayColor getColor(kState state);
+
+ OSystem *_system;
+ Graphics::Surface _screen;
+
+#ifdef OLDGUI_TRANSPARENCY
+ struct DialogState {
+ Graphics::Surface screen;
+ } *_dialog;
+
+ void blendScreenToDialog();
+#endif
+
+ bool _initOk;
+
+ const Graphics::Font *_font;
+ OverlayColor _color, _shadowcolor;
+ OverlayColor _bgcolor;
+ OverlayColor _textcolor;
+ OverlayColor _textcolorhi;
+};
+
+class ThemeNew : public Theme {
+public:
+ ThemeNew(OSystem *system, Common::String stylefile);
+ virtual ~ThemeNew();
+
+ bool init();
+ void deinit();
+
+ void refresh();
+
+ void enable();
+ void disable();
+
+ void openDialog();
+ void closeDialog();
+
+ void clearAll();
+ void drawAll();
+
+ void resetDrawArea();
+
+ const Graphics::Font *getFont() const { return _font; }
+ int getFontHeight() const { if (_font) return _font->getFontHeight(); return 0; }
+ int getStringWidth(const Common::String &str) const { if (_font) return _font->getStringWidth(str); return 0; }
+ int getCharWidth(byte c) const { if (_font) return _font->getCharWidth(c); return 0; }
+
+ void drawDialogBackground(const Common::Rect &r, kState state, bool mainDialog);
+ void drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis);
+ void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state);
+
+ void drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background, kState state);
+ void drawButton(const Common::Rect &r, const Common::String &str, kState state);
+ void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, kState state);
+ void drawSlider(const Common::Rect &r, int width, kState state);
+ void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, kState state);
+ void drawTab(const Common::Rect &r, const Common::String &str, bool active, kState state);
+ void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, kScrollbarState, kState state);
+ void drawCaret(const Common::Rect &r, bool erase, kState state);
+ void drawLineSeparator(const Common::Rect &r, kState state);
+private:
+ bool addDirtyRect(Common::Rect r, bool backup = false);
+
+ void colorFade(const Common::Rect &r, OverlayColor start, OverlayColor end);
+ void drawRect(const Common::Rect &r, const Graphics::Surface *corner,
+ const Graphics::Surface *top, const Graphics::Surface *left, const Graphics::Surface *fill, int alpha);
+ void 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 = 1);
+ void drawSurface(const Common::Rect &r, const Graphics::Surface *surf, bool upDown, bool leftRight, int alpha);
+ void drawSurfaceMasked(const Common::Rect &r, const Graphics::Surface *surf, bool upDown, bool leftRight, int alpha,
+ OverlayColor start, OverlayColor end, uint factor = 1);
+
+ OSystem *_system;
+ Graphics::Surface _screen;
+
+ bool _initOk;
+ bool _forceRedraw;
+
+ void restoreBackground(Common::Rect r);
+ OverlayColor getColor(kState state);
+
+ struct DialogState {
+ Graphics::Surface screen;
+ } *_dialog;
+
+ const Graphics::Font *_font;
+
+ enum kImageHandles {
+ kDialogBkgdCorner = 0,
+ kDialogBkgdTop = 1,
+ kDialogBkgdLeft = 2,
+ kDialogBkgd = 3,
+ kWidgetBkgdCorner = 4,
+ kWidgetBkgdTop = 5,
+ kWidgetBkgdLeft = 6,
+ kWidgetBkgd = 7,
+ kCheckboxEmpty = 8,
+ kCheckboxChecked = 9,
+ kWidgetArrow = 10,
+ kImageHandlesMax
+ };
+
+ const Common::String *_imageHandles;
+ const Graphics::Surface **_images;
+
+ enum kColorHandles {
+ kMainDialogStart = 0,
+ kMainDialogEnd = 1,
+
+ kDialogStart = 2,
+ kDialogEnd = 3,
+
+ kColorStateDisabled = 4,
+ kColorStateHighlight = 5,
+ kColorStateEnabled = 6,
+ kColorTransparency = 7,
+
+ kTextInvertedBackground = 8,
+ kTextInvertedColor = 9,
+
+ kWidgetBackgroundStart = 10,
+ kWidgetBackgroundEnd = 11,
+ kWidgetBackgroundSmallStart = 12,
+ kWidgetBackgroundSmallEnd = 13,
+
+ kButtonBackgroundStart = 14,
+ kButtonBackgroundEnd = 15,
+ kButtonTextEnabled = 16,
+ kButtonTextDisabled = 17,
+ kButtonTextHighlight = 18,
+
+ kSliderBackgroundStart = 19,
+ kSliderBackgroundEnd = 20,
+ kSliderStart = 21,
+ kSliderEnd = 22,
+
+ kTabBackgroundStart = 23,
+ kTabBackgroundEnd = 24,
+
+ kScrollbarBackgroundStart = 25,
+ kScrollbarBackgroundEnd = 26,
+ kScrollbarButtonStart = 27,
+ kScrollbarButtonEnd = 28,
+ kScrollbarSliderStart = 29,
+ kScrollbarSliderEnd = 30,
+
+ kCaretColor = 31,
+
+ kColorHandlesMax
+ };
+
+ OverlayColor _colors[kColorHandlesMax];
+};
+} // end of namespace GUI
+
+#endif // GUI_THEME_H
diff --git a/gui/themes/default-theme.zip b/gui/themes/default-theme.zip
new file mode 100644
index 0000000000..0f52429200
--- /dev/null
+++ b/gui/themes/default-theme.zip
Binary files differ
diff --git a/gui/widget.cpp b/gui/widget.cpp
index 3633715ce0..6608c4fd57 100644
--- a/gui/widget.cpp
+++ b/gui/widget.cpp
@@ -29,7 +29,7 @@ namespace GUI {
Widget::Widget(GuiObject *boss, int x, int y, int w, int h)
: GuiObject(x, y, w, h), _type(0), _boss(boss),
- _id(0), _flags(0), _hasFocus(false) {
+ _id(0), _flags(0), _hints(THEME_HINT_FIRST_DRAW), _hasFocus(false) {
// Insert into the widget list of the boss
_next = _boss->_firstWidget;
_boss->_firstWidget = this;
@@ -52,16 +52,12 @@ void Widget::draw() {
_y = getAbsY();
// Clear background (unless alpha blending is enabled)
- if (_flags & WIDGET_CLEARBG)
- gui->fillRect(_x, _y, _w, _h, gui->_bgcolor);
+ //if (_flags & WIDGET_CLEARBG)
+ // gui->fillRect(_x, _y, _w, _h, gui->_bgcolor);
// Draw border
if (_flags & WIDGET_BORDER) {
- OverlayColor colorA = gui->_color;
- OverlayColor colorB = gui->_shadowcolor;
- if ((_flags & WIDGET_INV_BORDER) == WIDGET_INV_BORDER)
- SWAP(colorA, colorB);
- gui->box(_x, _y, _w, _h, colorA, colorB);
+ gui->theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), _hints, Theme::kWidgetBackgroundBorder);
_x += 4;
_y += 4;
_w -= 8;
@@ -79,9 +75,6 @@ void Widget::draw() {
_h += 8;
}
- // Flag the draw area as dirty
- gui->addDirtyRect(_x, _y, _w, _h);
-
_x = oldX;
_y = oldY;
@@ -91,6 +84,8 @@ void Widget::draw() {
w->draw();
w = w->_next;
}
+
+ clearHints(THEME_HINT_FIRST_DRAW);
}
Widget *Widget::findWidgetInChain(Widget *w, int x, int y) {
@@ -137,8 +132,9 @@ void StaticTextWidget::setAlign(TextAlignment align) {
void StaticTextWidget::drawWidget(bool hilite) {
- NewGui *gui = &g_gui;
- gui->drawString(_label, _x, _y, _w, isEnabled() ? gui->_textcolor : gui->_color, _align);
+ g_gui.theme()->drawText(Common::Rect(_x, _y, _x+_w, _y+_h), _label,
+ isEnabled() ? Theme::kStateEnabled : Theme::kStateDisabled,
+ g_gui.theme()->convertAligment(_align));
}
#pragma mark -
@@ -146,7 +142,7 @@ void StaticTextWidget::drawWidget(bool hilite) {
ButtonWidget::ButtonWidget(GuiObject *boss, int x, int y, int w, int h, const String &label, uint32 cmd, uint8 hotkey, WidgetSize ws)
: StaticTextWidget(boss, x, y, w, h, label, kTextAlignCenter, ws), CommandSender(boss),
_cmd(cmd), _hotkey(hotkey) {
- _flags = WIDGET_ENABLED | WIDGET_BORDER | WIDGET_CLEARBG;
+ _flags = WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG;
_type = kButtonWidget;
}
@@ -156,11 +152,7 @@ void ButtonWidget::handleMouseUp(int x, int y, int button, int clickCount) {
}
void ButtonWidget::drawWidget(bool hilite) {
- NewGui *gui = &g_gui;
- const int off = (_h - g_gui.getFontHeight()) / 2;
- gui->drawString(_label, _x, _y + off, _w,
- !isEnabled() ? gui->_color :
- hilite ? gui->_textcolorhi : gui->_textcolor, _align);
+ g_gui.theme()->drawButton(Common::Rect(_x, _y, _x+_w, _y+_h), _label, isEnabled() ? (hilite ? Theme::kStateHighlight : Theme::kStateEnabled) : Theme::kStateDisabled);
}
#pragma mark -
@@ -187,39 +179,8 @@ void CheckboxWidget::setState(bool state) {
}
void CheckboxWidget::drawWidget(bool hilite) {
- NewGui *gui = &g_gui;
- int fontHeight = gui->getFontHeight();
-
- // Draw the box
- gui->box(_x, _y, fontHeight + 4, fontHeight + 4, gui->_color, gui->_shadowcolor);
- gui->fillRect(_x + 2, _y + 2, fontHeight, fontHeight, gui->_bgcolor);
-
- // If checked, draw cross inside the box
- if (_state) {
- Graphics::Surface &surf = gui->getScreen();
- Common::Point p0, p1, p2, p3;
- OverlayColor color = isEnabled() ? gui->_textcolor : gui->_color;
-
- p0 = Common::Point(_x + 4, _y + 4);
- p1 = Common::Point(_x + fontHeight - 1, _y + 4);
- p2 = Common::Point(_x + 4, _y + fontHeight - 1);
- p3 = Common::Point(_x + fontHeight - 1, _y + fontHeight - 1);
-
- if (_ws == kBigWidgetSize) {
- surf.drawLine(p0.x + 1, p0.y, p3.x, p3.y - 1, color);
- surf.drawLine(p0.x, p0.y + 1, p3.x - 1, p3.y, color);
- surf.drawLine(p0.x + 1, p0.y + 1, p3.x - 1, p3.y - 1, color);
- surf.drawLine(p2.x + 1, p2.y - 1, p1.x - 1, p1.y + 1, color);
- surf.drawLine(p2.x + 1, p2.y, p1.x, p1.y + 1, color);
- surf.drawLine(p2.x, p2.y - 1, p1.x - 1, p1.y, color);
- } else {
- surf.drawLine(p0.x, p0.y, p3.x, p3.y, color);
- surf.drawLine(p2.x, p2.y, p1.x, p1.y, color);
- }
- }
-
- // Finally draw the label
- gui->drawString(_label, _x + fontHeight + 10, _y + 3, _w, isEnabled() ? gui->_textcolor : gui->_color);
+ g_gui.theme()->drawCheckbox(Common::Rect(_x, _y, _x+_w, _y+_h), _label, _state,
+ isEnabled() ? Theme::kStateEnabled : Theme::kStateDisabled);
}
#pragma mark -
@@ -262,15 +223,8 @@ void SliderWidget::handleMouseUp(int x, int y, int button, int clickCount) {
}
void SliderWidget::drawWidget(bool hilite) {
- NewGui *gui = &g_gui;
-
- // Draw the box
- gui->box(_x, _y, _w, _h, gui->_color, gui->_shadowcolor);
-
- // Draw the 'bar'
- gui->fillRect(_x + 2, _y + 2, valueToPos(_value), _h - 4,
- !isEnabled() ? gui->_color :
- hilite ? gui->_textcolorhi : gui->_textcolor);
+ g_gui.theme()->drawSlider(Common::Rect(_x, _y, _x+_w, _y+_h), valueToPos(_value),
+ isEnabled() ? (hilite ? Theme::kStateHighlight : Theme::kStateEnabled) : Theme::kStateDisabled);
}
int SliderWidget::valueToPos(int value) {
@@ -305,13 +259,9 @@ void GraphicsWidget::setGfx(const Graphics::Surface *gfx) {
}
void GraphicsWidget::drawWidget(bool hilite) {
- if (sizeof(OverlayColor) != _gfx.bytesPerPixel || !_gfx.pixels) {
- // FIXME: It doesn't really make sense to render this text here, since
- // this widget might be used for other things than rendering savegame
- // graphics/previews...
- g_gui.drawString("No preview", _x, _y + _h / 2 - g_gui.getFontHeight() / 2, _w, g_gui._textcolor, Graphics::kTextAlignCenter);
- } else
- g_gui.drawSurface(_gfx, _x, _y);
+ if (sizeof(OverlayColor) == _gfx.bytesPerPixel && _gfx.pixels) {
+ g_gui.theme()->drawSurface(Common::Rect(_x, _y, _x+_w, _y+_h), _gfx);
+ }
}
} // End of namespace GUI
diff --git a/gui/widget.h b/gui/widget.h
index 6b5e7d5c98..737b96a3ee 100644
--- a/gui/widget.h
+++ b/gui/widget.h
@@ -45,7 +45,6 @@ enum {
WIDGET_WANT_TICKLE = 1 << 7,
WIDGET_TRACK_MOUSE = 1 << 8,
WIDGET_RETAIN_FOCUS = 1 << 9 // Retain focus on mouse up. By default widgets lose focus on mouseup, but some widgets might want to retain it - widgets where you enter text, for instance
-
};
enum {
@@ -93,6 +92,7 @@ protected:
Widget *_next;
uint16 _id;
uint16 _flags;
+ uint16 _hints;
bool _hasFocus;
public:
@@ -127,6 +127,10 @@ public:
void clearFlags(int flags) { _flags &= ~flags; }
int getFlags() const { return _flags; }
+ void setHints(int hints) { _hints |= hints; }
+ void clearHints(int hints) { _hints &= ~hints; }
+ int getHints() const { return _hints; }
+
void setEnabled(bool e) { if (e) setFlags(WIDGET_ENABLED); else clearFlags(WIDGET_ENABLED); }
bool isEnabled() const { return _flags & WIDGET_ENABLED; }
bool isVisible() const { return !(_flags & WIDGET_INVISIBLE); }