GUI: Create an interface for save/load dialogs.
This commit is contained in:
parent
62c66cdb9c
commit
1aa5200bb8
5 changed files with 475 additions and 388 deletions
|
@ -15,6 +15,7 @@ MODULE_OBJS := \
|
||||||
options.o \
|
options.o \
|
||||||
predictivedialog.o \
|
predictivedialog.o \
|
||||||
saveload.o \
|
saveload.o \
|
||||||
|
saveload-dialog.o \
|
||||||
themebrowser.o \
|
themebrowser.o \
|
||||||
ThemeEngine.o \
|
ThemeEngine.o \
|
||||||
ThemeEval.o \
|
ThemeEval.o \
|
||||||
|
|
380
gui/saveload-dialog.cpp
Normal file
380
gui/saveload-dialog.cpp
Normal file
|
@ -0,0 +1,380 @@
|
||||||
|
/* 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 "gui/message.h"
|
||||||
|
#include "gui/gui-manager.h"
|
||||||
|
#include "gui/ThemeEval.h"
|
||||||
|
|
||||||
|
#include "graphics/scaler.h"
|
||||||
|
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
SaveLoadChooserDialog::SaveLoadChooserDialog(const Common::String &dialogName)
|
||||||
|
: Dialog(dialogName), _metaEngine(0), _delSupport(false), _metaInfoSupport(false),
|
||||||
|
_thumbnailSupport(false), _saveDateSupport(false), _playTimeSupport(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveLoadChooserDialog::SaveLoadChooserDialog(int x, int y, int w, int h)
|
||||||
|
: Dialog(x, y, w, h), _metaEngine(0), _delSupport(false), _metaInfoSupport(false),
|
||||||
|
_thumbnailSupport(false), _saveDateSupport(false), _playTimeSupport(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveLoadChooserSimple implementation
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kChooseCmd = 'CHOS',
|
||||||
|
kDelCmd = 'DEL '
|
||||||
|
};
|
||||||
|
|
||||||
|
SaveLoadChooserSimple::SaveLoadChooserSimple(const String &title, const String &buttonLabel, bool saveMode)
|
||||||
|
: SaveLoadChooserDialog("SaveLoadChooser"), _list(0), _chooseButton(0), _deleteButton(0), _gfxWidget(0) {
|
||||||
|
_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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) {
|
||||||
|
_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);
|
||||||
|
|
||||||
|
_fillR = 0;
|
||||||
|
_fillG = 0;
|
||||||
|
_fillB = 0;
|
||||||
|
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();
|
||||||
|
|
||||||
|
_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 = _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::close() {
|
||||||
|
_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace GUI
|
90
gui/saveload-dialog.h
Normal file
90
gui/saveload-dialog.h
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/* 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 {
|
||||||
|
|
||||||
|
class SaveLoadChooserDialog : protected Dialog {
|
||||||
|
public:
|
||||||
|
SaveLoadChooserDialog(const Common::String &dialogName);
|
||||||
|
SaveLoadChooserDialog(int x, int y, int w, int h);
|
||||||
|
|
||||||
|
virtual void open();
|
||||||
|
|
||||||
|
int run(const Common::String &target, const MetaEngine *metaEngine);
|
||||||
|
virtual const Common::String &getResultString() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int runIntern() = 0;
|
||||||
|
|
||||||
|
const MetaEngine *_metaEngine;
|
||||||
|
bool _delSupport;
|
||||||
|
bool _metaInfoSupport;
|
||||||
|
bool _thumbnailSupport;
|
||||||
|
bool _saveDateSupport;
|
||||||
|
bool _playTimeSupport;
|
||||||
|
Common::String _target;
|
||||||
|
};
|
||||||
|
|
||||||
|
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(GUI::CommandSender *sender, uint32 cmd, uint32 data);
|
||||||
|
|
||||||
|
virtual const Common::String &getResultString() const;
|
||||||
|
|
||||||
|
virtual void reflowLayout();
|
||||||
|
|
||||||
|
virtual void close();
|
||||||
|
private:
|
||||||
|
virtual int runIntern();
|
||||||
|
|
||||||
|
GUI::ListWidget *_list;
|
||||||
|
GUI::ButtonWidget *_chooseButton;
|
||||||
|
GUI::ButtonWidget *_deleteButton;
|
||||||
|
GUI::GraphicsWidget *_gfxWidget;
|
||||||
|
GUI::ContainerWidget *_container;
|
||||||
|
GUI::StaticTextWidget *_date;
|
||||||
|
GUI::StaticTextWidget *_time;
|
||||||
|
GUI::StaticTextWidget *_playtime;
|
||||||
|
|
||||||
|
SaveStateList _saveList;
|
||||||
|
String _resultString;
|
||||||
|
|
||||||
|
uint8 _fillR, _fillG, _fillB;
|
||||||
|
|
||||||
|
void updateSaveList();
|
||||||
|
void updateSelection(bool redraw);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace GUI
|
||||||
|
|
||||||
|
#endif
|
388
gui/saveload.cpp
388
gui/saveload.cpp
|
@ -20,401 +20,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common/config-manager.h"
|
#include "common/config-manager.h"
|
||||||
#include "common/translation.h"
|
|
||||||
#include "common/system.h"
|
#include "common/system.h"
|
||||||
|
|
||||||
#include "gui/widgets/list.h"
|
|
||||||
#include "gui/message.h"
|
|
||||||
#include "gui/saveload.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"
|
#include "engines/metaengine.h"
|
||||||
|
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
enum {
|
|
||||||
kChooseCmd = 'CHOS',
|
|
||||||
kDelCmd = 'DEL '
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class SaveLoadChooserImpl : GUI::Dialog {
|
|
||||||
typedef Common::String String;
|
|
||||||
typedef Common::Array<Common::String> StringArray;
|
|
||||||
public:
|
|
||||||
SaveLoadChooserImpl(const String &title, const String &buttonLabel, bool saveMode);
|
|
||||||
|
|
||||||
int run(const String &target, const MetaEngine *metaEngine);
|
|
||||||
|
|
||||||
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
|
|
||||||
|
|
||||||
const Common::String &getResultString() const;
|
|
||||||
|
|
||||||
virtual void open();
|
|
||||||
|
|
||||||
virtual void reflowLayout();
|
|
||||||
|
|
||||||
virtual void close();
|
|
||||||
private:
|
|
||||||
GUI::ListWidget *_list;
|
|
||||||
GUI::ButtonWidget *_chooseButton;
|
|
||||||
GUI::ButtonWidget *_deleteButton;
|
|
||||||
GUI::GraphicsWidget *_gfxWidget;
|
|
||||||
GUI::ContainerWidget *_container;
|
|
||||||
GUI::StaticTextWidget *_date;
|
|
||||||
GUI::StaticTextWidget *_time;
|
|
||||||
GUI::StaticTextWidget *_playtime;
|
|
||||||
|
|
||||||
const MetaEngine *_metaEngine;
|
|
||||||
bool _delSupport;
|
|
||||||
bool _metaInfoSupport;
|
|
||||||
bool _thumbnailSupport;
|
|
||||||
bool _saveDateSupport;
|
|
||||||
bool _playTimeSupport;
|
|
||||||
String _target;
|
|
||||||
SaveStateList _saveList;
|
|
||||||
String _resultString;
|
|
||||||
|
|
||||||
uint8 _fillR, _fillG, _fillB;
|
|
||||||
|
|
||||||
void updateSaveList();
|
|
||||||
void updateSelection(bool redraw);
|
|
||||||
};
|
|
||||||
|
|
||||||
SaveLoadChooserImpl::SaveLoadChooserImpl(const String &title, const String &buttonLabel, bool saveMode)
|
|
||||||
: Dialog("SaveLoadChooser"), _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);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SaveLoadChooserImpl::run(const String &target, const MetaEngine *metaEngine) {
|
|
||||||
if (_gfxWidget)
|
|
||||||
_gfxWidget->setGfx(0);
|
|
||||||
|
|
||||||
_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);
|
|
||||||
_resultString.clear();
|
|
||||||
reflowLayout();
|
|
||||||
updateSaveList();
|
|
||||||
|
|
||||||
return Dialog::runModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveLoadChooserImpl::open() {
|
|
||||||
Dialog::open();
|
|
||||||
|
|
||||||
// So that quitting ScummVM will not cause the dialog result to say a
|
|
||||||
// savegame was selected.
|
|
||||||
setResult(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Common::String &SaveLoadChooserImpl::getResultString() const {
|
|
||||||
int selItem = _list->getSelected();
|
|
||||||
return (selItem >= 0) ? _list->getSelectedString() : _resultString;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveLoadChooserImpl::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) {
|
|
||||||
_metaEngine->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 SaveLoadChooserImpl::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);
|
|
||||||
|
|
||||||
_fillR = 0;
|
|
||||||
_fillG = 0;
|
|
||||||
_fillB = 0;
|
|
||||||
updateSelection(false);
|
|
||||||
} else {
|
|
||||||
_container->setVisible(false);
|
|
||||||
_gfxWidget->setVisible(false);
|
|
||||||
_date->setVisible(false);
|
|
||||||
_time->setVisible(false);
|
|
||||||
_playtime->setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dialog::reflowLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveLoadChooserImpl::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 = _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 SaveLoadChooserImpl::close() {
|
|
||||||
_metaEngine = 0;
|
|
||||||
_target.clear();
|
|
||||||
_saveList.clear();
|
|
||||||
_list->setList(StringArray());
|
|
||||||
|
|
||||||
Dialog::close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveLoadChooserImpl::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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- SaveLoadChooser implementation ---
|
|
||||||
|
|
||||||
SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode) {
|
SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode) {
|
||||||
_impl = new SaveLoadChooserImpl(title, buttonLabel, saveMode);
|
_impl = new SaveLoadChooserSimple(title, buttonLabel, saveMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveLoadChooser::~SaveLoadChooser() {
|
SaveLoadChooser::~SaveLoadChooser() {
|
||||||
|
|
|
@ -27,12 +27,12 @@
|
||||||
|
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
class SaveLoadChooserImpl;
|
class SaveLoadChooserDialog;
|
||||||
|
|
||||||
class SaveLoadChooser {
|
class SaveLoadChooser {
|
||||||
typedef Common::String String;
|
typedef Common::String String;
|
||||||
protected:
|
protected:
|
||||||
SaveLoadChooserImpl *_impl;
|
SaveLoadChooserDialog *_impl;
|
||||||
public:
|
public:
|
||||||
SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode);
|
SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode);
|
||||||
~SaveLoadChooser();
|
~SaveLoadChooser();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue