[Scummvm-cvs-logs] CVS: scummvm/gui ThemeNew.cpp,NONE,1.1 theme.cpp,NONE,1.1 theme.h,NONE,1.1 EditTextWidget.cpp,1.38,1.39 ListWidget.cpp,1.60,1.61 PopUpWidget.cpp,1.42,1.43 ScrollBarWidget.cpp,1.27,1.28 TabWidget.cpp,1.21,1.22 about.cpp,1.45,1.46 about.h,1.18,1.19 console.cpp,1.70,1.71 console.h,1.37,1.38 dialog.cpp,1.64,1.65 dialog.h,1.43,1.44 editable.cpp,1.11,1.12 launcher.cpp,1.132,1.133 module.mk,1.17,1.18 newgui.cpp,1.123,1.124 newgui.h,1.64,1.65 widget.cpp,1.56,1.57 widget.h,1.49,1.50

Johannes Schickel lordhoto at users.sourceforge.net
Fri Jan 27 07:44:06 CET 2006


Update of /cvsroot/scummvm/scummvm/gui
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10168/gui

Modified Files:
	EditTextWidget.cpp ListWidget.cpp PopUpWidget.cpp 
	ScrollBarWidget.cpp TabWidget.cpp about.cpp about.h 
	console.cpp console.h dialog.cpp dialog.h editable.cpp 
	launcher.cpp module.mk newgui.cpp newgui.h widget.cpp widget.h 
Added Files:
	ThemeNew.cpp theme.cpp theme.h 
Log Message:
 - 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.


--- NEW FILE: ThemeNew.cpp ---
/* 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 

--- NEW FILE: theme.cpp ---
/* 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


--- NEW FILE: theme.h ---
/* 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

Index: EditTextWidget.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/EditTextWidget.cpp,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -d -r1.38 -r1.39
--- EditTextWidget.cpp	18 Jan 2006 17:39:35 -0000	1.38
+++ EditTextWidget.cpp	27 Jan 2006 15:43:23 -0000	1.39
@@ -59,15 +59,11 @@
 
 
 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 {

Index: ListWidget.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/ListWidget.cpp,v
retrieving revision 1.60
retrieving revision 1.61
diff -u -d -r1.60 -r1.61
--- ListWidget.cpp	18 Jan 2006 17:39:35 -0000	1.60
+++ ListWidget.cpp	27 Jan 2006 15:43:23 -0000	1.61
@@ -37,6 +37,7 @@
 	}
 
 	_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::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 @@
 			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 @@
 			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);
 		}
 	}
 }

Index: PopUpWidget.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/PopUpWidget.cpp,v
retrieving revision 1.42
retrieving revision 1.43
diff -u -d -r1.42 -r1.43
--- PopUpWidget.cpp	18 Jan 2006 17:39:35 -0000	1.42
+++ PopUpWidget.cpp	27 Jan 2006 15:43:23 -0000	1.43
@@ -140,13 +140,10 @@
 
 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 @@
 	}
 
 	// 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 @@
 
 	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 @@
 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::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 @@
 	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));
 	}
 }
 

Index: ScrollBarWidget.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/ScrollBarWidget.cpp,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- ScrollBarWidget.cpp	18 Jan 2006 17:39:35 -0000	1.27
+++ ScrollBarWidget.cpp	27 Jan 2006 15:43:23 -0000	1.28
@@ -179,73 +179,22 @@
 }
 
 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

Index: TabWidget.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/TabWidget.cpp,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- TabWidget.cpp	18 Jan 2006 17:39:36 -0000	1.21
+++ TabWidget.cpp	27 Jan 2006 15:43:23 -0000	1.22
@@ -127,7 +127,7 @@
 	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 @@
 	}
 	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) {

Index: about.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/about.cpp,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -d -r1.45 -r1.46
--- about.cpp	26 Jan 2006 23:53:13 -0000	1.45
+++ about.cpp	27 Jan 2006 15:43:23 -0000	1.46
@@ -73,7 +73,6 @@
 
 #include "gui/credits.h"
 
-
 AboutDialog::AboutDialog()
 	: Dialog(10, 20, 300, 174),
 	_scrollPos(0), _scrollTime(0), _modifiers(0), _willClose(false) {
@@ -111,7 +110,6 @@
 	}
 	_w += 2*xOff;
 
-
 	for (i = 0; i < 1; i++)
 		_lines.push_back("");
 
@@ -166,7 +164,7 @@
 		_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 @@
 	_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 @@
 
 	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 @@
 			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::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 @@
 		close();
 }
 
-
 } // End of namespace GUI

Index: about.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/about.h,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- about.h	18 Jan 2006 17:39:36 -0000	1.18
+++ about.h	27 Jan 2006 15:43:23 -0000	1.19
@@ -36,7 +36,6 @@
 	uint32		_lineHeight;
 	byte		_modifiers;
 	bool		_willClose;
-	Graphics::Surface	_canvas;
 
 	int xOff, yOff;
 
@@ -49,7 +48,6 @@
 	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);

Index: console.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/console.cpp,v
retrieving revision 1.70
retrieving revision 1.71
diff -u -d -r1.70 -r1.71
--- console.cpp	18 Jan 2006 17:39:36 -0000	1.70
+++ console.cpp	27 Jan 2006 15:43:23 -0000	1.71
@@ -114,10 +114,7 @@
 }
 
 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::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 @@
 #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 @@
 
 	// 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 @@
 			draw();
 		} else if (_slideMode == kUpSlideMode && _y <= -_h) {
 			// End the slide
-			_slideMode = kNoSlideMode;
+			//_slideMode = kNoSlideMode;
 			close();
 		} else
 			draw();
@@ -614,6 +584,7 @@
 }
 
 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 @@
 	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() {

Index: console.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/console.h,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -d -r1.37 -r1.38
--- console.h	18 Jan 2006 17:39:36 -0000	1.37
+++ console.h	27 Jan 2006 15:43:23 -0000	1.38
@@ -43,7 +43,6 @@
 	typedef bool (*CompletionCallbackProc)(ConsoleDialog* console, const char *input, char*& completion, void *refCon);
 
 protected:
-	Graphics::Surface	_canvas;
 	const Graphics::Font *_font;
 
 	char	_buffer[kBufferSize];

Index: dialog.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/dialog.cpp,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -d -r1.64 -r1.65
--- dialog.cpp	18 Jan 2006 17:39:36 -0000	1.64
+++ dialog.cpp	27 Jan 2006 15:43:23 -0000	1.65
@@ -40,7 +40,7 @@
 
 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 @@
 	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 @@
 	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 @@
 		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) {

Index: dialog.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/dialog.h,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -d -r1.43 -r1.44
--- dialog.h	18 Jan 2006 17:39:36 -0000	1.43
+++ dialog.h	27 Jan 2006 15:43:23 -0000	1.44
@@ -44,6 +44,7 @@
 	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 @@
 	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
 

Index: editable.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/editable.cpp,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- editable.cpp	18 Jan 2006 17:39:36 -0000	1.11
+++ editable.cpp	27 Jan 2006 15:43:23 -0000	1.12
@@ -143,7 +143,6 @@
 
 	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 @@
 	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;
 }
 

Index: launcher.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/launcher.cpp,v
retrieving revision 1.132
retrieving revision 1.133
diff -u -d -r1.132 -r1.133
--- launcher.cpp	21 Jan 2006 13:01:18 -0000	1.132
+++ launcher.cpp	27 Jan 2006 15:43:23 -0000	1.133
@@ -490,6 +490,7 @@
 
 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();

Index: module.mk
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/module.mk,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- module.mk	6 Feb 2005 18:12:26 -0000	1.17
+++ module.mk	27 Jan 2006 15:43:23 -0000	1.18
@@ -16,7 +16,9 @@
 	gui/PopUpWidget.o \
 	gui/ScrollBarWidget.o \
 	gui/TabWidget.o \
-	gui/widget.o
+	gui/widget.o \
+	gui/theme.o \
+	gui/ThemeNew.o
 
 MODULE_DIRS += \
 	gui

Index: newgui.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/newgui.cpp,v
retrieving revision 1.123
retrieving revision 1.124
diff -u -d -r1.123 -r1.124
--- newgui.cpp	18 Jan 2006 17:39:36 -0000	1.123
+++ newgui.cpp	27 Jan 2006 15:43:23 -0000	1.124
@@ -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 @@
 
 // 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 @@
 	// 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 @@
 	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 @@
 				_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 @@
 		_system->delayMillis(10);
 	}
 
-	if (didSaveState)
+	_theme->closeDialog();
+
+	if (didSaveState) {
 		restoreState();
+		_theme->disable();
+	}
 }
 
 #pragma mark -
@@ -221,20 +220,6 @@
 	// 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::restoreState() {
 	_system->showMouse(_oldCursorMode);
 
-	_system->hideOverlay();
-	if (_screen.pixels) {
-		free(_screen.pixels);
-		_screen.pixels = 0;
-	}
-
 	_system->updateScreen();
 
 	_stateIsSaved = false;
@@ -272,194 +251,6 @@
 	_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.

Index: newgui.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/newgui.h,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -d -r1.64 -r1.65
--- newgui.h	18 Jan 2006 17:39:36 -0000	1.64
+++ newgui.h	27 Jan 2006 15:43:23 -0000	1.65
@@ -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 @@
 
 	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 @@
 	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

Index: widget.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/widget.cpp,v
retrieving revision 1.56
retrieving revision 1.57
diff -u -d -r1.56 -r1.57
--- widget.cpp	18 Jan 2006 17:39:36 -0000	1.56
+++ widget.cpp	27 Jan 2006 15:43:23 -0000	1.57
@@ -29,7 +29,7 @@
 
 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 @@
 	_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 @@
 		_h += 8;
 	}
 
-	// Flag the draw area as dirty
-	gui->addDirtyRect(_x, _y, _w, _h);
-
 	_x = oldX;
 	_y = oldY;
 
@@ -91,6 +84,8 @@
 		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::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 @@
 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::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::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::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::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

Index: widget.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/widget.h,v
retrieving revision 1.49
retrieving revision 1.50
diff -u -d -r1.49 -r1.50
--- widget.h	18 Jan 2006 17:39:36 -0000	1.49
+++ widget.h	27 Jan 2006 15:43:23 -0000	1.50
@@ -45,7 +45,6 @@
 	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 @@
 	Widget		*_next;
 	uint16		_id;
 	uint16		_flags;
+	uint16		_hints;
 	bool		_hasFocus;
 
 public:
@@ -127,6 +127,10 @@
 	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); }





More information about the Scummvm-git-logs mailing list