- adds the new gui renderer also a new implementation for the classic gui

- adds a ImageMan and ImageDec class for loading and managing image files
 - adds a loader for zip files which is used by the new theme and the image manager
 - changes the widgets to use the new gui code
 - changes the scumm dialogs to use the new gui code
 - fixes a #include problem in the sky debugger with the new gui code

 To use the new gui copy gui/themes/default-theme.zip to your extrapath.
If the theme zip can not be found the gui will fallback to the classic theme.
If you want to change the gui styles use "gui_theme=classic" for the classic theme
and "gui_theme=default-theme" for the new theme.

Thanks to eriktorbjorn for testing and help with the new theme and to sev for
reviewing this patch.

svn-id: r20227
This commit is contained in:
Johannes Schickel 2006-01-27 15:43:23 +00:00
parent 901645cb0f
commit 5051b080a2
32 changed files with 3868 additions and 627 deletions

View file

@ -13,7 +13,8 @@ MODULE_OBJS := \
common/savefile.o \ common/savefile.o \
common/system.o \ common/system.o \
common/scaler.o \ common/scaler.o \
common/scaler/thumbnail.o common/scaler/thumbnail.o \
common/unzip.o
ifndef DISABLE_SCALERS ifndef DISABLE_SCALERS
MODULE_OBJS += \ MODULE_OBJS += \

1231
common/unzip.cpp Normal file

File diff suppressed because it is too large Load diff

300
common/unzip.h Normal file
View file

@ -0,0 +1,300 @@
/* 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 $
*/
/* unzip.h -- IO for uncompress .zip files using zlib
Version 0.15 beta, Mar 19th, 1998,
Copyright (C) 1998 Gilles Vollant
This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
WinZip, InfoZip tools and compatible.
Encryption and multi volume ZipFile (span) are not supported.
Old compressions used by old PKZip 1.x are not supported
THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
CAN CHANGE IN FUTURE VERSION !!
I WAIT FEEDBACK at mail info@winimage.com
Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
Condition of use and distribution are the same than zlib :
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* for more info about .ZIP format, see
ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
PkWare has also a specification at :
ftp://ftp.pkware.com/probdesc.zip */
#ifndef _unz_H
#define _unz_H
#include "common/stdafx.h"
#include "common/scummsys.h"
#ifdef USE_ZLIB
#ifdef __cplusplus
extern "C" {
#endif
#include <zlib.h>
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
/* like the STRICT of WIN32, we define a pointer that cannot be converted
from (void*) without cast */
typedef struct TagunzFile__ { int unused; } unzFile__;
typedef unzFile__ *unzFile;
#else
typedef voidp unzFile;
#endif
#define UNZ_OK (0)
#define UNZ_END_OF_LIST_OF_FILE (-100)
#define UNZ_ERRNO (Z_ERRNO)
#define UNZ_EOF (0)
#define UNZ_PARAMERROR (-102)
#define UNZ_BADZIPFILE (-103)
#define UNZ_INTERNALERROR (-104)
#define UNZ_CRCERROR (-105)
/* tm_unz contain date/time info */
typedef struct tm_unz_s
{
uInt tm_sec; /* seconds after the minute - [0,59] */
uInt tm_min; /* minutes after the hour - [0,59] */
uInt tm_hour; /* hours since midnight - [0,23] */
uInt tm_mday; /* day of the month - [1,31] */
uInt tm_mon; /* months since January - [0,11] */
uInt tm_year; /* years - [1980..2044] */
} tm_unz;
/* unz_global_info structure contain global data about the ZIPfile
These data comes from the end of central dir */
typedef struct unz_global_info_s
{
uLong number_entry; /* total number of entries in
the central dir on this disk */
uLong size_comment; /* size of the global comment of the zipfile */
} unz_global_info;
/* unz_file_info contain information about a file in the zipfile */
typedef struct unz_file_info_s
{
uLong version; /* version made by 2 bytes */
uLong version_needed; /* version needed to extract 2 bytes */
uLong flag; /* general purpose bit flag 2 bytes */
uLong compression_method; /* compression method 2 bytes */
uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
uLong crc; /* crc-32 4 bytes */
uLong compressed_size; /* compressed size 4 bytes */
uLong uncompressed_size; /* uncompressed size 4 bytes */
uLong size_filename; /* filename length 2 bytes */
uLong size_file_extra; /* extra field length 2 bytes */
uLong size_file_comment; /* file comment length 2 bytes */
uLong disk_num_start; /* disk number start 2 bytes */
uLong internal_fa; /* internal file attributes 2 bytes */
uLong external_fa; /* external file attributes 4 bytes */
tm_unz tmu_date;
} unz_file_info;
extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
const char* fileName2,
int iCaseSensitivity));
/*
Compare two filename (fileName1,fileName2).
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
or strcasecmp)
If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
(like 1 on Unix, 2 on Windows)
*/
extern unzFile ZEXPORT unzOpen OF((const char *path));
/*
Open a Zip file. path contain the full pathname (by example,
on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
"zlib/zlib111.zip".
If the zipfile cannot be opened (file don't exist or in not valid), the
return value is NULL.
Else, the return value is a unzFile Handle, usable with other function
of this unzip package.
*/
extern int ZEXPORT unzClose OF((unzFile file));
/*
Close a ZipFile opened with unzipOpen.
If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
unz_global_info *pglobal_info));
/*
Write info about the ZipFile in the *pglobal_info structure.
No preparation of the structure is needed
return UNZ_OK if there is no problem. */
extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
char *szComment,
uLong uSizeBuf));
/*
Get the global comment string of the ZipFile, in the szComment buffer.
uSizeBuf is the size of the szComment buffer.
return the number of byte copied or an error code <0
*/
/***************************************************************************/
/* Unzip package allow you browse the directory of the zipfile */
extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
/*
Set the current file of the zipfile to the first file.
return UNZ_OK if there is no problem
*/
extern int ZEXPORT unzGoToNextFile OF((unzFile file));
/*
Set the current file of the zipfile to the next file.
return UNZ_OK if there is no problem
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
*/
extern int ZEXPORT unzLocateFile OF((unzFile file,
const char *szFileName,
int iCaseSensitivity));
/*
Try locate the file szFileName in the zipfile.
For the iCaseSensitivity signification, see unzStringFileNameCompare
return value :
UNZ_OK if the file is found. It becomes the current file.
UNZ_END_OF_LIST_OF_FILE if the file is not found
*/
extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
unz_file_info *pfile_info,
char *szFileName,
uLong fileNameBufferSize,
void *extraField,
uLong extraFieldBufferSize,
char *szComment,
uLong commentBufferSize));
/*
Get Info about the current file
if pfile_info!=NULL, the *pfile_info structure will contain somes info about
the current file
if szFileName!=NULL, the filemane string will be copied in szFileName
(fileNameBufferSize is the size of the buffer)
if extraField!=NULL, the extra field information will be copied in extraField
(extraFieldBufferSize is the size of the buffer).
This is the Central-header version of the extra field
if szComment!=NULL, the comment string of the file will be copied in szComment
(commentBufferSize is the size of the buffer)
*/
/***************************************************************************/
/* for reading the content of the current zipfile, you can open it, read data
from it, and close it (you can close it before reading all the file)
*/
extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
/*
Open for reading data the current file in the zipfile.
If there is no error, the return value is UNZ_OK.
*/
extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
/*
Close the file in zip opened with unzOpenCurrentFile
Return UNZ_CRCERROR if all the file was read but the CRC is not good
*/
extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
voidp buf,
unsigned len));
/*
Read bytes from the current file (opened by unzOpenCurrentFile)
buf contain buffer where data must be copied
len the size of buf.
return the number of byte copied if somes bytes are copied
return 0 if the end of file was reached
return <0 with error code if there is an error
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
*/
extern z_off_t ZEXPORT unztell OF((unzFile file));
/*
Give the current position in uncompressed data
*/
extern int ZEXPORT unzeof OF((unzFile file));
/*
return 1 if the end of file was reached, 0 elsewhere
*/
extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
voidp buf,
unsigned len));
/*
Read extra field from the current file (opened by unzOpenCurrentFile)
This is the local-header version of the extra field (sometimes, there is
more info in the local-header version than in the central-header)
if buf==NULL, it return the size of the local extra field
if buf!=NULL, len is the size of the buffer, the extra header is copied in
buf.
the return value is the number of bytes copied in buf, or (if <0)
the error code
*/
#ifdef __cplusplus
}
#endif
#endif
#endif /* _unz_H */

174
graphics/imagedec.cpp Normal file
View file

@ -0,0 +1,174 @@
/* 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 "graphics/imagedec.h"
#include "common/system.h"
#include "common/file.h"
namespace Graphics {
//
// BMP Decoder
//
class BMPDecoder : public ImageDecoder {
public:
BMPDecoder() {}
virtual ~BMPDecoder() {}
bool decodeable(Common::SeekableReadStream &stream);
Surface *decodeImage(Common::SeekableReadStream &stream);
struct BitmapHeader {
uint16 type;
uint32 size;
uint16 res1;
uint16 res2;
uint32 imageOffset;
};
struct InfoHeader {
uint32 size;
uint32 width;
uint32 height;
uint16 planes;
uint16 bitsPerPixel;
uint32 compression;
uint32 imageSize;
uint32 pixelsPerMeterX;
uint32 pixelsPerMeterY;
uint32 colorsUsed;
uint32 colorsImportant;
};
};
bool BMPDecoder::decodeable(Common::SeekableReadStream &stream) {
BitmapHeader header;
stream.seek(0);
header.type = stream.readUint16BE();
header.size = stream.readUint32LE();
// TODO: maybe improve this detection
if (header.size == 0 || header.type != 'BM')
return false;
return true;
}
Surface *BMPDecoder::decodeImage(Common::SeekableReadStream &stream) {
if (!decodeable(stream)) {
return 0;
}
BitmapHeader header;
InfoHeader info;
stream.seek(0);
header.type = stream.readUint16BE();
header.size = stream.readUint32LE();
header.res1 = stream.readUint16LE();
header.res2 = stream.readUint16LE();
header.imageOffset = stream.readUint32LE();
if (header.size == 0 || header.type != 'BM') {
stream.seek(0);
return 0;
}
info.size = stream.readUint32LE();
info.width = stream.readUint32LE();
info.height = stream.readUint32LE();
info.planes = stream.readUint16LE();
info.bitsPerPixel = stream.readUint16LE();
info.compression = stream.readUint32LE();
info.imageSize = stream.readUint32LE();
info.pixelsPerMeterX = stream.readUint32LE();
info.pixelsPerMeterY = stream.readUint32LE();
info.colorsUsed = stream.readUint32LE();
info.colorsImportant = stream.readUint32LE();
stream.seek(header.imageOffset);
if (info.bitsPerPixel != 24) {
stream.seek(0);
return 0;
}
uint8 r = 0, g = 0, b = 0;
Surface *newSurf = new Surface;
assert(newSurf);
newSurf->create(info.width, info.height, sizeof(OverlayColor));
assert(newSurf->pixels);
OverlayColor *curPixel = (OverlayColor*)newSurf->pixels + (newSurf->h-1) * newSurf->w;
int pitchAdd = info.width % 4;
for (int i = 0; i < newSurf->h; ++i) {
for (int i2 = 0; i2 < newSurf->w; ++i2) {
b = stream.readByte();
g = stream.readByte();
r = stream.readByte();
*curPixel = OSystem::instance().RGBToColor(r, g, b);
++curPixel;
}
stream.seek(pitchAdd, SEEK_CUR);
curPixel -= newSurf->w*2;
}
stream.seek(0);
return newSurf;
}
#pragma mark -
Surface *ImageDecoder::loadFile(const Common::String &name) {
Surface *newSurf = 0;
Common::File imageFile;
if (imageFile.open(name.c_str())) {
newSurf = loadFile(imageFile);
}
return newSurf;
}
Surface *ImageDecoder::loadFile(Common::SeekableReadStream &stream) {
// TODO: implement support for bzipped memory
// FIXME: this is not a very nice solution but it should work
// for the moment, we should use a different way to get all
// decoders
static BMPDecoder bmpDecoder;
static ImageDecoder *decoderList[] = {
&bmpDecoder, // for uncompressed .BMP files
0
};
ImageDecoder *decoder = 0;
for (int i = 0; decoderList[i] != 0; ++i) {
if (decoderList[i]->decodeable(stream)) {
decoder = decoderList[i];
break;
}
}
if (!decoder)
return 0;
return decoder->decodeImage(stream);
}
} // end of namespace Graphics

61
graphics/imagedec.h Normal file
View file

@ -0,0 +1,61 @@
/* 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 GRAPHICS_IMAGEDEC_H
#define GRAPHICS_IMAGEDEC_H
#include "common/stdafx.h"
#include "common/scummsys.h"
#include "common/str.h"
#include "common/stream.h"
#include "graphics/surface.h"
namespace Graphics {
class ImageDecoder {
public:
ImageDecoder() {}
virtual ~ImageDecoder() {}
static Surface *loadFile(const Common::String &name);
static Surface *loadFile(Common::SeekableReadStream &stream);
/**
* checks if the data can be decoded by this decoder
*
* @param stream memory read stream
* @return true if it can be decoded, otherwise false
*/
virtual bool decodeable(Common::SeekableReadStream &stream) = 0;
/**
* decodes the data and returns an pointer to the resulting surface.
* Surface::free() must be called by the user also it must be deleted
* with delete;
*
* @param stream the memory stream which should be decoded
* @return returns a new surface if the image could be decoded, otherwise 0
*/
virtual Surface *decodeImage(Common::SeekableReadStream &stream) = 0;
};
} // end of namespace Graphics
#endif

146
graphics/imageman.cpp Normal file
View file

@ -0,0 +1,146 @@
/* 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 "graphics/imagedec.h"
#include "graphics/imageman.h"
#include "graphics/surface.h"
DECLARE_SINGLETON(Graphics::ImageManager);
namespace Graphics {
ImageManager::ImageManager() : _surfaces()
#ifdef USE_ZLIB
, _archives()
#endif
{
}
ImageManager::~ImageManager() {
for (Iterator pos = _surfaces.begin(); pos != _surfaces.end(); ++pos) {
(*pos)->surface->free();
delete (*pos)->surface;
delete *pos;
*pos = 0;
}
_surfaces.clear();
#ifdef USE_ZLIB
for (ZipIterator pos = _archives.begin(); pos != _archives.end(); ++pos) {
unzClose(*pos);
}
_archives.clear();
#endif
}
bool ImageManager::addArchive(const Common::String &name) {
#ifdef USE_ZLIB
unzFile newFile = unzOpen(name.c_str());
if (!newFile)
return false;
_archives.push_back(newFile);
#endif
return true;
}
bool ImageManager::registerSurface(const Common::String &name, Surface *surf) {
if (getSurface(name)) {
return false;
}
Entry *newHandle = new Entry;
if (!newHandle)
return false;
if (!surf) {
surf = ImageDecoder::loadFile(name);
if (!surf) {
#ifdef USE_ZLIB
ZipIterator file = _archives.end();
for (ZipIterator pos = _archives.begin(); pos != _archives.end(); ++pos) {
if (unzLocateFile(*pos, name.c_str(), 2) == UNZ_OK) {
file = pos;
break;
}
}
if (file == _archives.end())
return false;
unz_file_info fileInfo;
unzOpenCurrentFile(*file);
unzGetCurrentFileInfo(*file, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
uint8 *buffer = new uint8[fileInfo.uncompressed_size];
assert(buffer);
unzReadCurrentFile(*file, buffer, fileInfo.uncompressed_size);
unzCloseCurrentFile(*file);
Common::MemoryReadStream stream(buffer, fileInfo.uncompressed_size);
surf = ImageDecoder::loadFile(stream);
delete [] buffer;
if (!surf)
return false;
#else
return false;
#endif
}
}
newHandle->surface = surf;
newHandle->name = name;
_surfaces.push_back(newHandle);
return true;
}
bool ImageManager::unregisterSurface(const Common::String &name) {
Iterator pos = searchHandle(name);
if (pos == _surfaces.end()) {
// no surface handle it as success
return true;
}
(*pos)->surface->free();
delete (*pos)->surface;
delete *pos;
*pos = 0;
_surfaces.erase(pos);
return true;
}
Surface * ImageManager::getSurface(const Common::String &name) {
Iterator pos = searchHandle(name);
if (pos == _surfaces.end()) {
// no surface handle it as success
return 0;
}
return (*pos)->surface;
}
ImageManager::Iterator ImageManager::searchHandle(const Common::String &name) {
Iterator pos = _surfaces.begin();
while (pos != _surfaces.end()) {
if ((*pos)->name == name)
break;
++pos;
}
return pos;
}
} // end of namespace Graphics

103
graphics/imageman.h Normal file
View file

@ -0,0 +1,103 @@
/* 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 GRAPHICS_IMAGEMAN_H
#define GRAPHICS_IMAGEMAN_H
#include "common/stdafx.h"
#include "common/scummsys.h"
#include "common/singleton.h"
#include "common/str.h"
#include "common/list.h"
#include "common/unzip.h"
namespace Graphics {
struct Surface;
class ImageManager : public Common::Singleton<ImageManager> {
public:
~ImageManager();
/**
* adds an .zip archive to the pool there the ImagaManager searches
* for image files
*
* @param name the name of the archive
* @return true on success and false on failure
*/
bool addArchive(const Common::String &name);
/**
* registers a surface to the ImageManager.
* surf->free(), also delete surf, will be called when the ImageManager will
* be destroyed or if ImageManager::unregisterSurface is called.
* if the parameter 'surf' is 0 the Manger will try to load an image with
* the filename 'name'
*
* @param name the name of the new handle
* @param surf the surface which should be associated to the given name
* @return returns true on success and false on failure
*/
bool registerSurface(const Common::String &name, Surface *surf);
/**
* unregisters a surface, after this the returned surface from
* getSurface should NOT be used anymore
*
* @param name the handle
* @return true on success, false on failure
*/
bool unregisterSurface(const Common::String &name);
/**
* gets a surface registered to a handle
*
* @param name the name of the handle
* @return returns an pointer to an Surface object or 0 on failure
*/
Surface *getSurface(const Common::String &name);
private:
friend class Common::Singleton<SingletonBaseType>;
ImageManager();
struct Entry {
Common::String name;
Surface *surface;
};
typedef Common::List<Entry*>::iterator Iterator;
#ifdef USE_ZLIB
typedef Common::List<unzFile>::iterator ZipIterator;
#endif
Iterator searchHandle(const Common::String &name);
Common::List<Entry*> _surfaces;
#ifdef USE_ZLIB
Common::List<unzFile> _archives;
#endif
};
} // end of namespace Graphics
/** Shortcut for accessing the font manager. */
#define ImageMan (Graphics::ImageManager::instance())
#endif

View file

@ -10,7 +10,9 @@ MODULE_OBJS := \
graphics/newfont_big.o \ graphics/newfont_big.o \
graphics/primitives.o \ graphics/primitives.o \
graphics/scummfont.o \ graphics/scummfont.o \
graphics/surface.o graphics/surface.o \
graphics/imageman.o \
graphics/imagedec.o
MODULE_DIRS += \ MODULE_DIRS += \
graphics graphics

View file

@ -59,15 +59,11 @@ void EditTextWidget::handleMouseDown(int x, int y, int button, int clickCount) {
void EditTextWidget::drawWidget(bool hilite) { void EditTextWidget::drawWidget(bool hilite) {
// Draw a thin frame around us. g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), _hints, Theme::kWidgetBackgroundBorderSmall);
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);
// Draw the text // Draw the text
adjustOffset(); 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 { Common::Rect EditTextWidget::getEditRect() const {

View file

@ -37,6 +37,7 @@ ListWidget::ListWidget(GuiObject *boss, int x, int y, int w, int h, WidgetSize w
} }
_flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_WANT_TICKLE; _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_WANT_TICKLE;
setHints(THEME_HINT_SAVE_BACKGROUND);
_type = kListWidget; _type = kListWidget;
_editMode = false; _editMode = false;
_numberingMode = kListNumberingOne; _numberingMode = kListNumberingOne;
@ -297,27 +298,25 @@ void ListWidget::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
} }
void ListWidget::drawWidget(bool hilite) { void ListWidget::drawWidget(bool hilite) {
NewGui *gui = &g_gui;
int i, pos, len = _list.size(); int i, pos, len = _list.size();
Common::String buffer; Common::String buffer;
int deltax; int deltax;
// Draw a thin frame around the list. // Draw a thin frame around the list.
gui->hLine(_x, _y, _x + _w - 1, gui->_color); g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), _hints, Theme::kWidgetBackgroundBorderSmall);
gui->hLine(_x, _y + _h - 1, _x + _w - 1, gui->_shadowcolor);
gui->vLine(_x, _y, _y + _h - 1, gui->_color);
// Draw the list items // Draw the list items
for (i = 0, pos = _currentPos; i < _entriesPerPage && pos < len; i++, pos++) { 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 y = _y + 2 + kLineHeight * i;
const int fontHeight = kLineHeight;
bool inverted = false;
// Draw the selected item inverted, on a highlighted background. // Draw the selected item inverted, on a highlighted background.
if (_selectedItem == pos) { if (_selectedItem == pos) {
if (_hasFocus) if (_hasFocus)
gui->fillRect(_x + 1, _y + 1 + kLineHeight * i, _w - 1, kLineHeight, gui->_textcolorhi); inverted = true;
else 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 // If in numbering mode, we first print a number prefix
@ -325,7 +324,7 @@ void ListWidget::drawWidget(bool hilite) {
char temp[10]; char temp[10];
sprintf(temp, "%2d. ", (pos + _numberingMode)); sprintf(temp, "%2d. ", (pos + _numberingMode));
buffer = temp; 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()); Common::Rect r(getEditRect());
@ -335,11 +334,11 @@ void ListWidget::drawWidget(bool hilite) {
adjustOffset(); adjustOffset();
deltax = -_editScrollOffset; 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 { } else {
buffer = _list[pos]; buffer = _list[pos];
deltax = 0; 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);
} }
} }
} }

View file

@ -140,13 +140,10 @@ PopUpDialog::PopUpDialog(PopUpWidget *boss, int clickX, int clickY, WidgetSize w
void PopUpDialog::drawDialog() { void PopUpDialog::drawDialog() {
// Draw the menu border // Draw the menu border
g_gui.hLine(_x, _y, _x+_w - 1, g_gui._color); g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), THEME_HINT_FIRST_DRAW | THEME_HINT_SAVE_BACKGROUND, Theme::kWidgetBackgroundBorderSmall);
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);
if (_twoColumns) /*if (_twoColumns)
g_gui.vLine(_x + _w / 2, _y, _y + _h - 2, g_gui._color); g_gui.vLine(_x + _w / 2, _y, _y + _h - 2, g_gui._color);*/
// Draw the entries // Draw the entries
int count = _popUpBoss->_entries.size(); int count = _popUpBoss->_entries.size();
@ -155,11 +152,9 @@ void PopUpDialog::drawDialog() {
} }
// The last entry may be empty. Fill it with black. // 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.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) { void PopUpDialog::handleMouseUp(int x, int y, int button, int clickCount) {
@ -322,15 +317,13 @@ void PopUpDialog::drawMenuEntry(int entry, bool hilite) {
Common::String &name = _popUpBoss->_entries[entry].name; 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) { if (name.size() == 0) {
// Draw a separator // Draw a separator
g_gui.hLine(x - 1, y + kLineHeight / 2, x + w, g_gui._shadowcolor); g_gui.theme()->drawLineSeparator(Common::Rect(x, y, x+w, y+kLineHeight));
g_gui.hLine(x, y + 1 + kLineHeight / 2, x + w, g_gui._color);
} else { } else {
g_gui.drawString(name, x + 1, y + 2, w - 2, hilite ? g_gui._bgcolor : g_gui._textcolor); g_gui.theme()->drawText(Common::Rect(x+1, y+2, x+w-1, y+kLineHeight), name, hilite ? Theme::kStateHighlight : Theme::kStateEnabled,
Theme::kTextAlignLeft);
} }
g_gui.addDirtyRect(x, y, w, kLineHeight);
} }
@ -343,6 +336,7 @@ void PopUpDialog::drawMenuEntry(int entry, bool hilite) {
PopUpWidget::PopUpWidget(GuiObject *boss, int x, int y, int w, int h, const String &label, uint labelWidth, WidgetSize ws) 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) { : Widget(boss, x, y - 1, w, h + 2), CommandSender(boss), _ws(ws), _label(label), _labelWidth(labelWidth) {
_flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS; _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS;
setHints(THEME_HINT_SAVE_BACKGROUND);
_type = kPopUpWidget; _type = kPopUpWidget;
_selectedItem = -1; _selectedItem = -1;
@ -397,22 +391,19 @@ void PopUpWidget::setSelectedTag(uint32 tag) {
} }
void PopUpWidget::drawWidget(bool hilite) { void PopUpWidget::drawWidget(bool hilite) {
NewGui *gui = &g_gui;
int x = _x + _labelWidth; int x = _x + _labelWidth;
int w = _w - _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 // Draw the label, if any
if (_labelWidth > 0) if (_labelWidth > 0)
gui->drawString(_label, _x, _y + 3, _labelWidth, isEnabled() ? gui->_textcolor : gui->_color, kTextAlignRight); 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 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);
// Draw a set of arrows at the right end to signal this is a dropdown/popup // 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); p0 = Common::Point(x + w + 1 - _h / 2, _y + 4);
p1 = Common::Point(x + w + 1 - _h / 2, _y + _h - 4); p1 = Common::Point(x + w + 1 - _h / 2, _y + _h - 4);
@ -425,12 +416,13 @@ void PopUpWidget::drawWidget(bool hilite) {
for (; p1.y - p0.y > 1; p0.y++, p0.x--, p1.y--, p1.x++) { 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, p0.y, p1.x, p0.y, color);
surf.drawLine(p0.x, p1.y, p1.x, p1.y, color); surf.drawLine(p0.x, p1.y, p1.x, p1.y, color);
} }*/
// Draw the selected entry, if any // Draw the selected entry, if any
if (_selectedItem >= 0) { if (_selectedItem >= 0) {
TextAlignment align = (g_gui.getStringWidth(_entries[_selectedItem].name) > w-6) ? kTextAlignRight : kTextAlignLeft; 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));
} }
} }

View file

@ -179,73 +179,22 @@ void ScrollBarWidget::recalc() {
} }
void ScrollBarWidget::drawWidget(bool hilite) { 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) if (_draggingPart != kNoPart)
_part = _draggingPart; _part = _draggingPart;
const int arrowSize = (_w / 2 - B + 1); Theme::kScrollbarState state = Theme::kScrollbarStateNo;
if (_numEntries <= _entriesPerPage) {
// state = Theme::kScrollbarStateSinglePage;
// Up arrow } else if (_part == kUpArrowPart) {
// state = Theme::kScrollbarStateUp;
color = isSinglePage ? gui->_color : } else if (_part == kDownArrowPart) {
(hilite && _part == kUpArrowPart) ? gui->_textcolorhi : gui->_textcolor; state = Theme::kScrollbarStateDown;
gui->frameRect(_x, _y, _w, UP_DOWN_BOX_HEIGHT, gui->_color); } else if (_part == kSliderPart) {
p0 = Common::Point(_x + _w / 2, _y + (UP_DOWN_BOX_HEIGHT - arrowSize - 1) / 2); state = Theme::kScrollbarStateSlider;
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);
} }
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 } // End of namespace GUI

View file

@ -127,7 +127,7 @@ bool TabWidget::handleKeyDown(uint16 ascii, int keycode, int modifiers) {
return Widget::handleKeyDown(ascii, keycode, modifiers); return Widget::handleKeyDown(ascii, keycode, modifiers);
} }
static void box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB, bool omitBottom) { /*static void box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB, bool omitBottom) {
NewGui &gui = g_gui; NewGui &gui = g_gui;
gui.hLine(x + 1, y, x + width - 2, colorA); gui.hLine(x + 1, y, x + width - 2, colorA);
@ -141,36 +141,18 @@ static void box(int x, int y, int width, int height, OverlayColor colorA, Overla
} }
gui.vLine(x + width - 1, y + 1, y + height - (omitBottom ? 1 : 2), colorB); gui.vLine(x + width - 1, y + 1, y + height - (omitBottom ? 1 : 2), colorB);
gui.vLine(x + width - 2, y + 1, y + height - (omitBottom ? 2 : 1), colorB); gui.vLine(x + width - 2, y + 1, y + height - (omitBottom ? 2 : 1), colorB);
} }*/
void TabWidget::drawWidget(bool hilite) { 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 // Iterate over all tabs and draw them
int i, x = _x + kTabLeftOffset; int i, x = _x + kTabLeftOffset;
for (i = 0; i < (int)_tabs.size(); ++i) { for (i = 0; i < (int)_tabs.size(); ++i) {
OverlayColor color = (i == _activeTab) ? gui->_color : gui->_shadowcolor;
int yOffset = (i == _activeTab) ? 0 : 2; int yOffset = (i == _activeTab) ? 0 : 2;
box(x, _y + yOffset, _tabWidth, _tabHeight - yOffset, color, color, (i == _activeTab)); g_gui.theme()->drawTab(Common::Rect(x, _y+yOffset, x+_tabWidth, _y+_tabHeight), _tabs[i].title, (i == _activeTab));
gui->drawString(_tabs[i].title, x + kTabPadding, _y + yOffset / 2 + (_tabHeight - gui->getFontHeight() - 3), _tabWidth - 2 * kTabPadding, gui->_textcolor, kTextAlignCenter);
x += _tabWidth + kTabSpacing; x += _tabWidth + kTabSpacing;
} }
g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y+_tabHeight-2, _x+_w, _y+_h), _hints, Theme::kWidgetBackgroundBorderSmall);
// 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);
} }
Widget *TabWidget::findWidget(int x, int y) { Widget *TabWidget::findWidget(int x, int y) {

801
gui/ThemeNew.cpp Normal file
View file

@ -0,0 +1,801 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2006 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Header $
*/
#include "gui/theme.h"
#include "graphics/imageman.h"
#include "graphics/imagedec.h"
#include "common/config-manager.h"
#include "common/file.h"
#include "common/unzip.h"
using Graphics::Surface;
/** Specifies the currently active 16bit pixel format, 555 or 565. */
extern int gBitFormat;
static void getColorFromConfig(const Common::ConfigFile &cfg, const Common::String &value, OverlayColor &color) {
Common::String temp;
cfg.getKey(value, "colors", temp);
int r, g, b;
sscanf(temp.c_str(), "%d %d %d", &r, &g, &b);
color = OSystem::instance().RGBToColor(r, g, b);
}
namespace GUI {
ThemeNew::ThemeNew(OSystem *system, Common::String stylefile) : Theme(), _system(system), _screen(), _initOk(false),
_forceRedraw(false), _font(0), _imageHandles(0), _images(0), _colors() {
_initOk = false;
memset(&_screen, 0, sizeof(_screen));
memset(&_dialog, 0, sizeof(_dialog));
memset(&_colors, 0, sizeof(_colors));
_screen.create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(OverlayColor));
if (_screen.pixels) {
_initOk = true;
clearAll();
if (_screen.w >= 400 && _screen.h >= 300) {
_font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
} else {
_font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
}
}
if (ConfMan.hasKey("extrapath")) {
Common::File::addDefaultDirectory(ConfMan.get("extrapath"));
}
if (ConfMan.hasKey("themepath")) {
Common::File::addDefaultDirectory(ConfMan.get("themepath"));
}
ImageMan.addArchive(stylefile + ".zip");
if (!_configFile.loadFromFile(stylefile + ".ini")) {
#ifdef USE_ZLIB
// Maybe find a nicer solution to this
unzFile zipFile = unzOpen((stylefile + ".zip").c_str());
if (zipFile == NULL) return;
if (unzLocateFile(zipFile, (stylefile + ".ini").c_str(), 2) == UNZ_OK) {
unz_file_info fileInfo;
unzOpenCurrentFile(zipFile);
unzGetCurrentFileInfo(zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
uint8 *buffer = new uint8[fileInfo.uncompressed_size];
assert(buffer);
unzReadCurrentFile(zipFile, buffer, fileInfo.uncompressed_size);
unzCloseCurrentFile(zipFile);
Common::MemoryReadStream stream(buffer, fileInfo.uncompressed_size);
if (!_configFile.loadFromStream(stream)) {
warning("Can not find theme config file '%s'", (stylefile + ".ini").c_str());
unzClose(zipFile);
return;
}
delete [] buffer;
buffer = 0;
} else {
warning("Can not find theme config file '%s'", (stylefile + ".ini").c_str());
return;
}
unzClose(zipFile);
#else
warning("Can not find theme config file '%s'", (stylefile + ".ini").c_str());
return;
#endif
}
Common::String temp = "";
_configFile.getKey("version", "theme", temp);
if (temp != "1") {
// TODO: improve this detection and handle it nicer
warning("Theme config uses a different version");
return;
}
static Common::String imageHandlesTable[kImageHandlesMax];
_configFile.getKey("dialog_corner", "pixmaps", imageHandlesTable[kDialogBkgdCorner]);
_configFile.getKey("dialog_top", "pixmaps", imageHandlesTable[kDialogBkgdTop]);
_configFile.getKey("dialog_left", "pixmaps", imageHandlesTable[kDialogBkgdLeft]);
_configFile.getKey("dialog_bkgd", "pixmaps", imageHandlesTable[kDialogBkgd]);
_configFile.getKey("widget_corner", "pixmaps", imageHandlesTable[kWidgetBkgdCorner]);
_configFile.getKey("widget_top", "pixmaps", imageHandlesTable[kWidgetBkgdTop]);
_configFile.getKey("widget_left", "pixmaps", imageHandlesTable[kWidgetBkgdLeft]);
_configFile.getKey("widget_bkgd", "pixmaps", imageHandlesTable[kWidgetBkgd]);
_configFile.getKey("checkbox_empty", "pixmaps", imageHandlesTable[kCheckboxEmpty]);
_configFile.getKey("checkbox_checked", "pixmaps", imageHandlesTable[kCheckboxChecked]);
_configFile.getKey("widget_arrow", "pixmaps", imageHandlesTable[kWidgetArrow]);
getColorFromConfig(_configFile, "main_dialog_start", _colors[kMainDialogStart]);
getColorFromConfig(_configFile, "main_dialog_end", _colors[kMainDialogEnd]);
getColorFromConfig(_configFile, "dialog_start", _colors[kDialogStart]);
getColorFromConfig(_configFile, "dialog_end", _colors[kDialogEnd]);
getColorFromConfig(_configFile, "color_state_disabled", _colors[kColorStateDisabled]);
getColorFromConfig(_configFile, "color_state_highlight", _colors[kColorStateHighlight]);
getColorFromConfig(_configFile, "color_state_enabled", _colors[kColorStateEnabled]);
getColorFromConfig(_configFile, "color_transparency", _colors[kColorTransparency]);
getColorFromConfig(_configFile, "text_inverted_background", _colors[kTextInvertedBackground]);
getColorFromConfig(_configFile, "text_inverted_color", _colors[kTextInvertedColor]);
getColorFromConfig(_configFile, "widget_bkgd_start", _colors[kWidgetBackgroundStart]);
getColorFromConfig(_configFile, "widget_bkgd_end", _colors[kWidgetBackgroundEnd]);
getColorFromConfig(_configFile, "widget_bkgd_small_start", _colors[kWidgetBackgroundSmallStart]);
getColorFromConfig(_configFile, "widget_bkgd_small_end", _colors[kWidgetBackgroundSmallEnd]);
getColorFromConfig(_configFile, "button_bkgd_start", _colors[kButtonBackgroundStart]);
getColorFromConfig(_configFile, "button_bkgd_end", _colors[kButtonBackgroundEnd]);
getColorFromConfig(_configFile, "button_text_enabled", _colors[kButtonTextEnabled]);
getColorFromConfig(_configFile, "button_text_disabled", _colors[kButtonTextDisabled]);
getColorFromConfig(_configFile, "button_text_highlight", _colors[kButtonTextHighlight]);
getColorFromConfig(_configFile, "slider_background_start", _colors[kSliderBackgroundStart]);
getColorFromConfig(_configFile, "slider_background_end", _colors[kSliderBackgroundEnd]);
getColorFromConfig(_configFile, "slider_start", _colors[kSliderStart]);
getColorFromConfig(_configFile, "slider_end", _colors[kSliderEnd]);
getColorFromConfig(_configFile, "tab_background_start", _colors[kTabBackgroundStart]);
getColorFromConfig(_configFile, "tab_background_end", _colors[kTabBackgroundEnd]);
getColorFromConfig(_configFile, "scrollbar_background_start", _colors[kScrollbarBackgroundStart]);
getColorFromConfig(_configFile, "scrollbar_background_end", _colors[kScrollbarBackgroundEnd]);
getColorFromConfig(_configFile, "scrollbar_button_start", _colors[kScrollbarButtonStart]);
getColorFromConfig(_configFile, "scrollbar_button_end", _colors[kScrollbarButtonEnd]);
getColorFromConfig(_configFile, "scrollbar_slider_start", _colors[kScrollbarSliderStart]);
getColorFromConfig(_configFile, "scrollbar_slider_end", _colors[kScrollbarSliderEnd]);
getColorFromConfig(_configFile, "caret_color", _colors[kCaretColor]);
_imageHandles = imageHandlesTable;
_images = new const Graphics::Surface*[ARRAYSIZE(imageHandlesTable)];
assert(_images);
for (int i = 0; _imageHandles[i] != "\0"; ++i) {
ImageMan.registerSurface(_imageHandles[i], 0);
_images[i] = ImageMan.getSurface(_imageHandles[i]);
}
}
ThemeNew::~ThemeNew() {
deinit();
delete [] _images;
_images = 0;
if (_imageHandles) {
for (int i = 0; i < kImageHandlesMax; ++i) {
ImageMan.unregisterSurface(_imageHandles[i]);
}
}
}
bool ThemeNew::init() {
if (!_images)
return false;
for (int i = 0; i < kImageHandlesMax; ++i) {
if (!_images[i]) {
return false;
}
}
deinit();
_screen.create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(OverlayColor));
if (_screen.pixels) {
_initOk = true;
clearAll();
if (_screen.w >= 400 && _screen.h >= 300) {
_font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
} else {
_font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
}
}
return true;
}
void ThemeNew::deinit() {
if (_initOk) {
_system->hideOverlay();
_screen.free();
_initOk = false;
}
}
void ThemeNew::refresh() {
init();
_system->showOverlay();
}
void ThemeNew::enable() {
_system->showOverlay();
clearAll();
}
void ThemeNew::disable() {
_system->hideOverlay();
}
void ThemeNew::openDialog() {
if (!_dialog) {
_dialog = new DialogState;
assert(_dialog);
// first dialog
_dialog->screen.create(_screen.w, _screen.h, sizeof(OverlayColor));
}
memcpy(_dialog->screen.pixels, _screen.pixels, _screen.pitch*_screen.h);
}
void ThemeNew::closeDialog() {
if (_dialog) {
_dialog->screen.free();
delete _dialog;
_dialog = 0;
}
_forceRedraw = true;
}
void ThemeNew::clearAll() {
if (!_initOk)
return;
_system->clearOverlay();
// FIXME: problem with the 'pitch'
_system->grabOverlay((OverlayColor*)_screen.pixels, _screen.w);
}
void ThemeNew::drawAll() {
// TODO: see ThemeNew::addDirtyRect
_forceRedraw = false;
}
void ThemeNew::resetDrawArea() {
if (_initOk) {
_drawArea = Common::Rect(0, 0, _screen.w, _screen.h);
}
}
#define surface(x) (_images[x])
void ThemeNew::drawDialogBackground(const Common::Rect &r, kState state, bool mainDialog) {
if (!_initOk)
return;
if (mainDialog) {
colorFade(r, _colors[kMainDialogStart], _colors[kMainDialogEnd]);
} else {
drawRectMasked(r, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd),
255, _colors[kDialogStart], _colors[kDialogEnd]);
}
addDirtyRect(r, true);
}
void ThemeNew::drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis) {
if (!_initOk)
return;
Common::Rect r2(r.left, r.top, r.right, r.top+_font->getFontHeight());
restoreBackground(r2);
if (inverted) {
_screen.fillRect(r, _colors[kTextInvertedBackground]);
_font->drawString(&_screen, str, r.left, r.top, r.width(), _colors[kTextInvertedColor], convertAligment(align), deltax, useEllipsis);
addDirtyRect(r2);
return;
} else {
_font->drawString(&_screen, str, r.left, r.top, r.width(), getColor(state), convertAligment(align), deltax, useEllipsis);
}
addDirtyRect(r2);
}
void ThemeNew::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state) {
if (!_initOk)
return;
restoreBackground(r);
font->drawChar(&_screen, ch, r.left, r.top, getColor(state));
addDirtyRect(r);
}
void ThemeNew::drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background, kState state) {
if (!_initOk)
return;
if ((hints & THEME_HINT_SAVE_BACKGROUND) && !(hints & THEME_HINT_FIRST_DRAW) && !_forceRedraw) {
restoreBackground(r);
return;
}
if (background == kWidgetBackgroundBorderSmall) {
drawRectMasked(r, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd),
(state == kStateDisabled) ? 128 : 256, _colors[kWidgetBackgroundSmallStart], _colors[kWidgetBackgroundSmallEnd]);
} else {
drawRectMasked(r, surface(kWidgetBkgdCorner), surface(kWidgetBkgdTop), surface(kWidgetBkgdLeft), surface(kWidgetBkgd),
(state == kStateDisabled) ? 128 : 256, _colors[kWidgetBackgroundStart], _colors[kWidgetBackgroundEnd], 2);
}
addDirtyRect(r, (hints & THEME_HINT_SAVE_BACKGROUND));
}
void ThemeNew::drawButton(const Common::Rect &r, const Common::String &str, kState state) {
if (!_initOk)
return;
drawRectMasked(r, surface(kWidgetBkgdCorner), surface(kWidgetBkgdTop), surface(kWidgetBkgdLeft), surface(kWidgetBkgd),
255, _colors[kButtonBackgroundStart], _colors[kButtonBackgroundEnd], 2);
const int off = (r.height() - _font->getFontHeight()) / 2;
OverlayColor col = 0;
switch (state) {
case kStateEnabled:
col = _colors[kButtonTextEnabled];
break;
case kStateHighlight:
col = _colors[kButtonTextHighlight];
break;
default:
col = _colors[kButtonTextDisabled];
break;
};
_font->drawString(&_screen, str, r.left, r.top + off, r.width(), col, Graphics::kTextAlignCenter, 0, true);
addDirtyRect(r);
}
void ThemeNew::drawSurface(const Common::Rect &r, const Graphics::Surface &surface, kState state) {
if (!_initOk)
return;
Common::Rect rect(r.left, r.top, r.left + surface.w, r.top + surface.h);
rect.clip(_screen.w, _screen.h);
if (!rect.isValidRect())
return;
assert(surface.bytesPerPixel == sizeof(OverlayColor));
OverlayColor *src = (OverlayColor *)surface.pixels;
OverlayColor *dst = (OverlayColor *)_screen.getBasePtr(rect.left, rect.top);
int w = rect.width();
int h = rect.height();
while (h--) {
memcpy(dst, src, surface.pitch);
src += w;
// FIXME: this should be pitch
dst += _screen.w;
}
addDirtyRect(r);
}
void ThemeNew::drawSlider(const Common::Rect &r, int width, kState state) {
if (!_initOk)
return;
drawRectMasked(r, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd), 255,
_colors[kSliderBackgroundStart], _colors[kSliderBackgroundEnd]);
Common::Rect r2 = r;
r2.left = r.left + 2;
r2.top = r.top + 2;
r2.bottom = r.bottom - 2;
r2.right = r2.left + width;
if (r2.right > r.right - 2) {
r2.right = r.right - 2;
}
drawRectMasked(r2, surface(kWidgetBkgdCorner), surface(kWidgetBkgdTop), surface(kWidgetBkgdLeft), surface(kWidgetBkgd),
(state == kStateDisabled) ? 128 : 256, _colors[kSliderStart], _colors[kSliderEnd], 2);
addDirtyRect(r);
}
void ThemeNew::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, kState state) {
if (!_initOk)
return;
Common::Rect r2 = r;
const Graphics::Surface *checkBox = surface(checked ? kCheckboxChecked : kCheckboxEmpty);
int checkBoxSize = checkBox->w;
drawSurface(Common::Rect(r.left, r.top, r.left+checkBox->w, r.top+checkBox->h), checkBox, false, false, (state == kStateDisabled) ? 128 : 256);
r2.left += checkBoxSize + 5;
_font->drawString(&_screen, str, r2.left, r2.top, r2.width(), getColor(state), Graphics::kTextAlignCenter, 0, false);
addDirtyRect(r);
}
void ThemeNew::drawTab(const Common::Rect &r, const Common::String &str, bool active, kState state) {
if (!_initOk)
return;
if (active) {
_font->drawString(&_screen, str, r.left, r.top+2, r.width(), getColor(kStateHighlight), Graphics::kTextAlignCenter, 0, true);
} else {
drawRectMasked(r, surface(kWidgetBkgdCorner), surface(kWidgetBkgdTop), surface(kWidgetBkgdLeft), surface(kWidgetBkgd),
(state == kStateDisabled) ? 128 : 256, _colors[kTabBackgroundStart], _colors[kTabBackgroundEnd], 2);
_font->drawString(&_screen, str, r.left, r.top+2, r.width(), getColor(state), Graphics::kTextAlignCenter, 0, true);
}
addDirtyRect(r);
}
void ThemeNew::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, kScrollbarState, kState state) {
if (!_initOk)
return;
const int UP_DOWN_BOX_HEIGHT = r.width() + 1;
Common::Rect r2 = r;
// draws the scrollbar background
drawRectMasked(r2, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd), 255,
_colors[kScrollbarBackgroundStart], _colors[kScrollbarBackgroundEnd]);
// draws the 'up' button
r2.bottom = r2.top + UP_DOWN_BOX_HEIGHT;
drawRectMasked(r2, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd), 255,
_colors[kScrollbarButtonStart], _colors[kScrollbarButtonEnd]);
const Graphics::Surface *arrow = surface(kWidgetArrow);
r2.left += 1 + (r2.width() - arrow->w) / 2;
r2.right = r2.left + arrow->w;
r2.top += (r2.height() - arrow->h) / 2;
r2.bottom = r2.top + arrow->h;
drawSurface(r2, arrow, false, false, 255);
// draws the slider
r2 = r;
r2.left += 2;
r2.right -= 2;
r2.top += sliderY;
r2.bottom = r2.top + sliderHeight / 2 + surface(kWidgetBkgdCorner)->h + 4;
drawRectMasked(r2, surface(kWidgetBkgdCorner), surface(kWidgetBkgdTop), surface(kWidgetBkgdLeft), surface(kWidgetBkgd), 255,
_colors[kScrollbarSliderStart], _colors[kScrollbarSliderEnd]);
r2.top += sliderHeight / 2;
r2.bottom += sliderHeight / 2 - surface(kWidgetBkgdCorner)->h - 4;
drawRectMasked(r2, surface(kWidgetBkgdCorner), surface(kWidgetBkgdTop), surface(kWidgetBkgdLeft), surface(kWidgetBkgd), 255,
_colors[kScrollbarSliderEnd], _colors[kScrollbarSliderStart]);
// draws the 'down' button
r2 = r;
r2.top = r2.bottom - UP_DOWN_BOX_HEIGHT;
drawRectMasked(r2, surface(kDialogBkgdCorner), surface(kDialogBkgdTop), surface(kDialogBkgdLeft), surface(kDialogBkgd), 255,
_colors[kScrollbarButtonStart], _colors[kScrollbarButtonEnd]);
r2.left += 1 + (r2.width() - arrow->w) / 2;
r2.right = r2.left + arrow->w;
r2.top += (r2.height() - arrow->h) / 2;
r2.bottom = r2.top + arrow->h;
drawSurface(r2, arrow, true, false, 255);
addDirtyRect(r);
}
void ThemeNew::drawCaret(const Common::Rect &r, bool erase, kState state) {
if (!_initOk)
return;
restoreBackground(Common::Rect(r.left, r.top, r.left+1, r.bottom));
if (!erase) {
_screen.vLine(r.left, r.top, r.bottom, _colors[kCaretColor]);
} else {
// FIXME: hack to restore the caret background correctly
const OverlayColor search = _colors[kTextInvertedBackground];
const OverlayColor *src = (const OverlayColor*)_screen.getBasePtr(r.left-1, r.top-1);
int height = r.height() + 2;
if (r.top + height > _screen.h) {
height = _screen.h - r.top;
}
bool drawInvBackground = false;
while (height--) {
if (src[0] == search || src[1] == search || src[2] == search) {
drawInvBackground = true;
}
src += _screen.w;
}
if (drawInvBackground) {
_screen.vLine(r.left, r.top, r.bottom, search);
}
}
addDirtyRect(r);
}
void ThemeNew::drawLineSeparator(const Common::Rect &r, kState state) {
if (!_initOk)
return;
_screen.hLine(r.left - 1, r.top + r.height() / 2, r.right, _system->RGBToColor(0, 0, 0));
addDirtyRect(r);
}
#pragma mark - intern drawing
void ThemeNew::restoreBackground(Common::Rect r) {
r.clip(_screen.w, _screen.h);
r.clip(_drawArea);
if (_dialog) {
if (!_dialog->screen.pixels) {
return;
}
const OverlayColor *src = (const OverlayColor*)_dialog->screen.getBasePtr(r.left, r.top);
OverlayColor *dst = (OverlayColor*)_screen.getBasePtr(r.left, r.top);
int h = r.height();
int w = r.width();
while (h--) {
memcpy(dst, src, w*sizeof(OverlayColor));
src += _dialog->screen.w;
dst += _screen.w;
}
}
}
bool ThemeNew::addDirtyRect(Common::Rect r, bool backup) {
// TODO: implement proper dirty rect handling
// FIXME: problem with the 'pitch'
r.clip(_screen.w, _screen.h);
r.clip(_drawArea);
_system->copyRectToOverlay((OverlayColor*)_screen.getBasePtr(r.left, r.top), _screen.w, r.left, r.top, r.width(), r.height());
if (_dialog && backup) {
if (_dialog->screen.pixels) {
OverlayColor *dst = (OverlayColor*)_dialog->screen.getBasePtr(r.left, r.top);
const OverlayColor *src = (const OverlayColor*)_screen.getBasePtr(r.left, r.top);
int h = r.height();
while (h--) {
memcpy(dst, src, r.width()*sizeof(OverlayColor));
dst += _dialog->screen.w;
src += _screen.w;
}
}
}
return true;
}
inline uint8 calcColor(uint8 start, uint8 end, int pos, int max) {
int diff = ((int)end - (int)start) * pos / max;
return start + diff;
}
OverlayColor calcColor(OverlayColor start, OverlayColor end, int pos, int max, uint factor = 1) {
pos *= factor;
if (pos > max) {
pos = max;
}
OverlayColor result = 0;
uint8 sr = 0, sg = 0, sb = 0;
uint8 er = 0, eg = 0, eb = 0;
if (gBitFormat == 565) {
sr = (start >> 11) & 0x1F;
sg = (start >> 5) & 0x3F;
sb = (start >> 0) & 0x1F;
er = (end >> 11) & 0x1F;
eg = (end >> 5) & 0x3F;
eb = (end >> 0) & 0x1F;
} else {
sr = (start >> 10) & 0x1F;
sg = (start >> 5) & 0x1F;
sb = (start >> 0) & 0x1F;
er = (end >> 10) & 0x1F;
eg = (end >> 5) & 0x1F;
eb = (end >> 0) & 0x1F;
}
uint8 cr = calcColor(sr, er, pos, max);
uint8 cg = calcColor(sg, eg, pos, max);
uint8 cb = calcColor(sb, eb, pos, max);
if (gBitFormat == 565) {
result = ((int)(cr & 0x1F) << 11) | ((int)(cg & 0x3F) << 5) | (int)(cb & 0x1F);
} else {
result = ((int)(cr & 0x1F) << 10) | ((int)(cg & 0x1F) << 5) | (int)(cb & 0x1F);
}
return result;
}
void ThemeNew::colorFade(const Common::Rect &r, OverlayColor start, OverlayColor end) {
OverlayColor *ptr = (OverlayColor*)_screen.getBasePtr(r.left, r.top);
int h = r.height();
while (h--) {
OverlayColor col = calcColor(start, end, r.height()-h, r.height());
for (int i = 0; i < r.width(); ++i) {
ptr[i] = col;
}
ptr += _screen.w;
}
}
void ThemeNew::drawRect(const Common::Rect &r, const Surface *corner, const Surface *top, const Surface *left, const Surface *fill, int alpha) {
// top left
drawRectMasked(r, corner, top, left, fill, alpha, _system->RGBToColor(255, 255, 255), _system->RGBToColor(255, 255, 255));
}
void ThemeNew::drawRectMasked(const Common::Rect &r, const Graphics::Surface *corner, const Graphics::Surface *top,
const Graphics::Surface *left, const Graphics::Surface *fill, int alpha,
OverlayColor start, OverlayColor end, uint factor) {
int drawWidth = MIN(corner->w, MIN(top->w, MIN(left->w, fill->w)));
int drawHeight = MIN(corner->h, MIN(top->h, MIN(left->h, fill->h)));
int partsH = r.height() / drawHeight;
int partsW = r.width() / drawWidth;
int yPos = r.top;
int specialHeight = 0;
int specialWidth = 0;
if (drawHeight*2 > r.height()) {
drawHeight = r.height() / 2;
partsH = 2;
} else {
specialHeight = r.height() % drawHeight;
if (specialHeight != 0)
++partsH;
}
if (drawWidth*2 > r.width()) {
drawWidth = r.width() / 2;
partsW = 2;
} else {
specialWidth = r.width() % drawWidth;
if (specialWidth != 0)
++partsW;
}
for (int y = 0; y < partsH; ++y) {
int xPos = r.left;
bool upDown = false;
if (y == partsH - 1)
upDown = true;
// calculate the correct drawing height
int usedHeight = drawHeight;
if (specialHeight && y == 1) {
usedHeight = specialHeight;
}
OverlayColor startCol = calcColor(start, end, yPos-r.top, r.height(), factor);
OverlayColor endCol = calcColor(start, end, yPos-r.top+usedHeight, r.height(), factor);
for (int i = 0; i < partsW; ++i) {
// calculate the correct drawing width
int usedWidth = drawWidth;
if (specialWidth && i == 1) {
usedWidth = specialWidth;
}
// draw the right surface
if (!i) {
if (!y || y == partsH - 1) {
drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), corner, upDown, false, alpha, startCol, endCol);
} else {
drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), left, upDown, false, alpha, startCol, endCol);
}
} else if (i == partsW - 1) {
if (!y || y == partsH - 1) {
drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), corner, upDown, true, alpha, startCol, endCol);
} else {
drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), left, upDown, true, alpha, startCol, endCol);
}
} else if (!y || y == partsH - 1) {
drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), top, upDown, false, alpha, startCol, endCol);
} else {
drawSurfaceMasked(Common::Rect(xPos, yPos, xPos+usedWidth, yPos+usedHeight), fill, upDown, false, alpha, startCol, endCol);
}
xPos += usedWidth;
}
yPos += usedHeight;
}
}
void ThemeNew::drawSurface(const Common::Rect &r, const Surface *surf, bool upDown, bool leftRight, int alpha) {
drawSurfaceMasked(r, surf, upDown, leftRight, alpha, _system->RGBToColor(255, 255, 255), _system->RGBToColor(255, 255, 255));
}
inline OverlayColor getColorAlpha(OverlayColor col1, OverlayColor col2, int alpha) {
if (alpha == 256) {
return col1;
}
uint8 r1, g1, b1;
uint8 r2, g2, b2;
OSystem::instance().colorToRGB(col1, r1, g1, b1);
OSystem::instance().colorToRGB(col2, r2, g2, b2);
uint8 r, g, b;
r = (alpha * (r1 - r2) >> 8) + r2;
g = (alpha * (g1 - g2) >> 8) + g2;
b = (alpha * (b1 - b2) >> 8) + b2;
return OSystem::instance().RGBToColor(r, g, b);
}
void ThemeNew::drawSurfaceMasked(const Common::Rect &r, const Graphics::Surface *surf, bool upDown, bool leftRight,
int alpha, OverlayColor start, OverlayColor end, uint factor) {
OverlayColor *dst = (OverlayColor*)_screen.getBasePtr(r.left, r.top);
const OverlayColor *src = 0;
const OverlayColor transparency = _colors[kColorTransparency];
if (upDown && !leftRight) { // upsidedown
src = (const OverlayColor*)surf->pixels + (surf->h - 1) * surf->w;
int drawWidth = (r.width() < surf->w) ? r.width() : surf->w;
for (int i = 0; i < r.height(); ++i) {
OverlayColor rowColor = calcColor(start, end, i, r.height(), factor);
for (int x = 0; x < drawWidth; ++x) {
if (src[x] != transparency && dst >= _screen.pixels) {
dst[x] = getColorAlpha(src[x], dst[x], alpha) & rowColor;
}
}
dst += _screen.w;
src -= surf->w;
}
} else if (upDown && leftRight) { // upsidedown + left right inverse
src = (const OverlayColor*)surf->pixels + (surf->h - 1) * surf->w;
int drawWidth = (r.width() < surf->w) ? r.width() : surf->w;
for (int i = 0; i < r.height(); ++i) {
OverlayColor rowColor = calcColor(start, end, i, r.height(), factor);
for (int x = 0; x < drawWidth; ++x) {
if (src[drawWidth-x-1] != transparency && dst >= _screen.pixels) {
dst[x] = getColorAlpha(src[drawWidth-x-1], dst[x], alpha) & rowColor;
}
}
dst += _screen.w;
src -= surf->w;
}
} else if (!upDown && leftRight) { // left right inverse
src = (const OverlayColor*)surf->pixels;
int drawWidth = (r.width() < surf->w) ? r.width() : surf->w;
for (int i = 0; i < r.height(); ++i) {
OverlayColor rowColor = calcColor(start, end, i, r.height(), factor);
for (int x = 0; x < drawWidth; ++x) {
if (src[drawWidth-x-1] != transparency && dst >= _screen.pixels) {
dst[x] = getColorAlpha(src[drawWidth-x-1], dst[x], alpha) & rowColor;
}
}
dst += _screen.w;
src += surf->w;
}
} else { // normal
src = (const OverlayColor*)surf->pixels;
int drawWidth = (r.width() < surf->w) ? r.width() : surf->w;
for (int i = 0; i < r.height(); ++i) {
OverlayColor rowColor = calcColor(start, end, i, r.height(), factor);
for (int x = 0; x < drawWidth; ++x) {
if (src[x] != transparency && dst >= _screen.pixels) {
dst[x] = getColorAlpha(src[x], dst[x], alpha) & rowColor;
}
}
dst += _screen.w;
src += surf->w;
}
}
}
OverlayColor ThemeNew::getColor(kState state) {
switch (state) {
case kStateDisabled:
return _colors[kColorStateDisabled];
break;
case kStateHighlight:
return _colors[kColorStateHighlight];
break;
default:
break;
};
return _colors[kColorStateEnabled];
}
} // end of namespace GUI

View file

@ -73,7 +73,6 @@ static const char *credits_intro[] = {
#include "gui/credits.h" #include "gui/credits.h"
AboutDialog::AboutDialog() AboutDialog::AboutDialog()
: Dialog(10, 20, 300, 174), : Dialog(10, 20, 300, 174),
_scrollPos(0), _scrollTime(0), _modifiers(0), _willClose(false) { _scrollPos(0), _scrollTime(0), _modifiers(0), _willClose(false) {
@ -111,7 +110,6 @@ AboutDialog::AboutDialog()
} }
_w += 2*xOff; _w += 2*xOff;
for (i = 0; i < 1; i++) for (i = 0; i < 1; i++)
_lines.push_back(""); _lines.push_back("");
@ -166,7 +164,7 @@ void AboutDialog::addLine(const char *str) {
_lines.push_back(format); _lines.push_back(format);
} else { } else {
Common::StringList wrappedLines; 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) { for (Common::StringList::const_iterator i = wrappedLines.begin(); i != wrappedLines.end(); ++i) {
_lines.push_back(format + *i); _lines.push_back(format + *i);
@ -180,27 +178,17 @@ void AboutDialog::open() {
_scrollPos = 0; _scrollPos = 0;
_modifiers = 0; _modifiers = 0;
_willClose = false; _willClose = false;
_canvas.pixels = NULL;
Dialog::open(); Dialog::open();
} }
void AboutDialog::close() { void AboutDialog::close() {
free(_canvas.pixels);
Dialog::close(); Dialog::close();
} }
void AboutDialog::drawDialog() { void AboutDialog::drawDialog() {
if (!_canvas.pixels) { g_gui.theme()->setDrawArea(Common::Rect(_x, _y, _x+_w, _y+_h));
// Blend over the background. Since we can't afford to do that Dialog::drawDialog();
// 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);
// Draw text // Draw text
// TODO: Add a "fade" effect for the top/bottom text lines // TODO: Add a "fade" effect for the top/bottom text lines
@ -213,35 +201,37 @@ void AboutDialog::drawDialog() {
for (int line = firstLine; line < lastLine; line++) { for (int line = firstLine; line < lastLine; line++) {
const char *str = _lines[line].c_str(); const char *str = _lines[line].c_str();
Graphics::TextAlignment align = Graphics::kTextAlignCenter; Theme::kTextAlign align = Theme::kTextAlignCenter;
OverlayColor color = g_gui._textcolor; Theme::kState state = Theme::kStateEnabled;
while (str[0] == '\\') { while (str[0] == '\\') {
switch (str[1]) { switch (str[1]) {
case 'C': case 'C':
align = Graphics::kTextAlignCenter; align = Theme::kTextAlignCenter;
break; break;
case 'L': case 'L':
align = Graphics::kTextAlignLeft; align = Theme::kTextAlignLeft;
break; break;
case 'R': case 'R':
align = Graphics::kTextAlignRight; align = Theme::kTextAlignRight;
break; break;
case 'c': case 'c':
switch (str[2]) { switch (str[2]) {
case '0': case '0':
color = g_gui._textcolor; state = Theme::kStateEnabled;
break; break;
case '1': case '1':
color = g_gui._textcolorhi; state = Theme::kStateHighlight;
break; break;
case '2': case '2':
color = g_gui._color; state = Theme::kStateDisabled;
break; break;
case '3': case '3':
color = g_gui._shadowcolor; warning("Need state for color 3");
// color = g_gui._shadowcolor;
break; break;
case '4': case '4':
color = g_gui._bgcolor; warning("Need state for color 4");
// color = g_gui._bgcolor;
break; break;
default: default:
error("Unknown color type '%c'", str[2]); error("Unknown color type '%c'", str[2]);
@ -255,31 +245,17 @@ void AboutDialog::drawDialog() {
str += 2; str += 2;
} }
// Trim leading whitespaces if center mode is on // Trim leading whitespaces if center mode is on
if (align == Graphics::kTextAlignCenter) if (align == Theme::kTextAlignCenter)
while (*str && *str == ' ') while (*str && *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; y += _lineHeight;
} }
g_gui.theme()->resetDrawArea();
// 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);
} }
void AboutDialog::handleTickle() { 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(); const uint32 t = getMillis();
int scrollOffset = ((int)t - (int)_scrollTime) / kScrollMillisPerPixel; int scrollOffset = ((int)t - (int)_scrollTime) / kScrollMillisPerPixel;
if (scrollOffset > 0) { if (scrollOffset > 0) {
@ -302,16 +278,6 @@ void AboutDialog::handleTickle() {
} }
} }
void AboutDialog::handleScreenChanged() {
// The screen has changed. That means the overlay colors in the canvas
// may no longer be correct. Reset it, and issue a full redraw.
// TODO: We could check if the bit format has changed, like we do in
// the MPEG player.
free(_canvas.pixels);
_canvas.pixels = NULL;
draw();
}
void AboutDialog::handleMouseUp(int x, int y, int button, int clickCount) { void AboutDialog::handleMouseUp(int x, int y, int button, int clickCount) {
// Close upon any mouse click // Close upon any mouse click
close(); close();
@ -329,5 +295,4 @@ void AboutDialog::handleKeyUp(uint16 ascii, int keycode, int modifiers) {
close(); close();
} }
} // End of namespace GUI } // End of namespace GUI

View file

@ -36,7 +36,6 @@ protected:
uint32 _lineHeight; uint32 _lineHeight;
byte _modifiers; byte _modifiers;
bool _willClose; bool _willClose;
Graphics::Surface _canvas;
int xOff, yOff; int xOff, yOff;
@ -49,7 +48,6 @@ public:
void close(); void close();
void drawDialog(); void drawDialog();
void handleTickle(); void handleTickle();
void handleScreenChanged();
void handleMouseUp(int x, int y, int button, int clickCount); void handleMouseUp(int x, int y, int button, int clickCount);
void handleKeyDown(uint16 ascii, int keycode, int modifiers); void handleKeyDown(uint16 ascii, int keycode, int modifiers);
void handleKeyUp(uint16 ascii, int keycode, int modifiers); void handleKeyUp(uint16 ascii, int keycode, int modifiers);

View file

@ -114,10 +114,7 @@ void ConsoleDialog::slideUpAndClose() {
} }
void ConsoleDialog::open() { void ConsoleDialog::open() {
// This dialog will be redrawn a lot, so we store a copy of the blended // TODO: find a new way to do this
// background in a separate "canvas", just like in the About dialog.
_canvas.pixels = NULL;
// Initiate sliding the console down. We do a very simple trick to achieve // 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 // this effect: we simply move the console dialog just above (outside) the
// visible screen area, then shift it down in handleTickle() over a // visible screen area, then shift it down in handleTickle() over a
@ -135,36 +132,16 @@ void ConsoleDialog::open() {
} }
void ConsoleDialog::close() { void ConsoleDialog::close() {
free(_canvas.pixels);
Dialog::close(); Dialog::close();
} }
void ConsoleDialog::drawDialog() { 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 // Draw text
int start = _scrollLine - _linesPerPage + 1; int start = _scrollLine - _linesPerPage + 1;
int y = _y + 2; int y = _y + 2;
g_gui.theme()->drawDialogBackground(Common::Rect(_x, _y, _x+_w, _y+_h));
for (int line = 0; line < _linesPerPage; line++) { for (int line = 0; line < _linesPerPage; line++) {
int x = _x + 1; int x = _x + 1;
for (int column = 0; column < _lineWidth; column++) { for (int column = 0; column < _lineWidth; column++) {
@ -174,7 +151,7 @@ void ConsoleDialog::drawDialog() {
#else #else
byte c = buffer((start + line) * _lineWidth + column); byte c = buffer((start + line) * _lineWidth + column);
#endif #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; x += kConsoleCharWidth;
} }
y += kConsoleLineHeight; y += kConsoleLineHeight;
@ -182,21 +159,14 @@ void ConsoleDialog::drawDialog() {
// Draw the scrollbar // Draw the scrollbar
_scrollBar->draw(); _scrollBar->draw();
// Finally blit it all to the screen
g_gui.addDirtyRect(_x, _y, _w, _h);
} }
void ConsoleDialog::handleScreenChanged() { void ConsoleDialog::handleScreenChanged() {
free(_canvas.pixels); Dialog::handleScreenChanged();
_canvas.pixels = NULL;
draw(); draw();
} }
void ConsoleDialog::handleTickle() { void ConsoleDialog::handleTickle() {
if (!_canvas.pixels)
return;
uint32 time = g_system->getMillis(); uint32 time = g_system->getMillis();
if (_caretTime < time) { if (_caretTime < time) {
_caretTime = time + kCaretBlinkTime; _caretTime = time + kCaretBlinkTime;
@ -219,7 +189,7 @@ void ConsoleDialog::handleTickle() {
draw(); draw();
} else if (_slideMode == kUpSlideMode && _y <= -_h) { } else if (_slideMode == kUpSlideMode && _y <= -_h) {
// End the slide // End the slide
_slideMode = kNoSlideMode; //_slideMode = kNoSlideMode;
close(); close();
} else } else
draw(); draw();
@ -614,6 +584,7 @@ void ConsoleDialog::print(const char *str) {
} }
void ConsoleDialog::drawCaret(bool erase) { void ConsoleDialog::drawCaret(bool erase) {
// TODO: use code from EditableWidget::drawCaret here
int line = _currentPos / _lineWidth; int line = _currentPos / _lineWidth;
int displayLine = line - _scrollLine + _linesPerPage - 1; int displayLine = line - _scrollLine + _linesPerPage - 1;
@ -626,17 +597,8 @@ void ConsoleDialog::drawCaret(bool erase) {
int x = _x + 1 + (_currentPos % _lineWidth) * kConsoleCharWidth; int x = _x + 1 + (_currentPos % _lineWidth) * kConsoleCharWidth;
int y = _y + displayLine * kConsoleLineHeight; 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; _caretVisible = !erase;
g_gui.theme()->drawCaret(Common::Rect(x, y, x+kConsoleCharWidth, y+kConsoleLineHeight), erase);
} }
void ConsoleDialog::scrollToCurrent() { void ConsoleDialog::scrollToCurrent() {

View file

@ -43,7 +43,6 @@ public:
typedef bool (*CompletionCallbackProc)(ConsoleDialog* console, const char *input, char*& completion, void *refCon); typedef bool (*CompletionCallbackProc)(ConsoleDialog* console, const char *input, char*& completion, void *refCon);
protected: protected:
Graphics::Surface _canvas;
const Graphics::Font *_font; const Graphics::Font *_font;
char _buffer[kBufferSize]; char _buffer[kBufferSize];

View file

@ -40,7 +40,7 @@ namespace GUI {
Dialog::Dialog(int x, int y, int w, int h) Dialog::Dialog(int x, int y, int w, int h)
: GuiObject(x, y, w, 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() { Dialog::~Dialog() {
@ -88,6 +88,18 @@ void Dialog::close() {
releaseFocus(); 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() { void Dialog::releaseFocus() {
if (_focusedWidget) { if (_focusedWidget) {
_focusedWidget->lostFocus(); _focusedWidget->lostFocus();
@ -104,8 +116,7 @@ void Dialog::drawDialog() {
if (!isVisible()) if (!isVisible())
return; return;
g_gui.blendRect(_x, _y, _w, _h, g_gui._bgcolor); g_gui.theme()->drawDialogBackground(Common::Rect(_x, _y, _x+_w, _y+_h), Theme::kStateEnabled, _mainDialog);
g_gui.box(_x, _y, _w, _h, g_gui._color, g_gui._shadowcolor);
// Draw all children // Draw all children
Widget *w = _firstWidget; Widget *w = _firstWidget;
@ -113,9 +124,6 @@ void Dialog::drawDialog() {
w->draw(); w->draw();
w = w->_next; 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) { void Dialog::handleMouseDown(int x, int y, int button, int clickCount) {

View file

@ -44,6 +44,7 @@ protected:
Widget *_focusedWidget; Widget *_focusedWidget;
Widget *_dragWidget; Widget *_dragWidget;
bool _visible; bool _visible;
bool _mainDialog; // FIXME: find a better solution for this and change the Theme class to handle it then
private: private:
int _result; int _result;
@ -73,7 +74,7 @@ protected:
virtual void handleKeyUp(uint16 ascii, int keycode, int modifiers); virtual void handleKeyUp(uint16 ascii, int keycode, int modifiers);
virtual void handleMouseMoved(int x, int y, int button); virtual void handleMouseMoved(int x, int y, int button);
virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data); 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 Widget *findWidget(int x, int y); // Find the widget at pos x,y if any

View file

@ -143,7 +143,6 @@ void EditableWidget::drawCaret(bool erase) {
Common::Rect editRect = getEditRect(); Common::Rect editRect = getEditRect();
int16 color = (erase ^ _caretInverse) ? g_gui._bgcolor : g_gui._textcolorhi;
int x = editRect.left; int x = editRect.left;
int y = editRect.top + 1; int y = editRect.top + 1;
@ -155,9 +154,8 @@ void EditableWidget::drawCaret(bool erase) {
x += getAbsX(); x += getAbsX();
y += getAbsY(); y += getAbsY();
g_gui.vLine(x, y, y + editRect.height() - 2, color); g_gui.theme()->drawCaret(Common::Rect(x, y, x+editRect.width(), y+editRect.height()-2), erase);
g_gui.addDirtyRect(x, y, 2, editRect.height() - 2);
_caretVisible = !erase; _caretVisible = !erase;
} }

View file

@ -490,6 +490,7 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
LauncherDialog::LauncherDialog(GameDetector &detector) LauncherDialog::LauncherDialog(GameDetector &detector)
: Dialog(0, 0, 320, 200), _detector(detector) { : Dialog(0, 0, 320, 200), _detector(detector) {
_mainDialog = true;
const int screenW = g_system->getOverlayWidth(); const int screenW = g_system->getOverlayWidth();
const int screenH = g_system->getOverlayHeight(); const int screenH = g_system->getOverlayHeight();

View file

@ -16,7 +16,9 @@ MODULE_OBJS := \
gui/PopUpWidget.o \ gui/PopUpWidget.o \
gui/ScrollBarWidget.o \ gui/ScrollBarWidget.o \
gui/TabWidget.o \ gui/TabWidget.o \
gui/widget.o gui/widget.o \
gui/theme.o \
gui/ThemeNew.o
MODULE_DIRS += \ MODULE_DIRS += \
gui gui

View file

@ -24,6 +24,8 @@
#include "gui/newgui.h" #include "gui/newgui.h"
#include "gui/dialog.h" #include "gui/dialog.h"
#include "common/config-manager.h"
DECLARE_SINGLETON(GUI::NewGui); DECLARE_SINGLETON(GUI::NewGui);
namespace GUI { namespace GUI {
@ -55,7 +57,7 @@ enum {
// Constructor // Constructor
NewGui::NewGui() : _needRedraw(false), NewGui::NewGui() : _needRedraw(false),
_stateIsSaved(false), _font(0), _cursorAnimateCounter(0), _cursorAnimateTimer(0) { _stateIsSaved(false), _cursorAnimateCounter(0), _cursorAnimateTimer(0) {
_system = &OSystem::instance(); _system = &OSystem::instance();
@ -65,32 +67,26 @@ NewGui::NewGui() : _needRedraw(false),
// Reset key repeat // Reset key repeat
_currentKeyDown.keycode = 0; _currentKeyDown.keycode = 0;
// updates the scaling factor ConfMan.registerDefault("gui_theme", "default-theme");
updateScaleFactor(); Common::String style = ConfMan.get("gui_theme");
} if (scumm_stricmp(style.c_str(), "classic") == 0) {
_theme = new ThemeClassic(_system);
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);
} else { } 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() { void NewGui::runLoop() {
@ -101,36 +97,34 @@ void NewGui::runLoop() {
if (activeDialog == 0) if (activeDialog == 0)
return; 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) { if (!_stateIsSaved) {
saveState(); saveState();
_theme->enable();
didSaveState = true; didSaveState = true;
} }
_theme->openDialog();
while (!_dialogStack.empty() && activeDialog == _dialogStack.top()) { while (!_dialogStack.empty() && activeDialog == _dialogStack.top()) {
activeDialog->handleTickle(); activeDialog->handleTickle();
if (_needRedraw) { if (_needRedraw) {
// Restore the overlay to its initial state, then draw all dialogs. // Restore the overlay to its initial state, then draw all dialogs.
// This is necessary to get the blending right. // This is necessary to get the blending right.
_system->clearOverlay(); _theme->clearAll();
_system->grabOverlay((OverlayColor *)_screen.pixels, _screenPitch);
for (int i = 0; i < _dialogStack.size(); ++i) {
_theme->closeDialog();
}
for (int i = 0; i < _dialogStack.size(); i++) { for (int i = 0; i < _dialogStack.size(); i++) {
// For each dialog we draw we have to ensure the correct _theme->openDialog();
// scaling mode is active.
updateScaleFactor();
_dialogStack[i]->drawDialog(); _dialogStack[i]->drawDialog();
} }
_needRedraw = false; _needRedraw = false;
} }
animateCursor(); animateCursor();
_theme->drawAll();
_system->updateScreen(); _system->updateScreen();
OSystem::Event event; OSystem::Event event;
@ -191,8 +185,9 @@ void NewGui::runLoop() {
_system->quit(); _system->quit();
return; return;
case OSystem::EVENT_SCREEN_CHANGED: case OSystem::EVENT_SCREEN_CHANGED:
updateColors(); // reinit the whole theme
updateScaleFactor(); _theme->refresh();
_needRedraw = true;
activeDialog->handleScreenChanged(); activeDialog->handleScreenChanged();
break; break;
} }
@ -211,8 +206,12 @@ void NewGui::runLoop() {
_system->delayMillis(10); _system->delayMillis(10);
} }
if (didSaveState) _theme->closeDialog();
if (didSaveState) {
restoreState(); restoreState();
_theme->disable();
}
} }
#pragma mark - #pragma mark -
@ -221,20 +220,6 @@ void NewGui::saveState() {
// Backup old cursor // Backup old cursor
_oldCursorMode = _system->showMouse(true); _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; _currentKeyDown.keycode = 0;
_lastClick.x = _lastClick.y = 0; _lastClick.x = _lastClick.y = 0;
_lastClick.time = 0; _lastClick.time = 0;
@ -246,12 +231,6 @@ void NewGui::saveState() {
void NewGui::restoreState() { void NewGui::restoreState() {
_system->showMouse(_oldCursorMode); _system->showMouse(_oldCursorMode);
_system->hideOverlay();
if (_screen.pixels) {
free(_screen.pixels);
_screen.pixels = 0;
}
_system->updateScreen(); _system->updateScreen();
_stateIsSaved = false; _stateIsSaved = false;
@ -272,194 +251,6 @@ void NewGui::closeTopDialog() {
_needRedraw = true; _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 // 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. // We could plug in a different cursor here if we like to.

View file

@ -26,6 +26,7 @@
#include "common/stack.h" #include "common/stack.h"
#include "common/str.h" #include "common/str.h"
#include "graphics/fontman.h" #include "graphics/fontman.h"
#include "gui/theme.h"
class OSystem; class OSystem;
@ -67,18 +68,23 @@ public:
bool isActive() const { return ! _dialogStack.empty(); } 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: protected:
OSystem *_system; OSystem *_system;
Graphics::Surface _screen;
int _screenPitch; Theme *_theme;
bool _needRedraw; bool _needRedraw;
DialogStack _dialogStack; DialogStack _dialogStack;
bool _stateIsSaved; bool _stateIsSaved;
const Graphics::Font *_font;
// for continuous events (keyDown) // for continuous events (keyDown)
struct { struct {
uint16 ascii; uint16 ascii;
@ -109,54 +115,6 @@ protected:
void loop(); void loop();
void animateCursor(); 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 } // End of namespace GUI

516
gui/theme.cpp Normal file
View file

@ -0,0 +1,516 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2006 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Header $
*/
#include "gui/theme.h"
namespace GUI {
ThemeClassic::ThemeClassic(OSystem *system) : Theme() {
_system = system;
_initOk = false;
memset(&_screen, 0, sizeof(_screen));
#ifdef OLDGUI_TRANSPARENCY
memset(&_dialog, 0, sizeof(_dialog));
#endif
_font = 0;
// Maybe change this filename
_configFile.loadFromFile("classic.ini");
}
ThemeClassic::~ThemeClassic() {
deinit();
}
bool ThemeClassic::init() {
deinit();
_screen.create(_system->getOverlayWidth(), _system->getOverlayHeight(), sizeof(OverlayColor));
if (_screen.pixels) {
_initOk = true;
clearAll();
_bgcolor = _system->RGBToColor(0, 0, 0);
_color = _system->RGBToColor(104, 104, 104);
_shadowcolor = _system->RGBToColor(64, 64, 64);
_textcolor = _system->RGBToColor(32, 160, 32);
_textcolorhi = _system->RGBToColor(0, 255, 0);
if (_screen.w >= 400 && _screen.h >= 300) {
_font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
} else {
_font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
}
}
return true;
}
void ThemeClassic::deinit() {
if (_initOk) {
_system->hideOverlay();
_screen.free();
_initOk = false;
}
}
void ThemeClassic::refresh() {
init();
_bgcolor = _system->RGBToColor(0, 0, 0);
_color = _system->RGBToColor(104, 104, 104);
_shadowcolor = _system->RGBToColor(64, 64, 64);
_textcolor = _system->RGBToColor(32, 160, 32);
_textcolorhi = _system->RGBToColor(0, 255, 0);
_system->showOverlay();
}
void ThemeClassic::enable() {
_system->showOverlay();
clearAll();
}
void ThemeClassic::disable() {
_system->hideOverlay();
}
void ThemeClassic::openDialog() {
#ifdef OLDGUI_TRANSPARENCY
if (!_dialog) {
_dialog = new DialogState;
assert(_dialog);
// first dialog
_dialog->screen.create(_screen.w, _screen.h, sizeof(OverlayColor));
}
memcpy(_dialog->screen.pixels, _screen.pixels, _screen.pitch*_screen.h);
blendScreenToDialog();
#endif
}
void ThemeClassic::closeDialog() {
#ifdef OLDGUI_TRANSPARENCY
if (_dialog) {
_dialog->screen.free();
delete _dialog;
_dialog = 0;
}
#endif
}
void ThemeClassic::clearAll() {
if (!_initOk)
return;
_system->clearOverlay();
// FIXME: problem with the 'pitch'
_system->grabOverlay((OverlayColor*)_screen.pixels, _screen.w);
}
void ThemeClassic::drawAll() {
if (!_initOk)
return;
}
void ThemeClassic::resetDrawArea() {
if (_initOk) {
_drawArea = Common::Rect(0, 0, _screen.w, _screen.h);
}
}
void ThemeClassic::drawDialogBackground(const Common::Rect &r, kState state, bool mainDialog) {
if (!_initOk)
return;
restoreBackground(r);
box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
addDirtyRect(r);
}
void ThemeClassic::drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis) {
if (!_initOk)
return;
if (!inverted) {
restoreBackground(r);
_font->drawString(&_screen, str, r.left, r.top, r.width(), getColor(state), convertAligment(align), deltax, useEllipsis);
} else {
_screen.fillRect(r, getColor(state));
_font->drawString(&_screen, str, r.left, r.top, r.width(), _bgcolor, convertAligment(align), deltax, useEllipsis);
}
addDirtyRect(r);
}
void ThemeClassic::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state) {
if (!_initOk)
return;
restoreBackground(r);
font->drawChar(&_screen, ch, r.left, r.top, getColor(state));
addDirtyRect(r);
}
void ThemeClassic::drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background, kState state) {
if (!_initOk || background == kWidgetBackgroundNo)
return;
switch (background) {
case kWidgetBackgroundBorder:
restoreBackground(r);
box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
break;
case kWidgetBackgroundBorderSmall:
restoreBackground(r);
box(r.left, r.top, r.width(), r.height());
break;
case kWidgetBackgroundPlain:
restoreBackground(r);
break;
default:
break;
};
addDirtyRect(r);
}
void ThemeClassic::drawButton(const Common::Rect &r, const Common::String &str, kState state) {
if (!_initOk)
return;
restoreBackground(r);
drawWidgetBackground(r, 0, kWidgetBackgroundBorder, state);
const int off = (r.height() - _font->getFontHeight()) / 2;
_font->drawString(&_screen, str, r.left, r.top+off, r.width(), getColor(state), Graphics::kTextAlignCenter, 0, false);
addDirtyRect(r);
}
void ThemeClassic::drawSurface(const Common::Rect &r, const Graphics::Surface &surface, kState state) {
if (!_initOk)
return;
Common::Rect rect(r.left, r.top, r.left + surface.w, r.top + surface.h);
rect.clip(_screen.w, _screen.h);
if (!rect.isValidRect())
return;
assert(surface.bytesPerPixel == sizeof(OverlayColor));
OverlayColor *src = (OverlayColor *)surface.pixels;
OverlayColor *dst = (OverlayColor *)_screen.getBasePtr(rect.left, rect.top);
int w = rect.width();
int h = rect.height();
while (h--) {
memcpy(dst, src, surface.pitch);
src += w;
// FIXME: this should be pitch
dst += _screen.w;
}
addDirtyRect(r);
}
void ThemeClassic::drawSlider(const Common::Rect &r, int width, kState state) {
if (!_initOk)
return;
Common::Rect r2 = r;
restoreBackground(r);
box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
r2.left = r.left + 2;
r2.top = r.top + 2;
r2.bottom = r.bottom - 2;
r2.right = r2.left + width;
if (r2.right > r.right - 2) {
r2.right = r.right - 2;
}
_screen.fillRect(r2, getColor(state));
addDirtyRect(r);
}
void ThemeClassic::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, kState state) {
if (!_initOk)
return;
Common::Rect r2 = r;
int checkBoxSize = getFontHeight();
if (checkBoxSize > r.height()) {
checkBoxSize = r.height();
}
r2.bottom = r2.top + checkBoxSize;
restoreBackground(r2);
box(r.left, r.top, checkBoxSize, checkBoxSize, _color, _shadowcolor);
if (checked) {
// TODO: implement old style
r2.top += 2;
r2.bottom = r.top + checkBoxSize - 2;
r2.left += 2;
r2.right = r.left + checkBoxSize - 2;
_screen.fillRect(r2, getColor(state));
r2 = r;
}
r2.left += checkBoxSize + 10;
_font->drawString(&_screen, str, r2.left, r2.top, r2.width(), getColor(state), Graphics::kTextAlignCenter, 0, true);
addDirtyRect(r);
}
void ThemeClassic::drawTab(const Common::Rect &r, const Common::String &str, bool active, kState state) {
if (!_initOk)
return;
restoreBackground(r);
box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
_font->drawString(&_screen, str, r.left, r.top+2, r.width(), getColor(state), Graphics::kTextAlignCenter, 0, true);
addDirtyRect(r);
}
void ThemeClassic::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, kScrollbarState scroll, kState state) {
if (!_initOk)
return;
restoreBackground(r);
Common::Rect r2 = r;
box(r.left, r.top, r.width(), r.height(), _color, _shadowcolor);
const int UP_DOWN_BOX_HEIGHT = r.width() + 1;
const int B = 3;
const int arrowSize = (r.width() / 2 - B + 1);
OverlayColor color = 0;
if (scroll == kScrollbarStateSinglePage) {
color = _color;
} else if (scroll == kScrollbarStateUp && state == kStateHighlight) {
color = _textcolorhi;
} else {
color = _textcolor;
}
// draws the 'up' button
box(r.left, r.top, r.width(), UP_DOWN_BOX_HEIGHT, _color, _shadowcolor);
Common::Point p0 = Common::Point(r.left + r.width() / 2, r.top + (UP_DOWN_BOX_HEIGHT - arrowSize - 1) / 2);
Common::Point p1 = Common::Point(p0.x - arrowSize, p0.y + arrowSize);
Common::Point p2 = Common::Point(p0.x + arrowSize, p0.y + arrowSize);
for (; p1.x <= p2.x; ++p1.x)
_screen.drawLine(p0.x, p0.y, p1.x, p1.y, color);
if (scroll != kScrollbarStateSinglePage) {
r2.top += sliderY;
r2.left += 2;
r2.right -= 2;
r2.bottom = r2.top + sliderHeight;
_screen.fillRect(r2, (state == kStateHighlight && scroll == kScrollbarStateSlider) ? _textcolorhi : _textcolor);
box(r2.left, r2.top, r2.width(), r2.height());
int y = r2.top + sliderHeight / 2;
color = (state == kStateHighlight && scroll == kScrollbarStateSlider) ? _color : _bgcolor;
_screen.hLine(r2.left + 1, y - 2, r2.right - 2, color);
_screen.hLine(r2.left + 1, y, r2.right - 2, color);
_screen.hLine(r2.left + 1, y + 2, r2.right - 2, color);
r2 = r;
}
r2.top = r2.bottom - UP_DOWN_BOX_HEIGHT;
if (scroll == kScrollbarStateSinglePage) {
color = _color;
} else if (scroll == kScrollbarStateDown && state == kStateHighlight) {
color = _textcolorhi;
} else {
color = _textcolor;
}
// draws the 'down' button
box(r2.left, r2.top, r2.width(), UP_DOWN_BOX_HEIGHT, _color, _shadowcolor);
p0 = Common::Point(r2.left + r2.width() / 2, r2.top + (UP_DOWN_BOX_HEIGHT + arrowSize + 1) / 2);
p1 = Common::Point(p0.x - arrowSize, p0.y - arrowSize);
p2 = Common::Point(p0.x + arrowSize, p0.y - arrowSize);
for (; p1.x <= p2.x; ++p1.x)
_screen.drawLine(p0.x, p0.y, p1.x, p1.y, color);
addDirtyRect(r);
}
void ThemeClassic::drawCaret(const Common::Rect &r, bool erase, kState state) {
if (!_initOk)
return;
OverlayColor color = 0;
if (erase) {
color = _bgcolor;
} else {
color = getColor(state);
}
_screen.vLine(r.left, r.top, r.bottom - 2, color);
addDirtyRect(r);
}
void ThemeClassic::drawLineSeparator(const Common::Rect &r, kState state) {
if (!_initOk)
return;
_screen.hLine(r.left - 1, r.top + r.height() / 2, r.right, _shadowcolor);
_screen.hLine(r.left, r.top + 1 + r.height() / 2, r.right, _color);
addDirtyRect(r);
}
// intern drawing
void ThemeClassic::restoreBackground(Common::Rect r) {
r.clip(_screen.w, _screen.h);
#ifndef OLDGUI_TRANSPARENCY
_screen.fillRect(r, _bgcolor);
#else
if (_dialog) {
if (!_dialog->screen.pixels) {
_screen.fillRect(r, _bgcolor);
return;
}
const OverlayColor *src = (const OverlayColor*)_dialog->screen.getBasePtr(r.left, r.top);
OverlayColor *dst = (OverlayColor*)_screen.getBasePtr(r.left, r.top);
int h = r.height();
int w = r.width();
while (h--) {
memcpy(dst, src, w*sizeof(OverlayColor));
src += _dialog->screen.w;
dst += _screen.w;
}
} else {
_screen.fillRect(r, _bgcolor);
}
#endif
}
bool ThemeClassic::addDirtyRect(Common::Rect r) {
// TODO: implement proper dirty rect handling
// FIXME: problem with the 'pitch'
r.clip(_screen.w, _screen.h);
r.clip(_drawArea);
_system->copyRectToOverlay((OverlayColor*)_screen.getBasePtr(r.left, r.top), _screen.w, r.left, r.top, r.width(), r.height());
return true;
}
void ThemeClassic::box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB) {
if (y >= 0) {
_screen.hLine(x + 1, y, x + width - 2, colorA);
_screen.hLine(x, y + 1, x + width - 1, colorA);
}
int drawY = y;
if (drawY < 0) {
height += drawY;
drawY = 0;
}
_screen.vLine(x, drawY + 1, drawY + height - 2, colorA);
_screen.vLine(x + 1, drawY, drawY + height - 1, colorA);
if (y + height >= 0) {
_screen.hLine(x + 1, drawY + height - 2, x + width - 1, colorB);
_screen.hLine(x + 1, drawY + height - 1, x + width - 2, colorB);
_screen.vLine(x + width - 1, drawY + 1, drawY + height - 2, colorB);
_screen.vLine(x + width - 2, drawY + 1, drawY + height - 1, colorB);
}
}
void ThemeClassic::box(int x, int y, int w, int h) {
_screen.hLine(x, y, x + w - 1, _color);
_screen.hLine(x, y + h - 1, x +w - 1, _shadowcolor);
_screen.vLine(x, y, y + h - 1, _color);
_screen.vLine(x + w - 1, y, y + h - 1, _shadowcolor);
}
OverlayColor ThemeClassic::getColor(kState state) {
OverlayColor usedColor = _color;
switch (state) {
case kStateEnabled:
usedColor = _textcolor;
break;
case kStateHighlight:
usedColor = _textcolorhi;
break;
default:
break;
}
return usedColor;
}
#ifdef OLDGUI_TRANSPARENCY
void ThemeClassic::blendScreenToDialog() {
Common::Rect rect(0, 0, _screen.w, _screen.h);
if (!rect.isValidRect())
return;
if (_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha)) {
int a, r, g, b;
uint8 aa, ar, ag, ab;
_system->colorToARGB(_bgcolor, aa, ar, ag, ab);
a = aa*3/(3+1);
if (a < 1)
return;
r = ar * a;
g = ag * a;
b = ab * a;
OverlayColor *ptr = (OverlayColor*)_dialog->screen.getBasePtr(rect.left, rect.top);
int h = rect.height();
int w = rect.width();
while (h--) {
for (int i = 0; i < w; i++) {
_system->colorToARGB(ptr[i], aa, ar, ag, ab);
int a2 = aa + a - (a*aa)/255;
ptr[i] = _system->ARGBToColor(a2,
((255-a)*aa*ar/255+r)/a2,
((255-a)*aa*ag/255+g)/a2,
((255-a)*aa*ab/255+b)/a2);
}
ptr += _screen.w;
}
} else {
int r, g, b;
uint8 ar, ag, ab;
_system->colorToRGB(_bgcolor, ar, ag, ab);
r = ar * 3;
g = ag * 3;
b = ab * 3;
OverlayColor *ptr = (OverlayColor*)_dialog->screen.getBasePtr(rect.left, rect.top);
int h = rect.height();
int w = rect.width();
while (h--) {
for (int i = 0; i < w; i++) {
_system->colorToRGB(ptr[i], ar, ag, ab);
ptr[i] = _system->RGBToColor((ar + r) / (3+1),
(ag + g) / (3+1),
(ab + b) / (3+1));
}
ptr += _screen.w;
}
}
}
#endif
} // end of namespace GUI

361
gui/theme.h Normal file
View file

@ -0,0 +1,361 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2006 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Header $
*/
#ifndef GUI_THEME_H
#define GUI_THEME_H
#include "common/stdafx.h"
#include "common/system.h"
#include "common/rect.h"
#include "common/str.h"
#include "common/config-file.h"
#include "graphics/surface.h"
#include "graphics/fontman.h"
namespace GUI {
// Hints to the theme engine that the widget is used in a non-standard way.
enum {
// Indicates that this is the first time the widget is drawn.
THEME_HINT_FIRST_DRAW = 1 << 0,
// Indicates that the widget will be redrawn often, e.g. list widgets.
// It may therefore be a good idea to save the background so that it
// can be redrawn quickly.
THEME_HINT_SAVE_BACKGROUND = 1 << 1
};
class Theme {
public:
Theme() : _drawArea(), _configFile() {}
virtual ~Theme() {}
enum kTextAlign {
kTextAlignLeft,
kTextAlignCenter,
kTextAlignRight
};
enum kWidgetBackground {
kWidgetBackgroundNo,
kWidgetBackgroundPlain,
kWidgetBackgroundBorder,
kWidgetBackgroundBorderSmall
};
enum kState {
kStateDisabled,
kStateEnabled,
kStateHighlight
};
enum kScrollbarState {
kScrollbarStateNo,
kScrollbarStateUp,
kScrollbarStateDown,
kScrollbarStateSlider,
kScrollbarStateSinglePage
};
virtual bool init() = 0;
virtual void deinit() = 0;
virtual void refresh() = 0;
virtual void enable() = 0;
virtual void disable() = 0;
virtual void openDialog() = 0;
virtual void closeDialog() = 0;
virtual void clearAll() = 0;
virtual void drawAll() = 0;
virtual void setDrawArea(const Common::Rect &r) { _drawArea = r; }
// resets the draw area to the screen size
virtual void resetDrawArea() = 0;
virtual const Common::ConfigFile &getConfigFile() { return _configFile; }
virtual const Graphics::Font *getFont() const = 0;
virtual int getFontHeight() const = 0;
virtual int getStringWidth(const Common::String &str) const = 0;
virtual int getCharWidth(byte c) const = 0;
virtual void drawDialogBackground(const Common::Rect &r, kState state = kStateEnabled, bool mainDialog = false) = 0;
virtual void drawText(const Common::Rect &r, const Common::String &str, kState state = kStateEnabled, kTextAlign align = kTextAlignCenter, bool inverted = false, int deltax = 0, bool useEllipsis = true) = 0;
// this should ONLY be used by the debugger until we get a nicer solution
virtual void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state = kStateEnabled) = 0;
virtual void drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background = kWidgetBackgroundPlain, kState state = kStateEnabled) = 0;
virtual void drawButton(const Common::Rect &r, const Common::String &str, kState state = kStateEnabled) = 0;
virtual void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, kState state = kStateEnabled) = 0;
virtual void drawSlider(const Common::Rect &r, int width, kState state = kStateEnabled) = 0;
virtual void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, kState state = kStateEnabled) = 0;
virtual void drawTab(const Common::Rect &r, const Common::String &str, bool active, kState state = kStateEnabled) = 0;
virtual void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, kScrollbarState, kState state = kStateEnabled) = 0;
virtual void drawCaret(const Common::Rect &r, bool erase, kState state = kStateEnabled) = 0;
virtual void drawLineSeparator(const Common::Rect &r, kState state = kStateEnabled) = 0;
Graphics::TextAlignment convertAligment(kTextAlign align) const {
switch (align) {
case kTextAlignLeft:
return Graphics::kTextAlignLeft;
break;
case kTextAlignRight:
return Graphics::kTextAlignRight;
break;
default:
break;
};
return Graphics::kTextAlignCenter;
};
kTextAlign convertAligment(Graphics::TextAlignment align) const {
switch (align) {
case Graphics::kTextAlignLeft:
return kTextAlignLeft;
break;
case Graphics::kTextAlignRight:
return kTextAlignRight;
break;
default:
break;
}
return kTextAlignCenter;
}
protected:
Common::Rect _drawArea;
Common::ConfigFile _configFile;
};
#define OLDGUI_TRANSPARENCY
class ThemeClassic : public Theme {
public:
ThemeClassic(OSystem *system);
virtual ~ThemeClassic();
bool init();
void deinit();
void refresh();
void enable();
void disable();
void openDialog();
void closeDialog();
void clearAll();
void drawAll();
void resetDrawArea();
const Graphics::Font *getFont() const { return _font; }
int getFontHeight() const { if (_initOk) return _font->getFontHeight(); return 0; }
int getStringWidth(const Common::String &str) const { if (_initOk) return _font->getStringWidth(str); return 0; }
int getCharWidth(byte c) const { if (_initOk) return _font->getCharWidth(c); return 0; }
void drawDialogBackground(const Common::Rect &r, kState state, bool mainDialog);
void drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis);
void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state);
void drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background, kState state);
void drawButton(const Common::Rect &r, const Common::String &str, kState state);
void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, kState state);
void drawSlider(const Common::Rect &r, int width, kState state);
void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, kState state);
void drawTab(const Common::Rect &r, const Common::String &str, bool active, kState state);
void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, kScrollbarState, kState state);
void drawCaret(const Common::Rect &r, bool erase, kState state);
void drawLineSeparator(const Common::Rect &r, kState state);
private:
void restoreBackground(Common::Rect r);
bool addDirtyRect(Common::Rect r);
void box(int x, int y, int width, int height, OverlayColor colorA, OverlayColor colorB);
void box(int x, int y, int width, int height);
OverlayColor getColor(kState state);
OSystem *_system;
Graphics::Surface _screen;
#ifdef OLDGUI_TRANSPARENCY
struct DialogState {
Graphics::Surface screen;
} *_dialog;
void blendScreenToDialog();
#endif
bool _initOk;
const Graphics::Font *_font;
OverlayColor _color, _shadowcolor;
OverlayColor _bgcolor;
OverlayColor _textcolor;
OverlayColor _textcolorhi;
};
class ThemeNew : public Theme {
public:
ThemeNew(OSystem *system, Common::String stylefile);
virtual ~ThemeNew();
bool init();
void deinit();
void refresh();
void enable();
void disable();
void openDialog();
void closeDialog();
void clearAll();
void drawAll();
void resetDrawArea();
const Graphics::Font *getFont() const { return _font; }
int getFontHeight() const { if (_font) return _font->getFontHeight(); return 0; }
int getStringWidth(const Common::String &str) const { if (_font) return _font->getStringWidth(str); return 0; }
int getCharWidth(byte c) const { if (_font) return _font->getCharWidth(c); return 0; }
void drawDialogBackground(const Common::Rect &r, kState state, bool mainDialog);
void drawText(const Common::Rect &r, const Common::String &str, kState state, kTextAlign align, bool inverted, int deltax, bool useEllipsis);
void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, kState state);
void drawWidgetBackground(const Common::Rect &r, uint16 hints, kWidgetBackground background, kState state);
void drawButton(const Common::Rect &r, const Common::String &str, kState state);
void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, kState state);
void drawSlider(const Common::Rect &r, int width, kState state);
void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, kState state);
void drawTab(const Common::Rect &r, const Common::String &str, bool active, kState state);
void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, kScrollbarState, kState state);
void drawCaret(const Common::Rect &r, bool erase, kState state);
void drawLineSeparator(const Common::Rect &r, kState state);
private:
bool addDirtyRect(Common::Rect r, bool backup = false);
void colorFade(const Common::Rect &r, OverlayColor start, OverlayColor end);
void drawRect(const Common::Rect &r, const Graphics::Surface *corner,
const Graphics::Surface *top, const Graphics::Surface *left, const Graphics::Surface *fill, int alpha);
void drawRectMasked(const Common::Rect &r, const Graphics::Surface *corner, const Graphics::Surface *top,
const Graphics::Surface *left, const Graphics::Surface *fill, int alpha,
OverlayColor start, OverlayColor end, uint factor = 1);
void drawSurface(const Common::Rect &r, const Graphics::Surface *surf, bool upDown, bool leftRight, int alpha);
void drawSurfaceMasked(const Common::Rect &r, const Graphics::Surface *surf, bool upDown, bool leftRight, int alpha,
OverlayColor start, OverlayColor end, uint factor = 1);
OSystem *_system;
Graphics::Surface _screen;
bool _initOk;
bool _forceRedraw;
void restoreBackground(Common::Rect r);
OverlayColor getColor(kState state);
struct DialogState {
Graphics::Surface screen;
} *_dialog;
const Graphics::Font *_font;
enum kImageHandles {
kDialogBkgdCorner = 0,
kDialogBkgdTop = 1,
kDialogBkgdLeft = 2,
kDialogBkgd = 3,
kWidgetBkgdCorner = 4,
kWidgetBkgdTop = 5,
kWidgetBkgdLeft = 6,
kWidgetBkgd = 7,
kCheckboxEmpty = 8,
kCheckboxChecked = 9,
kWidgetArrow = 10,
kImageHandlesMax
};
const Common::String *_imageHandles;
const Graphics::Surface **_images;
enum kColorHandles {
kMainDialogStart = 0,
kMainDialogEnd = 1,
kDialogStart = 2,
kDialogEnd = 3,
kColorStateDisabled = 4,
kColorStateHighlight = 5,
kColorStateEnabled = 6,
kColorTransparency = 7,
kTextInvertedBackground = 8,
kTextInvertedColor = 9,
kWidgetBackgroundStart = 10,
kWidgetBackgroundEnd = 11,
kWidgetBackgroundSmallStart = 12,
kWidgetBackgroundSmallEnd = 13,
kButtonBackgroundStart = 14,
kButtonBackgroundEnd = 15,
kButtonTextEnabled = 16,
kButtonTextDisabled = 17,
kButtonTextHighlight = 18,
kSliderBackgroundStart = 19,
kSliderBackgroundEnd = 20,
kSliderStart = 21,
kSliderEnd = 22,
kTabBackgroundStart = 23,
kTabBackgroundEnd = 24,
kScrollbarBackgroundStart = 25,
kScrollbarBackgroundEnd = 26,
kScrollbarButtonStart = 27,
kScrollbarButtonEnd = 28,
kScrollbarSliderStart = 29,
kScrollbarSliderEnd = 30,
kCaretColor = 31,
kColorHandlesMax
};
OverlayColor _colors[kColorHandlesMax];
};
} // end of namespace GUI
#endif // GUI_THEME_H

Binary file not shown.

View file

@ -29,7 +29,7 @@ namespace GUI {
Widget::Widget(GuiObject *boss, int x, int y, int w, int h) Widget::Widget(GuiObject *boss, int x, int y, int w, int h)
: GuiObject(x, y, w, h), _type(0), _boss(boss), : 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 // Insert into the widget list of the boss
_next = _boss->_firstWidget; _next = _boss->_firstWidget;
_boss->_firstWidget = this; _boss->_firstWidget = this;
@ -52,16 +52,12 @@ void Widget::draw() {
_y = getAbsY(); _y = getAbsY();
// Clear background (unless alpha blending is enabled) // Clear background (unless alpha blending is enabled)
if (_flags & WIDGET_CLEARBG) //if (_flags & WIDGET_CLEARBG)
gui->fillRect(_x, _y, _w, _h, gui->_bgcolor); // gui->fillRect(_x, _y, _w, _h, gui->_bgcolor);
// Draw border // Draw border
if (_flags & WIDGET_BORDER) { if (_flags & WIDGET_BORDER) {
OverlayColor colorA = gui->_color; gui->theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), _hints, Theme::kWidgetBackgroundBorder);
OverlayColor colorB = gui->_shadowcolor;
if ((_flags & WIDGET_INV_BORDER) == WIDGET_INV_BORDER)
SWAP(colorA, colorB);
gui->box(_x, _y, _w, _h, colorA, colorB);
_x += 4; _x += 4;
_y += 4; _y += 4;
_w -= 8; _w -= 8;
@ -79,9 +75,6 @@ void Widget::draw() {
_h += 8; _h += 8;
} }
// Flag the draw area as dirty
gui->addDirtyRect(_x, _y, _w, _h);
_x = oldX; _x = oldX;
_y = oldY; _y = oldY;
@ -91,6 +84,8 @@ void Widget::draw() {
w->draw(); w->draw();
w = w->_next; w = w->_next;
} }
clearHints(THEME_HINT_FIRST_DRAW);
} }
Widget *Widget::findWidgetInChain(Widget *w, int x, int y) { Widget *Widget::findWidgetInChain(Widget *w, int x, int y) {
@ -137,8 +132,9 @@ void StaticTextWidget::setAlign(TextAlignment align) {
void StaticTextWidget::drawWidget(bool hilite) { void StaticTextWidget::drawWidget(bool hilite) {
NewGui *gui = &g_gui; g_gui.theme()->drawText(Common::Rect(_x, _y, _x+_w, _y+_h), _label,
gui->drawString(_label, _x, _y, _w, isEnabled() ? gui->_textcolor : gui->_color, _align); isEnabled() ? Theme::kStateEnabled : Theme::kStateDisabled,
g_gui.theme()->convertAligment(_align));
} }
#pragma mark - #pragma mark -
@ -146,7 +142,7 @@ void StaticTextWidget::drawWidget(bool hilite) {
ButtonWidget::ButtonWidget(GuiObject *boss, int x, int y, int w, int h, const String &label, uint32 cmd, uint8 hotkey, WidgetSize ws) 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), : StaticTextWidget(boss, x, y, w, h, label, kTextAlignCenter, ws), CommandSender(boss),
_cmd(cmd), _hotkey(hotkey) { _cmd(cmd), _hotkey(hotkey) {
_flags = WIDGET_ENABLED | WIDGET_BORDER | WIDGET_CLEARBG; _flags = WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG;
_type = kButtonWidget; _type = kButtonWidget;
} }
@ -156,11 +152,7 @@ void ButtonWidget::handleMouseUp(int x, int y, int button, int clickCount) {
} }
void ButtonWidget::drawWidget(bool hilite) { void ButtonWidget::drawWidget(bool hilite) {
NewGui *gui = &g_gui; g_gui.theme()->drawButton(Common::Rect(_x, _y, _x+_w, _y+_h), _label, isEnabled() ? (hilite ? Theme::kStateHighlight : Theme::kStateEnabled) : Theme::kStateDisabled);
const int off = (_h - g_gui.getFontHeight()) / 2;
gui->drawString(_label, _x, _y + off, _w,
!isEnabled() ? gui->_color :
hilite ? gui->_textcolorhi : gui->_textcolor, _align);
} }
#pragma mark - #pragma mark -
@ -187,39 +179,8 @@ void CheckboxWidget::setState(bool state) {
} }
void CheckboxWidget::drawWidget(bool hilite) { void CheckboxWidget::drawWidget(bool hilite) {
NewGui *gui = &g_gui; g_gui.theme()->drawCheckbox(Common::Rect(_x, _y, _x+_w, _y+_h), _label, _state,
int fontHeight = gui->getFontHeight(); isEnabled() ? Theme::kStateEnabled : Theme::kStateDisabled);
// 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);
} }
#pragma mark - #pragma mark -
@ -262,15 +223,8 @@ void SliderWidget::handleMouseUp(int x, int y, int button, int clickCount) {
} }
void SliderWidget::drawWidget(bool hilite) { void SliderWidget::drawWidget(bool hilite) {
NewGui *gui = &g_gui; g_gui.theme()->drawSlider(Common::Rect(_x, _y, _x+_w, _y+_h), valueToPos(_value),
isEnabled() ? (hilite ? Theme::kStateHighlight : Theme::kStateEnabled) : Theme::kStateDisabled);
// 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);
} }
int SliderWidget::valueToPos(int value) { int SliderWidget::valueToPos(int value) {
@ -305,13 +259,9 @@ void GraphicsWidget::setGfx(const Graphics::Surface *gfx) {
} }
void GraphicsWidget::drawWidget(bool hilite) { void GraphicsWidget::drawWidget(bool hilite) {
if (sizeof(OverlayColor) != _gfx.bytesPerPixel || !_gfx.pixels) { if (sizeof(OverlayColor) == _gfx.bytesPerPixel && _gfx.pixels) {
// FIXME: It doesn't really make sense to render this text here, since g_gui.theme()->drawSurface(Common::Rect(_x, _y, _x+_w, _y+_h), _gfx);
// 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);
} }
} // End of namespace GUI } // End of namespace GUI

View file

@ -45,7 +45,6 @@ enum {
WIDGET_WANT_TICKLE = 1 << 7, WIDGET_WANT_TICKLE = 1 << 7,
WIDGET_TRACK_MOUSE = 1 << 8, 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 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 { enum {
@ -93,6 +92,7 @@ protected:
Widget *_next; Widget *_next;
uint16 _id; uint16 _id;
uint16 _flags; uint16 _flags;
uint16 _hints;
bool _hasFocus; bool _hasFocus;
public: public:
@ -127,6 +127,10 @@ public:
void clearFlags(int flags) { _flags &= ~flags; } void clearFlags(int flags) { _flags &= ~flags; }
int getFlags() const { return _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); } void setEnabled(bool e) { if (e) setFlags(WIDGET_ENABLED); else clearFlags(WIDGET_ENABLED); }
bool isEnabled() const { return _flags & WIDGET_ENABLED; } bool isEnabled() const { return _flags & WIDGET_ENABLED; }
bool isVisible() const { return !(_flags & WIDGET_INVISIBLE); } bool isVisible() const { return !(_flags & WIDGET_INVISIBLE); }

View file

@ -925,20 +925,10 @@ ValueDisplayDialog::ValueDisplayDialog(const Common::String& label, int minVal,
} }
void ValueDisplayDialog::drawDialog() { void ValueDisplayDialog::drawDialog() {
g_gui.blendRect(_x, _y, _w, _h, g_gui._bgcolor);
g_gui.box(_x, _y, _w, _h, g_gui._color, g_gui._shadowcolor);
const int labelWidth = _w - 8 - _percentBarWidth; const int labelWidth = _w - 8 - _percentBarWidth;
g_gui.theme()->drawDialogBackground(Common::Rect(_x, _y, _x+_w, _y+_h));
// Draw the label g_gui.theme()->drawText(Common::Rect(_x+4, _y+4, _x+labelWidth+4, _y+g_gui.theme()->getFontHeight()+4), _label);
g_gui.drawString(_label, _x + 4, _y + 4, labelWidth, g_gui._textcolor); g_gui.theme()->drawSlider(Common::Rect(_x+4+labelWidth, _y+4, _x+_w-4, _y+_h-4), _percentBarWidth * (_value - _min) / (_max - _min));
// Draw the percentage bar
g_gui.fillRect(_x + 4 + labelWidth, _y + 4, _percentBarWidth * (_value - _min) / (_max - _min), _h - 8, g_gui._textcolorhi);
g_gui.frameRect(_x + 4 + labelWidth, _y + 4, _percentBarWidth, _h - 8, g_gui._textcolor);
// Flag the draw area as dirty
g_gui.addDirtyRect(_x, _y, _w, _h);
} }
void ValueDisplayDialog::handleTickle() { void ValueDisplayDialog::handleTickle() {

View file

@ -21,6 +21,8 @@
#include "common/stdafx.h" #include "common/stdafx.h"
#include "common/util.h" #include "common/util.h"
#include "common/debugger.cpp"
#include "sky/debug.h" #include "sky/debug.h"
#include "sky/grid.h" #include "sky/grid.h"
#include "sky/logic.h" #include "sky/logic.h"
@ -30,8 +32,6 @@
#include "sky/struc.h" #include "sky/struc.h"
#include "sky/compact.h" #include "sky/compact.h"
#include "common/debugger.cpp"
namespace Sky { namespace Sky {
static const char *section_0_compacts[] = { static const char *section_0_compacts[] = {
@ -1278,7 +1278,7 @@ void Debug::mcode(uint32 mcode, uint32 a, uint32 b, uint32 c) {
Debugger::Debugger(Logic *logic, Mouse *mouse, Screen *screen, SkyCompact *skyCompact) Debugger::Debugger(Logic *logic, Mouse *mouse, Screen *screen, SkyCompact *skyCompact)
: _logic(logic), _mouse(mouse), _screen(screen), _skyCompact(skyCompact), _showGrid(false) { : Common::Debugger<Debugger>(), _logic(logic), _mouse(mouse), _screen(screen), _skyCompact(skyCompact), _showGrid(false) {
DCmd_Register("exit", &Debugger::Cmd_Exit); DCmd_Register("exit", &Debugger::Cmd_Exit);
DCmd_Register("help", &Debugger::Cmd_Help); DCmd_Register("help", &Debugger::Cmd_Help);
DCmd_Register("info", &Debugger::Cmd_Info); DCmd_Register("info", &Debugger::Cmd_Info);