2008-05-25 11:20:28 +00:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
*
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "common/system.h"
|
2008-06-25 22:30:28 +00:00
|
|
|
#include "common/config-manager.h"
|
2008-11-10 12:45:09 +00:00
|
|
|
#include "common/file.h"
|
2008-08-15 19:10:37 +00:00
|
|
|
#include "common/fs.h"
|
- Merged 75 revisions from trunk.
- Fixed new conflicts.
- Changed Theme loading to use the new ZipArchive class.
- Implemented ZipArchive::getAllNames()
Original log message from SVNMerge.py
================================
Merged revisions 34605,34613-34615,34617,34619-34624,34627-34628,34630-34639,34642-34649,34656-34661,34663-34664,34671-34672,34674-34676,34678-34685 via svnmerge from
https://tanoku@scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk
........
r34605 | Tanoku | 2008-09-20 12:32:59 +0200 (Sat, 20 Sep 2008) | 1 line
Fixed "empty control statement" warning in FSDirectory::matchPattern().
........
r34613 | lordhoto | 2008-09-20 16:53:31 +0200 (Sat, 20 Sep 2008) | 2 lines
Updated theme file version, to reflect latest addition of new required entries/files.
........
r34614 | wjpalenstijn | 2008-09-20 17:03:37 +0200 (Sat, 20 Sep 2008) | 1 line
fix drawing order in saveload choosers (draw container before contents)
........
r34615 | fingolfin | 2008-09-20 17:53:17 +0200 (Sat, 20 Sep 2008) | 1 line
Little readability tweak
........
r34617 | fingolfin | 2008-09-20 18:10:29 +0200 (Sat, 20 Sep 2008) | 1 line
Fix for bug #2120602: 5ALL: Starting the launcher with -f triggers assertion
........
r34619 | eriktorbjorn | 2008-09-20 18:21:27 +0200 (Sat, 20 Sep 2008) | 4 lines
I think this is the correct fix for bug #2081347 ("MM: Charset out of
bounds!"). If I understand correctly, version <= 2 games only have one (hard-
coded) font, so when that's initialised we can set _curId to 0.
........
r34620 | marcus_c | 2008-09-20 18:38:50 +0200 (Sat, 20 Sep 2008) | 1 line
game.h is now in engines, not base.
........
r34621 | marcus_c | 2008-09-20 18:47:31 +0200 (Sat, 20 Sep 2008) | 5 lines
In the CD filesystem, nothing can be opened for writing, so just
short-circuit any call to openForWriting(). Also, directories and
non-existing files can't be opened for reading either, so just
return 0 for those.
........
r34622 | sev | 2008-09-21 12:23:22 +0200 (Sun, 21 Sep 2008) | 2 lines
Patch #2054467: CRUISE: 64bits fixes
........
r34623 | sev | 2008-09-21 13:17:22 +0200 (Sun, 21 Sep 2008) | 2 lines
Add recent patch contributors. Reflect current ScummVM team in the credits
........
r34624 | sev | 2008-09-21 13:18:16 +0200 (Sun, 21 Sep 2008) | 2 lines
Reflect current team
........
r34627 | lordhoto | 2008-09-22 19:33:30 +0200 (Mon, 22 Sep 2008) | 1 line
Fixed full screen toggling via alt+enter.
........
r34628 | fingolfin | 2008-09-22 22:55:27 +0200 (Mon, 22 Sep 2008) | 1 line
Fix comments for random() funcs (thanks to salty-horse for pointing this out)
........
r34630 | fingolfin | 2008-09-23 11:39:37 +0200 (Tue, 23 Sep 2008) | 1 line
Moved ZipArchive implementation into unzip.cpp, added new ZipArchive::isOpen method
........
r34631 | fingolfin | 2008-09-23 11:42:38 +0200 (Tue, 23 Sep 2008) | 1 line
ImageManager: renamed remArchive() to removeArchive(); switched to using a SearchSet + ZipArchive to access ZIP files (code is much simpler now yet more flexible, yay)
........
r34632 | fingolfin | 2008-09-23 11:50:03 +0200 (Tue, 23 Sep 2008) | 1 line
Moved ZipArchive to namespace Common; moved unzip internals from unzip.h to unzip.cpp (to be cleaned up)
........
r34633 | fingolfin | 2008-09-23 12:08:45 +0200 (Tue, 23 Sep 2008) | 1 line
cleanup
........
r34634 | fingolfin | 2008-09-23 12:10:29 +0200 (Tue, 23 Sep 2008) | 1 line
Perform error checking when reading from a ZIP file
........
r34635 | fingolfin | 2008-09-23 13:43:57 +0200 (Tue, 23 Sep 2008) | 1 line
Fix for bug #1917981: Game crash when finishing Indy3 demo. At the same time, added a new paranoia check
........
r34636 | Kirben | 2008-09-23 14:34:02 +0200 (Tue, 23 Sep 2008) | 1 line
Add another French Windows version of Putt-Putt Enters the Race.
........
r34637 | lordhoto | 2008-09-23 18:40:41 +0200 (Tue, 23 Sep 2008) | 2 lines
Fix for bug #2120780 "GUI: gui-theme command-line option ignored", '-f' and '-g' command line switch behavior.
........
r34638 | john_doe | 2008-09-24 01:16:47 +0200 (Wed, 24 Sep 2008) | 1 line
Improved updateScreenAndWait; the mouse cursor is less jerky now in some scenes in Manhole:N&E
........
r34639 | thebluegr | 2008-09-24 09:26:45 +0200 (Wed, 24 Sep 2008) | 1 line
Readded missing special case for the storm animation in ITE. Fixes bug #2125675 - "ITE: Game locks up in storm clouds scene"
........
r34642 | fingolfin | 2008-09-24 22:29:29 +0200 (Wed, 24 Sep 2008) | 1 line
Changed Common::String to use a MemoryPool for its refcounts
........
r34643 | fingolfin | 2008-09-24 22:31:14 +0200 (Wed, 24 Sep 2008) | 1 line
cleanup
........
r34644 | fingolfin | 2008-09-24 22:35:31 +0200 (Wed, 24 Sep 2008) | 1 line
Changed builtin Common::String capacity to 24 (on 32 bit systems), to make sizeof(String) 32; reduces overall memory req by 200k on my system; overall # of mallocs after this + the refcount memory pool change is almost unchanged
........
r34645 | sev | 2008-09-25 00:44:01 +0200 (Thu, 25 Sep 2008) | 2 lines
Fix bugs #1981081: "ITE: No blinking disk icon" and #1971729: "IHNM: No Animation of Disk Icon"
........
r34646 | fingolfin | 2008-09-25 10:06:18 +0200 (Thu, 25 Sep 2008) | 1 line
SCUMM: Added a new ActorHE class, as well as a virtual Actor::prepareDrawActorCostume() method
........
r34647 | fingolfin | 2008-09-25 10:19:51 +0200 (Thu, 25 Sep 2008) | 1 line
SCUMM: Moved Actor::drawActorToBackBuf to class ActorHE
........
r34648 | fingolfin | 2008-09-25 12:11:06 +0200 (Thu, 25 Sep 2008) | 1 line
SCUMM: Moved more stuf from class Actor to ActorHE
........
r34649 | fingolfin | 2008-09-25 12:14:50 +0200 (Thu, 25 Sep 2008) | 1 line
cleanup
........
r34656 | eriktorbjorn | 2008-09-27 19:25:40 +0200 (Sat, 27 Sep 2008) | 2 lines
Fixed typos.
........
r34657 | eriktorbjorn | 2008-09-27 19:47:22 +0200 (Sat, 27 Sep 2008) | 2 lines
Allow quitting or returning to the launcher while cutscenes are playing.
........
r34658 | eriktorbjorn | 2008-09-27 19:51:22 +0200 (Sat, 27 Sep 2008) | 2 lines
Slight simplification of last commit.
........
r34659 | fingolfin | 2008-09-27 20:32:01 +0200 (Sat, 27 Sep 2008) | 1 line
Modified Common::SearchSet to take signed integer priorities, for convenience (so that one can add archives with less-than-default priority)
........
r34660 | fingolfin | 2008-09-27 20:34:24 +0200 (Sat, 27 Sep 2008) | 1 line
Fixed a nasty bug in SearchManager::addDirectory; made the 'char' constructor of Common::String explicit, to avoid such bugs in the future
........
r34661 | drmccoy | 2008-09-27 22:04:04 +0200 (Sat, 27 Sep 2008) | 2 lines
Added a spanish floppy version of Lost in Time, as supplied by goodoldgeorg in bug report #2105220
........
r34663 | fingolfin | 2008-09-28 01:00:46 +0200 (Sun, 28 Sep 2008) | 1 line
Changed Common::File to use SearchMan
........
r34664 | fingolfin | 2008-09-28 01:27:01 +0200 (Sun, 28 Sep 2008) | 1 line
SCUMM: Use FilesystemNode::openForReading instead of Common::File::open(FilesystemNode) in the detector
........
r34671 | john_doe | 2008-09-28 22:02:01 +0200 (Sun, 28 Sep 2008) | 1 line
Return 32000 in sfGetCdTime instead of 0; this fixes the Manhole intro/credits (until the function is actually implemented)
........
r34672 | sev | 2008-09-28 23:07:41 +0200 (Sun, 28 Sep 2008) | 2 lines
Add Italian C64 Zak
........
r34674 | sev | 2008-09-28 23:53:14 +0200 (Sun, 28 Sep 2008) | 2 lines
Fix bug #2043489: DRASCULA: Cannot disable speech
........
r34675 | sev | 2008-09-29 00:07:16 +0200 (Mon, 29 Sep 2008) | 3 lines
- Renamed withVoices to _subtitlesDisabled as it reflect the true meaning.
- Allowed to disable subtitles from options dialogs including RTL.
........
r34676 | sev | 2008-09-29 00:19:11 +0200 (Mon, 29 Sep 2008) | 2 lines
Use better "silence" without clicks when speech is disabled.
........
r34678 | fingolfin | 2008-09-29 12:29:01 +0200 (Mon, 29 Sep 2008) | 1 line
Added FIXME to GP2x port
........
r34679 | fingolfin | 2008-09-29 12:30:31 +0200 (Mon, 29 Sep 2008) | 1 line
Add priority parameter to the SearchMan API
........
r34680 | fingolfin | 2008-09-29 12:32:06 +0200 (Mon, 29 Sep 2008) | 1 line
File::open no longer falls back to searching the current dir (if this causes any regressions, please report them; don't work around them, don't revert this change, without discussing it first)
........
r34681 | fingolfin | 2008-09-29 12:49:36 +0200 (Mon, 29 Sep 2008) | 1 line
Don't subclass ArjFile from Common::File (there seems to be no good reason for it). BTW, this code is an abomination and should be replaced by an Archive/SearchSet approach
........
r34682 | fingolfin | 2008-09-29 13:01:25 +0200 (Mon, 29 Sep 2008) | 1 line
Added const qualifiers
........
r34683 | fingolfin | 2008-09-29 13:02:11 +0200 (Mon, 29 Sep 2008) | 1 line
SCUMM HE: Fixed leak in Win32ResExtractor::extractResource_, use _filename instead of File::name
........
r34684 | fingolfin | 2008-09-29 13:03:10 +0200 (Mon, 29 Sep 2008) | 1 line
Added const qualifiers
........
r34685 | fingolfin | 2008-09-29 13:07:39 +0200 (Mon, 29 Sep 2008) | 1 line
Don't use File::name() needlessly (i.e. if you still know which file you just opened :)
........
svn-id: r34687
2008-09-29 19:23:36 +00:00
|
|
|
#include "common/unzip.h"
|
2010-03-20 12:56:56 +00:00
|
|
|
#include "common/tokenizer.h"
|
2010-06-15 10:44:51 +00:00
|
|
|
#include "common/translation.h"
|
2008-11-09 15:14:01 +00:00
|
|
|
|
2008-08-10 11:09:28 +00:00
|
|
|
#include "graphics/cursorman.h"
|
2009-12-09 16:46:14 +00:00
|
|
|
#include "graphics/fontman.h"
|
|
|
|
#include "graphics/surface.h"
|
2008-11-09 15:14:01 +00:00
|
|
|
#include "graphics/VectorRenderer.h"
|
2011-07-01 19:10:25 +00:00
|
|
|
#include "graphics/fonts/bdf.h"
|
2012-01-07 01:51:50 +00:00
|
|
|
#include "graphics/fonts/ttf.h"
|
2014-02-28 02:27:23 +00:00
|
|
|
|
|
|
|
#include "image/bmp.h"
|
2008-07-01 15:57:30 +00:00
|
|
|
|
2011-04-24 08:34:27 +00:00
|
|
|
#include "gui/widget.h"
|
2008-09-02 17:51:08 +00:00
|
|
|
#include "gui/ThemeEngine.h"
|
2008-07-31 17:23:38 +00:00
|
|
|
#include "gui/ThemeEval.h"
|
2008-11-09 15:14:01 +00:00
|
|
|
#include "gui/ThemeParser.h"
|
2008-05-25 11:20:28 +00:00
|
|
|
|
|
|
|
namespace GUI {
|
|
|
|
|
2009-06-06 23:22:22 +00:00
|
|
|
const char * const ThemeEngine::kImageLogo = "logo.bmp";
|
|
|
|
const char * const ThemeEngine::kImageLogoSmall = "logo_small.bmp";
|
2011-10-24 04:17:54 +00:00
|
|
|
const char * const ThemeEngine::kImageSearch = "search.bmp";
|
|
|
|
const char * const ThemeEngine::kImageEraser = "eraser.bmp";
|
2012-02-22 15:15:02 +00:00
|
|
|
const char * const ThemeEngine::kImageDelbtn = "delbtn.bmp";
|
2012-06-29 13:52:56 +00:00
|
|
|
const char * const ThemeEngine::kImageList = "list.bmp";
|
|
|
|
const char * const ThemeEngine::kImageGrid = "grid.bmp";
|
2013-05-16 21:18:09 +00:00
|
|
|
const char * const ThemeEngine::kImageStopbtn = "stopbtn.bmp";
|
|
|
|
const char * const ThemeEngine::kImageEditbtn = "editbtn.bmp";
|
|
|
|
const char * const ThemeEngine::kImageSwitchModebtn = "switchbtn.bmp";
|
|
|
|
const char * const ThemeEngine::kImageFastReplaybtn = "fastreplay.bmp";
|
|
|
|
const char * const ThemeEngine::kImageStopSmallbtn = "stopbtn_small.bmp";
|
|
|
|
const char * const ThemeEngine::kImageEditSmallbtn = "editbtn_small.bmp";
|
|
|
|
const char * const ThemeEngine::kImageSwitchModeSmallbtn = "switchbtn_small.bmp";
|
|
|
|
const char * const ThemeEngine::kImageFastReplaySmallbtn = "fastreplay_small.bmp";
|
2009-06-06 23:22:22 +00:00
|
|
|
|
2009-01-17 17:13:04 +00:00
|
|
|
struct TextDrawData {
|
|
|
|
const Graphics::Font *_fontPtr;
|
2009-08-10 13:46:17 +00:00
|
|
|
};
|
2009-01-17 17:13:04 +00:00
|
|
|
|
2009-08-10 13:46:17 +00:00
|
|
|
struct TextColorData {
|
|
|
|
int r, g, b;
|
2009-01-17 17:13:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct WidgetDrawData {
|
|
|
|
/** List of all the steps needed to draw this widget */
|
|
|
|
Common::List<Graphics::DrawStep> _steps;
|
|
|
|
|
2009-01-18 14:48:00 +00:00
|
|
|
TextData _textDataId;
|
2009-08-10 13:46:17 +00:00
|
|
|
TextColor _textColorId;
|
2009-01-17 17:13:04 +00:00
|
|
|
Graphics::TextAlign _textAlignH;
|
|
|
|
GUI::ThemeEngine::TextAlignVertical _textAlignV;
|
|
|
|
|
|
|
|
/** Extra space that the widget occupies when it's drawn.
|
|
|
|
E.g. when taking into account rounded corners, drop shadows, etc
|
2011-04-03 13:04:20 +00:00
|
|
|
Used when restoring the widget background */
|
2009-01-17 17:13:04 +00:00
|
|
|
uint16 _backgroundOffset;
|
|
|
|
|
|
|
|
bool _buffer;
|
2009-01-18 14:48:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2011-04-03 13:04:20 +00:00
|
|
|
* Calculates the background threshold offset of a given DrawData item.
|
|
|
|
* After fully loading all DrawSteps of a DrawData item, this function must be
|
|
|
|
* called in order to calculate if such draw steps would be drawn outside of
|
|
|
|
* the actual widget drawing zone (e.g. shadows). If this is the case, a constant
|
|
|
|
* value will be added when restoring the background of the widget.
|
2009-01-18 14:48:00 +00:00
|
|
|
*/
|
|
|
|
void calcBackgroundOffset();
|
2009-01-17 17:13:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class ThemeItem {
|
|
|
|
|
|
|
|
public:
|
|
|
|
ThemeItem(ThemeEngine *engine, const Common::Rect &area) :
|
|
|
|
_engine(engine), _area(area) {}
|
|
|
|
virtual ~ThemeItem() {}
|
|
|
|
|
|
|
|
virtual void drawSelf(bool doDraw, bool doRestore) = 0;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
ThemeEngine *_engine;
|
|
|
|
Common::Rect _area;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ThemeItemDrawData : public ThemeItem {
|
|
|
|
public:
|
|
|
|
ThemeItemDrawData(ThemeEngine *engine, const WidgetDrawData *data, const Common::Rect &area, uint32 dynData) :
|
|
|
|
ThemeItem(engine, area), _dynamicData(dynData), _data(data) {}
|
|
|
|
|
|
|
|
void drawSelf(bool draw, bool restore);
|
|
|
|
|
|
|
|
protected:
|
|
|
|
uint32 _dynamicData;
|
|
|
|
const WidgetDrawData *_data;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ThemeItemTextData : public ThemeItem {
|
|
|
|
public:
|
2013-06-13 12:32:36 +00:00
|
|
|
ThemeItemTextData(ThemeEngine *engine, const TextDrawData *data, const TextColorData *color, const Common::Rect &area, const Common::Rect &textDrawableArea,
|
|
|
|
const Common::String &text, Graphics::TextAlign alignH, GUI::ThemeEngine::TextAlignVertical alignV,
|
2011-04-03 13:04:20 +00:00
|
|
|
bool ellipsis, bool restoreBg, int deltaX) :
|
2009-08-10 13:46:17 +00:00
|
|
|
ThemeItem(engine, area), _data(data), _color(color), _text(text), _alignH(alignH), _alignV(alignV),
|
2013-06-13 12:32:36 +00:00
|
|
|
_ellipsis(ellipsis), _restoreBg(restoreBg), _deltax(deltaX), _textDrawableArea(textDrawableArea) {}
|
2009-01-17 17:13:04 +00:00
|
|
|
|
|
|
|
void drawSelf(bool draw, bool restore);
|
|
|
|
|
|
|
|
protected:
|
2013-06-13 12:32:36 +00:00
|
|
|
Common::Rect _textDrawableArea;
|
2009-01-17 17:13:04 +00:00
|
|
|
const TextDrawData *_data;
|
2009-08-10 13:46:17 +00:00
|
|
|
const TextColorData *_color;
|
2009-01-17 17:13:04 +00:00
|
|
|
Common::String _text;
|
|
|
|
Graphics::TextAlign _alignH;
|
|
|
|
GUI::ThemeEngine::TextAlignVertical _alignV;
|
|
|
|
bool _ellipsis;
|
|
|
|
bool _restoreBg;
|
|
|
|
int _deltax;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ThemeItemBitmap : public ThemeItem {
|
|
|
|
public:
|
|
|
|
ThemeItemBitmap(ThemeEngine *engine, const Common::Rect &area, const Graphics::Surface *bitmap, bool alpha) :
|
|
|
|
ThemeItem(engine, area), _bitmap(bitmap), _alpha(alpha) {}
|
|
|
|
|
|
|
|
void drawSelf(bool draw, bool restore);
|
|
|
|
|
|
|
|
protected:
|
|
|
|
const Graphics::Surface *_bitmap;
|
|
|
|
bool _alpha;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************
|
2011-04-03 13:04:20 +00:00
|
|
|
* Data definitions for theme engine elements
|
2009-01-17 17:13:04 +00:00
|
|
|
*********************************************************/
|
|
|
|
struct DrawDataInfo {
|
2011-04-03 13:04:20 +00:00
|
|
|
DrawData id; ///< The actual ID of the DrawData item.
|
|
|
|
const char *name; ///< The name of the DrawData item as it appears in the Theme Description files
|
|
|
|
bool buffer; ///< Sets whether this item is buffered on the backbuffer or drawn directly to the screen.
|
|
|
|
DrawData parent; ///< Parent DrawData item, for items that overlay. E.g. kButtonIdle -> kButtonHover
|
2009-01-17 17:13:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Default values for each DrawData item.
|
|
|
|
*/
|
|
|
|
static const DrawDataInfo kDrawDataDefaults[] = {
|
2011-04-03 13:04:20 +00:00
|
|
|
{kDDMainDialogBackground, "mainmenu_bg", true, kDDNone},
|
|
|
|
{kDDSpecialColorBackground, "special_bg", true, kDDNone},
|
|
|
|
{kDDPlainColorBackground, "plain_bg", true, kDDNone},
|
|
|
|
{kDDTooltipBackground, "tooltip_bg", true, kDDNone},
|
|
|
|
{kDDDefaultBackground, "default_bg", true, kDDNone},
|
|
|
|
{kDDTextSelectionBackground, "text_selection", false, kDDNone},
|
|
|
|
{kDDTextSelectionFocusBackground, "text_selection_focus", false, kDDNone},
|
2009-01-17 17:13:04 +00:00
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
{kDDWidgetBackgroundDefault, "widget_default", true, kDDNone},
|
|
|
|
{kDDWidgetBackgroundSmall, "widget_small", true, kDDNone},
|
|
|
|
{kDDWidgetBackgroundEditText, "widget_textedit", true, kDDNone},
|
|
|
|
{kDDWidgetBackgroundSlider, "widget_slider", true, kDDNone},
|
2009-01-17 17:13:04 +00:00
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
{kDDButtonIdle, "button_idle", true, kDDWidgetBackgroundSlider},
|
|
|
|
{kDDButtonHover, "button_hover", false, kDDButtonIdle},
|
|
|
|
{kDDButtonDisabled, "button_disabled", true, kDDNone},
|
2012-05-03 16:32:08 +00:00
|
|
|
{kDDButtonPressed, "button_pressed", false, kDDButtonIdle},
|
2009-01-17 17:13:04 +00:00
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
{kDDSliderFull, "slider_full", false, kDDNone},
|
|
|
|
{kDDSliderHover, "slider_hover", false, kDDNone},
|
|
|
|
{kDDSliderDisabled, "slider_disabled", false, kDDNone},
|
2009-01-17 17:13:04 +00:00
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
{kDDCheckboxDefault, "checkbox_default", true, kDDNone},
|
|
|
|
{kDDCheckboxDisabled, "checkbox_disabled", true, kDDNone},
|
|
|
|
{kDDCheckboxSelected, "checkbox_selected", false, kDDCheckboxDefault},
|
2009-01-17 17:13:04 +00:00
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
{kDDRadiobuttonDefault, "radiobutton_default", true, kDDNone},
|
|
|
|
{kDDRadiobuttonDisabled, "radiobutton_disabled", true, kDDNone},
|
|
|
|
{kDDRadiobuttonSelected, "radiobutton_selected", false, kDDRadiobuttonDefault},
|
2010-06-15 10:48:39 +00:00
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
{kDDTabActive, "tab_active", false, kDDTabInactive},
|
|
|
|
{kDDTabInactive, "tab_inactive", true, kDDNone},
|
|
|
|
{kDDTabBackground, "tab_background", true, kDDNone},
|
2009-01-17 17:13:04 +00:00
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
{kDDScrollbarBase, "scrollbar_base", true, kDDNone},
|
2009-01-17 17:13:04 +00:00
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
{kDDScrollbarButtonIdle, "scrollbar_button_idle", true, kDDNone},
|
|
|
|
{kDDScrollbarButtonHover, "scrollbar_button_hover", false, kDDScrollbarButtonIdle},
|
2009-01-17 17:13:04 +00:00
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
{kDDScrollbarHandleIdle, "scrollbar_handle_idle", false, kDDNone},
|
|
|
|
{kDDScrollbarHandleHover, "scrollbar_handle_hover", false, kDDScrollbarBase},
|
2009-01-17 17:13:04 +00:00
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
{kDDPopUpIdle, "popup_idle", true, kDDNone},
|
|
|
|
{kDDPopUpHover, "popup_hover", false, kDDPopUpIdle},
|
|
|
|
{kDDPopUpDisabled, "popup_disabled", true, kDDNone},
|
2009-01-17 17:13:04 +00:00
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
{kDDCaret, "caret", false, kDDNone},
|
|
|
|
{kDDSeparator, "separator", true, kDDNone},
|
2009-01-17 17:13:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************
|
2011-04-03 13:04:20 +00:00
|
|
|
* ThemeItem functions for drawing queues.
|
2009-01-17 17:13:04 +00:00
|
|
|
*********************************************************/
|
|
|
|
void ThemeItemDrawData::drawSelf(bool draw, bool restore) {
|
|
|
|
|
|
|
|
Common::Rect extendedRect = _area;
|
|
|
|
extendedRect.grow(_engine->kDirtyRectangleThreshold + _data->_backgroundOffset);
|
|
|
|
|
|
|
|
if (restore)
|
|
|
|
_engine->restoreBackground(extendedRect);
|
|
|
|
|
|
|
|
if (draw) {
|
|
|
|
Common::List<Graphics::DrawStep>::const_iterator step;
|
|
|
|
for (step = _data->_steps.begin(); step != _data->_steps.end(); ++step)
|
|
|
|
_engine->renderer()->drawStep(_area, *step, _dynamicData);
|
|
|
|
}
|
|
|
|
|
|
|
|
_engine->addDirtyRect(extendedRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeItemTextData::drawSelf(bool draw, bool restore) {
|
|
|
|
if (_restoreBg || restore)
|
|
|
|
_engine->restoreBackground(_area);
|
|
|
|
|
|
|
|
if (draw) {
|
2009-08-10 13:46:17 +00:00
|
|
|
_engine->renderer()->setFgColor(_color->r, _color->g, _color->b);
|
2013-06-13 12:32:36 +00:00
|
|
|
_engine->renderer()->drawString(_data->_fontPtr, _text, _area, _alignH, _alignV, _deltax, _ellipsis, _textDrawableArea);
|
2009-01-17 17:13:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_engine->addDirtyRect(_area);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeItemBitmap::drawSelf(bool draw, bool restore) {
|
|
|
|
if (restore)
|
|
|
|
_engine->restoreBackground(_area);
|
|
|
|
|
|
|
|
if (draw) {
|
|
|
|
if (_alpha)
|
|
|
|
_engine->renderer()->blitAlphaBitmap(_bitmap, _area);
|
|
|
|
else
|
|
|
|
_engine->renderer()->blitSubSurface(_bitmap, _area);
|
|
|
|
}
|
|
|
|
|
|
|
|
_engine->addDirtyRect(_area);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
/**********************************************************
|
2011-04-03 13:04:20 +00:00
|
|
|
* ThemeEngine class
|
2008-11-10 11:24:55 +00:00
|
|
|
*********************************************************/
|
2009-01-02 21:24:13 +00:00
|
|
|
ThemeEngine::ThemeEngine(Common::String id, GraphicsMode mode) :
|
2009-01-01 21:41:55 +00:00
|
|
|
_system(0), _vectorRenderer(0),
|
2008-11-10 11:24:55 +00:00
|
|
|
_buffering(false), _bytesPerPixel(0), _graphicsMode(kGfxDisabled),
|
2012-01-06 20:55:58 +00:00
|
|
|
_font(0), _initOk(false), _themeOk(false), _enabled(false), _themeFiles(),
|
|
|
|
_cursor(0) {
|
2008-12-22 11:22:15 +00:00
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
_system = g_system;
|
|
|
|
_parser = new ThemeParser(this);
|
|
|
|
_themeEval = new GUI::ThemeEval();
|
2008-11-08 00:54:58 +00:00
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
_useCursor = false;
|
2008-11-08 00:54:58 +00:00
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
for (int i = 0; i < kDrawDataMAX; ++i) {
|
|
|
|
_widgets[i] = 0;
|
2008-11-08 00:54:58 +00:00
|
|
|
}
|
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
for (int i = 0; i < kTextDataMAX; ++i) {
|
|
|
|
_texts[i] = 0;
|
|
|
|
}
|
2008-11-08 00:54:58 +00:00
|
|
|
|
2009-08-10 13:46:17 +00:00
|
|
|
for (int i = 0; i < kTextColorMAX; ++i) {
|
|
|
|
_textColors[i] = 0;
|
|
|
|
}
|
|
|
|
|
2009-01-02 21:24:13 +00:00
|
|
|
// We currently allow two different ways of theme selection in our config file:
|
|
|
|
// 1) Via full path
|
|
|
|
// 2) Via a basename, which will need to be translated into a full path
|
|
|
|
// This function assures we have a correct path to pass to the ThemeEngine
|
|
|
|
// constructor.
|
|
|
|
_themeFile = getThemeFile(id);
|
|
|
|
// We will use getThemeId to retrive the theme id from the given filename
|
|
|
|
// here, since the user could have passed a fixed filename as 'id'.
|
|
|
|
_themeId = getThemeId(_themeFile);
|
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
_graphicsMode = mode;
|
2008-12-31 15:07:30 +00:00
|
|
|
_themeArchive = 0;
|
2008-11-10 11:24:55 +00:00
|
|
|
_initOk = false;
|
2012-01-06 20:55:58 +00:00
|
|
|
|
|
|
|
// We prefer files in archive bundles over the common search paths.
|
|
|
|
_themeFiles.add("default", &SearchMan, 0, false);
|
2008-11-10 11:24:55 +00:00
|
|
|
}
|
2008-11-08 00:54:58 +00:00
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
ThemeEngine::~ThemeEngine() {
|
2009-01-01 21:41:55 +00:00
|
|
|
delete _vectorRenderer;
|
|
|
|
_vectorRenderer = 0;
|
|
|
|
_screen.free();
|
|
|
|
_backBuffer.free();
|
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
unloadTheme();
|
2009-01-02 01:32:40 +00:00
|
|
|
|
|
|
|
// Release all graphics surfaces
|
|
|
|
for (ImagesMap::iterator i = _bitmaps.begin(); i != _bitmaps.end(); ++i) {
|
|
|
|
Graphics::Surface *surf = i->_value;
|
|
|
|
if (surf) {
|
|
|
|
surf->free();
|
|
|
|
delete surf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_bitmaps.clear();
|
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
delete _parser;
|
|
|
|
delete _themeEval;
|
|
|
|
delete[] _cursor;
|
|
|
|
}
|
2008-11-08 00:54:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
/**********************************************************
|
2011-04-03 13:04:20 +00:00
|
|
|
* Rendering mode management
|
2008-11-10 11:24:55 +00:00
|
|
|
*********************************************************/
|
2008-10-29 20:45:28 +00:00
|
|
|
const ThemeEngine::Renderer ThemeEngine::_rendererModes[] = {
|
2010-09-12 11:43:51 +00:00
|
|
|
{ _s("Disabled GFX"), _sc("Disabled GFX", "lowres"), "none", kGfxDisabled },
|
2013-07-31 23:38:22 +00:00
|
|
|
{ _s("Standard Renderer"), _s("Standard"), "normal", kGfxStandard },
|
2008-10-29 19:48:15 +00:00
|
|
|
#ifndef DISABLE_FANCY_THEMES
|
2013-07-31 23:38:22 +00:00
|
|
|
{ _s("Antialiased Renderer"), _s("Antialiased"), "antialias", kGfxAntialias }
|
2008-10-29 19:48:15 +00:00
|
|
|
#endif
|
2008-08-15 11:05:25 +00:00
|
|
|
};
|
|
|
|
|
2008-10-29 20:45:28 +00:00
|
|
|
const uint ThemeEngine::_rendererModesSize = ARRAYSIZE(ThemeEngine::_rendererModes);
|
|
|
|
|
2008-11-04 05:29:53 +00:00
|
|
|
const ThemeEngine::GraphicsMode ThemeEngine::_defaultRendererMode =
|
2008-10-29 20:45:28 +00:00
|
|
|
#ifndef DISABLE_FANCY_THEMES
|
2013-07-31 23:38:22 +00:00
|
|
|
ThemeEngine::kGfxAntialias;
|
2008-10-29 20:45:28 +00:00
|
|
|
#else
|
2013-07-31 23:38:22 +00:00
|
|
|
ThemeEngine::kGfxStandard;
|
2008-10-29 20:45:28 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
ThemeEngine::GraphicsMode ThemeEngine::findMode(const Common::String &cfg) {
|
|
|
|
for (uint i = 0; i < _rendererModesSize; ++i) {
|
|
|
|
if (cfg.equalsIgnoreCase(_rendererModes[i].cfg))
|
|
|
|
return _rendererModes[i].mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
return kGfxDisabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *ThemeEngine::findModeConfigName(GraphicsMode mode) {
|
|
|
|
for (uint i = 0; i < _rendererModesSize; ++i) {
|
|
|
|
if (mode == _rendererModes[i].mode)
|
|
|
|
return _rendererModes[i].cfg;
|
|
|
|
}
|
|
|
|
|
|
|
|
return findModeConfigName(kGfxDisabled);
|
|
|
|
}
|
2008-09-02 17:51:08 +00:00
|
|
|
|
2008-06-24 19:48:01 +00:00
|
|
|
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-09 14:15:34 +00:00
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
|
|
|
|
/**********************************************************
|
2011-04-03 13:04:20 +00:00
|
|
|
* Theme setup/initialization
|
2008-09-02 17:51:08 +00:00
|
|
|
*********************************************************/
|
|
|
|
bool ThemeEngine::init() {
|
2008-07-03 10:26:55 +00:00
|
|
|
// reset everything and reload the graphics
|
2009-01-01 21:41:55 +00:00
|
|
|
_initOk = false;
|
2009-01-22 18:45:06 +00:00
|
|
|
_overlayFormat = _system->getOverlayFormat();
|
2011-04-17 14:34:58 +00:00
|
|
|
setGraphicsMode(_graphicsMode);
|
2008-07-03 10:26:55 +00:00
|
|
|
|
2013-08-03 00:36:28 +00:00
|
|
|
if (_screen.getPixels() && _backBuffer.getPixels()) {
|
2008-07-03 10:26:55 +00:00
|
|
|
_initOk = true;
|
|
|
|
}
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2009-01-01 21:41:55 +00:00
|
|
|
// TODO: Instead of hard coding the font here, it should be possible
|
|
|
|
// to specify the fonts to be used for each resolution in the theme XML.
|
|
|
|
if (_screen.w >= 400 && _screen.h >= 300) {
|
2008-08-13 10:42:01 +00:00
|
|
|
_font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
|
|
|
|
} else {
|
|
|
|
_font = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
|
|
|
|
}
|
2008-07-03 10:26:55 +00:00
|
|
|
|
2009-01-02 01:32:40 +00:00
|
|
|
// Try to create a Common::Archive with the files of the theme.
|
2009-01-02 21:24:13 +00:00
|
|
|
if (!_themeArchive && !_themeFile.empty()) {
|
|
|
|
Common::FSNode node(_themeFile);
|
2010-07-19 14:28:46 +00:00
|
|
|
if (node.isDirectory()) {
|
2009-01-02 01:32:40 +00:00
|
|
|
_themeArchive = new Common::FSDirectory(node);
|
2011-05-07 13:49:57 +00:00
|
|
|
} else if (_themeFile.matchString("*.zip", true)) {
|
2010-07-19 14:28:46 +00:00
|
|
|
// TODO: Also use "node" directly?
|
|
|
|
// Look for the zip file via SearchMan
|
|
|
|
Common::ArchiveMemberPtr member = SearchMan.getMember(_themeFile);
|
|
|
|
if (member) {
|
|
|
|
_themeArchive = Common::makeZipArchive(member->createReadStream());
|
|
|
|
if (!_themeArchive) {
|
|
|
|
warning("Failed to open Zip archive '%s'.", member->getDisplayName().c_str());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
_themeArchive = Common::makeZipArchive(node);
|
|
|
|
if (!_themeArchive) {
|
|
|
|
warning("Failed to open Zip archive '%s'.", node.getPath().c_str());
|
|
|
|
}
|
|
|
|
}
|
2009-01-02 01:32:40 +00:00
|
|
|
}
|
2012-01-06 20:55:58 +00:00
|
|
|
|
|
|
|
if (_themeArchive)
|
|
|
|
_themeFiles.add("theme_archive", _themeArchive, 1, true);
|
2009-01-02 01:32:40 +00:00
|
|
|
}
|
2009-05-24 15:17:42 +00:00
|
|
|
|
2009-01-02 01:32:40 +00:00
|
|
|
// Load the theme
|
2009-01-02 21:24:13 +00:00
|
|
|
// We pass the theme file here by default, so the user will
|
|
|
|
// have a descriptive error message. The only exception will
|
|
|
|
// be the builtin theme which has no filename.
|
|
|
|
loadTheme(_themeFile.empty() ? _themeId : _themeFile);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2009-01-01 21:41:55 +00:00
|
|
|
return ready();
|
2008-08-09 22:40:05 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::clearAll() {
|
2011-02-24 22:49:07 +00:00
|
|
|
if (_initOk) {
|
|
|
|
_system->clearOverlay();
|
2013-08-03 00:36:28 +00:00
|
|
|
_system->grabOverlay(_screen.getPixels(), _screen.pitch);
|
2011-02-24 22:49:07 +00:00
|
|
|
}
|
2008-07-03 19:42:04 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::refresh() {
|
2009-05-24 15:17:42 +00:00
|
|
|
|
2009-01-22 18:45:06 +00:00
|
|
|
// Flush all bitmaps if the overlay pixel format changed.
|
|
|
|
if (_overlayFormat != _system->getOverlayFormat()) {
|
|
|
|
for (ImagesMap::iterator i = _bitmaps.begin(); i != _bitmaps.end(); ++i) {
|
|
|
|
Graphics::Surface *surf = i->_value;
|
|
|
|
if (surf) {
|
|
|
|
surf->free();
|
|
|
|
delete surf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_bitmaps.clear();
|
|
|
|
}
|
|
|
|
|
2008-08-10 09:53:42 +00:00
|
|
|
init();
|
2009-01-22 18:45:06 +00:00
|
|
|
|
2008-08-10 09:53:42 +00:00
|
|
|
if (_enabled) {
|
|
|
|
_system->showOverlay();
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-15 13:50:08 +00:00
|
|
|
if (_useCursor) {
|
2009-01-14 02:44:09 +00:00
|
|
|
CursorMan.replaceCursorPalette(_cursorPal, 0, _cursorPalSize);
|
2012-06-03 00:02:57 +00:00
|
|
|
CursorMan.replaceCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, true);
|
2008-08-15 13:50:08 +00:00
|
|
|
}
|
2008-08-10 09:53:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::enable() {
|
2009-01-02 01:23:17 +00:00
|
|
|
if (_enabled)
|
|
|
|
return;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2013-05-16 21:18:09 +00:00
|
|
|
showCursor();
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-03 19:42:04 +00:00
|
|
|
_system->showOverlay();
|
|
|
|
clearAll();
|
|
|
|
_enabled = true;
|
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::disable() {
|
2009-01-02 01:23:17 +00:00
|
|
|
if (!_enabled)
|
|
|
|
return;
|
|
|
|
|
2008-07-03 19:42:04 +00:00
|
|
|
_system->hideOverlay();
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2013-05-16 21:18:09 +00:00
|
|
|
hideCursor();
|
|
|
|
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-03 19:42:04 +00:00
|
|
|
_enabled = false;
|
2008-06-09 21:16:26 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::setGraphicsMode(GraphicsMode mode) {
|
2008-05-28 14:27:22 +00:00
|
|
|
switch (mode) {
|
2013-07-31 23:38:22 +00:00
|
|
|
case kGfxStandard:
|
2008-10-29 19:48:15 +00:00
|
|
|
#ifndef DISABLE_FANCY_THEMES
|
2013-07-31 23:38:22 +00:00
|
|
|
case kGfxAntialias:
|
2008-10-29 19:48:15 +00:00
|
|
|
#endif
|
2013-08-05 15:59:36 +00:00
|
|
|
if (g_system->getOverlayFormat().bytesPerPixel == 4) {
|
|
|
|
_bytesPerPixel = sizeof(uint32);
|
|
|
|
break;
|
|
|
|
} else if (g_system->getOverlayFormat().bytesPerPixel == 2) {
|
|
|
|
_bytesPerPixel = sizeof(uint16);
|
|
|
|
break;
|
|
|
|
}
|
2008-05-28 14:30:51 +00:00
|
|
|
default:
|
2008-08-15 11:05:25 +00:00
|
|
|
error("Invalid graphics mode");
|
2008-05-28 14:27:22 +00:00
|
|
|
}
|
|
|
|
|
2009-01-01 21:41:55 +00:00
|
|
|
uint32 width = _system->getOverlayWidth();
|
|
|
|
uint32 height = _system->getOverlayHeight();
|
|
|
|
|
|
|
|
_backBuffer.free();
|
2011-04-17 14:34:58 +00:00
|
|
|
_backBuffer.create(width, height, _overlayFormat);
|
2009-01-01 21:41:55 +00:00
|
|
|
|
|
|
|
_screen.free();
|
2011-04-17 14:34:58 +00:00
|
|
|
_screen.create(width, height, _overlayFormat);
|
2009-01-01 21:41:55 +00:00
|
|
|
|
2008-12-31 14:10:23 +00:00
|
|
|
delete _vectorRenderer;
|
2008-11-09 15:14:01 +00:00
|
|
|
_vectorRenderer = Graphics::createRenderer(mode);
|
2009-01-01 21:41:55 +00:00
|
|
|
_vectorRenderer->setSurface(&_screen);
|
2013-08-18 18:12:12 +00:00
|
|
|
|
|
|
|
// Since we reinitialized our screen surfaces we know nothing has been
|
|
|
|
// drawn so far. Sometimes we still end up with dirty screen bits in the
|
|
|
|
// list. Clearing it avoids invalid overlay writes when the backend
|
|
|
|
// resizes the overlay.
|
|
|
|
_dirtyScreen.clear();
|
2008-05-28 14:27:22 +00:00
|
|
|
}
|
|
|
|
|
2009-01-18 14:48:00 +00:00
|
|
|
void WidgetDrawData::calcBackgroundOffset() {
|
2008-09-02 17:51:08 +00:00
|
|
|
uint maxShadow = 0;
|
2009-01-18 14:48:00 +00:00
|
|
|
for (Common::List<Graphics::DrawStep>::const_iterator step = _steps.begin();
|
2011-04-03 13:04:20 +00:00
|
|
|
step != _steps.end(); ++step) {
|
2008-11-04 05:29:53 +00:00
|
|
|
if ((step->autoWidth || step->autoHeight) && step->shadow > maxShadow)
|
2008-09-02 17:51:08 +00:00
|
|
|
maxShadow = step->shadow;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
if (step->drawingCall == &Graphics::VectorRenderer::drawCallback_BEVELSQ && step->bevel > maxShadow)
|
|
|
|
maxShadow = step->bevel;
|
|
|
|
}
|
|
|
|
|
2009-01-18 14:48:00 +00:00
|
|
|
_backgroundOffset = maxShadow;
|
2008-09-02 17:51:08 +00:00
|
|
|
}
|
|
|
|
|
2008-11-12 22:23:19 +00:00
|
|
|
void ThemeEngine::restoreBackground(Common::Rect r) {
|
2009-01-08 18:09:13 +00:00
|
|
|
r.clip(_screen.w, _screen.h);
|
2009-01-01 21:41:55 +00:00
|
|
|
_vectorRenderer->blitSurface(&_backBuffer, r);
|
2008-09-02 17:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************
|
2011-04-03 13:04:20 +00:00
|
|
|
* Theme elements management
|
2008-09-02 17:51:08 +00:00
|
|
|
*********************************************************/
|
2008-11-08 01:30:32 +00:00
|
|
|
void ThemeEngine::addDrawStep(const Common::String &drawDataId, const Graphics::DrawStep &step) {
|
2009-01-18 14:48:00 +00:00
|
|
|
DrawData id = parseDrawDataId(drawDataId);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-06-24 19:48:01 +00:00
|
|
|
assert(_widgets[id] != 0);
|
|
|
|
_widgets[id]->_steps.push_back(step);
|
2008-06-18 00:15:21 +00:00
|
|
|
}
|
|
|
|
|
2009-08-10 13:46:17 +00:00
|
|
|
bool ThemeEngine::addTextData(const Common::String &drawDataId, TextData textId, TextColor colorId, Graphics::TextAlign alignH, TextAlignVertical alignV) {
|
2009-01-18 14:48:00 +00:00
|
|
|
DrawData id = parseDrawDataId(drawDataId);
|
2008-07-20 22:23:35 +00:00
|
|
|
|
2009-08-10 13:46:17 +00:00
|
|
|
if (id == -1 || textId == -1 || colorId == kTextColorMAX || !_widgets[id])
|
2008-07-23 16:38:39 +00:00
|
|
|
return false;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-23 16:38:39 +00:00
|
|
|
_widgets[id]->_textDataId = textId;
|
2009-08-10 13:46:17 +00:00
|
|
|
_widgets[id]->_textColorId = colorId;
|
2008-07-23 16:38:39 +00:00
|
|
|
_widgets[id]->_textAlignH = alignH;
|
2008-11-04 05:29:53 +00:00
|
|
|
_widgets[id]->_textAlignV = alignV;
|
2008-07-20 21:47:28 +00:00
|
|
|
|
2008-07-23 16:38:39 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-01-07 01:51:50 +00:00
|
|
|
bool ThemeEngine::addFont(TextData textId, const Common::String &file, const Common::String &scalableFile, const int pointsize) {
|
2008-07-23 16:38:39 +00:00
|
|
|
if (textId == -1)
|
|
|
|
return false;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-23 16:38:39 +00:00
|
|
|
if (_texts[textId] != 0)
|
2008-08-08 18:30:16 +00:00
|
|
|
delete _texts[textId];
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-23 16:38:39 +00:00
|
|
|
_texts[textId] = new TextDrawData;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-07 18:42:47 +00:00
|
|
|
if (file == "default") {
|
|
|
|
_texts[textId]->_fontPtr = _font;
|
|
|
|
} else {
|
2011-05-22 14:43:35 +00:00
|
|
|
Common::String localized = FontMan.genLocalizedFontFilename(file);
|
2012-01-29 18:18:36 +00:00
|
|
|
const Common::String charset
|
2012-01-07 01:51:50 +00:00
|
|
|
#ifdef USE_TRANSLATION
|
2012-01-29 18:18:36 +00:00
|
|
|
(TransMan.getCurrentCharset())
|
2012-01-07 01:51:50 +00:00
|
|
|
#endif
|
2012-01-29 18:18:36 +00:00
|
|
|
;
|
2012-01-07 01:51:50 +00:00
|
|
|
|
2012-01-06 23:34:03 +00:00
|
|
|
// Try localized fonts
|
2012-01-07 01:51:50 +00:00
|
|
|
_texts[textId]->_fontPtr = loadFont(localized, scalableFile, charset, pointsize, textId == kTextDataDefault);
|
2008-08-07 18:42:47 +00:00
|
|
|
|
|
|
|
if (!_texts[textId]->_fontPtr) {
|
2012-01-06 23:34:03 +00:00
|
|
|
// Try standard fonts
|
2012-01-07 01:51:50 +00:00
|
|
|
_texts[textId]->_fontPtr = loadFont(file, scalableFile, Common::String(), pointsize, textId == kTextDataDefault);
|
2010-10-12 02:18:11 +00:00
|
|
|
|
2012-01-06 23:34:03 +00:00
|
|
|
if (!_texts[textId]->_fontPtr)
|
2012-01-07 01:51:50 +00:00
|
|
|
error("Couldn't load font '%s'/'%s'", file.c_str(), scalableFile.c_str());
|
2012-01-07 00:00:31 +00:00
|
|
|
|
2010-11-30 18:50:19 +00:00
|
|
|
#ifdef USE_TRANSLATION
|
2012-01-06 23:34:03 +00:00
|
|
|
TransMan.setLanguage("C");
|
2010-11-30 18:50:19 +00:00
|
|
|
#endif
|
2012-01-06 23:34:03 +00:00
|
|
|
warning("Failed to load localized font '%s'. Using non-localized font and default GUI language instead", localized.c_str());
|
2008-08-07 18:42:47 +00:00
|
|
|
}
|
|
|
|
}
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-10 15:50:44 +00:00
|
|
|
return true;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-10 15:50:44 +00:00
|
|
|
}
|
|
|
|
|
2009-08-10 13:46:17 +00:00
|
|
|
bool ThemeEngine::addTextColor(TextColor colorId, int r, int g, int b) {
|
|
|
|
if (colorId >= kTextColorMAX)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (_textColors[colorId] != 0)
|
|
|
|
delete _textColors[colorId];
|
|
|
|
|
|
|
|
_textColors[colorId] = new TextColorData;
|
|
|
|
|
|
|
|
_textColors[colorId]->r = r;
|
|
|
|
_textColors[colorId]->g = g;
|
|
|
|
_textColors[colorId]->b = b;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
bool ThemeEngine::addBitmap(const Common::String &filename) {
|
2009-01-02 01:32:40 +00:00
|
|
|
// Nothing has to be done if the bitmap already has been loaded.
|
2008-12-31 15:07:30 +00:00
|
|
|
Graphics::Surface *surf = _bitmaps[filename];
|
2009-01-02 01:32:40 +00:00
|
|
|
if (surf)
|
|
|
|
return true;
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2011-06-30 12:16:19 +00:00
|
|
|
// If not, try to load the bitmap via the BitmapDecoder class.
|
2014-02-28 02:27:23 +00:00
|
|
|
Image::BitmapDecoder bitmapDecoder;
|
2011-06-30 12:16:19 +00:00
|
|
|
const Graphics::Surface *srcSurface = 0;
|
2012-01-06 20:55:58 +00:00
|
|
|
Common::ArchiveMemberList members;
|
|
|
|
_themeFiles.listMatchingMembers(members, filename);
|
|
|
|
for (Common::ArchiveMemberList::const_iterator i = members.begin(), end = members.end(); i != end; ++i) {
|
|
|
|
Common::SeekableReadStream *stream = (*i)->createReadStream();
|
2008-12-31 15:07:30 +00:00
|
|
|
if (stream) {
|
2011-06-30 12:16:19 +00:00
|
|
|
bitmapDecoder.loadStream(*stream);
|
|
|
|
srcSurface = bitmapDecoder.getSurface();
|
2011-10-24 04:17:54 +00:00
|
|
|
delete stream;
|
2011-06-30 12:16:19 +00:00
|
|
|
if (srcSurface)
|
2012-01-06 20:55:58 +00:00
|
|
|
break;
|
2008-12-31 15:07:30 +00:00
|
|
|
}
|
|
|
|
}
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2011-06-30 12:16:19 +00:00
|
|
|
if (srcSurface && srcSurface->format.bytesPerPixel != 1)
|
|
|
|
surf = srcSurface->convertTo(_overlayFormat);
|
|
|
|
|
2008-12-31 15:07:30 +00:00
|
|
|
// Store the surface into our hashmap (attention, may store NULL entries!)
|
|
|
|
_bitmaps[filename] = surf;
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-12-31 15:07:30 +00:00
|
|
|
return surf != 0;
|
2008-08-09 18:34:16 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
bool ThemeEngine::addDrawData(const Common::String &data, bool cached) {
|
2009-01-18 14:48:00 +00:00
|
|
|
DrawData id = parseDrawDataId(data);
|
2008-06-24 19:48:01 +00:00
|
|
|
|
2009-01-18 14:48:00 +00:00
|
|
|
if (id == -1)
|
2008-06-24 19:48:01 +00:00
|
|
|
return false;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2009-01-18 14:48:00 +00:00
|
|
|
if (_widgets[id] != 0)
|
|
|
|
delete _widgets[id];
|
2008-06-24 19:48:01 +00:00
|
|
|
|
2009-01-18 14:48:00 +00:00
|
|
|
_widgets[id] = new WidgetDrawData;
|
|
|
|
_widgets[id]->_buffer = kDrawDataDefaults[id].buffer;
|
|
|
|
_widgets[id]->_textDataId = kTextDataNone;
|
2008-06-24 19:48:01 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2008-06-18 00:15:21 +00:00
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
|
|
|
|
/**********************************************************
|
2011-04-03 13:04:20 +00:00
|
|
|
* Theme XML loading
|
2008-09-02 17:51:08 +00:00
|
|
|
*********************************************************/
|
2009-01-01 21:52:15 +00:00
|
|
|
void ThemeEngine::loadTheme(const Common::String &themeId) {
|
2008-06-29 12:08:53 +00:00
|
|
|
unloadTheme();
|
|
|
|
|
2011-10-17 16:13:50 +00:00
|
|
|
debug(6, "Loading theme %s", themeId.c_str());
|
|
|
|
|
2009-01-01 21:52:15 +00:00
|
|
|
if (themeId == "builtin") {
|
2009-01-01 21:41:55 +00:00
|
|
|
_themeOk = loadDefaultXML();
|
|
|
|
} else {
|
2008-12-31 15:07:30 +00:00
|
|
|
// Load the archive containing image and XML data
|
2009-01-01 21:52:15 +00:00
|
|
|
_themeOk = loadThemeXML(themeId);
|
2008-11-04 19:49:26 +00:00
|
|
|
}
|
2009-05-24 15:17:42 +00:00
|
|
|
|
2009-01-01 21:41:55 +00:00
|
|
|
if (!_themeOk) {
|
2009-01-01 21:52:15 +00:00
|
|
|
warning("Failed to load theme '%s'", themeId.c_str());
|
2009-01-01 21:41:55 +00:00
|
|
|
return;
|
2008-06-25 22:30:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < kDrawDataMAX; ++i) {
|
|
|
|
if (_widgets[i] == 0) {
|
2008-07-23 22:32:00 +00:00
|
|
|
warning("Missing data asset: '%s'", kDrawDataDefaults[i].name);
|
2008-07-17 21:58:43 +00:00
|
|
|
} else {
|
2009-01-18 14:48:00 +00:00
|
|
|
_widgets[i]->calcBackgroundOffset();
|
2008-06-25 22:30:28 +00:00
|
|
|
}
|
|
|
|
}
|
2009-01-01 21:41:55 +00:00
|
|
|
}
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2009-01-01 21:41:55 +00:00
|
|
|
void ThemeEngine::unloadTheme() {
|
|
|
|
if (!_themeOk)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (int i = 0; i < kDrawDataMAX; ++i) {
|
|
|
|
delete _widgets[i];
|
|
|
|
_widgets[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < kTextDataMAX; ++i) {
|
|
|
|
delete _texts[i];
|
|
|
|
_texts[i] = 0;
|
|
|
|
}
|
|
|
|
|
2009-08-10 13:46:17 +00:00
|
|
|
for (int i = 0; i < kTextColorMAX; ++i) {
|
|
|
|
delete _textColors[i];
|
|
|
|
_textColors[i] = 0;
|
|
|
|
}
|
|
|
|
|
2009-01-01 21:41:55 +00:00
|
|
|
_themeEval->reset();
|
|
|
|
_themeOk = false;
|
2008-06-25 22:30:28 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
bool ThemeEngine::loadDefaultXML() {
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-02 15:15:32 +00:00
|
|
|
// The default XML theme is included on runtime from a pregenerated
|
|
|
|
// file inside the themes directory.
|
|
|
|
// Use the Python script "makedeftheme.py" to convert a normal XML theme
|
|
|
|
// into the "default.inc" file, which is ready to be included in the code.
|
2010-09-28 20:31:17 +00:00
|
|
|
#ifndef DISABLE_GUI_BUILTIN_THEME
|
2008-08-02 15:15:32 +00:00
|
|
|
const char *defaultXML =
|
|
|
|
#include "themes/default.inc"
|
2011-04-03 13:04:20 +00:00
|
|
|
;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
if (!_parser->loadBuffer((const byte *)defaultXML, strlen(defaultXML)))
|
2008-08-02 15:15:32 +00:00
|
|
|
return false;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-14 18:43:27 +00:00
|
|
|
_themeName = "ScummVM Classic Theme (Builtin Version)";
|
2009-01-01 21:41:55 +00:00
|
|
|
_themeId = "builtin";
|
2009-01-02 21:24:13 +00:00
|
|
|
_themeFile.clear();
|
2008-08-02 15:15:32 +00:00
|
|
|
|
2009-01-02 21:24:13 +00:00
|
|
|
bool result = _parser->parse();
|
2008-10-11 22:14:47 +00:00
|
|
|
_parser->close();
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-09-29 10:27:16 +00:00
|
|
|
return result;
|
2008-08-09 22:40:05 +00:00
|
|
|
#else
|
|
|
|
warning("The built-in theme is not enabled in the current build. Please load an external theme");
|
|
|
|
return false;
|
|
|
|
#endif
|
2008-08-02 15:15:32 +00:00
|
|
|
}
|
|
|
|
|
2009-01-01 21:52:15 +00:00
|
|
|
bool ThemeEngine::loadThemeXML(const Common::String &themeId) {
|
2008-06-25 22:30:28 +00:00
|
|
|
assert(_parser);
|
2009-01-02 01:32:40 +00:00
|
|
|
assert(_themeArchive);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2009-01-02 01:32:40 +00:00
|
|
|
_themeName.clear();
|
2008-10-11 22:14:47 +00:00
|
|
|
|
2008-11-04 19:49:26 +00:00
|
|
|
|
2009-01-01 21:52:15 +00:00
|
|
|
//
|
|
|
|
// Now that we have a Common::Archive, verify that it contains a valid THEMERC File
|
|
|
|
//
|
2008-10-11 22:14:47 +00:00
|
|
|
Common::File themercFile;
|
2009-01-01 21:52:15 +00:00
|
|
|
themercFile.open("THEMERC", *_themeArchive);
|
2008-10-11 22:14:47 +00:00
|
|
|
if (!themercFile.isOpen()) {
|
2009-01-01 21:52:15 +00:00
|
|
|
warning("Theme '%s' contains no 'THEMERC' file.", themeId.c_str());
|
2008-10-11 22:14:47 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Common::String stxHeader = themercFile.readLine();
|
|
|
|
if (!themeConfigParseHeader(stxHeader, _themeName) || _themeName.empty()) {
|
2009-01-01 21:52:15 +00:00
|
|
|
warning("Corrupted 'THEMERC' file in theme '%s'", themeId.c_str());
|
2008-10-11 22:14:47 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Common::ArchiveMemberList members;
|
2009-01-01 21:52:15 +00:00
|
|
|
if (0 == _themeArchive->listMatchingMembers(members, "*.stx")) {
|
|
|
|
warning("Found no STX files for theme '%s'.", themeId.c_str());
|
2008-10-11 22:14:47 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-01-01 21:52:15 +00:00
|
|
|
//
|
|
|
|
// Loop over all STX files, load and parse them
|
|
|
|
//
|
2008-10-11 22:14:47 +00:00
|
|
|
for (Common::ArchiveMemberList::iterator i = members.begin(); i != members.end(); ++i) {
|
|
|
|
assert((*i)->getName().hasSuffix(".stx"));
|
|
|
|
|
2009-01-23 04:36:18 +00:00
|
|
|
if (_parser->loadStream((*i)->createReadStream()) == false) {
|
2008-11-21 12:17:35 +00:00
|
|
|
warning("Failed to load STX file '%s'", (*i)->getDisplayName().c_str());
|
2008-10-11 22:14:47 +00:00
|
|
|
_parser->close();
|
|
|
|
return false;
|
2008-08-15 21:01:32 +00:00
|
|
|
}
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-10-11 22:14:47 +00:00
|
|
|
if (_parser->parse() == false) {
|
2008-11-21 12:17:35 +00:00
|
|
|
warning("Failed to parse STX file '%s'", (*i)->getDisplayName().c_str());
|
2008-10-11 22:14:47 +00:00
|
|
|
_parser->close();
|
|
|
|
return false;
|
|
|
|
}
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-10-11 22:14:47 +00:00
|
|
|
_parser->close();
|
|
|
|
}
|
2008-08-15 21:01:32 +00:00
|
|
|
|
2008-10-11 22:14:47 +00:00
|
|
|
assert(!_themeName.empty());
|
|
|
|
return true;
|
2008-06-25 22:30:28 +00:00
|
|
|
}
|
|
|
|
|
2008-06-12 11:26:11 +00:00
|
|
|
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
/**********************************************************
|
2011-04-03 13:04:20 +00:00
|
|
|
* Drawing Queue management
|
2008-09-02 17:51:08 +00:00
|
|
|
*********************************************************/
|
2009-02-07 00:23:53 +00:00
|
|
|
void ThemeEngine::queueDD(DrawData type, const Common::Rect &r, uint32 dynamic, bool restore) {
|
2008-07-10 15:50:44 +00:00
|
|
|
if (_widgets[type] == 0)
|
|
|
|
return;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
Common::Rect area = r;
|
2009-01-01 21:41:55 +00:00
|
|
|
area.clip(_screen.w, _screen.h);
|
2008-09-02 17:51:08 +00:00
|
|
|
|
|
|
|
ThemeItemDrawData *q = new ThemeItemDrawData(this, _widgets[type], area, dynamic);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-20 21:47:28 +00:00
|
|
|
if (_buffering) {
|
2008-07-21 16:14:06 +00:00
|
|
|
if (_widgets[type]->_buffer) {
|
2008-11-04 05:29:53 +00:00
|
|
|
_bufferQueue.push_back(q);
|
2008-07-21 16:14:06 +00:00
|
|
|
} else {
|
2008-07-21 19:15:59 +00:00
|
|
|
if (kDrawDataDefaults[type].parent != kDDNone && kDrawDataDefaults[type].parent != type)
|
|
|
|
queueDD(kDrawDataDefaults[type].parent, r);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-06 13:58:07 +00:00
|
|
|
_screenQueue.push_back(q);
|
2008-07-20 21:47:28 +00:00
|
|
|
}
|
|
|
|
} else {
|
2009-02-07 00:23:53 +00:00
|
|
|
q->drawSelf(!_widgets[type]->_buffer, restore || _widgets[type]->_buffer);
|
2008-09-02 17:51:08 +00:00
|
|
|
delete q;
|
2008-07-20 21:47:28 +00:00
|
|
|
}
|
|
|
|
}
|
2008-07-18 16:44:42 +00:00
|
|
|
|
2009-08-10 13:46:17 +00:00
|
|
|
void ThemeEngine::queueDDText(TextData type, TextColor color, const Common::Rect &r, const Common::String &text, bool restoreBg,
|
2013-06-13 12:32:36 +00:00
|
|
|
bool ellipsis, Graphics::TextAlign alignH, TextAlignVertical alignV, int deltax, const Common::Rect &drawableTextArea) {
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-23 16:38:39 +00:00
|
|
|
if (_texts[type] == 0)
|
|
|
|
return;
|
2008-09-02 17:51:08 +00:00
|
|
|
|
|
|
|
Common::Rect area = r;
|
2009-01-01 21:41:55 +00:00
|
|
|
area.clip(_screen.w, _screen.h);
|
2008-09-02 17:51:08 +00:00
|
|
|
|
2013-06-13 12:32:36 +00:00
|
|
|
ThemeItemTextData *q = new ThemeItemTextData(this, _texts[type], _textColors[color], area, drawableTextArea, text, alignH, alignV, ellipsis, restoreBg, deltax);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
|
|
|
if (_buffering) {
|
2008-09-02 17:51:08 +00:00
|
|
|
_screenQueue.push_back(q);
|
2008-07-10 15:50:44 +00:00
|
|
|
} else {
|
2008-09-02 17:51:08 +00:00
|
|
|
q->drawSelf(true, false);
|
|
|
|
delete q;
|
2008-06-12 11:26:11 +00:00
|
|
|
}
|
2008-07-20 21:47:28 +00:00
|
|
|
}
|
2008-07-18 16:44:42 +00:00
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &r, bool alpha) {
|
|
|
|
|
|
|
|
Common::Rect area = r;
|
2009-01-01 21:41:55 +00:00
|
|
|
area.clip(_screen.w, _screen.h);
|
2008-09-02 17:51:08 +00:00
|
|
|
|
|
|
|
ThemeItemBitmap *q = new ThemeItemBitmap(this, area, bitmap, alpha);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-09 18:34:16 +00:00
|
|
|
if (_buffering) {
|
2012-02-03 18:09:17 +00:00
|
|
|
_screenQueue.push_back(q);
|
2008-08-09 18:34:16 +00:00
|
|
|
} else {
|
2008-09-02 17:51:08 +00:00
|
|
|
q->drawSelf(true, false);
|
|
|
|
delete q;
|
2008-07-18 16:44:42 +00:00
|
|
|
}
|
2008-08-09 18:34:16 +00:00
|
|
|
}
|
|
|
|
|
2008-07-17 21:58:43 +00:00
|
|
|
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
/**********************************************************
|
2011-04-03 13:04:20 +00:00
|
|
|
* Widget drawing functions
|
2008-09-02 17:51:08 +00:00
|
|
|
*********************************************************/
|
|
|
|
void ThemeEngine::drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, uint16 hints) {
|
2008-06-28 16:49:39 +00:00
|
|
|
if (!ready())
|
2008-06-12 11:26:11 +00:00
|
|
|
return;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-10 16:37:45 +00:00
|
|
|
DrawData dd = kDDButtonIdle;
|
2008-06-12 11:26:11 +00:00
|
|
|
|
|
|
|
if (state == kStateEnabled)
|
2008-07-10 15:50:44 +00:00
|
|
|
dd = kDDButtonIdle;
|
2008-06-12 11:26:11 +00:00
|
|
|
else if (state == kStateHighlight)
|
2008-07-10 15:50:44 +00:00
|
|
|
dd = kDDButtonHover;
|
2008-07-03 19:42:04 +00:00
|
|
|
else if (state == kStateDisabled)
|
2008-07-10 15:50:44 +00:00
|
|
|
dd = kDDButtonDisabled;
|
2012-05-03 16:32:08 +00:00
|
|
|
else if (state == kStatePressed)
|
|
|
|
dd = kDDButtonPressed;
|
2008-06-12 11:26:11 +00:00
|
|
|
|
2009-02-07 00:23:53 +00:00
|
|
|
queueDD(dd, r, 0, hints & WIDGET_CLEARBG);
|
2009-12-15 08:19:59 +00:00
|
|
|
queueDDText(getTextData(dd), getTextColor(dd), r, str, false, true, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV);
|
2008-06-12 11:26:11 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state) {
|
2008-06-28 16:49:39 +00:00
|
|
|
if (!ready())
|
2008-06-12 11:26:11 +00:00
|
|
|
return;
|
|
|
|
|
2008-07-20 21:47:28 +00:00
|
|
|
queueDD(kDDSeparator, r);
|
2008-06-12 11:26:11 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) {
|
2008-06-28 16:49:39 +00:00
|
|
|
if (!ready())
|
2008-06-12 19:06:37 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
Common::Rect r2 = r;
|
2008-08-01 20:19:37 +00:00
|
|
|
DrawData dd = kDDCheckboxDefault;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-01 20:19:37 +00:00
|
|
|
if (checked)
|
|
|
|
dd = kDDCheckboxSelected;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-01 20:19:37 +00:00
|
|
|
if (state == kStateDisabled)
|
|
|
|
dd = kDDCheckboxDisabled;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-11 13:25:23 +00:00
|
|
|
const int checkBoxSize = MIN((int)r.height(), getFontHeight());
|
2008-07-07 18:37:22 +00:00
|
|
|
|
|
|
|
r2.bottom = r2.top + checkBoxSize;
|
|
|
|
r2.right = r2.left + checkBoxSize;
|
|
|
|
|
2008-07-23 16:38:39 +00:00
|
|
|
queueDD(dd, r2);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-11 13:25:23 +00:00
|
|
|
r2.left = r2.right + checkBoxSize;
|
|
|
|
r2.right = r.right;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2012-01-27 23:14:52 +00:00
|
|
|
queueDDText(getTextData(dd), getTextColor(dd), r2, str, true, false, _widgets[kDDCheckboxDefault]->_textAlignH, _widgets[dd]->_textAlignV);
|
2008-06-12 19:06:37 +00:00
|
|
|
}
|
|
|
|
|
2010-06-15 10:48:39 +00:00
|
|
|
void ThemeEngine::drawRadiobutton(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) {
|
|
|
|
if (!ready())
|
|
|
|
return;
|
|
|
|
|
|
|
|
Common::Rect r2 = r;
|
|
|
|
DrawData dd = kDDRadiobuttonDefault;
|
|
|
|
|
|
|
|
if (checked)
|
|
|
|
dd = kDDRadiobuttonSelected;
|
|
|
|
|
|
|
|
if (state == kStateDisabled)
|
|
|
|
dd = kDDRadiobuttonDisabled;
|
|
|
|
|
|
|
|
const int checkBoxSize = MIN((int)r.height(), getFontHeight());
|
|
|
|
|
|
|
|
r2.bottom = r2.top + checkBoxSize;
|
|
|
|
r2.right = r2.left + checkBoxSize;
|
|
|
|
|
|
|
|
queueDD(dd, r2);
|
|
|
|
|
|
|
|
r2.left = r2.right + checkBoxSize;
|
|
|
|
r2.right = r.right;
|
|
|
|
|
2012-01-27 23:14:52 +00:00
|
|
|
queueDDText(getTextData(dd), getTextColor(dd), r2, str, true, false, _widgets[kDDRadiobuttonDefault]->_textAlignH, _widgets[dd]->_textAlignV);
|
2010-06-15 10:48:39 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::drawSlider(const Common::Rect &r, int width, WidgetStateInfo state) {
|
2008-06-28 16:49:39 +00:00
|
|
|
if (!ready())
|
2008-06-12 19:06:37 +00:00
|
|
|
return;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-02 15:15:32 +00:00
|
|
|
DrawData dd = kDDSliderFull;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-02 15:15:32 +00:00
|
|
|
if (state == kStateHighlight)
|
|
|
|
dd = kDDSliderHover;
|
|
|
|
else if (state == kStateDisabled)
|
|
|
|
dd = kDDSliderDisabled;
|
2008-06-12 19:06:37 +00:00
|
|
|
|
|
|
|
Common::Rect r2 = r;
|
|
|
|
r2.setWidth(MIN((int16)width, r.width()));
|
2008-08-02 22:11:57 +00:00
|
|
|
// r2.top++; r2.bottom--; r2.left++; r2.right--;
|
2008-06-12 19:06:37 +00:00
|
|
|
|
2008-07-21 16:14:06 +00:00
|
|
|
drawWidgetBackground(r, 0, kWidgetBackgroundSlider, kStateEnabled);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-12-26 12:15:51 +00:00
|
|
|
queueDD(dd, r2);
|
2008-06-12 19:06:37 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState scrollState, WidgetStateInfo state) {
|
2008-06-28 16:49:39 +00:00
|
|
|
if (!ready())
|
2008-06-12 19:06:37 +00:00
|
|
|
return;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-20 21:47:28 +00:00
|
|
|
queueDD(kDDScrollbarBase, r);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-24 18:40:36 +00:00
|
|
|
Common::Rect r2 = r;
|
|
|
|
const int buttonExtra = (r.width() * 120) / 100;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-24 18:40:36 +00:00
|
|
|
r2.bottom = r2.top + buttonExtra;
|
2008-07-25 00:59:53 +00:00
|
|
|
queueDD(scrollState == kScrollbarStateUp ? kDDScrollbarButtonHover : kDDScrollbarButtonIdle, r2, Graphics::VectorRenderer::kTriangleUp);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-24 18:40:36 +00:00
|
|
|
r2.translate(0, r.height() - r2.height());
|
2008-07-25 00:59:53 +00:00
|
|
|
queueDD(scrollState == kScrollbarStateDown ? kDDScrollbarButtonHover : kDDScrollbarButtonIdle, r2, Graphics::VectorRenderer::kTriangleDown);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-24 18:40:36 +00:00
|
|
|
r2 = r;
|
|
|
|
r2.left += 1;
|
|
|
|
r2.right -= 1;
|
|
|
|
r2.top += sliderY;
|
2011-12-07 14:01:53 +00:00
|
|
|
r2.bottom = r2.top + sliderHeight;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-15 19:10:37 +00:00
|
|
|
r2.top += r.width() / 5;
|
2008-11-04 05:29:53 +00:00
|
|
|
r2.bottom -= r.width() / 5;
|
2008-07-24 18:40:36 +00:00
|
|
|
queueDD(scrollState == kScrollbarStateSlider ? kDDScrollbarHandleHover : kDDScrollbarHandleIdle, r2);
|
2008-07-07 18:37:22 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::drawDialogBackground(const Common::Rect &r, DialogBackground bgtype, WidgetStateInfo state) {
|
2008-07-07 18:37:22 +00:00
|
|
|
if (!ready())
|
|
|
|
return;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-13 17:46:00 +00:00
|
|
|
switch (bgtype) {
|
2009-07-15 18:08:54 +00:00
|
|
|
case kDialogBackgroundMain:
|
|
|
|
queueDD(kDDMainDialogBackground, r);
|
|
|
|
break;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2009-07-15 18:08:54 +00:00
|
|
|
case kDialogBackgroundSpecial:
|
|
|
|
queueDD(kDDSpecialColorBackground, r);
|
|
|
|
break;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2009-07-15 18:08:54 +00:00
|
|
|
case kDialogBackgroundPlain:
|
|
|
|
queueDD(kDDPlainColorBackground, r);
|
|
|
|
break;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2010-07-23 19:36:47 +00:00
|
|
|
case kDialogBackgroundTooltip:
|
|
|
|
queueDD(kDDTooltipBackground, r);
|
|
|
|
break;
|
|
|
|
|
2009-07-15 18:08:54 +00:00
|
|
|
case kDialogBackgroundDefault:
|
|
|
|
queueDD(kDDDefaultBackground, r);
|
|
|
|
break;
|
2008-07-12 01:59:33 +00:00
|
|
|
}
|
2008-07-07 18:37:22 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state) {
|
2008-07-07 18:37:22 +00:00
|
|
|
if (!ready())
|
|
|
|
return;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-07 18:42:47 +00:00
|
|
|
if (erase) {
|
|
|
|
restoreBackground(r);
|
|
|
|
addDirtyRect(r);
|
|
|
|
} else
|
|
|
|
queueDD(kDDCaret, r);
|
2008-07-07 18:37:22 +00:00
|
|
|
}
|
|
|
|
|
2008-11-12 14:30:16 +00:00
|
|
|
void ThemeEngine::drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state, Graphics::TextAlign align) {
|
2008-07-07 18:37:22 +00:00
|
|
|
if (!ready())
|
|
|
|
return;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-12-22 10:31:01 +00:00
|
|
|
DrawData dd = kDDPopUpIdle;
|
|
|
|
|
|
|
|
if (state == kStateEnabled)
|
|
|
|
dd = kDDPopUpIdle;
|
|
|
|
else if (state == kStateHighlight)
|
|
|
|
dd = kDDPopUpHover;
|
|
|
|
else if (state == kStateDisabled)
|
|
|
|
dd = kDDPopUpDisabled;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-20 21:47:28 +00:00
|
|
|
queueDD(dd, r);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-14 18:42:38 +00:00
|
|
|
if (!sel.empty()) {
|
2009-06-06 17:48:46 +00:00
|
|
|
Common::Rect text(r.left + 3, r.top + 1, r.right - 10, r.bottom);
|
2009-08-10 13:46:17 +00:00
|
|
|
queueDDText(getTextData(dd), getTextColor(dd), text, sel, true, false, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV, deltax);
|
2008-07-15 10:50:31 +00:00
|
|
|
}
|
2008-07-07 18:37:22 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::drawSurface(const Common::Rect &r, const Graphics::Surface &surface, WidgetStateInfo state, int alpha, bool themeTrans) {
|
2008-07-07 18:37:22 +00:00
|
|
|
if (!ready())
|
|
|
|
return;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-09 18:34:16 +00:00
|
|
|
queueBitmap(&surface, r, themeTrans);
|
2008-07-07 18:37:22 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background, WidgetStateInfo state) {
|
2008-07-07 18:37:22 +00:00
|
|
|
if (!ready())
|
|
|
|
return;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-13 11:07:56 +00:00
|
|
|
switch (background) {
|
|
|
|
case kWidgetBackgroundBorderSmall:
|
2008-07-20 21:47:28 +00:00
|
|
|
queueDD(kDDWidgetBackgroundSmall, r);
|
2008-07-13 11:07:56 +00:00
|
|
|
break;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-13 11:07:56 +00:00
|
|
|
case kWidgetBackgroundEditText:
|
2008-07-20 21:47:28 +00:00
|
|
|
queueDD(kDDWidgetBackgroundEditText, r);
|
2008-07-13 11:07:56 +00:00
|
|
|
break;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-13 11:07:56 +00:00
|
|
|
case kWidgetBackgroundSlider:
|
2008-07-20 21:47:28 +00:00
|
|
|
queueDD(kDDWidgetBackgroundSlider, r);
|
2008-07-13 11:07:56 +00:00
|
|
|
break;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-13 11:07:56 +00:00
|
|
|
default:
|
2008-07-20 21:47:28 +00:00
|
|
|
queueDD(kDDWidgetBackgroundDefault, r);
|
2008-07-13 11:07:56 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-07-07 18:37:22 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state) {
|
2008-07-07 18:37:22 +00:00
|
|
|
if (!ready())
|
|
|
|
return;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-01 20:19:37 +00:00
|
|
|
queueDD(kDDTabBackground, Common::Rect(r.left, r.top, r.right, r.top + tabHeight));
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-15 18:53:22 +00:00
|
|
|
for (int i = 0; i < (int)tabs.size(); ++i) {
|
|
|
|
if (i == active)
|
|
|
|
continue;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2010-07-24 22:54:56 +00:00
|
|
|
if (r.left + i * tabWidth > r.right || r.left + (i + 1) * tabWidth > r.right)
|
|
|
|
continue;
|
|
|
|
|
2009-07-15 22:19:16 +00:00
|
|
|
Common::Rect tabRect(r.left + i * tabWidth, r.top, r.left + (i + 1) * tabWidth, r.top + tabHeight);
|
2008-07-20 21:47:28 +00:00
|
|
|
queueDD(kDDTabInactive, tabRect);
|
2009-08-10 13:46:17 +00:00
|
|
|
queueDDText(getTextData(kDDTabInactive), getTextColor(kDDTabInactive), tabRect, tabs[i], false, false, _widgets[kDDTabInactive]->_textAlignH, _widgets[kDDTabInactive]->_textAlignV);
|
2008-07-15 18:53:22 +00:00
|
|
|
}
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2010-07-24 22:54:56 +00:00
|
|
|
if (active >= 0 &&
|
2011-04-03 13:04:20 +00:00
|
|
|
(r.left + active * tabWidth < r.right) && (r.left + (active + 1) * tabWidth < r.right)) {
|
2009-07-15 22:19:16 +00:00
|
|
|
Common::Rect tabRect(r.left + active * tabWidth, r.top, r.left + (active + 1) * tabWidth, r.top + tabHeight);
|
|
|
|
const uint16 tabLeft = active * tabWidth;
|
2008-07-22 13:32:18 +00:00
|
|
|
const uint16 tabRight = MAX(r.right - tabRect.right, 0);
|
2008-07-20 21:47:28 +00:00
|
|
|
queueDD(kDDTabActive, tabRect, (tabLeft << 16) | (tabRight & 0xFFFF));
|
2009-08-10 13:46:17 +00:00
|
|
|
queueDDText(getTextData(kDDTabActive), getTextColor(kDDTabActive), tabRect, tabs[active], false, false, _widgets[kDDTabActive]->_textAlignH, _widgets[kDDTabActive]->_textAlignV);
|
2008-07-15 18:53:22 +00:00
|
|
|
}
|
2008-07-07 18:37:22 +00:00
|
|
|
}
|
|
|
|
|
2013-06-13 12:32:36 +00:00
|
|
|
void ThemeEngine::drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, Graphics::TextAlign align, TextInversionState inverted, int deltax, bool useEllipsis, FontStyle font, FontColor color, bool restore, const Common::Rect &drawableTextArea) {
|
2008-07-23 17:57:11 +00:00
|
|
|
if (!ready())
|
2008-11-04 05:29:53 +00:00
|
|
|
return;
|
|
|
|
|
2009-08-10 13:46:17 +00:00
|
|
|
TextColor colorId = kTextColorMAX;
|
|
|
|
|
|
|
|
switch (color) {
|
|
|
|
case kFontColorNormal:
|
|
|
|
if (inverted) {
|
|
|
|
colorId = kTextColorNormalInverted;
|
|
|
|
} else {
|
|
|
|
switch (state) {
|
|
|
|
case kStateDisabled:
|
|
|
|
colorId = kTextColorNormalDisabled;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kStateHighlight:
|
|
|
|
colorId = kTextColorNormalHover;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kStateEnabled:
|
2012-05-03 16:32:08 +00:00
|
|
|
case kStatePressed:
|
2009-08-10 13:46:17 +00:00
|
|
|
colorId = kTextColorNormal;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kFontColorAlternate:
|
|
|
|
if (inverted) {
|
|
|
|
colorId = kTextColorAlternativeInverted;
|
|
|
|
} else {
|
|
|
|
switch (state) {
|
|
|
|
case kStateDisabled:
|
|
|
|
colorId = kTextColorAlternativeDisabled;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kStateHighlight:
|
|
|
|
colorId = kTextColorAlternativeHover;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kStateEnabled:
|
2012-05-03 16:32:08 +00:00
|
|
|
case kStatePressed:
|
2009-08-10 13:46:17 +00:00
|
|
|
colorId = kTextColorAlternative;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-06-15 10:52:35 +00:00
|
|
|
TextData textId = fontStyleToData(font);
|
2009-08-10 13:46:17 +00:00
|
|
|
|
2009-07-15 18:05:37 +00:00
|
|
|
switch (inverted) {
|
|
|
|
case kTextInversion:
|
2008-07-23 16:38:39 +00:00
|
|
|
queueDD(kDDTextSelectionBackground, r);
|
2009-08-10 13:46:17 +00:00
|
|
|
restore = false;
|
|
|
|
break;
|
2009-07-15 18:05:37 +00:00
|
|
|
|
|
|
|
case kTextInversionFocus:
|
|
|
|
queueDD(kDDTextSelectionFocusBackground, r);
|
2009-08-10 13:46:17 +00:00
|
|
|
restore = false;
|
2009-07-15 18:05:37 +00:00
|
|
|
break;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2009-07-15 18:08:54 +00:00
|
|
|
default:
|
|
|
|
break;
|
2008-08-07 18:42:47 +00:00
|
|
|
}
|
2008-07-23 17:57:11 +00:00
|
|
|
|
2013-06-13 12:32:36 +00:00
|
|
|
queueDDText(textId, colorId, r, str, restore, useEllipsis, align, kTextAlignVCenter, deltax, drawableTextArea);
|
2008-07-15 10:50:31 +00:00
|
|
|
}
|
|
|
|
|
2009-08-10 13:46:17 +00:00
|
|
|
void ThemeEngine::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state, FontColor color) {
|
2008-08-08 18:30:16 +00:00
|
|
|
if (!ready())
|
|
|
|
return;
|
2008-10-18 00:29:23 +00:00
|
|
|
|
|
|
|
Common::Rect charArea = r;
|
2009-01-01 21:41:55 +00:00
|
|
|
charArea.clip(_screen.w, _screen.h);
|
2008-10-18 01:44:12 +00:00
|
|
|
|
2009-08-10 13:46:17 +00:00
|
|
|
uint32 rgbColor = _overlayFormat.RGBToColor(_textColors[color]->r, _textColors[color]->g, _textColors[color]->b);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-10-18 00:29:23 +00:00
|
|
|
restoreBackground(charArea);
|
2009-08-10 13:46:17 +00:00
|
|
|
font->drawChar(&_screen, ch, charArea.left, charArea.top, rgbColor);
|
2008-10-18 00:29:23 +00:00
|
|
|
addDirtyRect(charArea);
|
2008-08-08 18:30:16 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::debugWidgetPosition(const char *name, const Common::Rect &r) {
|
2009-01-01 21:41:55 +00:00
|
|
|
_font->drawString(&_screen, name, r.left, r.top, r.width(), 0xFFFF, Graphics::kTextAlignRight, 0, true);
|
|
|
|
_screen.hLine(r.left, r.top, r.right, 0xFFFF);
|
|
|
|
_screen.hLine(r.left, r.bottom, r.right, 0xFFFF);
|
|
|
|
_screen.vLine(r.left, r.top, r.bottom, 0xFFFF);
|
|
|
|
_screen.vLine(r.right, r.top, r.bottom, 0xFFFF);
|
2008-06-12 19:06:37 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
/**********************************************************
|
2011-04-03 13:04:20 +00:00
|
|
|
* Screen/overlay management
|
2008-09-02 17:51:08 +00:00
|
|
|
*********************************************************/
|
2011-02-24 21:32:32 +00:00
|
|
|
void ThemeEngine::updateScreen(bool render) {
|
2008-07-20 21:47:28 +00:00
|
|
|
if (!_bufferQueue.empty()) {
|
2009-01-01 21:41:55 +00:00
|
|
|
_vectorRenderer->setSurface(&_backBuffer);
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
for (Common::List<ThemeItem *>::iterator q = _bufferQueue.begin(); q != _bufferQueue.end(); ++q) {
|
2008-09-02 17:51:08 +00:00
|
|
|
(*q)->drawSelf(true, false);
|
|
|
|
delete *q;
|
|
|
|
}
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2009-01-01 21:41:55 +00:00
|
|
|
_vectorRenderer->setSurface(&_screen);
|
2013-08-03 00:36:28 +00:00
|
|
|
memcpy(_screen.getPixels(), _backBuffer.getPixels(), _screen.pitch * _screen.h);
|
2008-07-20 21:47:28 +00:00
|
|
|
_bufferQueue.clear();
|
|
|
|
}
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-20 21:47:28 +00:00
|
|
|
if (!_screenQueue.empty()) {
|
|
|
|
_vectorRenderer->disableShadows();
|
2011-04-03 13:04:20 +00:00
|
|
|
for (Common::List<ThemeItem *>::iterator q = _screenQueue.begin(); q != _screenQueue.end(); ++q) {
|
2008-09-02 17:51:08 +00:00
|
|
|
(*q)->drawSelf(true, false);
|
|
|
|
delete *q;
|
|
|
|
}
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-20 21:47:28 +00:00
|
|
|
_vectorRenderer->enableShadows();
|
|
|
|
_screenQueue.clear();
|
|
|
|
}
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2011-02-24 21:32:32 +00:00
|
|
|
if (render)
|
|
|
|
renderDirtyScreen();
|
2008-07-03 19:42:04 +00:00
|
|
|
}
|
|
|
|
|
2009-04-09 17:07:38 +00:00
|
|
|
void ThemeEngine::addDirtyRect(Common::Rect r) {
|
|
|
|
// Clip the rect to screen coords
|
|
|
|
r.clip(_screen.w, _screen.h);
|
|
|
|
|
|
|
|
// If it is empty after clipping, we are done
|
|
|
|
if (r.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Check if the new rectangle is contained within another in the list
|
|
|
|
Common::List<Common::Rect>::iterator it;
|
2011-04-03 13:04:20 +00:00
|
|
|
for (it = _dirtyScreen.begin(); it != _dirtyScreen.end();) {
|
2009-04-09 17:07:38 +00:00
|
|
|
// If we find a rectangle which fully contains the new one,
|
|
|
|
// we can abort the search.
|
|
|
|
if (it->contains(r))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Conversely, if we find rectangles which are contained in
|
|
|
|
// the new one, we can remove them
|
|
|
|
if (r.contains(*it))
|
|
|
|
it = _dirtyScreen.erase(it);
|
2009-04-10 14:06:21 +00:00
|
|
|
else
|
2009-04-09 17:07:38 +00:00
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we got here, we can safely add r to the list of dirty rects.
|
|
|
|
_dirtyScreen.push_back(r);
|
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::renderDirtyScreen() {
|
2008-07-02 18:11:41 +00:00
|
|
|
if (_dirtyScreen.empty())
|
|
|
|
return;
|
2008-07-22 12:07:03 +00:00
|
|
|
|
2009-10-09 22:21:45 +00:00
|
|
|
Common::List<Common::Rect>::iterator i;
|
2008-07-22 17:39:30 +00:00
|
|
|
for (i = _dirtyScreen.begin(); i != _dirtyScreen.end(); ++i) {
|
|
|
|
_vectorRenderer->copyFrame(_system, *i);
|
2008-07-22 09:23:37 +00:00
|
|
|
}
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-07-02 18:11:41 +00:00
|
|
|
_dirtyScreen.clear();
|
2008-05-28 14:27:22 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 17:51:08 +00:00
|
|
|
void ThemeEngine::openDialog(bool doBuffer, ShadingStyle style) {
|
2008-07-18 16:44:42 +00:00
|
|
|
if (doBuffer)
|
|
|
|
_buffering = true;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-08-02 16:23:58 +00:00
|
|
|
if (style != kShadingNone) {
|
|
|
|
_vectorRenderer->applyScreenShading(style);
|
2009-01-01 21:41:55 +00:00
|
|
|
addDirtyRect(Common::Rect(0, 0, _screen.w, _screen.h));
|
2008-08-02 16:23:58 +00:00
|
|
|
}
|
2008-07-17 21:58:43 +00:00
|
|
|
|
2013-08-03 00:36:28 +00:00
|
|
|
memcpy(_backBuffer.getPixels(), _screen.getPixels(), _screen.pitch * _screen.h);
|
2009-01-01 21:41:55 +00:00
|
|
|
_vectorRenderer->setSurface(&_screen);
|
2008-08-10 11:09:28 +00:00
|
|
|
}
|
|
|
|
|
2012-06-03 00:02:57 +00:00
|
|
|
bool ThemeEngine::createCursor(const Common::String &filename, int hotspotX, int hotspotY) {
|
2011-06-03 21:30:55 +00:00
|
|
|
if (!_system->hasFeature(OSystem::kFeatureCursorPalette))
|
2008-09-07 21:45:18 +00:00
|
|
|
return true;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2008-11-03 16:00:13 +00:00
|
|
|
// Try to locate the specified file among all loaded bitmaps
|
2008-11-09 15:14:01 +00:00
|
|
|
const Graphics::Surface *cursor = _bitmaps[filename];
|
2008-08-10 11:09:28 +00:00
|
|
|
if (!cursor)
|
2008-08-10 17:22:12 +00:00
|
|
|
return false;
|
2008-11-04 05:29:53 +00:00
|
|
|
|
2009-08-21 18:16:37 +00:00
|
|
|
#ifdef USE_RGB_COLOR
|
2009-06-13 10:24:52 +00:00
|
|
|
_cursorFormat.bytesPerPixel = 1;
|
|
|
|
_cursorFormat.rLoss = _cursorFormat.gLoss = _cursorFormat.bLoss = _cursorFormat.aLoss = 8;
|
|
|
|
_cursorFormat.rShift = _cursorFormat.gShift = _cursorFormat.bShift = _cursorFormat.aShift = 0;
|
|
|
|
#endif
|
|
|
|
|
2008-11-03 16:00:13 +00:00
|
|
|
// Set up the cursor parameters
|
2008-08-10 17:22:12 +00:00
|
|
|
_cursorHotspotX = hotspotX;
|
|
|
|
_cursorHotspotY = hotspotY;
|
2008-08-10 11:09:28 +00:00
|
|
|
|
|
|
|
_cursorWidth = cursor->w;
|
|
|
|
_cursorHeight = cursor->h;
|
|
|
|
|
2008-11-03 16:00:13 +00:00
|
|
|
// Allocate a new buffer for the cursor
|
2008-08-10 11:09:28 +00:00
|
|
|
delete[] _cursor;
|
|
|
|
_cursor = new byte[_cursorWidth * _cursorHeight];
|
|
|
|
assert(_cursor);
|
2008-11-03 15:15:32 +00:00
|
|
|
memset(_cursor, 0xFF, sizeof(byte) * _cursorWidth * _cursorHeight);
|
2008-08-10 11:09:28 +00:00
|
|
|
|
2009-08-30 16:58:55 +00:00
|
|
|
// the transparent color is 0xFF00FF
|
2012-06-20 16:39:03 +00:00
|
|
|
const uint32 colTransparent = _overlayFormat.RGBToColor(0xFF, 0, 0xFF);
|
2009-08-30 16:58:55 +00:00
|
|
|
|
2008-11-03 16:00:13 +00:00
|
|
|
// Now, scan the bitmap. We have to convert it from 16 bit color mode
|
|
|
|
// to 8 bit mode, and have to create a suitable palette on the fly.
|
|
|
|
uint colorsFound = 0;
|
2011-04-03 13:04:20 +00:00
|
|
|
Common::HashMap<int, int> colorToIndex;
|
2012-06-20 16:39:03 +00:00
|
|
|
const byte *src = (const byte *)cursor->getPixels();
|
2008-08-10 11:09:28 +00:00
|
|
|
for (uint y = 0; y < _cursorHeight; ++y) {
|
|
|
|
for (uint x = 0; x < _cursorWidth; ++x) {
|
2012-06-20 16:39:03 +00:00
|
|
|
uint32 color = colTransparent;
|
2008-11-03 16:00:13 +00:00
|
|
|
byte r, g, b;
|
|
|
|
|
2012-06-20 16:39:03 +00:00
|
|
|
if (cursor->format.bytesPerPixel == 2) {
|
|
|
|
color = READ_UINT16(src);
|
|
|
|
} else if (cursor->format.bytesPerPixel == 4) {
|
|
|
|
color = READ_UINT32(src);
|
|
|
|
}
|
|
|
|
|
|
|
|
src += cursor->format.bytesPerPixel;
|
|
|
|
|
2009-08-30 16:58:55 +00:00
|
|
|
// Skip transparency
|
2012-06-20 16:39:03 +00:00
|
|
|
if (color == colTransparent)
|
2008-11-03 16:00:13 +00:00
|
|
|
continue;
|
|
|
|
|
2012-06-20 16:39:03 +00:00
|
|
|
cursor->format.colorToRGB(color, r, g, b);
|
2009-08-30 16:58:55 +00:00
|
|
|
const int col = (r << 16) | (g << 8) | b;
|
|
|
|
|
2008-11-03 16:00:13 +00:00
|
|
|
// If there is no entry yet for this color in the palette: Add one
|
|
|
|
if (!colorToIndex.contains(col)) {
|
2013-10-27 19:42:03 +00:00
|
|
|
if (colorsFound >= MAX_CURS_COLORS) {
|
|
|
|
warning("Cursor contains too many colors (%d, but only %d are allowed)", colorsFound, MAX_CURS_COLORS);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-11-03 15:15:32 +00:00
|
|
|
const int index = colorsFound++;
|
|
|
|
colorToIndex[col] = index;
|
2008-08-10 11:09:28 +00:00
|
|
|
|
2011-02-13 13:58:44 +00:00
|
|
|
_cursorPal[index * 3 + 0] = r;
|
|
|
|
_cursorPal[index * 3 + 1] = g;
|
|
|
|
_cursorPal[index * 3 + 2] = b;
|
2008-08-10 11:09:28 +00:00
|
|
|
}
|
|
|
|
|
2008-11-03 16:00:13 +00:00
|
|
|
// Copy pixel from the 16 bit source surface to the 8bit target surface
|
|
|
|
const int index = colorToIndex[col];
|
|
|
|
_cursor[y * _cursorWidth + x] = index;
|
2008-08-10 11:09:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_useCursor = true;
|
2009-01-14 02:44:09 +00:00
|
|
|
_cursorPalSize = colorsFound;
|
2008-11-03 15:15:32 +00:00
|
|
|
|
2008-08-10 17:22:12 +00:00
|
|
|
return true;
|
2008-08-10 11:09:28 +00:00
|
|
|
}
|
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
|
|
|
|
/**********************************************************
|
2011-04-03 13:04:20 +00:00
|
|
|
* Legacy GUI::Theme support functions
|
2008-11-10 11:24:55 +00:00
|
|
|
*********************************************************/
|
|
|
|
|
2008-11-08 00:54:58 +00:00
|
|
|
const Graphics::Font *ThemeEngine::getFont(FontStyle font) const {
|
|
|
|
return _texts[fontStyleToData(font)]->_fontPtr;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ThemeEngine::getFontHeight(FontStyle font) const {
|
|
|
|
return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getFontHeight() : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ThemeEngine::getStringWidth(const Common::String &str, FontStyle font) const {
|
|
|
|
return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getStringWidth(str) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ThemeEngine::getCharWidth(byte c, FontStyle font) const {
|
|
|
|
return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getCharWidth(c) : 0;
|
|
|
|
}
|
|
|
|
|
2012-01-08 01:33:34 +00:00
|
|
|
int ThemeEngine::getKerningOffset(byte left, byte right, FontStyle font) const {
|
|
|
|
return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getKerningOffset(left, right) : 0;
|
|
|
|
}
|
|
|
|
|
2009-01-17 17:13:04 +00:00
|
|
|
TextData ThemeEngine::getTextData(DrawData ddId) const {
|
2008-11-08 00:54:58 +00:00
|
|
|
return _widgets[ddId] ? (TextData)_widgets[ddId]->_textDataId : kTextDataNone;
|
|
|
|
}
|
|
|
|
|
2009-08-10 13:46:17 +00:00
|
|
|
TextColor ThemeEngine::getTextColor(DrawData ddId) const {
|
|
|
|
return _widgets[ddId] ? _widgets[ddId]->_textColorId : kTextColorMAX;
|
|
|
|
}
|
2008-11-08 00:54:58 +00:00
|
|
|
|
2009-01-18 14:48:00 +00:00
|
|
|
DrawData ThemeEngine::parseDrawDataId(const Common::String &name) const {
|
2009-01-17 17:13:04 +00:00
|
|
|
for (int i = 0; i < kDrawDataMAX; ++i)
|
|
|
|
if (name.compareToIgnoreCase(kDrawDataDefaults[i].name) == 0)
|
|
|
|
return kDrawDataDefaults[i].id;
|
|
|
|
|
|
|
|
return kDDNone;
|
|
|
|
}
|
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
/**********************************************************
|
2011-04-03 13:04:20 +00:00
|
|
|
* External data loading
|
2008-11-10 11:24:55 +00:00
|
|
|
*********************************************************/
|
|
|
|
|
2012-01-07 01:51:50 +00:00
|
|
|
const Graphics::Font *ThemeEngine::loadScalableFont(const Common::String &filename, const Common::String &charset, const int pointsize, Common::String &name) {
|
|
|
|
#ifdef USE_FREETYPE2
|
|
|
|
name = Common::String::format("%s-%s@%d", filename.c_str(), charset.c_str(), pointsize);
|
|
|
|
|
2012-01-06 23:34:03 +00:00
|
|
|
// Try already loaded fonts.
|
2012-01-07 01:51:50 +00:00
|
|
|
const Graphics::Font *font = FontMan.getFontByName(name);
|
2012-01-06 23:34:03 +00:00
|
|
|
if (font)
|
|
|
|
return font;
|
|
|
|
|
2012-01-07 01:51:50 +00:00
|
|
|
Common::ArchiveMemberList members;
|
|
|
|
_themeFiles.listMatchingMembers(members, filename);
|
|
|
|
|
|
|
|
for (Common::ArchiveMemberList::const_iterator i = members.begin(), end = members.end(); i != end; ++i) {
|
|
|
|
Common::SeekableReadStream *stream = (*i)->createReadStream();
|
|
|
|
if (stream) {
|
2014-06-08 23:04:47 +00:00
|
|
|
font = Graphics::loadTTFFont(*stream, pointsize, 0, Graphics::kTTFRenderModeLight,
|
2012-01-29 18:18:36 +00:00
|
|
|
#ifdef USE_TRANSLATION
|
|
|
|
TransMan.getCharsetMapping()
|
|
|
|
#else
|
|
|
|
0
|
|
|
|
#endif
|
|
|
|
);
|
2012-01-07 01:51:50 +00:00
|
|
|
delete stream;
|
|
|
|
|
|
|
|
if (font)
|
|
|
|
return font;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Graphics::Font *ThemeEngine::loadFont(const Common::String &filename, Common::String &name) {
|
|
|
|
name = filename;
|
|
|
|
|
|
|
|
// Try already loaded fonts.
|
|
|
|
const Graphics::Font *font = FontMan.getFontByName(name);
|
|
|
|
if (font)
|
|
|
|
return font;
|
2008-11-10 11:24:55 +00:00
|
|
|
|
2012-01-06 20:55:58 +00:00
|
|
|
Common::ArchiveMemberList members;
|
2012-01-07 01:51:50 +00:00
|
|
|
const Common::String cacheFilename(genCacheFilename(filename));
|
2012-01-06 20:55:58 +00:00
|
|
|
_themeFiles.listMatchingMembers(members, cacheFilename);
|
|
|
|
_themeFiles.listMatchingMembers(members, filename);
|
2008-11-10 11:24:55 +00:00
|
|
|
|
2012-01-06 20:55:58 +00:00
|
|
|
for (Common::ArchiveMemberList::const_iterator i = members.begin(), end = members.end(); i != end; ++i) {
|
|
|
|
Common::SeekableReadStream *stream = (*i)->createReadStream();
|
|
|
|
if (stream) {
|
2012-01-06 21:27:26 +00:00
|
|
|
if ((*i)->getName().equalsIgnoreCase(cacheFilename)) {
|
2012-01-06 20:55:58 +00:00
|
|
|
font = Graphics::BdfFont::loadFromCache(*stream);
|
|
|
|
} else {
|
|
|
|
font = Graphics::BdfFont::loadFont(*stream);
|
|
|
|
if (font && !cacheFilename.empty()) {
|
|
|
|
if (!Graphics::BdfFont::cacheFontData(*(const Graphics::BdfFont *)font, cacheFilename))
|
|
|
|
warning("Couldn't create cache file for font '%s'", filename.c_str());
|
|
|
|
}
|
2008-11-10 11:24:55 +00:00
|
|
|
}
|
2012-01-06 20:55:58 +00:00
|
|
|
delete stream;
|
|
|
|
|
2012-01-07 01:51:50 +00:00
|
|
|
if (font)
|
|
|
|
return font;
|
|
|
|
}
|
2008-11-10 11:24:55 +00:00
|
|
|
}
|
|
|
|
|
2012-01-07 01:51:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Graphics::Font *ThemeEngine::loadFont(const Common::String &filename, const Common::String &scalableFilename, const Common::String &charset, const int pointsize, const bool makeLocalizedFont) {
|
|
|
|
Common::String fontName;
|
|
|
|
|
|
|
|
const Graphics::Font *font = 0;
|
|
|
|
|
|
|
|
// Prefer scalable fonts over non-scalable fonts
|
|
|
|
font = loadScalableFont(scalableFilename, charset, pointsize, fontName);
|
|
|
|
if (!font)
|
|
|
|
font = loadFont(filename, fontName);
|
|
|
|
|
2012-01-06 23:34:03 +00:00
|
|
|
// If the font is successfully loaded store it in the font manager.
|
2012-01-07 00:00:31 +00:00
|
|
|
if (font) {
|
2012-01-07 01:51:50 +00:00
|
|
|
FontMan.assignFontToName(fontName, font);
|
2012-01-07 00:00:31 +00:00
|
|
|
// If this font should be the new default localized font, we set it up
|
|
|
|
// for that.
|
|
|
|
if (makeLocalizedFont)
|
2012-01-07 01:51:50 +00:00
|
|
|
FontMan.setLocalizedFont(fontName);
|
2012-01-07 00:00:31 +00:00
|
|
|
}
|
2012-01-07 01:51:50 +00:00
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
return font;
|
|
|
|
}
|
|
|
|
|
2010-11-15 23:51:46 +00:00
|
|
|
Common::String ThemeEngine::genCacheFilename(const Common::String &filename) const {
|
2008-11-10 11:24:55 +00:00
|
|
|
Common::String cacheName(filename);
|
|
|
|
for (int i = cacheName.size() - 1; i >= 0; --i) {
|
|
|
|
if (cacheName[i] == '.') {
|
|
|
|
while ((uint)i < cacheName.size() - 1) {
|
|
|
|
cacheName.deleteLastChar();
|
|
|
|
}
|
|
|
|
|
|
|
|
cacheName += "fcc";
|
|
|
|
return cacheName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-02 22:16:33 +00:00
|
|
|
return Common::String();
|
2008-11-10 11:24:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************
|
2011-04-03 13:04:20 +00:00
|
|
|
* Static Theme XML functions
|
2008-11-10 11:24:55 +00:00
|
|
|
*********************************************************/
|
|
|
|
|
2008-12-22 11:22:15 +00:00
|
|
|
bool ThemeEngine::themeConfigParseHeader(Common::String header, Common::String &themeName) {
|
2011-04-25 02:45:36 +00:00
|
|
|
// Check that header is not corrupted
|
2011-04-26 12:24:38 +00:00
|
|
|
if ((byte)header[0] > 127) {
|
2011-04-25 02:45:36 +00:00
|
|
|
warning("Corrupted theme header found");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
header.trim();
|
|
|
|
|
|
|
|
if (header.empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (header[0] != '[' || header.lastChar() != ']')
|
|
|
|
return false;
|
|
|
|
|
|
|
|
header.deleteChar(0);
|
|
|
|
header.deleteLastChar();
|
|
|
|
|
|
|
|
Common::StringTokenizer tok(header, ":");
|
|
|
|
|
|
|
|
if (tok.nextToken() != SCUMMVM_THEME_VERSION_STR)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
themeName = tok.nextToken();
|
|
|
|
Common::String author = tok.nextToken();
|
|
|
|
|
|
|
|
return tok.empty();
|
|
|
|
}
|
|
|
|
|
2010-07-19 14:28:46 +00:00
|
|
|
bool ThemeEngine::themeConfigUsable(const Common::ArchiveMember &member, Common::String &themeName) {
|
|
|
|
Common::File stream;
|
|
|
|
bool foundHeader = false;
|
|
|
|
|
2011-05-07 13:49:57 +00:00
|
|
|
if (member.getName().matchString("*.zip", true)) {
|
2010-07-19 14:28:46 +00:00
|
|
|
Common::Archive *zipArchive = Common::makeZipArchive(member.createReadStream());
|
|
|
|
|
|
|
|
if (zipArchive && zipArchive->hasFile("THEMERC")) {
|
|
|
|
stream.open("THEMERC", *zipArchive);
|
|
|
|
}
|
|
|
|
|
|
|
|
delete zipArchive;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stream.isOpen()) {
|
|
|
|
Common::String stxHeader = stream.readLine();
|
|
|
|
foundHeader = themeConfigParseHeader(stxHeader, themeName);
|
|
|
|
}
|
|
|
|
|
|
|
|
return foundHeader;
|
|
|
|
}
|
|
|
|
|
2009-01-02 21:24:13 +00:00
|
|
|
bool ThemeEngine::themeConfigUsable(const Common::FSNode &node, Common::String &themeName) {
|
2008-11-10 11:24:55 +00:00
|
|
|
Common::File stream;
|
|
|
|
bool foundHeader = false;
|
|
|
|
|
2011-05-07 13:49:57 +00:00
|
|
|
if (node.getName().matchString("*.zip", true) && !node.isDirectory()) {
|
2010-02-13 11:56:30 +00:00
|
|
|
Common::Archive *zipArchive = Common::makeZipArchive(node);
|
|
|
|
if (zipArchive && zipArchive->hasFile("THEMERC")) {
|
|
|
|
// Open THEMERC from the ZIP file.
|
|
|
|
stream.open("THEMERC", *zipArchive);
|
2008-11-10 11:24:55 +00:00
|
|
|
}
|
2010-02-13 11:56:30 +00:00
|
|
|
// Delete the ZIP archive again. Note: This only works because
|
|
|
|
// stream.open() only uses ZipArchive::createReadStreamForMember,
|
|
|
|
// and that in turn happens to read all the data for a given
|
|
|
|
// archive member into a memory block. So there will be no dangling
|
|
|
|
// reference to zipArchive anywhere. This could change if we
|
|
|
|
// ever modify ZipArchive::createReadStreamForMember.
|
|
|
|
delete zipArchive;
|
2008-12-22 11:22:15 +00:00
|
|
|
} else if (node.isDirectory()) {
|
2008-11-10 11:24:55 +00:00
|
|
|
Common::FSNode headerfile = node.getChild("THEMERC");
|
|
|
|
if (!headerfile.exists() || !headerfile.isReadable() || headerfile.isDirectory())
|
|
|
|
return false;
|
|
|
|
stream.open(headerfile);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stream.isOpen()) {
|
|
|
|
Common::String stxHeader = stream.readLine();
|
|
|
|
foundHeader = themeConfigParseHeader(stxHeader, themeName);
|
|
|
|
}
|
|
|
|
|
|
|
|
return foundHeader;
|
|
|
|
}
|
|
|
|
|
2009-01-02 21:24:13 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
struct TDComparator {
|
|
|
|
const Common::String _id;
|
|
|
|
TDComparator(const Common::String &id) : _id(id) {}
|
|
|
|
|
2011-04-03 13:04:20 +00:00
|
|
|
bool operator()(const ThemeEngine::ThemeDescriptor &r) {
|
|
|
|
return _id == r.id;
|
|
|
|
}
|
2009-01-02 21:24:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // end of anonymous namespace
|
|
|
|
|
|
|
|
void ThemeEngine::listUsableThemes(Common::List<ThemeDescriptor> &list) {
|
2010-09-28 20:31:17 +00:00
|
|
|
#ifndef DISABLE_GUI_BUILTIN_THEME
|
2009-01-02 21:24:13 +00:00
|
|
|
ThemeDescriptor th;
|
|
|
|
th.name = "ScummVM Classic Theme (Builtin Version)";
|
|
|
|
th.id = "builtin";
|
2009-01-02 22:16:33 +00:00
|
|
|
th.filename.clear();
|
2009-01-02 21:24:13 +00:00
|
|
|
list.push_back(th);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (ConfMan.hasKey("themepath"))
|
|
|
|
listUsableThemes(Common::FSNode(ConfMan.get("themepath")), list);
|
|
|
|
|
2010-07-19 14:28:46 +00:00
|
|
|
listUsableThemes(SearchMan, list);
|
2009-01-02 21:24:13 +00:00
|
|
|
|
|
|
|
// Now we need to strip all duplicates
|
|
|
|
// TODO: It might not be the best idea to strip duplicates. The user might
|
|
|
|
// have different versions of a specific theme in his paths, thus this code
|
|
|
|
// might show him the wrong version. The problem is we have no ways of checking
|
|
|
|
// a theme version currently. Also since we want to avoid saving the full path
|
|
|
|
// in the config file we can not do any better currently.
|
|
|
|
Common::List<ThemeDescriptor> output;
|
|
|
|
|
|
|
|
for (Common::List<ThemeDescriptor>::const_iterator i = list.begin(); i != list.end(); ++i) {
|
2009-03-09 22:26:02 +00:00
|
|
|
if (Common::find_if(output.begin(), output.end(), TDComparator(i->id)) == output.end())
|
2009-01-02 21:24:13 +00:00
|
|
|
output.push_back(*i);
|
|
|
|
}
|
|
|
|
|
|
|
|
list = output;
|
|
|
|
output.clear();
|
|
|
|
}
|
|
|
|
|
2010-07-19 14:28:46 +00:00
|
|
|
void ThemeEngine::listUsableThemes(Common::Archive &archive, Common::List<ThemeDescriptor> &list) {
|
|
|
|
ThemeDescriptor td;
|
|
|
|
|
|
|
|
Common::ArchiveMemberList fileList;
|
|
|
|
archive.listMatchingMembers(fileList, "*.zip");
|
|
|
|
for (Common::ArchiveMemberList::iterator i = fileList.begin();
|
2011-04-03 13:04:20 +00:00
|
|
|
i != fileList.end(); ++i) {
|
2010-07-19 14:28:46 +00:00
|
|
|
td.name.clear();
|
|
|
|
if (themeConfigUsable(**i, td.name)) {
|
|
|
|
td.filename = (*i)->getName();
|
|
|
|
td.id = (*i)->getDisplayName();
|
|
|
|
|
|
|
|
// If the name of the node object also contains
|
|
|
|
// the ".zip" suffix, we will strip it.
|
2011-05-07 13:49:57 +00:00
|
|
|
if (td.id.matchString("*.zip", true)) {
|
2010-07-19 14:28:46 +00:00
|
|
|
for (int j = 0; j < 4; ++j)
|
|
|
|
td.id.deleteLastChar();
|
|
|
|
}
|
|
|
|
|
|
|
|
list.push_back(td);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fileList.clear();
|
|
|
|
}
|
|
|
|
|
2009-06-28 19:57:27 +00:00
|
|
|
void ThemeEngine::listUsableThemes(const Common::FSNode &node, Common::List<ThemeDescriptor> &list, int depth) {
|
2009-01-02 21:24:13 +00:00
|
|
|
if (!node.exists() || !node.isReadable() || !node.isDirectory())
|
|
|
|
return;
|
|
|
|
|
|
|
|
ThemeDescriptor td;
|
|
|
|
|
|
|
|
// Check whether we point to a valid theme directory.
|
|
|
|
if (themeConfigUsable(node, td.name)) {
|
|
|
|
td.filename = node.getPath();
|
|
|
|
td.id = node.getName();
|
|
|
|
|
|
|
|
list.push_back(td);
|
|
|
|
|
|
|
|
// A theme directory should never contain any other themes
|
|
|
|
// thus we just return to the caller here.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Common::FSList fileList;
|
|
|
|
// Check all files. We need this to find all themes inside ZIP archives.
|
|
|
|
if (!node.getChildren(fileList, Common::FSNode::kListFilesOnly))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (Common::FSList::iterator i = fileList.begin(); i != fileList.end(); ++i) {
|
|
|
|
// We will only process zip files for now
|
2011-05-07 13:49:57 +00:00
|
|
|
if (!i->getPath().matchString("*.zip", true))
|
2009-01-02 21:24:13 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
td.name.clear();
|
|
|
|
if (themeConfigUsable(*i, td.name)) {
|
|
|
|
td.filename = i->getPath();
|
|
|
|
td.id = i->getName();
|
|
|
|
|
|
|
|
// If the name of the node object also contains
|
|
|
|
// the ".zip" suffix, we will strip it.
|
2011-05-07 13:49:57 +00:00
|
|
|
if (td.id.matchString("*.zip", true)) {
|
2009-01-02 21:24:13 +00:00
|
|
|
for (int j = 0; j < 4; ++j)
|
|
|
|
td.id.deleteLastChar();
|
|
|
|
}
|
|
|
|
|
|
|
|
list.push_back(td);
|
|
|
|
}
|
|
|
|
}
|
2009-05-24 15:17:42 +00:00
|
|
|
|
2009-01-02 21:24:13 +00:00
|
|
|
fileList.clear();
|
2009-05-24 15:17:42 +00:00
|
|
|
|
2009-01-03 16:24:10 +00:00
|
|
|
// Check if we exceeded the given recursion depth
|
|
|
|
if (depth - 1 == -1)
|
|
|
|
return;
|
|
|
|
|
2009-01-02 21:24:13 +00:00
|
|
|
// As next step we will search all subdirectories
|
|
|
|
if (!node.getChildren(fileList, Common::FSNode::kListDirectoriesOnly))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (Common::FSList::iterator i = fileList.begin(); i != fileList.end(); ++i)
|
2009-01-03 16:24:10 +00:00
|
|
|
listUsableThemes(*i, list, depth == -1 ? - 1 : depth - 1);
|
2009-01-02 21:24:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Common::String ThemeEngine::getThemeFile(const Common::String &id) {
|
|
|
|
// FIXME: Actually "default" rather sounds like it should use
|
|
|
|
// our default theme which would mean "scummmodern" instead
|
|
|
|
// of the builtin one.
|
|
|
|
if (id.equalsIgnoreCase("default"))
|
2009-01-02 22:16:33 +00:00
|
|
|
return Common::String();
|
2009-05-24 15:17:42 +00:00
|
|
|
|
2009-01-03 16:24:10 +00:00
|
|
|
// For our builtin theme we don't have to do anything for now too
|
|
|
|
if (id.equalsIgnoreCase("builtin"))
|
|
|
|
return Common::String();
|
2009-01-02 21:24:13 +00:00
|
|
|
|
|
|
|
Common::FSNode node(id);
|
|
|
|
|
|
|
|
// If the given id is a full path we'll just use it
|
2011-05-07 13:49:57 +00:00
|
|
|
if (node.exists() && (node.isDirectory() || node.getName().matchString("*.zip", true)))
|
2009-01-02 21:24:13 +00:00
|
|
|
return id;
|
|
|
|
|
|
|
|
// FIXME:
|
|
|
|
// A very ugly hack to map a id to a filename, this will generate
|
|
|
|
// a complete theme list, thus it is slower than it could be.
|
|
|
|
// But it is the easiest solution for now.
|
|
|
|
Common::List<ThemeDescriptor> list;
|
|
|
|
listUsableThemes(list);
|
|
|
|
|
|
|
|
for (Common::List<ThemeDescriptor>::const_iterator i = list.begin(); i != list.end(); ++i) {
|
|
|
|
if (id.equalsIgnoreCase(i->id))
|
|
|
|
return i->filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
warning("Could not find theme '%s' falling back to builtin", id.c_str());
|
|
|
|
|
|
|
|
// If no matching id has been found we will
|
|
|
|
// just fall back to the builtin theme
|
2009-01-02 22:16:33 +00:00
|
|
|
return Common::String();
|
2009-01-02 21:24:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Common::String ThemeEngine::getThemeId(const Common::String &filename) {
|
|
|
|
// If no filename has been given we will initialize the builtin theme
|
|
|
|
if (filename.empty())
|
|
|
|
return "builtin";
|
|
|
|
|
|
|
|
Common::FSNode node(filename);
|
|
|
|
if (!node.exists())
|
|
|
|
return "builtin";
|
|
|
|
|
2011-05-07 13:49:57 +00:00
|
|
|
if (node.getName().matchString("*.zip", true)) {
|
2009-01-02 21:24:13 +00:00
|
|
|
Common::String id = node.getName();
|
|
|
|
|
|
|
|
for (int i = 0; i < 4; ++i)
|
|
|
|
id.deleteLastChar();
|
|
|
|
|
|
|
|
return id;
|
|
|
|
} else {
|
|
|
|
return node.getName();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-16 21:18:09 +00:00
|
|
|
void ThemeEngine::showCursor() {
|
|
|
|
if (_useCursor) {
|
|
|
|
CursorMan.pushCursorPalette(_cursorPal, 0, _cursorPalSize);
|
|
|
|
CursorMan.pushCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, true);
|
|
|
|
CursorMan.showMouse(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThemeEngine::hideCursor() {
|
|
|
|
if (_useCursor) {
|
|
|
|
CursorMan.popCursorPalette();
|
|
|
|
CursorMan.popCursor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-10 11:24:55 +00:00
|
|
|
|
2009-10-04 21:26:33 +00:00
|
|
|
} // End of namespace GUI.
|