aboutsummaryrefslogtreecommitdiff
path: root/gui
diff options
context:
space:
mode:
authorD G Turner2012-10-12 17:03:32 +0100
committerD G Turner2012-10-12 17:03:32 +0100
commit151b7beb47ec4b964862d6779bd48e3a33482bbd (patch)
tree867717c5266d0908d95edd82560599be20a4ede9 /gui
parent80af0e239473f85c49cc2da3c848dfcde41d4a37 (diff)
parent2b55837650c4229dc3d75b660cecfc7a3292e5e0 (diff)
downloadscummvm-rg350-151b7beb47ec4b964862d6779bd48e3a33482bbd.tar.gz
scummvm-rg350-151b7beb47ec4b964862d6779bd48e3a33482bbd.tar.bz2
scummvm-rg350-151b7beb47ec4b964862d6779bd48e3a33482bbd.zip
Merge branch 'master' into teenagentRefactor
Conflicts: engines/teenagent/callbacks.cpp
Diffstat (limited to 'gui')
-rw-r--r--gui/ThemeEngine.cpp4
-rw-r--r--gui/ThemeEngine.h4
-rw-r--r--gui/ThemeParser.cpp4
-rw-r--r--gui/ThemeParser.h2
-rw-r--r--gui/Tooltip.cpp2
-rw-r--r--gui/credits.h29
-rw-r--r--gui/gui-manager.cpp2
-rw-r--r--gui/launcher.cpp2
-rw-r--r--gui/module.mk1
-rw-r--r--gui/options.cpp2
-rw-r--r--gui/predictivedialog.cpp18
-rw-r--r--gui/saveload-dialog.cpp946
-rw-r--r--gui/saveload-dialog.h209
-rw-r--r--gui/saveload.cpp391
-rw-r--r--gui/saveload.h47
-rw-r--r--gui/themes/default.inc66
-rw-r--r--gui/themes/scummclassic.zipbin93390 -> 95180 bytes
-rw-r--r--gui/themes/scummclassic/THEMERC2
-rw-r--r--gui/themes/scummclassic/classic_layout.stx45
-rw-r--r--gui/themes/scummclassic/classic_layout_lowres.stx31
-rw-r--r--gui/themes/scummmodern.zipbin1449870 -> 1453485 bytes
-rw-r--r--gui/themes/scummmodern/THEMERC2
-rw-r--r--gui/themes/scummmodern/grid.bmpbin0 -> 822 bytes
-rw-r--r--gui/themes/scummmodern/list.bmpbin0 -> 822 bytes
-rw-r--r--gui/themes/scummmodern/scummmodern_gfx.stx4
-rw-r--r--gui/themes/scummmodern/scummmodern_layout.stx45
-rw-r--r--gui/themes/scummmodern/scummmodern_layout_lowres.stx31
-rw-r--r--gui/themes/translations.datbin342397 -> 370908 bytes
-rw-r--r--gui/widget.cpp95
-rw-r--r--gui/widget.h14
-rw-r--r--gui/widgets/editable.h4
-rw-r--r--gui/widgets/list.h1
32 files changed, 1555 insertions, 448 deletions
diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp
index e37022f5f1..e2fa2580f5 100644
--- a/gui/ThemeEngine.cpp
+++ b/gui/ThemeEngine.cpp
@@ -48,6 +48,8 @@ const char * const ThemeEngine::kImageLogoSmall = "logo_small.bmp";
const char * const ThemeEngine::kImageSearch = "search.bmp";
const char * const ThemeEngine::kImageEraser = "eraser.bmp";
const char * const ThemeEngine::kImageDelbtn = "delbtn.bmp";
+const char * const ThemeEngine::kImageList = "list.bmp";
+const char * const ThemeEngine::kImageGrid = "grid.bmp";
struct TextDrawData {
const Graphics::Font *_fontPtr;
@@ -1422,7 +1424,7 @@ const Graphics::Font *ThemeEngine::loadScalableFont(const Common::String &filena
for (Common::ArchiveMemberList::const_iterator i = members.begin(), end = members.end(); i != end; ++i) {
Common::SeekableReadStream *stream = (*i)->createReadStream();
if (stream) {
- font = Graphics::loadTTFFont(*stream, pointsize, false,
+ font = Graphics::loadTTFFont(*stream, pointsize, 0, false,
#ifdef USE_TRANSLATION
TransMan.getCharsetMapping()
#else
diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h
index 21711e2955..6fb93d3b46 100644
--- a/gui/ThemeEngine.h
+++ b/gui/ThemeEngine.h
@@ -35,7 +35,7 @@
#include "graphics/pixelformat.h"
-#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.13"
+#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.16"
class OSystem;
@@ -232,6 +232,8 @@ public:
static const char *const kImageSearch; ///< Search tool image used in the launcher
static const char *const kImageEraser; ///< Clear input image used in the launcher
static const char *const kImageDelbtn; ///< Delete characters in the predictive dialog
+ static const char *const kImageList; ///< List image used in save/load chooser selection
+ static const char *const kImageGrid; ///< Grid image used in save/load chooser selection
/**
* Graphics mode enumeration.
diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp
index 9a85399ed1..8285aff7ca 100644
--- a/gui/ThemeParser.cpp
+++ b/gui/ThemeParser.cpp
@@ -548,11 +548,11 @@ bool ThemeParser::parseDrawStep(ParserNode *stepNode, Graphics::DrawStep *drawst
else
return parserError("'" + stepNode->values["fill"] + "' is not a valid fill mode for a shape.");
}
-
+
if (stepNode->values.contains("padding")) {
val = stepNode->values["padding"];
int pr, pt, pl, pb;
- if (parseIntegerKey(val, 4, &pl, &pt, &pr, &pb))
+ if (parseIntegerKey(val, 4, &pl, &pt, &pr, &pb))
drawstep->padding.left = pl,
drawstep->padding.top = pt,
drawstep->padding.right = pr,
diff --git a/gui/ThemeParser.h b/gui/ThemeParser.h
index 82f774b803..360e3da009 100644
--- a/gui/ThemeParser.h
+++ b/gui/ThemeParser.h
@@ -139,7 +139,7 @@ protected:
XML_PROP(height, false)
XML_PROP(xpos, false)
XML_PROP(ypos, false)
- XML_PROP(padding, false)
+ XML_PROP(padding, false)
XML_PROP(orientation, false)
XML_PROP(file, false)
KEY_END()
diff --git a/gui/Tooltip.cpp b/gui/Tooltip.cpp
index 85e5856cff..88124e782b 100644
--- a/gui/Tooltip.cpp
+++ b/gui/Tooltip.cpp
@@ -37,7 +37,7 @@ Tooltip::Tooltip() :
}
void Tooltip::setup(Dialog *parent, Widget *widget, int x, int y) {
- assert(widget->getTooltip());
+ assert(widget->hasTooltip());
_maxWidth = g_gui.xmlEval()->getVar("Globals.Tooltip.MaxWidth", 100);
_xdelta = g_gui.xmlEval()->getVar("Globals.Tooltip.XDelta", 0);
diff --git a/gui/credits.h b/gui/credits.h
index 7226864543..37c5a7bd95 100644
--- a/gui/credits.h
+++ b/gui/credits.h
@@ -106,8 +106,10 @@ static const char *credits[] = {
"C1""DreamWeb",
"C0""Torbj\366rn Andersson",
"C0""Bertrand Augereau",
+"C0""Filippos Karapetis",
"C0""Vladimir Menshakov",
"C2""(retired)",
+"C0""Willem Jan Palenstijn",
"",
"C1""Gob",
"C0""Torbj\366rn Andersson",
@@ -157,6 +159,9 @@ static const char *credits[] = {
"C1""Parallaction",
"C0""peres",
"",
+"C1""Pegasus",
+"C0""Matthew Hoops",
+"",
"C1""Queen",
"C0""David Eriksson",
"C2""(retired)",
@@ -232,6 +237,11 @@ static const char *credits[] = {
"C0""Filippos Karapetis",
"C0""Joost Peters",
"",
+"C1""Tony",
+"C0""Arnaud Boutonn\351",
+"C0""Paul Gilbert",
+"C0""Alyssa Milburn",
+"",
"C1""Toon",
"C0""Sylvain Dupont",
"",
@@ -247,6 +257,9 @@ static const char *credits[] = {
"C0""Gregory Montoir",
"C2""(retired)",
"",
+"C1""Wintermute",
+"C0""Einar Johan T. S\370m\345en",
+"",
"",
"C1""Backend Teams",
"C1""Android",
@@ -474,9 +487,13 @@ static const char *credits[] = {
"C1""French",
"C0""Thierry Crozat",
"",
+"C1""Galician",
+"C0""Santiago G. Sanz",
+"",
"C1""German",
"C0""Simon Sawatzki",
"C0""Lothar Serra Mari",
+"C2""(retired)",
"",
"C1""Hungarian",
"C0""Alex Bevilacqua",
@@ -674,6 +691,8 @@ static const char *credits[] = {
"C2""For generously providing hosting for our buildbot, SVN repository, planet and doxygen sites as well as tons of HD space",
"C0""DOSBox Team",
"C2""For their awesome OPL2 and OPL3 emulator",
+"C0""Yusuke Kamiyamane",
+"C2""For contributing some GUI icons ",
"C0""Till Kresslein",
"C2""For design of modern ScummVM GUI",
"C0""Jezar",
@@ -690,8 +709,6 @@ static const char *credits[] = {
"C2""For additional work on the original MT-32 emulator",
"C0""James Woodcock",
"C2""Soundtrack enhancements",
-"C0""Some icons by Yusuke Kamiyamane",
-"C0""",
"C0""Tony Warriner and everyone at Revolution Software Ltd. for sharing with us the source of some of their brilliant games, allowing us to release Beneath a Steel Sky as freeware... and generally being supportive above and beyond the call of duty.",
"C0""",
"C0""John Passfield and Steve Stamatiadis for sharing the source of their classic title, Flight of the Amazon Queen and also being incredibly supportive.",
@@ -710,5 +727,13 @@ static const char *credits[] = {
"C0""",
"C0""Broken Sword 2.5 team for providing sources of their engine and their great support.",
"C0""",
+"C0""Neil Dodwell and David Dew from Creative Reality for providing the source of Dreamweb and for their tremendous support.",
+"C0""",
+"C0""Janusz Wisniewski and Miroslaw Liminowicz from Laboratorium Komputerowe Avalon for providing full source code for Soltys and letting us redistribute the game.",
+"C0""",
+"C0""Jan Nedoma for providing the sources to the Wintermute-engine, and for his support while porting the engine to ScummVM.",
+"C0""",
+"C0""Bob Bell, Michel Kripalani, Tommy Yune, from Presto Studios for providing the source code of The Journeyman Project: Pegasus Prime.",
+"C0""",
"",
};
diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index abd781e1a3..a0ef4216aa 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -381,7 +381,7 @@ void GuiManager::runLoop() {
if (tooltipCheck && _lastMousePosition.time + kTooltipDelay < _system->getMillis()) {
Widget *wdg = activeDialog->findWidget(_lastMousePosition.x, _lastMousePosition.y);
- if (wdg && wdg->getTooltip() && !(wdg->getFlags() & WIDGET_PRESSED)) {
+ if (wdg && wdg->hasTooltip() && !(wdg->getFlags() & WIDGET_PRESSED)) {
Tooltip *tooltip = new Tooltip();
tooltip->setup(activeDialog, wdg, _lastMousePosition.x, _lastMousePosition.y);
tooltip->runModal();
diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index 26fafa5279..0f4867ced5 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -166,7 +166,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
} else {
warning("Plugin for target \"%s\" not found! Game specific settings might be missing", domain.c_str());
}
-
+
// GAME: Path to game data (r/o), extra data (r/o), and save data (r/w)
String gamePath(ConfMan.get("path", _domain));
String extraPath(ConfMan.get("extrapath", _domain));
diff --git a/gui/module.mk b/gui/module.mk
index d272bb0313..a435d8cca7 100644
--- a/gui/module.mk
+++ b/gui/module.mk
@@ -15,6 +15,7 @@ MODULE_OBJS := \
options.o \
predictivedialog.o \
saveload.o \
+ saveload-dialog.o \
themebrowser.o \
ThemeEngine.o \
ThemeEval.o \
diff --git a/gui/options.cpp b/gui/options.cpp
index 4fc37c93da..4868f1876d 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -992,7 +992,7 @@ void OptionsDialog::addEngineControls(GuiObject *boss, const Common::String &pre
ExtraGuiOptions::const_iterator iter;
for (iter = engineOptions.begin(); iter != engineOptions.end(); ++iter, ++i) {
Common::String id = Common::String::format("%d", i);
- _engineCheckboxes.push_back(new CheckboxWidget(boss,
+ _engineCheckboxes.push_back(new CheckboxWidget(boss,
prefix + "customOption" + id + "Checkbox", _(iter->label), _(iter->tooltip)));
}
}
diff --git a/gui/predictivedialog.cpp b/gui/predictivedialog.cpp
index b827d49416..ed18847a40 100644
--- a/gui/predictivedialog.cpp
+++ b/gui/predictivedialog.cpp
@@ -71,7 +71,7 @@ PredictiveDialog::PredictiveDialog() : Dialog("Predictive") {
_btns = (ButtonWidget **)calloc(1, sizeof(ButtonWidget *) * 16);
- _btns[kCancelAct] = new ButtonWidget(this, "Predictive.Cancel", _("Cancel") , 0, kCancelCmd);
+ _btns[kCancelAct] = new ButtonWidget(this, "Predictive.Cancel", _("Cancel") , 0, kCancelCmd);
_btns[kOkAct] = new ButtonWidget(this, "Predictive.OK", _("Ok") , 0, kOkCmd);
_btns[kBtn1Act] = new ButtonWidget(this, "Predictive.Button1", "1 `-.&" , 0, kBut1Cmd);
_btns[kBtn2Act] = new ButtonWidget(this, "Predictive.Button2", "2 abc" , 0, kBut2Cmd);
@@ -84,10 +84,10 @@ PredictiveDialog::PredictiveDialog() : Dialog("Predictive") {
_btns[kBtn9Act] = new ButtonWidget(this, "Predictive.Button9", "9 wxyz" , 0, kBut9Cmd);
_btns[kBtn0Act] = new ButtonWidget(this, "Predictive.Button0", "0" , 0, kBut0Cmd);
// I18N: You must leave "#" as is, only word 'next' is translatable
- _btns[kNextAct] = new ButtonWidget(this, "Predictive.Next", _("# next") , 0, kNextCmd);
+ _btns[kNextAct] = new ButtonWidget(this, "Predictive.Next", _("# next") , 0, kNextCmd);
_btns[kAddAct] = new ButtonWidget(this, "Predictive.Add", _("add") , 0, kAddCmd);
_btns[kAddAct]->setEnabled(false);
-
+
#ifndef DISABLE_FANCY_THEMES
_btns[kDelAct] = new PicButtonWidget(this, "Predictive.Delete", _("Delete char"), kDelCmd);
((PicButtonWidget *)_btns[kDelAct])->useThemeTransparency(true);
@@ -214,7 +214,7 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
_navigationwithkeys = true;
if (_lastbutton == kBtn1Act || _lastbutton == kBtn4Act || _lastbutton == kBtn7Act)
_currBtn = ButtonId(_lastbutton + 2);
- else if (_lastbutton == kDelAct)
+ else if (_lastbutton == kDelAct)
_currBtn = kBtn1Act;
else if (_lastbutton == kModeAct)
_currBtn = kNextAct;
@@ -227,7 +227,7 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
else
_currBtn = ButtonId(_lastbutton - 1);
-
+
if (_mode != kModeAbc && _lastbutton == kCancelAct)
_currBtn = kOkAct;
@@ -237,7 +237,7 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
_navigationwithkeys = true;
if (_lastbutton == kBtn3Act || _lastbutton == kBtn6Act || _lastbutton == kBtn9Act || _lastbutton == kOkAct)
_currBtn = ButtonId(_lastbutton - 2);
- else if (_lastbutton == kDelAct)
+ else if (_lastbutton == kDelAct)
_currBtn = kBtn3Act;
else if (_lastbutton == kBtn0Act)
_currBtn = kNextAct;
@@ -249,7 +249,7 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
_currBtn = kAddAct;
else
_currBtn = ButtonId(_lastbutton + 1);
-
+
if (_mode != kModeAbc && _lastbutton == kOkAct)
_currBtn = kCancelAct;
_needRefresh = true;
@@ -260,7 +260,7 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
_currBtn = kDelAct;
else if (_lastbutton == kDelAct)
_currBtn = kOkAct;
- else if (_lastbutton == kModeAct)
+ else if (_lastbutton == kModeAct)
_currBtn = kBtn7Act;
else if (_lastbutton == kBtn0Act)
_currBtn = kBtn8Act;
@@ -286,7 +286,7 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
_currBtn = kBtn0Act;
else if (_lastbutton == kBtn9Act)
_currBtn = kNextAct;
- else if (_lastbutton == kModeAct)
+ else if (_lastbutton == kModeAct)
_currBtn = kAddAct;
else if (_lastbutton == kBtn0Act)
_currBtn = kCancelAct;
diff --git a/gui/saveload-dialog.cpp b/gui/saveload-dialog.cpp
new file mode 100644
index 0000000000..df8dda7470
--- /dev/null
+++ b/gui/saveload-dialog.cpp
@@ -0,0 +1,946 @@
+/* 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 "gui/saveload-dialog.h"
+#include "common/translation.h"
+#include "common/config-manager.h"
+
+#include "gui/message.h"
+#include "gui/gui-manager.h"
+#include "gui/ThemeEval.h"
+#include "gui/widgets/edittext.h"
+
+#include "graphics/scaler.h"
+
+namespace GUI {
+
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+SaveLoadChooserType getRequestedSaveLoadDialog(const MetaEngine &metaEngine) {
+ const Common::String &userConfig = ConfMan.get("gui_saveload_chooser", Common::ConfigManager::kApplicationDomain);
+ if (g_gui.getWidth() >= 640 && g_gui.getHeight() >= 400
+ && metaEngine.hasFeature(MetaEngine::kSavesSupportMetaInfo)
+ && metaEngine.hasFeature(MetaEngine::kSavesSupportThumbnail)
+ && userConfig.equalsIgnoreCase("grid")) {
+ // In case we are 640x400 or higher, this dialog is not in save mode,
+ // the user requested the grid dialog and the engines supports it we
+ // try to set it up.
+ return kSaveLoadDialogGrid;
+ } else {
+ // In all other cases we want to use the list dialog.
+ return kSaveLoadDialogList;
+ }
+}
+
+enum {
+ kListSwitchCmd = 'LIST',
+ kGridSwitchCmd = 'GRID'
+};
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+
+SaveLoadChooserDialog::SaveLoadChooserDialog(const Common::String &dialogName, const bool saveMode)
+ : Dialog(dialogName), _metaEngine(0), _delSupport(false), _metaInfoSupport(false),
+ _thumbnailSupport(false), _saveDateSupport(false), _playTimeSupport(false), _saveMode(saveMode)
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+ , _listButton(0), _gridButton(0)
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+ {
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+ addChooserButtons();
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+}
+
+SaveLoadChooserDialog::SaveLoadChooserDialog(int x, int y, int w, int h, const bool saveMode)
+ : Dialog(x, y, w, h), _metaEngine(0), _delSupport(false), _metaInfoSupport(false),
+ _thumbnailSupport(false), _saveDateSupport(false), _playTimeSupport(false), _saveMode(saveMode)
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+ , _listButton(0), _gridButton(0)
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+ {
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+ addChooserButtons();
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+}
+
+void SaveLoadChooserDialog::open() {
+ Dialog::open();
+
+ // So that quitting ScummVM will not cause the dialog result to say a
+ // savegame was selected.
+ setResult(-1);
+}
+
+int SaveLoadChooserDialog::run(const Common::String &target, const MetaEngine *metaEngine) {
+ _metaEngine = metaEngine;
+ _target = target;
+ _delSupport = _metaEngine->hasFeature(MetaEngine::kSupportsDeleteSave);
+ _metaInfoSupport = _metaEngine->hasFeature(MetaEngine::kSavesSupportMetaInfo);
+ _thumbnailSupport = _metaInfoSupport && _metaEngine->hasFeature(MetaEngine::kSavesSupportThumbnail);
+ _saveDateSupport = _metaInfoSupport && _metaEngine->hasFeature(MetaEngine::kSavesSupportCreationDate);
+ _playTimeSupport = _metaInfoSupport && _metaEngine->hasFeature(MetaEngine::kSavesSupportPlayTime);
+
+ return runIntern();
+}
+
+void SaveLoadChooserDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+ switch (cmd) {
+ case kListSwitchCmd:
+ setResult(kSwitchSaveLoadDialog);
+ // We save the requested dialog type here to avoid the setting to be
+ // overwritten when our reflowLayout logic selects a different dialog
+ // type.
+ ConfMan.set("gui_saveload_chooser", "list", Common::ConfigManager::kApplicationDomain);
+ close();
+ break;
+
+ case kGridSwitchCmd:
+ setResult(kSwitchSaveLoadDialog);
+ // See above.
+ ConfMan.set("gui_saveload_chooser", "grid", Common::ConfigManager::kApplicationDomain);
+ close();
+ break;
+
+ default:
+ break;
+ }
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+
+ return Dialog::handleCommand(sender, cmd, data);
+}
+
+void SaveLoadChooserDialog::reflowLayout() {
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+ addChooserButtons();
+
+ const SaveLoadChooserType currentType = getType();
+ const SaveLoadChooserType requestedType = getRequestedSaveLoadDialog(*_metaEngine);
+
+ // Change the dialog type if there is any need for it.
+ if (requestedType != currentType) {
+ setResult(kSwitchSaveLoadDialog);
+ close();
+ }
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+
+ Dialog::reflowLayout();
+}
+
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+void SaveLoadChooserDialog::addChooserButtons() {
+ if (_listButton) {
+ removeWidget(_listButton);
+ delete _listButton;
+ }
+
+ if (_gridButton) {
+ removeWidget(_gridButton);
+ delete _gridButton;
+ }
+
+ _listButton = createSwitchButton("SaveLoadChooser.ListSwitch", "L", _("List view"), ThemeEngine::kImageList, kListSwitchCmd);
+ _gridButton = createSwitchButton("SaveLoadChooser.GridSwitch", "G", _("Grid view"), ThemeEngine::kImageGrid, kGridSwitchCmd);
+ if (!_metaInfoSupport || !_thumbnailSupport || !(g_gui.getWidth() >= 640 && g_gui.getHeight() >= 400)) {
+ _gridButton->setEnabled(false);
+ _listButton->setEnabled(false);
+ }
+}
+
+ButtonWidget *SaveLoadChooserDialog::createSwitchButton(const Common::String &name, const char *desc, const char *tooltip, const char *image, uint32 cmd) {
+ ButtonWidget *button;
+
+#ifndef DISABLE_FANCY_THEMES
+ if (g_gui.xmlEval()->getVar("Globals.ShowChooserPics") == 1 && g_gui.theme()->supportsImages()) {
+ button = new PicButtonWidget(this, name, tooltip, cmd);
+ ((PicButtonWidget *)button)->useThemeTransparency(true);
+ ((PicButtonWidget *)button)->setGfx(g_gui.theme()->getImageSurface(image));
+ } else
+#endif
+ button = new ButtonWidget(this, name, desc, tooltip, cmd);
+
+ return button;
+}
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+
+// SaveLoadChooserSimple implementation
+
+enum {
+ kChooseCmd = 'CHOS',
+ kDelCmd = 'DEL '
+};
+
+SaveLoadChooserSimple::SaveLoadChooserSimple(const String &title, const String &buttonLabel, bool saveMode)
+ : SaveLoadChooserDialog("SaveLoadChooser", saveMode), _list(0), _chooseButton(0), _deleteButton(0), _gfxWidget(0) {
+ _backgroundType = ThemeEngine::kDialogBackgroundSpecial;
+
+ new StaticTextWidget(this, "SaveLoadChooser.Title", title);
+
+ // Add choice list
+ _list = new ListWidget(this, "SaveLoadChooser.List");
+ _list->setNumberingMode(kListNumberingZero);
+ _list->setEditable(saveMode);
+
+ _gfxWidget = new GraphicsWidget(this, 0, 0, 10, 10);
+
+ _date = new StaticTextWidget(this, 0, 0, 10, 10, _("No date saved"), Graphics::kTextAlignCenter);
+ _time = new StaticTextWidget(this, 0, 0, 10, 10, _("No time saved"), Graphics::kTextAlignCenter);
+ _playtime = new StaticTextWidget(this, 0, 0, 10, 10, _("No playtime saved"), Graphics::kTextAlignCenter);
+
+ // Buttons
+ new ButtonWidget(this, "SaveLoadChooser.Cancel", _("Cancel"), 0, kCloseCmd);
+ _chooseButton = new ButtonWidget(this, "SaveLoadChooser.Choose", buttonLabel, 0, kChooseCmd);
+ _chooseButton->setEnabled(false);
+
+ _deleteButton = new ButtonWidget(this, "SaveLoadChooser.Delete", _("Delete"), 0, kDelCmd);
+ _deleteButton->setEnabled(false);
+
+ _delSupport = _metaInfoSupport = _thumbnailSupport = false;
+
+ _container = new ContainerWidget(this, 0, 0, 10, 10);
+// _container->setHints(THEME_HINT_USE_SHADOW);
+}
+
+int SaveLoadChooserSimple::runIntern() {
+ if (_gfxWidget)
+ _gfxWidget->setGfx(0);
+
+ _resultString.clear();
+ reflowLayout();
+ updateSaveList();
+
+ return Dialog::runModal();
+}
+
+const Common::String &SaveLoadChooserSimple::getResultString() const {
+ int selItem = _list->getSelected();
+ return (selItem >= 0) ? _list->getSelectedString() : _resultString;
+}
+
+void SaveLoadChooserSimple::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ int selItem = _list->getSelected();
+
+ switch (cmd) {
+ case kListItemActivatedCmd:
+ case kListItemDoubleClickedCmd:
+ if (selItem >= 0 && _chooseButton->isEnabled()) {
+ if (_list->isEditable() || !_list->getSelectedString().empty()) {
+ _list->endEditMode();
+ if (!_saveList.empty()) {
+ setResult(_saveList[selItem].getSaveSlot());
+ _resultString = _list->getSelectedString();
+ }
+ close();
+ }
+ }
+ break;
+ case kChooseCmd:
+ _list->endEditMode();
+ if (!_saveList.empty()) {
+ setResult(_saveList[selItem].getSaveSlot());
+ _resultString = _list->getSelectedString();
+ }
+ close();
+ break;
+ case kListSelectionChangedCmd:
+ updateSelection(true);
+ break;
+ case kDelCmd:
+ if (selItem >= 0 && _delSupport) {
+ MessageDialog alert(_("Do you really want to delete this savegame?"),
+ _("Delete"), _("Cancel"));
+ if (alert.runModal() == kMessageOK) {
+ _metaEngine->removeSaveState(_target.c_str(), _saveList[selItem].getSaveSlot());
+
+ setResult(-1);
+ _list->setSelected(-1);
+
+ updateSaveList();
+ updateSelection(true);
+ }
+ }
+ break;
+ case kCloseCmd:
+ setResult(-1);
+ default:
+ SaveLoadChooserDialog::handleCommand(sender, cmd, data);
+ }
+}
+
+void SaveLoadChooserSimple::reflowLayout() {
+ if (g_gui.xmlEval()->getVar("Globals.SaveLoadChooser.ExtInfo.Visible") == 1 && _thumbnailSupport) {
+ int16 x, y;
+ uint16 w, h;
+
+ if (!g_gui.xmlEval()->getWidgetData("SaveLoadChooser.Thumbnail", x, y, w, h))
+ error("Error when loading position data for Save/Load Thumbnails");
+
+ int thumbW = kThumbnailWidth;
+ int thumbH = kThumbnailHeight2;
+ int thumbX = x + (w >> 1) - (thumbW >> 1);
+ int thumbY = y + kLineHeight;
+
+ int textLines = 0;
+ if (!_saveDateSupport)
+ textLines++;
+ if (!_playTimeSupport)
+ textLines++;
+
+ _container->resize(x, y, w, h - (kLineHeight * textLines));
+ _gfxWidget->resize(thumbX, thumbY, thumbW, thumbH);
+
+ int height = thumbY + thumbH + kLineHeight;
+
+ if (_saveDateSupport) {
+ _date->resize(thumbX, height, kThumbnailWidth, kLineHeight);
+ height += kLineHeight;
+ _time->resize(thumbX, height, kThumbnailWidth, kLineHeight);
+ height += kLineHeight;
+ }
+
+ if (_playTimeSupport)
+ _playtime->resize(thumbX, height, kThumbnailWidth, kLineHeight);
+
+ _container->setVisible(true);
+ _gfxWidget->setVisible(true);
+
+ _date->setVisible(_saveDateSupport);
+ _time->setVisible(_saveDateSupport);
+
+ _playtime->setVisible(_playTimeSupport);
+
+ updateSelection(false);
+ } else {
+ _container->setVisible(false);
+ _gfxWidget->setVisible(false);
+ _date->setVisible(false);
+ _time->setVisible(false);
+ _playtime->setVisible(false);
+ }
+
+ SaveLoadChooserDialog::reflowLayout();
+}
+
+void SaveLoadChooserSimple::updateSelection(bool redraw) {
+ int selItem = _list->getSelected();
+
+ bool isDeletable = _delSupport;
+ bool isWriteProtected = false;
+ bool startEditMode = _list->isEditable();
+
+ // We used to support letting the themes specify the fill color with our
+ // initial theme based GUI. But this support was dropped.
+ _gfxWidget->setGfx(-1, -1, 0, 0, 0);
+ _date->setLabel(_("No date saved"));
+ _time->setLabel(_("No time saved"));
+ _playtime->setLabel(_("No playtime saved"));
+
+ if (selItem >= 0 && _metaInfoSupport) {
+ SaveStateDescriptor desc = _metaEngine->querySaveMetaInfos(_target.c_str(), _saveList[selItem].getSaveSlot());
+
+ isDeletable = desc.getDeletableFlag() && _delSupport;
+ isWriteProtected = desc.getWriteProtectedFlag();
+
+ // Don't allow the user to change the description of write protected games
+ if (isWriteProtected)
+ startEditMode = false;
+
+ if (_thumbnailSupport) {
+ const Graphics::Surface *thumb = desc.getThumbnail();
+ if (thumb) {
+ _gfxWidget->setGfx(thumb);
+ _gfxWidget->useAlpha(256);
+ }
+ }
+
+ if (_saveDateSupport) {
+ const Common::String &saveDate = desc.getSaveDate();
+ if (!saveDate.empty())
+ _date->setLabel(_("Date: ") + saveDate);
+
+ const Common::String &saveTime = desc.getSaveTime();
+ if (!saveTime.empty())
+ _time->setLabel(_("Time: ") + saveTime);
+ }
+
+ if (_playTimeSupport) {
+ const Common::String &playTime = desc.getPlayTime();
+ if (!playTime.empty())
+ _playtime->setLabel(_("Playtime: ") + playTime);
+ }
+ }
+
+
+ if (_list->isEditable()) {
+ // Disable the save button if nothing is selected, or if the selected
+ // game is write protected
+ _chooseButton->setEnabled(selItem >= 0 && !isWriteProtected);
+
+ if (startEditMode) {
+ _list->startEditMode();
+
+ if (_chooseButton->isEnabled() && _list->getSelectedString() == _("Untitled savestate") &&
+ _list->getSelectionColor() == ThemeEngine::kFontColorAlternate) {
+ _list->setEditString("");
+ _list->setEditColor(ThemeEngine::kFontColorNormal);
+ }
+ }
+ } else {
+ // Disable the load button if nothing is selected, or if an empty
+ // list item is selected.
+ _chooseButton->setEnabled(selItem >= 0 && !_list->getSelectedString().empty());
+ }
+
+ // Delete will always be disabled if the engine doesn't support it.
+ _deleteButton->setEnabled(isDeletable && (selItem >= 0) && (!_list->getSelectedString().empty()));
+
+ if (redraw) {
+ _gfxWidget->draw();
+ _date->draw();
+ _time->draw();
+ _playtime->draw();
+ _chooseButton->draw();
+ _deleteButton->draw();
+
+ draw();
+ }
+}
+
+void SaveLoadChooserSimple::open() {
+ SaveLoadChooserDialog::open();
+
+ // Scroll the list to the last used entry.
+ _list->scrollTo(ConfMan.getInt("gui_saveload_last_pos"));
+}
+
+void SaveLoadChooserSimple::close() {
+ // Save the current scroll position/used entry.
+ const int result = getResult();
+ if (result >= 0) {
+ ConfMan.setInt("gui_saveload_last_pos", result);
+ } else {
+ // Use the current scroll position here.
+ // TODO: This means we canceled the dialog (or switch to the grid). Do
+ // we want to save this position here? Does the user want that?
+ // TODO: Do we want to save the current scroll position or the
+ // currently selected item here? The scroll position is what the user
+ // currently sees and seems to make more sense.
+ ConfMan.setInt("gui_saveload_last_pos", _list->getCurrentScrollPos());
+ }
+
+ _metaEngine = 0;
+ _target.clear();
+ _saveList.clear();
+ _list->setList(StringArray());
+
+ SaveLoadChooserDialog::close();
+}
+
+void SaveLoadChooserSimple::updateSaveList() {
+ _saveList = _metaEngine->listSaves(_target.c_str());
+
+ int curSlot = 0;
+ int saveSlot = 0;
+ StringArray saveNames;
+ ListWidget::ColorList colors;
+ for (SaveStateList::const_iterator x = _saveList.begin(); x != _saveList.end(); ++x) {
+ // Handle gaps in the list of save games
+ saveSlot = x->getSaveSlot();
+ if (curSlot < saveSlot) {
+ while (curSlot < saveSlot) {
+ SaveStateDescriptor dummySave(curSlot, "");
+ _saveList.insert_at(curSlot, dummySave);
+ saveNames.push_back(dummySave.getDescription());
+ colors.push_back(ThemeEngine::kFontColorNormal);
+ curSlot++;
+ }
+
+ // Sync the save list iterator
+ for (x = _saveList.begin(); x != _saveList.end(); ++x) {
+ if (x->getSaveSlot() == saveSlot)
+ break;
+ }
+ }
+
+ // Show "Untitled savestate" for empty/whitespace savegame descriptions
+ Common::String description = x->getDescription();
+ Common::String trimmedDescription = description;
+ trimmedDescription.trim();
+ if (trimmedDescription.empty()) {
+ description = _("Untitled savestate");
+ colors.push_back(ThemeEngine::kFontColorAlternate);
+ } else {
+ colors.push_back(ThemeEngine::kFontColorNormal);
+ }
+
+ saveNames.push_back(description);
+ curSlot++;
+ }
+
+ // Fill the rest of the save slots with empty saves
+
+ int maximumSaveSlots = _metaEngine->getMaximumSaveSlot();
+
+#ifdef __DS__
+ // Low memory on the DS means too many save slots are impractical, so limit
+ // the maximum here.
+ if (maximumSaveSlots > 99) {
+ maximumSaveSlots = 99;
+ }
+#endif
+
+ Common::String emptyDesc;
+ for (int i = curSlot; i <= maximumSaveSlots; i++) {
+ saveNames.push_back(emptyDesc);
+ SaveStateDescriptor dummySave(i, "");
+ _saveList.push_back(dummySave);
+ colors.push_back(ThemeEngine::kFontColorNormal);
+ }
+
+ _list->setList(saveNames, &colors);
+}
+
+// SaveLoadChooserGrid implementation
+
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+
+enum {
+ kNextCmd = 'NEXT',
+ kPrevCmd = 'PREV',
+ kNewSaveCmd = 'SAVE'
+};
+
+SaveLoadChooserGrid::SaveLoadChooserGrid(const Common::String &title, bool saveMode)
+ : SaveLoadChooserDialog("SaveLoadChooser", saveMode), _lines(0), _columns(0), _entriesPerPage(0),
+ _curPage(0), _newSaveContainer(0), _nextFreeSaveSlot(0), _buttons() {
+ _backgroundType = ThemeEngine::kDialogBackgroundSpecial;
+
+ new StaticTextWidget(this, "SaveLoadChooser.Title", title);
+
+ // Buttons
+ new ButtonWidget(this, "SaveLoadChooser.Delete", _("Cancel"), 0, kCloseCmd);
+ _nextButton = new ButtonWidget(this, "SaveLoadChooser.Choose", _("Next"), 0, kNextCmd);
+ _nextButton->setEnabled(false);
+
+ _prevButton = new ButtonWidget(this, "SaveLoadChooser.Cancel", _("Prev"), 0, kPrevCmd);
+ _prevButton->setEnabled(false);
+
+ // Page display
+ _pageDisplay = new StaticTextWidget(this, "SaveLoadChooser.PageDisplay", Common::String());
+ _pageDisplay->setAlign(Graphics::kTextAlignRight);
+}
+
+SaveLoadChooserGrid::~SaveLoadChooserGrid() {
+ removeWidget(_pageDisplay);
+ delete _pageDisplay;
+}
+
+const Common::String &SaveLoadChooserGrid::getResultString() const {
+ return _resultString;
+}
+
+void SaveLoadChooserGrid::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ if (cmd <= _entriesPerPage && cmd + _curPage * _entriesPerPage <= _saveList.size()) {
+ const SaveStateDescriptor &desc = _saveList[cmd - 1 + _curPage * _entriesPerPage];
+
+ if (_saveMode) {
+ _resultString = desc.getDescription();
+ }
+
+ setResult(desc.getSaveSlot());
+ close();
+ }
+
+ switch (cmd) {
+ case kNextCmd:
+ ++_curPage;
+ updateSaves();
+ draw();
+ break;
+
+ case kPrevCmd:
+ --_curPage;
+ updateSaves();
+ draw();
+ break;
+
+ case kNewSaveCmd:
+ setResult(_nextFreeSaveSlot);
+ close();
+ break;
+
+ case kCloseCmd:
+ setResult(-1);
+ default:
+ SaveLoadChooserDialog::handleCommand(sender, cmd, data);
+ }
+}
+
+void SaveLoadChooserGrid::handleMouseWheel(int x, int y, int direction) {
+ if (direction > 0) {
+ if (_nextButton->isEnabled()) {
+ ++_curPage;
+ updateSaves();
+ draw();
+ }
+ } else {
+ if (_prevButton->isEnabled()) {
+ --_curPage;
+ updateSaves();
+ draw();
+ }
+ }
+}
+
+void SaveLoadChooserGrid::open() {
+ SaveLoadChooserDialog::open();
+
+ _saveList = _metaEngine->listSaves(_target.c_str());
+ _resultString.clear();
+
+ // Load information to restore the last page the user had open.
+ assert(_entriesPerPage != 0);
+ const uint lastPos = ConfMan.getInt("gui_saveload_last_pos");
+ const uint listSize = _saveList.size();
+ uint bestMatch = 0;
+ uint diff = 0xFFFFFFFF;
+
+ // We look for the nearest available slot, since a slot might be missing
+ // due to the user deleting it via the list based chooser, by deleting
+ // it by hand, etc.
+ for (uint i = 0; i < listSize; ++i) {
+ uint curDiff = ABS(_saveList[i].getSaveSlot() - (int)lastPos);
+ if (curDiff < diff) {
+ diff = curDiff;
+ bestMatch = i;
+ }
+ }
+
+ _curPage = bestMatch / _entriesPerPage;
+
+ // Determine the next free save slot for save mode
+ if (_saveMode) {
+ int lastSlot = -1;
+ _nextFreeSaveSlot = -1;
+ for (SaveStateList::const_iterator x = _saveList.begin(); x != _saveList.end(); ++x) {
+ const int curSlot = x->getSaveSlot();
+
+ // In case there was a gap found use the slot.
+ if (lastSlot + 1 < curSlot) {
+ _nextFreeSaveSlot = lastSlot + 1;
+ break;
+ }
+
+ lastSlot = curSlot;
+ }
+
+ // Use the next available slot otherwise.
+ if (_nextFreeSaveSlot == -1 && lastSlot + 1 < _metaEngine->getMaximumSaveSlot()) {
+ _nextFreeSaveSlot = lastSlot + 1;
+ }
+ }
+
+ updateSaves();
+}
+
+void SaveLoadChooserGrid::reflowLayout() {
+ // HACK: The page display is not available in low resolution layout. We
+ // remove and readd the widget here to avoid our GUI from erroring out.
+ removeWidget(_pageDisplay);
+ if (g_gui.xmlEval()->getVar("Globals.ShowChooserPageDisplay") == 1) {
+ _pageDisplay->init();
+ }
+
+ SaveLoadChooserDialog::reflowLayout();
+ destroyButtons();
+
+ // HACK: The whole code below really works around the fact, that we have
+ // no easy way to dynamically layout widgets.
+ const uint16 availableWidth = getWidth() - 20;
+ uint16 availableHeight;
+
+ int16 x, y;
+ uint16 w;
+ g_gui.xmlEval()->getWidgetData("SaveLoadChooser.List", x, y, w, availableHeight);
+
+ const int16 buttonWidth = kThumbnailWidth + 6;
+ const int16 buttonHeight = kThumbnailHeight2 + 6;
+
+ const int16 containerFrameWidthAdd = 10;
+ const int16 containerFrameHeightAdd = 0;
+ const int16 containerWidth = buttonWidth + containerFrameWidthAdd;
+ const int16 containerHeight = buttonHeight + kLineHeight + containerFrameHeightAdd;
+
+ const int16 defaultSpacingHorizontal = 4;
+ const int16 defaultSpacingVertical = 8;
+ const int16 slotAreaWidth = containerWidth + defaultSpacingHorizontal;
+ const int16 slotAreaHeight = containerHeight + defaultSpacingVertical;
+
+ const uint oldEntriesPerPage = _entriesPerPage;
+ _columns = MAX<uint>(1, availableWidth / slotAreaWidth);
+ _lines = MAX<uint>(1, availableHeight / slotAreaHeight);
+ _entriesPerPage = _columns * _lines;
+
+ // In save mode the first button is always "New Save", thus we need to
+ // adjust the entries per page here.
+ if (_saveMode) {
+ --_entriesPerPage;
+ }
+
+ // Recalculate the page number
+ if (!_saveList.empty() && oldEntriesPerPage != 0) {
+ if (_entriesPerPage != 0) {
+ _curPage = (_curPage * oldEntriesPerPage) / _entriesPerPage;
+ } else {
+ _curPage = 0;
+ }
+ }
+
+ const uint addX = _columns > 1 ? (availableWidth % slotAreaWidth) / (_columns - 1) : 0;
+ //const uint addY = _lines > 1 ? (availableHeight % slotAreaHeight) / (_lines - 1) : 0;
+
+ _buttons.reserve(_lines * _columns);
+ y += defaultSpacingVertical / 2;
+ for (uint curLine = 0; curLine < _lines; ++curLine, y += slotAreaHeight/* + addY*/) {
+ for (uint curColumn = 0, curX = x + defaultSpacingHorizontal / 2; curColumn < _columns; ++curColumn, curX += slotAreaWidth + addX) {
+ int dstY = containerFrameHeightAdd / 2;
+ int dstX = containerFrameWidthAdd / 2;
+
+ // In the save mode we will always create a new save button as the first button.
+ if (_saveMode && curLine == 0 && curColumn == 0) {
+ _newSaveContainer = new ContainerWidget(this, curX, y, containerWidth, containerHeight);
+ ButtonWidget *newSave = new ButtonWidget(_newSaveContainer, dstX, dstY, buttonWidth, buttonHeight, _("New Save"), _("Create a new save game"), kNewSaveCmd);
+ // In case no more slots are free, we will disable the new save button
+ if (_nextFreeSaveSlot == -1) {
+ newSave->setEnabled(false);
+ }
+ continue;
+ }
+
+ ContainerWidget *container = new ContainerWidget(this, curX, y, containerWidth, containerHeight);
+ container->setVisible(false);
+
+ // Command 0 cannot be used, since it won't be send. Thus we will adjust
+ // command number here, if required. This is only the case for load mode
+ // since for save mode, the first button used is index 1 anyway.
+ uint buttonCmd = curLine * _columns + curColumn;
+ if (!_saveMode) {
+ buttonCmd += 1;
+ }
+
+ PicButtonWidget *button = new PicButtonWidget(container, dstX, dstY, buttonWidth, buttonHeight, 0, buttonCmd);
+ dstY += buttonHeight;
+
+ StaticTextWidget *description = new StaticTextWidget(container, dstX, dstY, buttonWidth, kLineHeight, Common::String(), Graphics::kTextAlignLeft);
+
+ _buttons.push_back(SlotButton(container, button, description));
+ }
+ }
+
+ if (!_target.empty())
+ updateSaves();
+}
+
+void SaveLoadChooserGrid::close() {
+ // Save the current page.
+ const int result = getResult();
+ if (result >= 0 && result != _nextFreeSaveSlot) {
+ // If the user selected a slot we use that one. We ignore new slots
+ // here, since otherwise the dialog would reset to page 0 when the
+ // user cancels the savename dialog.
+ ConfMan.setInt("gui_saveload_last_pos", result);
+ } else {
+ // Otherwise save the first entry on the current page.
+ // This is less precise than the solution above, since the number of
+ // entries shown differs between save and load version of the dialog,
+ // thus it might wrap to a different page than expected.
+ // Similar things happen on resolution changes.
+ // TODO: Should we ignore this here? Is the user likely to be
+ // interested in having this page restored when he canceled?
+ ConfMan.setInt("gui_saveload_last_pos", !_saveList.empty() ? _saveList[_curPage * _entriesPerPage].getSaveSlot() : 0);
+ }
+
+ SaveLoadChooserDialog::close();
+ hideButtons();
+}
+
+int SaveLoadChooserGrid::runIntern() {
+ int slot;
+ do {
+ const SaveLoadChooserType currentType = getType();
+ const SaveLoadChooserType requestedType = getRequestedSaveLoadDialog(*_metaEngine);
+
+ // Catch resolution changes when the save name dialog was open.
+ if (currentType != requestedType) {
+ setResult(kSwitchSaveLoadDialog);
+ return kSwitchSaveLoadDialog;
+ }
+
+ slot = runModal();
+ } while (_saveMode && slot >= 0 && !selectDescription());
+
+ // Special case for new save games. We need to handle this here, since
+ // we cannot handle it in close() without problems.
+ if (slot == _nextFreeSaveSlot) {
+ ConfMan.setInt("gui_saveload_last_pos", slot);
+ }
+
+ return slot;
+}
+
+bool SaveLoadChooserGrid::selectDescription() {
+ _savenameDialog.setDescription(_resultString);
+ _savenameDialog.setTargetSlot(getResult());
+ if (_savenameDialog.runModal() == 0) {
+ _resultString = _savenameDialog.getDescription();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void SaveLoadChooserGrid::destroyButtons() {
+ if (_newSaveContainer) {
+ removeWidget(_newSaveContainer);
+ delete _newSaveContainer;
+ _newSaveContainer = 0;
+ }
+
+ for (ButtonArray::iterator i = _buttons.begin(), end = _buttons.end(); i != end; ++i) {
+ removeWidget(i->container);
+ delete i->container;
+ }
+
+ _buttons.clear();
+}
+
+void SaveLoadChooserGrid::hideButtons() {
+ for (ButtonArray::iterator i = _buttons.begin(), end = _buttons.end(); i != end; ++i) {
+ i->button->setGfx(0);
+ i->setVisible(false);
+ }
+}
+
+void SaveLoadChooserGrid::updateSaves() {
+ hideButtons();
+
+ for (uint i = _curPage * _entriesPerPage, curNum = 0; i < _saveList.size() && curNum < _entriesPerPage; ++i, ++curNum) {
+ const uint saveSlot = _saveList[i].getSaveSlot();
+
+ SaveStateDescriptor desc = _metaEngine->querySaveMetaInfos(_target.c_str(), saveSlot);
+ SlotButton &curButton = _buttons[curNum];
+ curButton.setVisible(true);
+ const Graphics::Surface *thumbnail = desc.getThumbnail();
+ if (thumbnail) {
+ curButton.button->setGfx(desc.getThumbnail());
+ } else {
+ curButton.button->setGfx(kThumbnailWidth, kThumbnailHeight2, 0, 0, 0);
+ }
+ curButton.description->setLabel(Common::String::format("%d. %s", saveSlot, desc.getDescription().c_str()));
+
+ Common::String tooltip(_("Name: "));
+ tooltip += desc.getDescription();
+
+ if (_saveDateSupport) {
+ const Common::String &saveDate = desc.getSaveDate();
+ if (!saveDate.empty()) {
+ tooltip += "\n";
+ tooltip += _("Date: ") + saveDate;
+ }
+
+ const Common::String &saveTime = desc.getSaveTime();
+ if (!saveTime.empty()) {
+ tooltip += "\n";
+ tooltip += _("Time: ") + saveTime;
+ }
+ }
+
+ if (_playTimeSupport) {
+ const Common::String &playTime = desc.getPlayTime();
+ if (!playTime.empty()) {
+ tooltip += "\n";
+ tooltip += _("Playtime: ") + playTime;
+ }
+ }
+
+ curButton.button->setTooltip(tooltip);
+
+ // In save mode we disable the button, when it's write protected.
+ // TODO: Maybe we should not display it at all then?
+ if (_saveMode && desc.getWriteProtectedFlag()) {
+ curButton.button->setEnabled(false);
+ } else {
+ curButton.button->setEnabled(true);
+ }
+ }
+
+ const uint numPages = (_entriesPerPage != 0 && !_saveList.empty()) ? ((_saveList.size() + _entriesPerPage - 1) / _entriesPerPage) : 1;
+ _pageDisplay->setLabel(Common::String::format("%u/%u", _curPage + 1, numPages));
+
+ if (_curPage > 0)
+ _prevButton->setEnabled(true);
+ else
+ _prevButton->setEnabled(false);
+
+ if ((_curPage + 1) * _entriesPerPage < _saveList.size())
+ _nextButton->setEnabled(true);
+ else
+ _nextButton->setEnabled(false);
+}
+
+SavenameDialog::SavenameDialog()
+ : Dialog("SavenameDialog") {
+ _title = new StaticTextWidget(this, "SavenameDialog.DescriptionText", Common::String());
+
+ new ButtonWidget(this, "SavenameDialog.Cancel", _("Cancel"), 0, kCloseCmd);
+ new ButtonWidget(this, "SavenameDialog.Ok", _("OK"), 0, kOKCmd);
+
+ _description = new EditTextWidget(this, "SavenameDialog.Description", Common::String(), 0, 0, kOKCmd);
+}
+
+void SavenameDialog::setDescription(const Common::String &desc) {
+ _description->setEditString(desc);
+}
+
+const Common::String &SavenameDialog::getDescription() {
+ return _description->getEditString();
+}
+
+void SavenameDialog::open() {
+ Dialog::open();
+ setResult(-1);
+
+ _title->setLabel(Common::String::format(_("Enter a description for slot %d:"), _targetSlot));
+}
+
+void SavenameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ switch (cmd) {
+ case kOKCmd:
+ setResult(0);
+ close();
+ break;
+
+ default:
+ Dialog::handleCommand(sender, cmd, data);
+ }
+}
+
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+
+} // End of namespace GUI
diff --git a/gui/saveload-dialog.h b/gui/saveload-dialog.h
new file mode 100644
index 0000000000..6f7d95f73f
--- /dev/null
+++ b/gui/saveload-dialog.h
@@ -0,0 +1,209 @@
+/* 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.
+ */
+
+#ifndef GUI_SAVELOAD_DIALOG_H
+#define GUI_SAVELOAD_DIALOG_H
+
+#include "gui/dialog.h"
+#include "gui/widgets/list.h"
+
+#include "engines/metaengine.h"
+
+namespace GUI {
+
+#define kSwitchSaveLoadDialog -2
+
+// TODO: We might want to disable the grid based save/load chooser for more
+// platforms, than those which define DISABLE_FANCY_THEMES. But those are
+// probably not able to handle the grid chooser anyway, so disabling it
+// for them is a good start.
+#ifdef DISABLE_FANCY_THEMES
+#define DISABLE_SAVELOADCHOOSER_GRID
+#endif // DISABLE_FANCY_THEMES
+
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+enum SaveLoadChooserType {
+ kSaveLoadDialogList = 0,
+ kSaveLoadDialogGrid = 1
+};
+
+SaveLoadChooserType getRequestedSaveLoadDialog(const MetaEngine &metaEngine);
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+
+class SaveLoadChooserDialog : protected Dialog {
+public:
+ SaveLoadChooserDialog(const Common::String &dialogName, const bool saveMode);
+ SaveLoadChooserDialog(int x, int y, int w, int h, const bool saveMode);
+
+ virtual void open();
+
+ virtual void reflowLayout();
+
+ virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
+
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+ virtual SaveLoadChooserType getType() const = 0;
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+
+ int run(const Common::String &target, const MetaEngine *metaEngine);
+ virtual const Common::String &getResultString() const = 0;
+
+protected:
+ virtual int runIntern() = 0;
+
+ const bool _saveMode;
+ const MetaEngine *_metaEngine;
+ bool _delSupport;
+ bool _metaInfoSupport;
+ bool _thumbnailSupport;
+ bool _saveDateSupport;
+ bool _playTimeSupport;
+ Common::String _target;
+
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+ ButtonWidget *_listButton;
+ ButtonWidget *_gridButton;
+
+ void addChooserButtons();
+ ButtonWidget *createSwitchButton(const Common::String &name, const char *desc, const char *tooltip, const char *image, uint32 cmd = 0);
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+};
+
+class SaveLoadChooserSimple : public SaveLoadChooserDialog {
+ typedef Common::String String;
+ typedef Common::Array<Common::String> StringArray;
+public:
+ SaveLoadChooserSimple(const String &title, const String &buttonLabel, bool saveMode);
+
+ virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
+
+ virtual const Common::String &getResultString() const;
+
+ virtual void reflowLayout();
+
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+ virtual SaveLoadChooserType getType() const { return kSaveLoadDialogList; }
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+
+ virtual void open();
+ virtual void close();
+private:
+ virtual int runIntern();
+
+ ListWidget *_list;
+ ButtonWidget *_chooseButton;
+ ButtonWidget *_deleteButton;
+ GraphicsWidget *_gfxWidget;
+ ContainerWidget *_container;
+ StaticTextWidget *_date;
+ StaticTextWidget *_time;
+ StaticTextWidget *_playtime;
+
+ SaveStateList _saveList;
+ String _resultString;
+
+ void updateSaveList();
+ void updateSelection(bool redraw);
+};
+
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+
+class EditTextWidget;
+
+class SavenameDialog : public Dialog {
+public:
+ SavenameDialog();
+
+ void setDescription(const Common::String &desc);
+ const Common::String &getDescription();
+
+ void setTargetSlot(int slot) { _targetSlot = slot; }
+
+ virtual void open();
+protected:
+ virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
+private:
+ int _targetSlot;
+ StaticTextWidget *_title;
+ EditTextWidget *_description;
+};
+
+class SaveLoadChooserGrid : public SaveLoadChooserDialog {
+public:
+ SaveLoadChooserGrid(const Common::String &title, bool saveMode);
+ ~SaveLoadChooserGrid();
+
+ virtual const Common::String &getResultString() const;
+
+ virtual void open();
+
+ virtual void reflowLayout();
+
+ virtual SaveLoadChooserType getType() const { return kSaveLoadDialogGrid; }
+
+ virtual void close();
+protected:
+ virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
+ virtual void handleMouseWheel(int x, int y, int direction);
+private:
+ virtual int runIntern();
+
+ uint _columns, _lines;
+ uint _entriesPerPage;
+ uint _curPage;
+ SaveStateList _saveList;
+
+ ButtonWidget *_nextButton;
+ ButtonWidget *_prevButton;
+
+ StaticTextWidget *_pageDisplay;
+
+ ContainerWidget *_newSaveContainer;
+ int _nextFreeSaveSlot;
+ Common::String _resultString;
+
+ SavenameDialog _savenameDialog;
+ bool selectDescription();
+
+ struct SlotButton {
+ SlotButton() : container(0), button(0), description(0) {}
+ SlotButton(ContainerWidget *c, PicButtonWidget *b, StaticTextWidget *d) : container(c), button(b), description(d) {}
+
+ ContainerWidget *container;
+ PicButtonWidget *button;
+ StaticTextWidget *description;
+
+ void setVisible(bool state) {
+ container->setVisible(state);
+ }
+ };
+ typedef Common::Array<SlotButton> ButtonArray;
+ ButtonArray _buttons;
+ void destroyButtons();
+ void hideButtons();
+ void updateSaves();
+};
+
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+
+} // End of namespace GUI
+
+#endif
diff --git a/gui/saveload.cpp b/gui/saveload.cpp
index 67d871e133..c2bbcd9bec 100644
--- a/gui/saveload.cpp
+++ b/gui/saveload.cpp
@@ -20,111 +20,45 @@
*/
#include "common/config-manager.h"
-#include "common/translation.h"
#include "common/system.h"
-#include "gui/widgets/list.h"
-#include "gui/message.h"
#include "gui/saveload.h"
-#include "gui/ThemeEval.h"
+#include "gui/saveload-dialog.h"
#include "gui/gui-manager.h"
-#include "graphics/scaler.h"
-
#include "engines/metaengine.h"
namespace GUI {
-enum {
- kChooseCmd = 'CHOS',
- kDelCmd = 'DEL '
-
-};
-
SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode)
- : Dialog("SaveLoadChooser"), _delSupport(0), _list(0), _chooseButton(0), _deleteButton(0), _gfxWidget(0) {
- _delSupport = _metaInfoSupport = _thumbnailSupport = _saveDateSupport = _playTimeSupport = false;
-
- _backgroundType = ThemeEngine::kDialogBackgroundSpecial;
-
- new StaticTextWidget(this, "SaveLoadChooser.Title", title);
-
- // Add choice list
- _list = new GUI::ListWidget(this, "SaveLoadChooser.List");
- _list->setNumberingMode(GUI::kListNumberingZero);
- _list->setEditable(saveMode);
-
- _gfxWidget = new GUI::GraphicsWidget(this, 0, 0, 10, 10);
-
- _date = new StaticTextWidget(this, 0, 0, 10, 10, _("No date saved"), Graphics::kTextAlignCenter);
- _time = new StaticTextWidget(this, 0, 0, 10, 10, _("No time saved"), Graphics::kTextAlignCenter);
- _playtime = new StaticTextWidget(this, 0, 0, 10, 10, _("No playtime saved"), Graphics::kTextAlignCenter);
-
- // Buttons
- new GUI::ButtonWidget(this, "SaveLoadChooser.Cancel", _("Cancel"), 0, kCloseCmd);
- _chooseButton = new GUI::ButtonWidget(this, "SaveLoadChooser.Choose", buttonLabel, 0, kChooseCmd);
- _chooseButton->setEnabled(false);
-
- _deleteButton = new GUI::ButtonWidget(this, "SaveLoadChooser.Delete", _("Delete"), 0, kDelCmd);
- _deleteButton->setEnabled(false);
-
- _delSupport = _metaInfoSupport = _thumbnailSupport = false;
-
- _container = new GUI::ContainerWidget(this, 0, 0, 10, 10);
-// _container->setHints(GUI::THEME_HINT_USE_SHADOW);
+ : _impl(0), _title(title), _buttonLabel(buttonLabel), _saveMode(saveMode) {
}
SaveLoadChooser::~SaveLoadChooser() {
+ delete _impl;
+ _impl = 0;
}
-int SaveLoadChooser::runModalWithCurrentTarget() {
- const Common::String gameId = ConfMan.get("gameid");
-
- const EnginePlugin *plugin = 0;
- EngineMan.findGame(gameId, &plugin);
-
- return runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName());
-}
-
-int SaveLoadChooser::runModalWithPluginAndTarget(const EnginePlugin *plugin, const String &target) {
- if (_gfxWidget)
- _gfxWidget->setGfx(0);
-
- // Set up the game domain as newly active domain, so
- // target specific savepath will be checked
- String oldDomain = ConfMan.getActiveDomainName();
- ConfMan.setActiveDomain(target);
-
- _plugin = plugin;
- _target = target;
- _delSupport = (*_plugin)->hasFeature(MetaEngine::kSupportsDeleteSave);
- _metaInfoSupport = (*_plugin)->hasFeature(MetaEngine::kSavesSupportMetaInfo);
- _thumbnailSupport = _metaInfoSupport && (*_plugin)->hasFeature(MetaEngine::kSavesSupportThumbnail);
- _saveDateSupport = _metaInfoSupport && (*_plugin)->hasFeature(MetaEngine::kSavesSupportCreationDate);
- _playTimeSupport = _metaInfoSupport && (*_plugin)->hasFeature(MetaEngine::kSavesSupportPlayTime);
- _resultString.clear();
- reflowLayout();
- updateSaveList();
-
- int ret = Dialog::runModal();
-
- // Revert to the old active domain
- ConfMan.setActiveDomain(oldDomain);
-
- return ret;
-}
-
-void SaveLoadChooser::open() {
- Dialog::open();
-
- // So that quitting ScummVM will not cause the dialog result to say a
- // savegame was selected.
- setResult(-1);
-}
-
-const Common::String &SaveLoadChooser::getResultString() const {
- int selItem = _list->getSelected();
- return (selItem >= 0) ? _list->getSelectedString() : _resultString;
+void SaveLoadChooser::selectChooser(const MetaEngine &engine) {
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+ const SaveLoadChooserType requestedType = getRequestedSaveLoadDialog(engine);
+ if (!_impl || _impl->getType() != requestedType) {
+ delete _impl;
+ _impl = 0;
+
+ switch (requestedType) {
+ case kSaveLoadDialogGrid:
+ _impl = new SaveLoadChooserGrid(_title, _saveMode);
+ break;
+
+ case kSaveLoadDialogList:
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+ _impl = new SaveLoadChooserSimple(_title, _buttonLabel, _saveMode);
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+ break;
+ }
+ }
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
}
Common::String SaveLoadChooser::createDefaultSaveDescription(const int slot) const {
@@ -139,267 +73,44 @@ Common::String SaveLoadChooser::createDefaultSaveDescription(const int slot) con
#endif
}
-void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
- int selItem = _list->getSelected();
-
- switch (cmd) {
- case GUI::kListItemActivatedCmd:
- case GUI::kListItemDoubleClickedCmd:
- if (selItem >= 0 && _chooseButton->isEnabled()) {
- if (_list->isEditable() || !_list->getSelectedString().empty()) {
- _list->endEditMode();
- if (!_saveList.empty()) {
- setResult(_saveList[selItem].getSaveSlot());
- _resultString = _list->getSelectedString();
- }
- close();
- }
- }
- break;
- case kChooseCmd:
- _list->endEditMode();
- if (!_saveList.empty()) {
- setResult(_saveList[selItem].getSaveSlot());
- _resultString = _list->getSelectedString();
- }
- close();
- break;
- case GUI::kListSelectionChangedCmd:
- updateSelection(true);
- break;
- case kDelCmd:
- if (selItem >= 0 && _delSupport) {
- MessageDialog alert(_("Do you really want to delete this savegame?"),
- _("Delete"), _("Cancel"));
- if (alert.runModal() == GUI::kMessageOK) {
- (*_plugin)->removeSaveState(_target.c_str(), _saveList[selItem].getSaveSlot());
-
- setResult(-1);
- _list->setSelected(-1);
-
- updateSaveList();
- updateSelection(true);
- }
- }
- break;
- case kCloseCmd:
- setResult(-1);
- default:
- Dialog::handleCommand(sender, cmd, data);
- }
-}
-
-void SaveLoadChooser::reflowLayout() {
- if (g_gui.xmlEval()->getVar("Globals.SaveLoadChooser.ExtInfo.Visible") == 1 && _thumbnailSupport) {
- int16 x, y;
- uint16 w, h;
-
- if (!g_gui.xmlEval()->getWidgetData("SaveLoadChooser.Thumbnail", x, y, w, h))
- error("Error when loading position data for Save/Load Thumbnails");
-
- int thumbW = kThumbnailWidth;
- int thumbH = kThumbnailHeight2;
- int thumbX = x + (w >> 1) - (thumbW >> 1);
- int thumbY = y + kLineHeight;
-
- int textLines = 0;
- if (!_saveDateSupport)
- textLines++;
- if (!_playTimeSupport)
- textLines++;
-
- _container->resize(x, y, w, h - (kLineHeight * textLines));
- _gfxWidget->resize(thumbX, thumbY, thumbW, thumbH);
-
- int height = thumbY + thumbH + kLineHeight;
-
- if (_saveDateSupport) {
- _date->resize(thumbX, height, kThumbnailWidth, kLineHeight);
- height += kLineHeight;
- _time->resize(thumbX, height, kThumbnailWidth, kLineHeight);
- height += kLineHeight;
- }
-
- if (_playTimeSupport)
- _playtime->resize(thumbX, height, kThumbnailWidth, kLineHeight);
-
- _container->setVisible(true);
- _gfxWidget->setVisible(true);
-
- _date->setVisible(_saveDateSupport);
- _time->setVisible(_saveDateSupport);
-
- _playtime->setVisible(_playTimeSupport);
+int SaveLoadChooser::runModalWithCurrentTarget() {
+ const Common::String gameId = ConfMan.get("gameid");
- _fillR = 0;
- _fillG = 0;
- _fillB = 0;
- updateSelection(false);
- } else {
- _container->setVisible(false);
- _gfxWidget->setVisible(false);
- _date->setVisible(false);
- _time->setVisible(false);
- _playtime->setVisible(false);
- }
+ const EnginePlugin *plugin = 0;
+ EngineMan.findGame(gameId, &plugin);
- Dialog::reflowLayout();
+ return runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName());
}
-void SaveLoadChooser::updateSelection(bool redraw) {
- int selItem = _list->getSelected();
-
- bool isDeletable = _delSupport;
- bool isWriteProtected = false;
- bool startEditMode = _list->isEditable();
-
- _gfxWidget->setGfx(-1, -1, _fillR, _fillG, _fillB);
- _date->setLabel(_("No date saved"));
- _time->setLabel(_("No time saved"));
- _playtime->setLabel(_("No playtime saved"));
-
- if (selItem >= 0 && _metaInfoSupport) {
- SaveStateDescriptor desc = (*_plugin)->querySaveMetaInfos(_target.c_str(), _saveList[selItem].getSaveSlot());
-
- isDeletable = desc.getDeletableFlag() && _delSupport;
- isWriteProtected = desc.getWriteProtectedFlag();
-
- // Don't allow the user to change the description of write protected games
- if (isWriteProtected)
- startEditMode = false;
-
- if (_thumbnailSupport) {
- const Graphics::Surface *thumb = desc.getThumbnail();
- if (thumb) {
- _gfxWidget->setGfx(thumb);
- _gfxWidget->useAlpha(256);
- }
- }
-
- if (_saveDateSupport) {
- const Common::String &saveDate = desc.getSaveDate();
- if (!saveDate.empty())
- _date->setLabel(_("Date: ") + saveDate);
-
- const Common::String &saveTime = desc.getSaveTime();
- if (!saveTime.empty())
- _time->setLabel(_("Time: ") + saveTime);
- }
-
- if (_playTimeSupport) {
- const Common::String &playTime = desc.getPlayTime();
- if (!playTime.empty())
- _playtime->setLabel(_("Playtime: ") + playTime);
- }
- }
-
-
- if (_list->isEditable()) {
- // Disable the save button if nothing is selected, or if the selected
- // game is write protected
- _chooseButton->setEnabled(selItem >= 0 && !isWriteProtected);
+int SaveLoadChooser::runModalWithPluginAndTarget(const EnginePlugin *plugin, const String &target) {
+ selectChooser(**plugin);
+ if (!_impl)
+ return -1;
- if (startEditMode) {
- _list->startEditMode();
+ // Set up the game domain as newly active domain, so
+ // target specific savepath will be checked
+ String oldDomain = ConfMan.getActiveDomainName();
+ ConfMan.setActiveDomain(target);
- if (_chooseButton->isEnabled() && _list->getSelectedString() == _("Untitled savestate") &&
- _list->getSelectionColor() == ThemeEngine::kFontColorAlternate) {
- _list->setEditString("");
- _list->setEditColor(ThemeEngine::kFontColorNormal);
- }
+ int ret;
+ do {
+ ret = _impl->run(target, &(**plugin));
+#ifndef DISABLE_SAVELOADCHOOSER_GRID
+ if (ret == kSwitchSaveLoadDialog) {
+ selectChooser(**plugin);
}
- } else {
- // Disable the load button if nothing is selected, or if an empty
- // list item is selected.
- _chooseButton->setEnabled(selItem >= 0 && !_list->getSelectedString().empty());
- }
-
- // Delete will always be disabled if the engine doesn't support it.
- _deleteButton->setEnabled(isDeletable && (selItem >= 0) && (!_list->getSelectedString().empty()));
-
- if (redraw) {
- _gfxWidget->draw();
- _date->draw();
- _time->draw();
- _playtime->draw();
- _chooseButton->draw();
- _deleteButton->draw();
-
- draw();
- }
-}
+#endif // !DISABLE_SAVELOADCHOOSER_GRID
+ } while (ret < -1);
-void SaveLoadChooser::close() {
- _plugin = 0;
- _target.clear();
- _saveList.clear();
- _list->setList(StringArray());
+ // Revert to the old active domain
+ ConfMan.setActiveDomain(oldDomain);
- Dialog::close();
+ return ret;
}
-void SaveLoadChooser::updateSaveList() {
- _saveList = (*_plugin)->listSaves(_target.c_str());
-
- int curSlot = 0;
- int saveSlot = 0;
- StringArray saveNames;
- ListWidget::ColorList colors;
- for (SaveStateList::const_iterator x = _saveList.begin(); x != _saveList.end(); ++x) {
- // Handle gaps in the list of save games
- saveSlot = x->getSaveSlot();
- if (curSlot < saveSlot) {
- while (curSlot < saveSlot) {
- SaveStateDescriptor dummySave(curSlot, "");
- _saveList.insert_at(curSlot, dummySave);
- saveNames.push_back(dummySave.getDescription());
- colors.push_back(ThemeEngine::kFontColorNormal);
- curSlot++;
- }
-
- // Sync the save list iterator
- for (x = _saveList.begin(); x != _saveList.end(); ++x) {
- if (x->getSaveSlot() == saveSlot)
- break;
- }
- }
-
- // Show "Untitled savestate" for empty/whitespace savegame descriptions
- Common::String description = x->getDescription();
- Common::String trimmedDescription = description;
- trimmedDescription.trim();
- if (trimmedDescription.empty()) {
- description = _("Untitled savestate");
- colors.push_back(ThemeEngine::kFontColorAlternate);
- } else {
- colors.push_back(ThemeEngine::kFontColorNormal);
- }
-
- saveNames.push_back(description);
- curSlot++;
- }
-
- // Fill the rest of the save slots with empty saves
-
- int maximumSaveSlots = (*_plugin)->getMaximumSaveSlot();
-
-#ifdef __DS__
- // Low memory on the DS means too many save slots are impractical, so limit
- // the maximum here.
- if (maximumSaveSlots > 99) {
- maximumSaveSlots = 99;
- }
-#endif
-
- Common::String emptyDesc;
- for (int i = curSlot; i <= maximumSaveSlots; i++) {
- saveNames.push_back(emptyDesc);
- SaveStateDescriptor dummySave(i, "");
- _saveList.push_back(dummySave);
- colors.push_back(ThemeEngine::kFontColorNormal);
- }
-
- _list->setList(saveNames, &colors);
+const Common::String &SaveLoadChooser::getResultString() const {
+ assert(_impl);
+ return _impl->getResultString();
}
} // End of namespace GUI
diff --git a/gui/saveload.h b/gui/saveload.h
index a19f5ab083..17fd99a31d 100644
--- a/gui/saveload.h
+++ b/gui/saveload.h
@@ -19,54 +19,30 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef GUI_SAVELOAD_DIALOG_H
-#define GUI_SAVELOAD_DIALOG_H
+#ifndef GUI_SAVELOAD_H
+#define GUI_SAVELOAD_H
#include "gui/dialog.h"
#include "engines/metaengine.h"
namespace GUI {
-class ListWidget;
-class GraphicsWidget;
-class ButtonWidget;
-class CommandSender;
-class ContainerWidget;
-class StaticTextWidget;
+class SaveLoadChooserDialog;
-class SaveLoadChooser : GUI::Dialog {
+class SaveLoadChooser {
typedef Common::String String;
- typedef Common::Array<Common::String> StringArray;
protected:
- GUI::ListWidget *_list;
- GUI::ButtonWidget *_chooseButton;
- GUI::ButtonWidget *_deleteButton;
- GUI::GraphicsWidget *_gfxWidget;
- GUI::ContainerWidget *_container;
- GUI::StaticTextWidget *_date;
- GUI::StaticTextWidget *_time;
- GUI::StaticTextWidget *_playtime;
+ SaveLoadChooserDialog *_impl;
- const EnginePlugin *_plugin;
- bool _delSupport;
- bool _metaInfoSupport;
- bool _thumbnailSupport;
- bool _saveDateSupport;
- bool _playTimeSupport;
- String _target;
- SaveStateList _saveList;
- String _resultString;
+ const String _title;
+ const String _buttonLabel;
+ const bool _saveMode;
- uint8 _fillR, _fillG, _fillB;
-
- void updateSaveList();
- void updateSelection(bool redraw);
+ void selectChooser(const MetaEngine &engine);
public:
SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode);
~SaveLoadChooser();
- virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
-
/**
* Runs the save/load chooser with the currently active config manager
* domain as target.
@@ -75,7 +51,6 @@ public:
*/
int runModalWithCurrentTarget();
int runModalWithPluginAndTarget(const EnginePlugin *plugin, const String &target);
- void open();
const Common::String &getResultString() const;
@@ -93,10 +68,6 @@ public:
* @return The slot description.
*/
Common::String createDefaultSaveDescription(const int slot) const;
-
- virtual void reflowLayout();
-
- virtual void close();
};
} // End of namespace GUI
diff --git a/gui/themes/default.inc b/gui/themes/default.inc
index 86d0061e1b..7f565eb05d 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -619,6 +619,8 @@
"<def var='ShowLauncherLogo' value='0'/> "
"<def var='ShowGlobalMenuLogo' value='0'/> "
"<def var='ShowSearchPic' value='0'/> "
+"<def var='ShowChooserPics' value='0'/> "
+"<def var='ShowChooserPageDisplay' value='0'/> "
"<def var='SaveLoadChooser.ExtInfo.Visible' value='0'/> "
"<def var='KeyMapper.Spacing' value='5'/> "
"<def var='KeyMapper.LabelWidth' value='80'/> "
@@ -1362,6 +1364,14 @@
"<widget name='Title' height='Globals.Line.Height'/> "
"<widget name='List' /> "
"<layout type='horizontal' padding='0,0,16,0'> "
+"<widget name='ListSwitch' "
+"height='Globals.Line.Height' "
+"width='Globals.Line.Height' "
+"/> "
+"<widget name='GridSwitch' "
+"height='Globals.Line.Height' "
+"width='Globals.Line.Height' "
+"/> "
"<space/> "
"<widget name='Delete' "
"type='Button' "
@@ -1376,6 +1386,25 @@
"</layout> "
"</layout> "
"</dialog> "
+"<dialog name='SavenameDialog' overlays='screen_center'> "
+"<layout type='vertical' padding='8,8,8,8'> "
+"<widget name='DescriptionText' "
+"width='180' "
+"height='Globals.Line.Height' "
+"/> "
+"<widget name='Description' "
+"height='19' "
+"/> "
+"<layout type='horizontal' padding='0,0,16,0'> "
+"<widget name='Cancel' "
+"type='Button' "
+"/> "
+"<widget name='Ok' "
+"type='Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
"<dialog name='ScummHelp' overlays='screen'> "
"<layout type='vertical' padding='8,8,8,8'> "
"<widget name='Title' "
@@ -1564,6 +1593,8 @@
"<def var='ShowLauncherLogo' value='0'/> "
"<def var='ShowGlobalMenuLogo' value='0'/> "
"<def var='ShowSearchPic' value='0'/> "
+"<def var='ShowChooserPics' value='0'/> "
+"<def var='ShowChooserPageDisplay' value='1'/> "
"<def var='SaveLoadChooser.ExtInfo.Visible' value='1'/> "
"<def var='KeyMapper.Spacing' value='10'/> "
"<def var='KeyMapper.LabelWidth' value='100'/> "
@@ -2294,9 +2325,16 @@
"</dialog> "
"<dialog name='SaveLoadChooser' overlays='screen' inset='8' shading='dim'> "
"<layout type='vertical' padding='8,8,8,32' center='true'> "
+"<layout type='horizontal' padding='0,0,0,0'> "
"<widget name='Title' "
"height='Globals.Line.Height' "
"/> "
+"<space/> "
+"<widget name='PageDisplay' "
+"width='200' "
+"height='Globals.Line.Height' "
+"/> "
+"</layout> "
"<layout type='horizontal' padding='0,0,0,16' spacing='16'> "
"<widget name='List' /> "
"<widget name='Thumbnail' "
@@ -2305,6 +2343,14 @@
"/> "
"</layout> "
"<layout type='horizontal' padding='0,0,0,0'> "
+"<widget name='ListSwitch' "
+"height='Globals.Line.Height' "
+"width='Globals.Line.Height' "
+"/> "
+"<widget name='GridSwitch' "
+"height='Globals.Line.Height' "
+"width='Globals.Line.Height' "
+"/> "
"<space/> "
"<widget name='Delete' "
"type='Button' "
@@ -2319,6 +2365,26 @@
"</layout> "
"</layout> "
"</dialog> "
+"<dialog name='SavenameDialog' overlays='screen_center'> "
+"<layout type='vertical' padding='8,8,8,8'> "
+"<widget name='DescriptionText' "
+"width='320' "
+"height='Globals.Line.Height' "
+"/> "
+"<widget name='Description' "
+"height='19' "
+"/> "
+"<layout type='horizontal' padding='0,0,16,0'> "
+"<widget name='Cancel' "
+"type='Button' "
+"/> "
+"<space size='96'/> "
+"<widget name='Ok' "
+"type='Button' "
+"/> "
+"</layout> "
+"</layout> "
+"</dialog> "
"<dialog name='ScummHelp' overlays='screen_center'> "
"<layout type='vertical' padding='8,8,8,8' center='true'> "
"<widget name='Title' "
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index d126ed0774..62eae0cd43 100644
--- a/gui/themes/scummclassic.zip
+++ b/gui/themes/scummclassic.zip
Binary files differ
diff --git a/gui/themes/scummclassic/THEMERC b/gui/themes/scummclassic/THEMERC
index d4bed29cf8..b8937adcb2 100644
--- a/gui/themes/scummclassic/THEMERC
+++ b/gui/themes/scummclassic/THEMERC
@@ -1 +1 @@
-[SCUMMVM_STX0.8.13:ScummVM Classic Theme:No Author]
+[SCUMMVM_STX0.8.16:ScummVM Classic Theme:No Author]
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index 8717892995..4a6aae00bc 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -32,6 +32,9 @@
<def var = 'ShowGlobalMenuLogo' value = '0'/>
<def var = 'ShowSearchPic' value = '0'/>
+ <def var = 'ShowChooserPics' value = '0'/>
+ <def var = 'ShowChooserPageDisplay' value = '1'/>
+
<def var = 'SaveLoadChooser.ExtInfo.Visible' value = '1'/>
<def var = 'KeyMapper.Spacing' value = '10'/>
@@ -793,9 +796,16 @@
<dialog name = 'SaveLoadChooser' overlays = 'screen' inset = '8' shading = 'dim'>
<layout type = 'vertical' padding = '8, 8, 8, 32' center = 'true'>
- <widget name = 'Title'
- height = 'Globals.Line.Height'
- />
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'Title'
+ height = 'Globals.Line.Height'
+ />
+ <space/>
+ <widget name = 'PageDisplay'
+ width = '200'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
<layout type = 'horizontal' padding = '0, 0, 0, 16' spacing = '16'>
<widget name = 'List' />
<widget name = 'Thumbnail'
@@ -804,6 +814,14 @@
/>
</layout>
<layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'ListSwitch'
+ height = 'Globals.Line.Height'
+ width = 'Globals.Line.Height'
+ />
+ <widget name = 'GridSwitch'
+ height = 'Globals.Line.Height'
+ width = 'Globals.Line.Height'
+ />
<space/>
<widget name = 'Delete'
type = 'Button'
@@ -819,6 +837,27 @@
</layout>
</dialog>
+ <dialog name = 'SavenameDialog' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'DescriptionText'
+ width = '320'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Description'
+ height = '19'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <space size = '96'/>
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
<dialog name = 'ScummHelp' overlays = 'screen_center'>
<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>
<widget name = 'Title'
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index 8f5db9d364..57e149b570 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -33,6 +33,9 @@
<def var = 'ShowGlobalMenuLogo' value = '0'/>
<def var = 'ShowSearchPic' value = '0'/>
+ <def var = 'ShowChooserPics' value = '0'/>
+ <def var = 'ShowChooserPageDisplay' value = '0'/>
+
<def var = 'SaveLoadChooser.ExtInfo.Visible' value = '0'/>
<def var = 'KeyMapper.Spacing' value = '5'/>
@@ -807,6 +810,14 @@
<widget name = 'Title' height = 'Globals.Line.Height'/>
<widget name = 'List' />
<layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <widget name = 'ListSwitch'
+ height = 'Globals.Line.Height'
+ width = 'Globals.Line.Height'
+ />
+ <widget name = 'GridSwitch'
+ height = 'Globals.Line.Height'
+ width = 'Globals.Line.Height'
+ />
<space/>
<widget name = 'Delete'
type = 'Button'
@@ -822,6 +833,26 @@
</layout>
</dialog>
+ <dialog name = 'SavenameDialog' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'DescriptionText'
+ width = '180'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Description'
+ height = '19'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
<dialog name = 'ScummHelp' overlays = 'screen'>
<layout type = 'vertical' padding = '8, 8, 8, 8'>
<widget name = 'Title'
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index db116325e2..38352bcc2f 100644
--- a/gui/themes/scummmodern.zip
+++ b/gui/themes/scummmodern.zip
Binary files differ
diff --git a/gui/themes/scummmodern/THEMERC b/gui/themes/scummmodern/THEMERC
index 60744d386f..52eb683ebd 100644
--- a/gui/themes/scummmodern/THEMERC
+++ b/gui/themes/scummmodern/THEMERC
@@ -1 +1 @@
-[SCUMMVM_STX0.8.13:ScummVM Modern Theme:No Author]
+[SCUMMVM_STX0.8.16:ScummVM Modern Theme:No Author]
diff --git a/gui/themes/scummmodern/grid.bmp b/gui/themes/scummmodern/grid.bmp
new file mode 100644
index 0000000000..adeb209380
--- /dev/null
+++ b/gui/themes/scummmodern/grid.bmp
Binary files differ
diff --git a/gui/themes/scummmodern/list.bmp b/gui/themes/scummmodern/list.bmp
new file mode 100644
index 0000000000..2f54a40bcd
--- /dev/null
+++ b/gui/themes/scummmodern/list.bmp
Binary files differ
diff --git a/gui/themes/scummmodern/scummmodern_gfx.stx b/gui/themes/scummmodern/scummmodern_gfx.stx
index 037c327235..4d449f50ec 100644
--- a/gui/themes/scummmodern/scummmodern_gfx.stx
+++ b/gui/themes/scummmodern/scummmodern_gfx.stx
@@ -101,6 +101,8 @@
<bitmap filename = 'search.bmp'/>
<bitmap filename = 'eraser.bmp'/>
<bitmap filename = 'delbtn.bmp'/>
+ <bitmap filename = 'list.bmp'/>
+ <bitmap filename = 'grid.bmp'/>
</bitmaps>
<fonts>
@@ -153,7 +155,7 @@
/>
<text_color id = 'color_normal_disabled'
- color = '192, 192, 192'
+ color = '96, 96, 96'
/>
<text_color id = 'color_alternative'
diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx
index 087a844a1b..d99d7416c2 100644
--- a/gui/themes/scummmodern/scummmodern_layout.stx
+++ b/gui/themes/scummmodern/scummmodern_layout.stx
@@ -39,6 +39,9 @@
<def var = 'ShowGlobalMenuLogo' value = '1'/>
<def var = 'ShowSearchPic' value = '1'/>
+ <def var = 'ShowChooserPics' value = '1'/>
+ <def var = 'ShowChooserPageDisplay' value = '1'/>
+
<def var = 'SaveLoadChooser.ExtInfo.Visible' value = '1'/>
<def var = 'KeyMapper.Spacing' value = '10'/>
@@ -807,9 +810,16 @@
<dialog name = 'SaveLoadChooser' overlays = 'screen' inset = '8' shading = 'dim'>
<layout type = 'vertical' padding = '8, 8, 8, 32' center = 'true'>
- <widget name = 'Title'
- height = 'Globals.Line.Height'
- />
+ <layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'Title'
+ height = 'Globals.Line.Height'
+ />
+ <space/>
+ <widget name = 'PageDisplay'
+ width = '200'
+ height = 'Globals.Line.Height'
+ />
+ </layout>
<layout type = 'horizontal' padding = '0, 0, 0, 16' spacing = '16'>
<widget name = 'List' />
<widget name = 'Thumbnail'
@@ -818,6 +828,14 @@
/>
</layout>
<layout type = 'horizontal' padding = '0, 0, 0, 0'>
+ <widget name = 'ListSwitch'
+ height = '20'
+ width = '20'
+ />
+ <widget name = 'GridSwitch'
+ height = '20'
+ width = '20'
+ />
<space/>
<widget name = 'Delete'
type = 'Button'
@@ -833,6 +851,27 @@
</layout>
</dialog>
+ <dialog name = 'SavenameDialog' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'DescriptionText'
+ width = '320'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Description'
+ height = '19'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <space size = '96'/>
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
<dialog name = 'ScummHelp' overlays = 'screen_center'>
<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>
<widget name = 'Title'
diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
index 987fee800a..4fd5bdcf40 100644
--- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx
+++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
@@ -31,6 +31,9 @@
<def var = 'ShowGlobalMenuLogo' value = '0'/>
<def var = 'ShowSearchPic' value = '0'/>
+ <def var = 'ShowChooserPics' value = '0'/>
+ <def var = 'ShowChooserPageDisplay' value = '0'/>
+
<def var = 'SaveLoadChooser.ExtInfo.Visible' value = '0'/>
<def var = 'Predictive.Button.Width' value = '45' />
@@ -806,6 +809,14 @@
<widget name = 'Title' height = 'Globals.Line.Height'/>
<widget name = 'List' />
<layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <widget name = 'ListSwitch'
+ height = 'Globals.Line.Height'
+ width = 'Globals.Line.Height'
+ />
+ <widget name = 'GridSwitch'
+ height = 'Globals.Line.Height'
+ width = 'Globals.Line.Height'
+ />
<space/>
<widget name = 'Delete'
type = 'Button'
@@ -821,6 +832,26 @@
</layout>
</dialog>
+ <dialog name = 'SavenameDialog' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'DescriptionText'
+ width = '180'
+ height = 'Globals.Line.Height'
+ />
+ <widget name = 'Description'
+ height = '19'
+ />
+ <layout type = 'horizontal' padding = '0, 0, 16, 0'>
+ <widget name = 'Cancel'
+ type = 'Button'
+ />
+ <widget name = 'Ok'
+ type = 'Button'
+ />
+ </layout>
+ </layout>
+ </dialog>
+
<dialog name = 'ScummHelp' overlays = 'screen' inset = '8'>
<layout type = 'vertical' padding = '8, 8, 8, 8'>
<widget name = 'Title'
diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat
index 4b35fdb9a8..1c3abf84a8 100644
--- a/gui/themes/translations.dat
+++ b/gui/themes/translations.dat
Binary files differ
diff --git a/gui/widget.cpp b/gui/widget.cpp
index 1b68e36ea8..4ffb63e945 100644
--- a/gui/widget.cpp
+++ b/gui/widget.cpp
@@ -296,8 +296,8 @@ ButtonWidget::ButtonWidget(GuiObject *boss, const Common::String &name, const Co
void ButtonWidget::handleMouseUp(int x, int y, int button, int clickCount) {
if (isEnabled() && x >= 0 && x < _w && y >= 0 && y < _h) {
- sendCommand(_cmd, 0);
startAnimatePressedState();
+ sendCommand(_cmd, 0);
}
}
@@ -366,7 +366,7 @@ void ButtonWidget::startAnimatePressedState() {
}
void ButtonWidget::wantTickle(bool tickled) {
- if (tickled)
+ if (tickled)
((GUI::Dialog *)_boss)->setTickleWidget(this);
else
((GUI::Dialog *)_boss)->unSetTickleWidget();
@@ -376,7 +376,7 @@ void ButtonWidget::wantTickle(bool tickled) {
PicButtonWidget::PicButtonWidget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip, uint32 cmd, uint8 hotkey)
: ButtonWidget(boss, x, y, w, h, "", tooltip, cmd, hotkey),
- _gfx(new Graphics::Surface()), _alpha(256), _transparency(false) {
+ _gfx(), _alpha(256), _transparency(false) {
setFlags(WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG);
_type = kButtonWidget;
@@ -384,18 +384,17 @@ PicButtonWidget::PicButtonWidget(GuiObject *boss, int x, int y, int w, int h, co
PicButtonWidget::PicButtonWidget(GuiObject *boss, const Common::String &name, const char *tooltip, uint32 cmd, uint8 hotkey)
: ButtonWidget(boss, name, "", tooltip, cmd, hotkey),
- _gfx(new Graphics::Surface()), _alpha(256), _transparency(false) {
+ _gfx(), _alpha(256), _transparency(false) {
setFlags(WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG);
_type = kButtonWidget;
}
PicButtonWidget::~PicButtonWidget() {
- _gfx->free();
- delete _gfx;
+ _gfx.free();
}
void PicButtonWidget::setGfx(const Graphics::Surface *gfx) {
- _gfx->free();
+ _gfx.free();
if (!gfx || !gfx->pixels)
return;
@@ -411,27 +410,37 @@ void PicButtonWidget::setGfx(const Graphics::Surface *gfx) {
return;
}
- _gfx->copyFrom(*gfx);
+ _gfx.copyFrom(*gfx);
+}
+
+void PicButtonWidget::setGfx(int w, int h, int r, int g, int b) {
+ if (w == -1)
+ w = _w;
+ if (h == -1)
+ h = _h;
+
+ const Graphics::PixelFormat &requiredFormat = g_gui.theme()->getPixelFormat();
+
+ _gfx.free();
+ _gfx.create(w, h, requiredFormat);
+ _gfx.fillRect(Common::Rect(0, 0, w, h), _gfx.format.RGBToColor(r, g, b));
}
void PicButtonWidget::drawWidget() {
g_gui.theme()->drawButton(Common::Rect(_x, _y, _x+_w, _y+_h), "", _state, getFlags());
- if (_gfx->pixels) {
+ if (_gfx.pixels) {
// Check whether the set up surface needs to be converted to the GUI
// color format.
const Graphics::PixelFormat &requiredFormat = g_gui.theme()->getPixelFormat();
- if (_gfx->format != requiredFormat) {
- Graphics::Surface *converted = _gfx->convertTo(requiredFormat);
- _gfx->free();
- delete _gfx;
- _gfx = converted;
+ if (_gfx.format != requiredFormat) {
+ _gfx.convertToInPlace(requiredFormat);
}
- const int x = _x + (_w - _gfx->w) / 2;
- const int y = _y + (_h - _gfx->h) / 2;
+ const int x = _x + (_w - _gfx.w) / 2;
+ const int y = _y + (_h - _gfx.h) / 2;
- g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx->w, y + _gfx->h), *_gfx, _state, _alpha, _transparency);
+ g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), _gfx, _state, _alpha, _transparency);
}
}
@@ -619,24 +628,23 @@ int SliderWidget::posToValue(int pos) {
#pragma mark -
GraphicsWidget::GraphicsWidget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip)
- : Widget(boss, x, y, w, h, tooltip), _gfx(new Graphics::Surface()), _alpha(256), _transparency(false) {
+ : Widget(boss, x, y, w, h, tooltip), _gfx(), _alpha(256), _transparency(false) {
setFlags(WIDGET_ENABLED | WIDGET_CLEARBG);
_type = kGraphicsWidget;
}
GraphicsWidget::GraphicsWidget(GuiObject *boss, const Common::String &name, const char *tooltip)
- : Widget(boss, name, tooltip), _gfx(new Graphics::Surface()), _alpha(256), _transparency(false) {
+ : Widget(boss, name, tooltip), _gfx(), _alpha(256), _transparency(false) {
setFlags(WIDGET_ENABLED | WIDGET_CLEARBG);
_type = kGraphicsWidget;
}
GraphicsWidget::~GraphicsWidget() {
- _gfx->free();
- delete _gfx;
+ _gfx.free();
}
void GraphicsWidget::setGfx(const Graphics::Surface *gfx) {
- _gfx->free();
+ _gfx.free();
if (!gfx || !gfx->pixels)
return;
@@ -651,7 +659,7 @@ void GraphicsWidget::setGfx(const Graphics::Surface *gfx) {
return;
}
- _gfx->copyFrom(*gfx);
+ _gfx.copyFrom(*gfx);
}
void GraphicsWidget::setGfx(int w, int h, int r, int g, int b) {
@@ -662,27 +670,24 @@ void GraphicsWidget::setGfx(int w, int h, int r, int g, int b) {
const Graphics::PixelFormat &requiredFormat = g_gui.theme()->getPixelFormat();
- _gfx->free();
- _gfx->create(w, h, requiredFormat);
- _gfx->fillRect(Common::Rect(0, 0, w, h), _gfx->format.RGBToColor(r, g, b));
+ _gfx.free();
+ _gfx.create(w, h, requiredFormat);
+ _gfx.fillRect(Common::Rect(0, 0, w, h), _gfx.format.RGBToColor(r, g, b));
}
void GraphicsWidget::drawWidget() {
- if (_gfx->pixels) {
+ if (_gfx.pixels) {
// Check whether the set up surface needs to be converted to the GUI
// color format.
const Graphics::PixelFormat &requiredFormat = g_gui.theme()->getPixelFormat();
- if (_gfx->format != requiredFormat) {
- Graphics::Surface *converted = _gfx->convertTo(requiredFormat);
- _gfx->free();
- delete _gfx;
- _gfx = converted;
+ if (_gfx.format != requiredFormat) {
+ _gfx.convertToInPlace(requiredFormat);
}
- const int x = _x + (_w - _gfx->w) / 2;
- const int y = _y + (_h - _gfx->h) / 2;
+ const int x = _x + (_w - _gfx.w) / 2;
+ const int y = _y + (_h - _gfx.h) / 2;
- g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx->w, y + _gfx->h), *_gfx, _state, _alpha, _transparency);
+ g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), _gfx, _state, _alpha, _transparency);
}
}
@@ -698,6 +703,26 @@ ContainerWidget::ContainerWidget(GuiObject *boss, const Common::String &name) :
_type = kContainerWidget;
}
+ContainerWidget::~ContainerWidget() {
+ // We also remove the widget from the boss to avoid segfaults, when the
+ // deleted widget is an active widget in the boss.
+ for (Widget *w = _firstWidget; w; w = w->next()) {
+ _boss->removeWidget(w);
+ }
+}
+
+Widget *ContainerWidget::findWidget(int x, int y) {
+ return findWidgetInChain(_firstWidget, x, y);
+}
+
+void ContainerWidget::removeWidget(Widget *widget) {
+ // We also remove the widget from the boss to avoid a reference to a
+ // widget not in the widget chain anymore.
+ _boss->removeWidget(widget);
+
+ Widget::removeWidget(widget);
+}
+
void ContainerWidget::drawWidget() {
g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), 0, ThemeEngine::kWidgetBackgroundBorder);
}
diff --git a/gui/widget.h b/gui/widget.h
index 6de56862c3..e3f712564f 100644
--- a/gui/widget.h
+++ b/gui/widget.h
@@ -88,7 +88,7 @@ protected:
uint16 _id;
bool _hasFocus;
ThemeEngine::WidgetStateInfo _state;
- const char *_tooltip;
+ Common::String _tooltip;
private:
uint16 _flags;
@@ -142,7 +142,9 @@ public:
uint8 parseHotkey(const Common::String &label);
Common::String cleanupHotkey(const Common::String &label);
- const char *getTooltip() const { return _tooltip; }
+ bool hasTooltip() const { return !_tooltip.empty(); }
+ const Common::String &getTooltip() const { return _tooltip; }
+ void setTooltip(const Common::String &tooltip) { _tooltip = tooltip; }
protected:
void updateState(int oldFlags, int newFlags);
@@ -220,6 +222,7 @@ public:
~PicButtonWidget();
void setGfx(const Graphics::Surface *gfx);
+ void setGfx(int w, int h, int r, int g, int b);
void useAlpha(int alpha) { _alpha = alpha; }
void useThemeTransparency(bool enable) { _transparency = enable; }
@@ -227,7 +230,7 @@ public:
protected:
void drawWidget();
- Graphics::Surface *_gfx;
+ Graphics::Surface _gfx;
int _alpha;
bool _transparency;
};
@@ -355,7 +358,7 @@ public:
protected:
void drawWidget();
- Graphics::Surface *_gfx;
+ Graphics::Surface _gfx;
int _alpha;
bool _transparency;
};
@@ -365,7 +368,10 @@ class ContainerWidget : public Widget {
public:
ContainerWidget(GuiObject *boss, int x, int y, int w, int h);
ContainerWidget(GuiObject *boss, const Common::String &name);
+ ~ContainerWidget();
+ virtual Widget *findWidget(int x, int y);
+ virtual void removeWidget(Widget *widget);
protected:
void drawWidget();
};
diff --git a/gui/widgets/editable.h b/gui/widgets/editable.h
index 7e453c1204..4a18d5e689 100644
--- a/gui/widgets/editable.h
+++ b/gui/widgets/editable.h
@@ -77,10 +77,10 @@ public:
protected:
virtual void startEditMode() = 0;
virtual void endEditMode() = 0;
- virtual void abortEditMode() = 0;
+ virtual void abortEditMode() = 0;
virtual Common::Rect getEditRect() const = 0;
virtual int getCaretOffset() const;
- void drawCaret(bool erase);
+ void drawCaret(bool erase);
bool adjustOffset();
void makeCaretVisible();
diff --git a/gui/widgets/list.h b/gui/widgets/list.h
index 41fae37a71..47613b79f3 100644
--- a/gui/widgets/list.h
+++ b/gui/widgets/list.h
@@ -105,6 +105,7 @@ public:
void scrollTo(int item);
void scrollToEnd();
+ int getCurrentScrollPos() const { return _currentPos; }
void enableQuickSelect(bool enable) { _quickSelect = enable; }
String getQuickSelectString() const { return _quickSelectStr; }