ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

saveload-dialog.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "gui/saveload-dialog.h"
00024 
00025 #if defined(USE_CLOUD) && defined(USE_LIBCURL)
00026 #include "backends/cloud/cloudmanager.h"
00027 #include "backends/cloud/savessyncrequest.h"
00028 #include "backends/networking/curl/connectionmanager.h"
00029 #endif
00030 
00031 #include "common/translation.h"
00032 #include "common/config-manager.h"
00033 
00034 #include "gui/message.h"
00035 #include "gui/gui-manager.h"
00036 #include "gui/ThemeEval.h"
00037 #include "gui/widgets/edittext.h"
00038 
00039 #include "graphics/scaler.h"
00040 #include <common/savefile.h>
00041 
00042 namespace GUI {
00043 
00044 #if defined(USE_CLOUD) && defined(USE_LIBCURL)
00045 
00046 enum {
00047     kCancelSyncCmd = 'PDCS',
00048     kBackgroundSyncCmd = 'PDBS'
00049 };
00050 
00051 SaveLoadCloudSyncProgressDialog::SaveLoadCloudSyncProgressDialog(bool canRunInBackground): Dialog("SaveLoadCloudSyncProgress"), _close(false) {
00052     _label = new StaticTextWidget(this, "SaveLoadCloudSyncProgress.TitleText", "Downloading saves...");
00053     uint32 progress = (uint32)(100 * CloudMan.getSyncDownloadingProgress());
00054     _progressBar = new SliderWidget(this, "SaveLoadCloudSyncProgress.ProgressBar");
00055     _progressBar->setMinValue(0);
00056     _progressBar->setMaxValue(100);
00057     _progressBar->setValue(progress);
00058     _progressBar->setEnabled(false);
00059     _percentLabel = new StaticTextWidget(this, "SaveLoadCloudSyncProgress.PercentText", Common::String::format("%u %%", progress));
00060     new ButtonWidget(this, "SaveLoadCloudSyncProgress.Cancel", "Cancel", nullptr, kCancelSyncCmd, Common::ASCII_ESCAPE);    // Cancel dialog
00061     ButtonWidget *backgroundButton = new ButtonWidget(this, "SaveLoadCloudSyncProgress.Background", "Run in background", nullptr, kBackgroundSyncCmd, Common::ASCII_RETURN);    // Confirm dialog
00062     backgroundButton->setEnabled(canRunInBackground);
00063     g_gui.scheduleTopDialogRedraw();
00064 }
00065 
00066 SaveLoadCloudSyncProgressDialog::~SaveLoadCloudSyncProgressDialog() {
00067     CloudMan.setSyncTarget(nullptr); //not that dialog, at least
00068 }
00069 
00070 void SaveLoadCloudSyncProgressDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
00071     switch(cmd) {
00072     case kSavesSyncProgressCmd:
00073         _percentLabel->setLabel(Common::String::format("%u%%", data));
00074         _progressBar->setValue(data);
00075         _progressBar->markAsDirty();
00076         break;
00077 
00078     case kCancelSyncCmd:
00079         setResult(kCancelSyncCmd);
00080         close();
00081         break;
00082 
00083     case kSavesSyncEndedCmd:
00084     case kBackgroundSyncCmd:
00085         _close = true;
00086         break;
00087 
00088     default:
00089         break;
00090     }
00091 
00092     Dialog::handleCommand(sender, cmd, data);
00093 }
00094 
00095 void SaveLoadCloudSyncProgressDialog::handleTickle() {
00096     if (_close) {
00097         setResult(kBackgroundSyncCmd);
00098         close();
00099     }
00100 
00101     Dialog::handleTickle();
00102 }
00103 #endif
00104 
00105 #ifndef DISABLE_SAVELOADCHOOSER_GRID
00106 SaveLoadChooserType getRequestedSaveLoadDialog(const MetaEngine &metaEngine) {
00107     const Common::String &userConfig = ConfMan.get("gui_saveload_chooser", Common::ConfigManager::kApplicationDomain);
00108 
00109     // Check (and update if necessary) the theme config here. This catches
00110     // resolution changes, which happened after the GUI was closed. This
00111     // should assure that the correct GUI width/height are returned below and
00112     // prevent the logic from picking the grid dialog, even though it is not
00113     // possible to use it.
00114     g_gui.checkScreenChange();
00115 
00116     if (g_gui.getWidth() >= 640 && g_gui.getHeight() >= 400
00117         && metaEngine.hasFeature(MetaEngine::kSavesSupportMetaInfo)
00118         && metaEngine.hasFeature(MetaEngine::kSavesSupportThumbnail)
00119         && userConfig.equalsIgnoreCase("grid")) {
00120         // In case we are 640x400 or higher, this dialog is not in save mode,
00121         // the user requested the grid dialog and the engines supports it we
00122         // try to set it up.
00123         return kSaveLoadDialogGrid;
00124     } else {
00125         // In all other cases we want to use the list dialog.
00126         return kSaveLoadDialogList;
00127     }
00128 }
00129 
00130 enum {
00131     kListSwitchCmd = 'LIST',
00132     kGridSwitchCmd = 'GRID'
00133 };
00134 #endif // !DISABLE_SAVELOADCHOOSER_GRID
00135 
00136 SaveLoadChooserDialog::SaveLoadChooserDialog(const Common::String &dialogName, const bool saveMode)
00137     : Dialog(dialogName), _metaEngine(nullptr), _delSupport(false), _metaInfoSupport(false),
00138     _thumbnailSupport(false), _saveDateSupport(false), _playTimeSupport(false), _saveMode(saveMode),
00139     _dialogWasShown(false)
00140 #ifndef DISABLE_SAVELOADCHOOSER_GRID
00141     , _listButton(nullptr), _gridButton(nullptr)
00142 #endif // !DISABLE_SAVELOADCHOOSER_GRID
00143     {
00144 #ifndef DISABLE_SAVELOADCHOOSER_GRID
00145     addChooserButtons();
00146 #endif // !DISABLE_SAVELOADCHOOSER_GRID
00147 }
00148 
00149 SaveLoadChooserDialog::SaveLoadChooserDialog(int x, int y, int w, int h, const bool saveMode)
00150     : Dialog(x, y, w, h), _metaEngine(nullptr), _delSupport(false), _metaInfoSupport(false),
00151     _thumbnailSupport(false), _saveDateSupport(false), _playTimeSupport(false), _saveMode(saveMode),
00152     _dialogWasShown(false)
00153 #ifndef DISABLE_SAVELOADCHOOSER_GRID
00154     , _listButton(nullptr), _gridButton(nullptr)
00155 #endif // !DISABLE_SAVELOADCHOOSER_GRID
00156     {
00157 #ifndef DISABLE_SAVELOADCHOOSER_GRID
00158     addChooserButtons();
00159 #endif // !DISABLE_SAVELOADCHOOSER_GRID
00160 }
00161 
00162 SaveLoadChooserDialog::~SaveLoadChooserDialog() {
00163 #if defined(USE_CLOUD) && defined(USE_LIBCURL)
00164     CloudMan.setSyncTarget(nullptr); //not that dialog, at least
00165 #endif
00166 }
00167 
00168 void SaveLoadChooserDialog::open() {
00169     Dialog::open();
00170 
00171     // So that quitting ScummVM will not cause the dialog result to say a
00172     // saved game was selected.
00173     setResult(-1);
00174 
00175     _dialogWasShown = false;
00176 }
00177 
00178 void SaveLoadChooserDialog::close() {
00179 #if defined(USE_CLOUD) && defined(USE_LIBCURL)
00180     CloudMan.setSyncTarget(nullptr); //not that dialog, at least
00181 #endif
00182     Dialog::close();
00183 }
00184 
00185 int SaveLoadChooserDialog::run(const Common::String &target, const MetaEngine *metaEngine) {
00186     _metaEngine = metaEngine;
00187     _target = target;
00188     _delSupport = _metaEngine->hasFeature(MetaEngine::kSupportsDeleteSave);
00189     _metaInfoSupport = _metaEngine->hasFeature(MetaEngine::kSavesSupportMetaInfo);
00190     _thumbnailSupport = _metaInfoSupport && _metaEngine->hasFeature(MetaEngine::kSavesSupportThumbnail);
00191     _saveDateSupport = _metaInfoSupport && _metaEngine->hasFeature(MetaEngine::kSavesSupportCreationDate);
00192     _playTimeSupport = _metaInfoSupport && _metaEngine->hasFeature(MetaEngine::kSavesSupportPlayTime);
00193 
00194     return runIntern();
00195 }
00196 
00197 void SaveLoadChooserDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
00198 #ifndef DISABLE_SAVELOADCHOOSER_GRID
00199     switch (cmd) {
00200     case kListSwitchCmd:
00201         setResult(kSwitchSaveLoadDialog);
00202         // We save the requested dialog type here to avoid the setting to be
00203         // overwritten when our reflowLayout logic selects a different dialog
00204         // type.
00205         ConfMan.set("gui_saveload_chooser", "list", Common::ConfigManager::kApplicationDomain);
00206         close();
00207         break;
00208 
00209     case kGridSwitchCmd:
00210         setResult(kSwitchSaveLoadDialog);
00211         // See above.
00212         ConfMan.set("gui_saveload_chooser", "grid", Common::ConfigManager::kApplicationDomain);
00213         close();
00214         break;
00215 
00216     default:
00217         break;
00218     }
00219 #endif // !DISABLE_SAVELOADCHOOSER_GRID
00220 
00221 #if defined(USE_CLOUD) && defined(USE_LIBCURL)
00222     if (cmd == kSavesSyncProgressCmd || cmd == kSavesSyncEndedCmd) {
00223         //this dialog only gets these commands if the progress dialog was shown and user clicked "run in background"
00224         return updateSaveList();
00225     }
00226 #endif
00227 
00228     return Dialog::handleCommand(sender, cmd, data);
00229 }
00230 
00231 #if defined(USE_CLOUD) && defined(USE_LIBCURL)
00232 void SaveLoadChooserDialog::runSaveSync(bool hasSavepathOverride) {
00233     if (!CloudMan.isSyncing()) {
00234         if (hasSavepathOverride) {
00235             CloudMan.showCloudDisabledIcon();
00236         } else {
00237             Cloud::SavesSyncRequest *request = CloudMan.syncSaves();
00238             if (request)
00239                 request->setTarget(this);
00240         }
00241     }
00242 }
00243 #endif
00244 
00245 void SaveLoadChooserDialog::handleTickle() {
00246 #if defined(USE_CLOUD) && defined(USE_LIBCURL)
00247     if (!_dialogWasShown && CloudMan.isSyncing()) {
00248         Common::Array<Common::String> files = CloudMan.getSyncingFiles();
00249         if (!files.empty()) {
00250             {
00251                 SaveLoadCloudSyncProgressDialog dialog(_metaEngine ? _metaEngine->hasFeature(MetaEngine::kSimpleSavesNames) : false);
00252                 CloudMan.setSyncTarget(&dialog);
00253                 int result = dialog.runModal();
00254                 if (result == kCancelSyncCmd) {
00255                     CloudMan.cancelSync();
00256                 }
00257             }
00258             //dialog changes syncTarget to nullptr after that }
00259             CloudMan.setSyncTarget(this);
00260             _dialogWasShown = true;
00261             updateSaveList();
00262         }
00263     }
00264 #endif
00265     Dialog::handleTickle();
00266 }
00267 
00268 void SaveLoadChooserDialog::reflowLayout() {
00269 #ifndef DISABLE_SAVELOADCHOOSER_GRID
00270     const SaveLoadChooserType currentType = getType();
00271     const SaveLoadChooserType requestedType = getRequestedSaveLoadDialog(*_metaEngine);
00272 
00273     addChooserButtons();
00274     if (currentType == kSaveLoadDialogList) {
00275         _listButton->setEnabled(false);
00276     }
00277     if (currentType == kSaveLoadDialogGrid) {
00278         _gridButton->setEnabled(false);
00279     }
00280 
00281     // Change the dialog type if there is any need for it.
00282     if (requestedType != currentType) {
00283         setResult(kSwitchSaveLoadDialog);
00284         close();
00285     }
00286 #endif // !DISABLE_SAVELOADCHOOSER_GRID
00287 
00288     Dialog::reflowLayout();
00289 }
00290 
00291 void SaveLoadChooserDialog::updateSaveList() {
00292 #if defined(USE_CLOUD) && defined(USE_LIBCURL)
00293     Common::Array<Common::String> files = CloudMan.getSyncingFiles(); //returns empty array if not syncing
00294     g_system->getSavefileManager()->updateSavefilesList(files);
00295 #endif
00296     listSaves();
00297 }
00298 
00299 void SaveLoadChooserDialog::listSaves() {
00300     if (!_metaEngine) return; //very strange
00301     _saveList = _metaEngine->listSaves(_target.c_str(), _saveMode);
00302 
00303 #if defined(USE_CLOUD) && defined(USE_LIBCURL)
00304     //if there is Cloud support, add currently synced files as "locked" saves in the list
00305     if (_metaEngine->hasFeature(MetaEngine::kSimpleSavesNames)) {
00306         Common::String pattern = _target + ".###";
00307         Common::Array<Common::String> files = CloudMan.getSyncingFiles(); //returns empty array if not syncing
00308         for (uint32 i = 0; i < files.size(); ++i) {
00309             if (!files[i].matchString(pattern, true))
00310                 continue;
00311 
00312             //make up some slot number
00313             int slotNum = 0;
00314             for (uint32 j = (files[i].size() > 3 ? files[i].size() - 3 : 0); j < files[i].size(); ++j) { //3 last chars
00315                 char c = files[i][j];
00316                 if (c < '0' || c > '9')
00317                     continue;
00318                 slotNum = slotNum * 10 + (c - '0');
00319             }
00320 
00321             SaveStateDescriptor slot(slotNum, files[i]);
00322             slot.setLocked(true);
00323             _saveList.push_back(slot);
00324         }
00325 
00326         Common::sort(_saveList.begin(), _saveList.end(), SaveStateDescriptorSlotComparator());
00327     }
00328 #endif
00329 }
00330 
00331 #ifndef DISABLE_SAVELOADCHOOSER_GRID
00332 void SaveLoadChooserDialog::addChooserButtons() {
00333     if (_listButton) {
00334         removeWidget(_listButton);
00335         delete _listButton;
00336     }
00337 
00338     if (_gridButton) {
00339         removeWidget(_gridButton);
00340         delete _gridButton;
00341     }
00342 
00343     _listButton = createSwitchButton("SaveLoadChooser.ListSwitch", "L", _("List view"), ThemeEngine::kImageList, kListSwitchCmd);
00344     _gridButton = createSwitchButton("SaveLoadChooser.GridSwitch", "G", _("Grid view"), ThemeEngine::kImageGrid, kGridSwitchCmd);
00345     if (!_metaInfoSupport || !_thumbnailSupport || !(g_gui.getWidth() >= 640 && g_gui.getHeight() >= 400)) {
00346         _gridButton->setEnabled(false);
00347         _listButton->setEnabled(false);
00348     }
00349 }
00350 
00351 ButtonWidget *SaveLoadChooserDialog::createSwitchButton(const Common::String &name, const char *desc, const char *tooltip, const char *image, uint32 cmd) {
00352     ButtonWidget *button;
00353 
00354 #ifndef DISABLE_FANCY_THEMES
00355     if (g_gui.xmlEval()->getVar("Globals.ShowChooserPics") == 1 && g_gui.theme()->supportsImages()) {
00356         button = new PicButtonWidget(this, name, tooltip, cmd);
00357         ((PicButtonWidget *)button)->useThemeTransparency(true);
00358         ((PicButtonWidget *)button)->setGfx(g_gui.theme()->getImageSurface(image));
00359     } else
00360 #endif
00361         button = new ButtonWidget(this, name, desc, tooltip, cmd);
00362 
00363     return button;
00364 }
00365 #endif // !DISABLE_SAVELOADCHOOSER_GRID
00366 
00367 // SaveLoadChooserSimple implementation
00368 
00369 enum {
00370     kChooseCmd = 'CHOS',
00371     kDelCmd = 'DEL '
00372 };
00373 
00374 SaveLoadChooserSimple::SaveLoadChooserSimple(const String &title, const String &buttonLabel, bool saveMode)
00375     : SaveLoadChooserDialog("SaveLoadChooser", saveMode), _list(nullptr), _chooseButton(nullptr), _deleteButton(nullptr), _gfxWidget(nullptr),
00376     _container(nullptr) {
00377     _backgroundType = ThemeEngine::kDialogBackgroundSpecial;
00378 
00379     new StaticTextWidget(this, "SaveLoadChooser.Title", title);
00380 
00381     // Add choice list
00382     _list = new ListWidget(this, "SaveLoadChooser.List");
00383     _list->setNumberingMode(kListNumberingZero);
00384     _list->setEditable(saveMode);
00385 
00386     _gfxWidget = new GraphicsWidget(this, 0, 0, 10, 10);
00387 
00388     _date = new StaticTextWidget(this, 0, 0, 10, 10, _("No date saved"), Graphics::kTextAlignCenter);
00389     _time = new StaticTextWidget(this, 0, 0, 10, 10, _("No time saved"), Graphics::kTextAlignCenter);
00390     _playtime = new StaticTextWidget(this, 0, 0, 10, 10, _("No playtime saved"), Graphics::kTextAlignCenter);
00391 
00392     // Buttons
00393     new ButtonWidget(this, "SaveLoadChooser.Cancel", _("Cancel"), nullptr, kCloseCmd);
00394     _chooseButton = new ButtonWidget(this, "SaveLoadChooser.Choose", buttonLabel, nullptr, kChooseCmd);
00395     _chooseButton->setEnabled(false);
00396 
00397     _deleteButton = new ButtonWidget(this, "SaveLoadChooser.Delete", _("Delete"), nullptr, kDelCmd);
00398     _deleteButton->setEnabled(false);
00399 
00400     _delSupport = _metaInfoSupport = _thumbnailSupport = false;
00401 
00402     addThumbnailContainer();
00403 }
00404 
00405 void SaveLoadChooserSimple::addThumbnailContainer() {
00406     // When switching layouts, create / remove the thumbnail container as needed
00407     if (g_gui.xmlEval()->getVar("Globals.SaveLoadChooser.ExtInfo.Visible") == 1 && !_container) {
00408         _container = new ContainerWidget(this, "SaveLoadChooser.Thumbnail");
00409     } else if (g_gui.xmlEval()->getVar("Globals.SaveLoadChooser.ExtInfo.Visible") == 0 && _container) {
00410         removeWidget(_container);
00411         delete _container;
00412         _container = nullptr;
00413     }
00414 }
00415 
00416 int SaveLoadChooserSimple::runIntern() {
00417     if (_gfxWidget)
00418         _gfxWidget->setGfx(nullptr);
00419 
00420     _resultString.clear();
00421     reflowLayout();
00422     updateSaveList();
00423 
00424     return Dialog::runModal();
00425 }
00426 
00427 const Common::String &SaveLoadChooserSimple::getResultString() const {
00428     int selItem = _list->getSelected();
00429     return (selItem >= 0) ? _list->getSelectedString() : _resultString;
00430 }
00431 
00432 void SaveLoadChooserSimple::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
00433     int selItem = _list->getSelected();
00434 
00435     switch (cmd) {
00436     case kListItemActivatedCmd:
00437     case kListItemDoubleClickedCmd:
00438         if (selItem >= 0 && _chooseButton->isEnabled()) {
00439             if (_list->isEditable() || !_list->getSelectedString().empty()) {
00440                 _list->endEditMode();
00441                 if (!_saveList.empty()) {
00442                     setResult(_saveList[selItem].getSaveSlot());
00443                     _resultString = _list->getSelectedString();
00444                 }
00445                 close();
00446             }
00447         }
00448         break;
00449     case kChooseCmd:
00450         _list->endEditMode();
00451         if (selItem >= 0) {
00452             if (!_saveList.empty()) {
00453                 setResult(_saveList[selItem].getSaveSlot());
00454                 _resultString = _list->getSelectedString();
00455             }
00456             close();
00457         }
00458         break;
00459     case kListSelectionChangedCmd:
00460         updateSelection(true);
00461         break;
00462     case kDelCmd:
00463         if (selItem >= 0 && _delSupport) {
00464             MessageDialog alert(_("Do you really want to delete this saved game?"),
00465                                 _("Delete"), _("Cancel"));
00466             if (alert.runModal() == kMessageOK) {
00467                 _metaEngine->removeSaveState(_target.c_str(), _saveList[selItem].getSaveSlot());
00468 
00469                 setResult(-1);
00470                 _list->setSelected(-1);
00471 
00472                 updateSaveList();
00473                 updateSelection(true);
00474             }
00475         }
00476         break;
00477     case kCloseCmd:
00478         setResult(-1);
00479         // Fall through
00480     default:
00481         SaveLoadChooserDialog::handleCommand(sender, cmd, data);
00482     }
00483 }
00484 
00485 void SaveLoadChooserSimple::reflowLayout() {
00486     addThumbnailContainer();
00487 
00488     SaveLoadChooserDialog::reflowLayout();
00489 
00490     if (g_gui.xmlEval()->getVar("Globals.SaveLoadChooser.ExtInfo.Visible") == 1 && (_thumbnailSupport || _saveDateSupport || _playTimeSupport)) {
00491         int16 x, y;
00492         int16 w, h;
00493 
00494         if (!g_gui.xmlEval()->getWidgetData("SaveLoadChooser.Thumbnail", x, y, w, h))
00495             error("Error when loading position data for Save/Load Thumbnails");
00496 
00497         // Even if there is no thumbnail support, getWidgetData() will provide default thumbnail values
00498         int thumbW = kThumbnailWidth;
00499         int thumbH = kThumbnailHeight2;
00500         int thumbX = x + (w >> 1) - (thumbW >> 1);
00501         int thumbY = y + kLineHeight;
00502 
00503         int textLines = 0;
00504         if (_saveDateSupport)
00505             textLines += 2;
00506         if (_playTimeSupport)
00507             textLines++;
00508         if (textLines > 0)
00509             textLines++; // add a line of padding at the bottom
00510 
00511         if (_thumbnailSupport) {
00512             _gfxWidget->resize(thumbX, thumbY, thumbW, thumbH);
00513             _gfxWidget->setVisible(true);
00514         } else {
00515             // choose sensible values for displaying playtime and date/time when a thumbnail is not being used
00516             thumbH = 0;
00517             thumbY = y;
00518             h = kLineHeight;
00519             _gfxWidget->setVisible(false);
00520         }
00521 
00522         int height = thumbY + thumbH + kLineHeight;
00523 
00524         if (_saveDateSupport) {
00525             _date->resize(thumbX, height, thumbW, kLineHeight);
00526             height += kLineHeight;
00527             _time->resize(thumbX, height, thumbW, kLineHeight);
00528             height += kLineHeight;
00529             _date->setVisible(_saveDateSupport);
00530             _time->setVisible(_saveDateSupport);
00531         } else {
00532             _date->setVisible(false);
00533             _time->setVisible(false);
00534         }
00535 
00536         if (_playTimeSupport) {
00537             _playtime->resize(thumbX, height, thumbW, kLineHeight);
00538             _playtime->setVisible(_playTimeSupport);
00539         } else {
00540             _playtime->setVisible(false);
00541         }
00542 
00543         _container->resize(x, y, w, h + (kLineHeight * textLines));
00544         _container->setVisible(true);
00545 
00546         updateSelection(false);
00547     } else {
00548         if (_container) _container->setVisible(false);
00549         _gfxWidget->setVisible(false);
00550         _date->setVisible(false);
00551         _time->setVisible(false);
00552         _playtime->setVisible(false);
00553     }
00554 }
00555 
00556 void SaveLoadChooserSimple::updateSelection(bool redraw) {
00557     int selItem = _list->getSelected();
00558 
00559     bool isDeletable = _delSupport;
00560     bool isWriteProtected = false;
00561     bool startEditMode = _list->isEditable();
00562     bool isLocked = false;
00563 
00564     // We used to support letting the themes specify the fill color with our
00565     // initial theme based GUI. But this support was dropped.
00566     _gfxWidget->setGfx(-1, -1, 0, 0, 0);
00567     _date->setLabel(_("No date saved"));
00568     _time->setLabel(_("No time saved"));
00569     _playtime->setLabel(_("No playtime saved"));
00570 
00571     if (selItem >= 0 && _metaInfoSupport) {
00572         SaveStateDescriptor desc = (_saveList[selItem].getLocked() ? _saveList[selItem] : _metaEngine->querySaveMetaInfos(_target.c_str(), _saveList[selItem].getSaveSlot()));
00573 
00574         isDeletable = desc.getDeletableFlag() && _delSupport;
00575         isWriteProtected = desc.getWriteProtectedFlag() ||
00576             _saveList[selItem].getWriteProtectedFlag();
00577         isLocked = desc.getLocked();
00578 
00579         // Don't allow the user to change the description of write protected games
00580         if (isWriteProtected)
00581             startEditMode = false;
00582 
00583         if (_thumbnailSupport) {
00584             const Graphics::Surface *thumb = desc.getThumbnail();
00585             if (thumb) {
00586                 _gfxWidget->setGfx(thumb);
00587                 _gfxWidget->useAlpha(256);
00588             }
00589         }
00590 
00591         if (_saveDateSupport) {
00592             const Common::String &saveDate = desc.getSaveDate();
00593             if (!saveDate.empty())
00594                 _date->setLabel(_("Date: ") + saveDate);
00595 
00596             const Common::String &saveTime = desc.getSaveTime();
00597             if (!saveTime.empty())
00598                 _time->setLabel(_("Time: ") + saveTime);
00599         }
00600 
00601         if (_playTimeSupport) {
00602             const Common::String &playTime = desc.getPlayTime();
00603             if (!playTime.empty())
00604                 _playtime->setLabel(_("Playtime: ") + playTime);
00605         }
00606     }
00607 
00608 
00609     if (_list->isEditable()) {
00610         // Disable the save button if slot is locked, nothing is selected,
00611         // or if the selected game is write protected
00612         _chooseButton->setEnabled(!isLocked && selItem >= 0 && !isWriteProtected);
00613 
00614         if (startEditMode) {
00615             _list->startEditMode();
00616 
00617             if (_chooseButton->isEnabled() && _list->getSelectedString() == _("Untitled saved game") &&
00618                     _list->getSelectionColor() == ThemeEngine::kFontColorAlternate) {
00619                 _list->setEditString("");
00620                 _list->setEditColor(ThemeEngine::kFontColorNormal);
00621             }
00622         }
00623     } else {
00624         // Disable the load button if slot is locked, nothing is selected,
00625         // or if an empty list item is selected.
00626         _chooseButton->setEnabled(!isLocked && selItem >= 0 && !_list->getSelectedString().empty());
00627     }
00628 
00629     // Delete will always be disabled if the engine doesn't support it.
00630     _deleteButton->setEnabled(isDeletable && !isLocked && (selItem >= 0) && (!_list->getSelectedString().empty()));
00631 
00632     if (redraw) {
00633         _gfxWidget->markAsDirty();
00634         _date->markAsDirty();
00635         _time->markAsDirty();
00636         _playtime->markAsDirty();
00637         _chooseButton->markAsDirty();
00638         _deleteButton->markAsDirty();
00639 
00640         g_gui.scheduleTopDialogRedraw();
00641     }
00642 }
00643 
00644 void SaveLoadChooserSimple::open() {
00645     SaveLoadChooserDialog::open();
00646 
00647     // Scroll the list to the last used entry.
00648     _list->scrollTo(ConfMan.getInt("gui_saveload_last_pos"));
00649 }
00650 
00651 void SaveLoadChooserSimple::close() {
00652     // Save the current scroll position/used entry.
00653     const int result = getResult();
00654     if (result >= 0) {
00655         ConfMan.setInt("gui_saveload_last_pos", result);
00656     } else {
00657         // Use the current scroll position here.
00658         // TODO: This means we canceled the dialog (or switch to the grid). Do
00659         // we want to save this position here? Does the user want that?
00660         // TODO: Do we want to save the current scroll position or the
00661         // currently selected item here? The scroll position is what the user
00662         // currently sees and seems to make more sense.
00663         ConfMan.setInt("gui_saveload_last_pos", _list->getCurrentScrollPos());
00664     }
00665 
00666     _metaEngine = nullptr;
00667     _target.clear();
00668     _saveList.clear();
00669     _list->setList(StringArray());
00670 
00671     SaveLoadChooserDialog::close();
00672 }
00673 
00674 void SaveLoadChooserSimple::updateSaveList() {
00675     SaveLoadChooserDialog::updateSaveList();
00676 
00677     int curSlot = 0;
00678     int saveSlot = 0;
00679     StringArray saveNames;
00680     ListWidget::ColorList colors;
00681     for (SaveStateList::const_iterator x = _saveList.begin(); x != _saveList.end(); ++x) {
00682         // Handle gaps in the list of save games
00683         saveSlot = x->getSaveSlot();
00684         if (curSlot < saveSlot) {
00685             while (curSlot < saveSlot) {
00686                 SaveStateDescriptor dummySave(curSlot, "");
00687                 _saveList.insert_at(curSlot, dummySave);
00688                 saveNames.push_back(dummySave.getDescription());
00689                 colors.push_back(ThemeEngine::kFontColorNormal);
00690                 curSlot++;
00691             }
00692 
00693             // Sync the save list iterator
00694             for (x = _saveList.begin(); x != _saveList.end(); ++x) {
00695                 if (x->getSaveSlot() == saveSlot)
00696                     break;
00697             }
00698         }
00699 
00700         // Show "Untitled saved game" for empty/whitespace saved game descriptions
00701         Common::String description = x->getDescription();
00702         Common::String trimmedDescription = description;
00703         trimmedDescription.trim();
00704         if (trimmedDescription.empty()) {
00705             description = _("Untitled saved game");
00706             colors.push_back(ThemeEngine::kFontColorAlternate);
00707         } else {
00708             colors.push_back((x->getLocked() ? ThemeEngine::kFontColorAlternate : ThemeEngine::kFontColorNormal));
00709         }
00710 
00711         saveNames.push_back(description);
00712         curSlot++;
00713     }
00714 
00715     // Fill the rest of the save slots with empty saves
00716 
00717     int maximumSaveSlots = _metaEngine->getMaximumSaveSlot();
00718 
00719 #ifdef __DS__
00720     // Low memory on the DS means too many save slots are impractical, so limit
00721     // the maximum here.
00722     if (maximumSaveSlots > 99) {
00723         maximumSaveSlots = 99;
00724     }
00725 #endif
00726 
00727     Common::String emptyDesc;
00728     for (int i = curSlot; i <= maximumSaveSlots; i++) {
00729         saveNames.push_back(emptyDesc);
00730         SaveStateDescriptor dummySave(i, "");
00731         _saveList.push_back(dummySave);
00732         colors.push_back(ThemeEngine::kFontColorNormal);
00733     }
00734 
00735     int selected = _list->getSelected();
00736     _list->setList(saveNames, &colors);
00737     if (selected >= 0 && selected < (int)saveNames.size())
00738         _list->setSelected(selected);
00739     else
00740         _chooseButton->setEnabled(false);
00741 
00742     g_gui.scheduleTopDialogRedraw();
00743 }
00744 
00745 // SaveLoadChooserGrid implementation
00746 
00747 #ifndef DISABLE_SAVELOADCHOOSER_GRID
00748 
00749 enum {
00750     kNextCmd = 'NEXT',
00751     kPrevCmd = 'PREV',
00752     kNewSaveCmd = 'SAVE'
00753 };
00754 
00755 SaveLoadChooserGrid::SaveLoadChooserGrid(const Common::String &title, bool saveMode)
00756     : SaveLoadChooserDialog("SaveLoadChooser", saveMode), _lines(0), _columns(0), _entriesPerPage(0),
00757     _curPage(0), _newSaveContainer(nullptr), _nextFreeSaveSlot(0), _buttons() {
00758     _backgroundType = ThemeEngine::kDialogBackgroundSpecial;
00759 
00760     new StaticTextWidget(this, "SaveLoadChooser.Title", title);
00761 
00762     // The list widget needs to be bound so it takes space in the layout
00763     ContainerWidget *list = new ContainerWidget(this, "SaveLoadChooser.List");
00764     list->setBackgroundType(ThemeEngine::kWidgetBackgroundNo);
00765 
00766     // Buttons
00767     new ButtonWidget(this, "SaveLoadChooser.Delete", _("Cancel"), nullptr, kCloseCmd);
00768     _nextButton = new ButtonWidget(this, "SaveLoadChooser.Choose", _("Next"), nullptr, kNextCmd);
00769     _nextButton->setEnabled(false);
00770 
00771     _prevButton = new ButtonWidget(this, "SaveLoadChooser.Cancel", _("Prev"), nullptr, kPrevCmd);
00772     _prevButton->setEnabled(false);
00773 
00774     // Page display
00775     _pageDisplay = new StaticTextWidget(this, "SaveLoadChooser.PageDisplay", Common::String());
00776     _pageDisplay->setAlign(Graphics::kTextAlignRight);
00777 }
00778 
00779 SaveLoadChooserGrid::~SaveLoadChooserGrid() {
00780     removeWidget(_pageDisplay);
00781     delete _pageDisplay;
00782 }
00783 
00784 const Common::String &SaveLoadChooserGrid::getResultString() const {
00785     return _resultString;
00786 }
00787 
00788 void SaveLoadChooserGrid::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
00789     if (cmd <= _entriesPerPage && cmd + _curPage * _entriesPerPage <= _saveList.size()) {
00790         const SaveStateDescriptor &desc = _saveList[cmd - 1 + _curPage * _entriesPerPage];
00791 
00792         if (_saveMode) {
00793             _resultString = desc.getDescription();
00794         }
00795 
00796         setResult(desc.getSaveSlot());
00797         close();
00798     }
00799 
00800     switch (cmd) {
00801     case kNextCmd:
00802         ++_curPage;
00803         updateSaves();
00804         g_gui.scheduleTopDialogRedraw();
00805         break;
00806 
00807     case kPrevCmd:
00808         --_curPage;
00809         updateSaves();
00810         g_gui.scheduleTopDialogRedraw();
00811         break;
00812 
00813     case kNewSaveCmd:
00814         setResult(_nextFreeSaveSlot);
00815         close();
00816         break;
00817 
00818     case kCloseCmd:
00819         setResult(-1);
00820         // Fall through
00821     default:
00822         SaveLoadChooserDialog::handleCommand(sender, cmd, data);
00823     }
00824 }
00825 
00826 void SaveLoadChooserGrid::handleMouseWheel(int x, int y, int direction) {
00827     if (direction > 0) {
00828         if (_nextButton->isEnabled()) {
00829             ++_curPage;
00830             updateSaves();
00831             g_gui.scheduleTopDialogRedraw();
00832         }
00833     } else {
00834         if (_prevButton->isEnabled()) {
00835             --_curPage;
00836             updateSaves();
00837             g_gui.scheduleTopDialogRedraw();
00838         }
00839     }
00840 }
00841 
00842 void SaveLoadChooserGrid::updateSaveList() {
00843     SaveLoadChooserDialog::updateSaveList();
00844     updateSaves();
00845     g_gui.scheduleTopDialogRedraw();
00846 }
00847 
00848 void SaveLoadChooserGrid::open() {
00849     SaveLoadChooserDialog::open();
00850 
00851     listSaves();
00852     _resultString.clear();
00853 
00854     // Load information to restore the last page the user had open.
00855     assert(_entriesPerPage != 0);
00856     const uint lastPos = ConfMan.getInt("gui_saveload_last_pos");
00857     const uint listSize = _saveList.size();
00858     uint bestMatch = 0;
00859     uint diff = 0xFFFFFFFF;
00860 
00861     // We look for the nearest available slot, since a slot might be missing
00862     // due to the user deleting it via the list based chooser, by deleting
00863     // it by hand, etc.
00864     for (uint i = 0; i < listSize; ++i) {
00865         uint curDiff = ABS(_saveList[i].getSaveSlot() - (int)lastPos);
00866         if (curDiff < diff) {
00867             diff = curDiff;
00868             bestMatch = i;
00869         }
00870     }
00871 
00872     _curPage = bestMatch / _entriesPerPage;
00873 
00874     // Determine the next free save slot for save mode
00875     if (_saveMode) {
00876         int lastSlot = -1;
00877         _nextFreeSaveSlot = -1;
00878         for (SaveStateList::const_iterator x = _saveList.begin(); x != _saveList.end(); ++x) {
00879             const int curSlot = x->getSaveSlot();
00880 
00881             // In case there was a gap found use the slot.
00882             if (lastSlot + 1 < curSlot) {
00883                 // Check that the save slot can be used for user saves.
00884                 SaveStateDescriptor desc = _metaEngine->querySaveMetaInfos(_target.c_str(), lastSlot + 1);
00885                 if (!desc.getWriteProtectedFlag()) {
00886                     _nextFreeSaveSlot = lastSlot + 1;
00887                     break;
00888                 }
00889             }
00890 
00891             lastSlot = curSlot;
00892         }
00893 
00894         // Use the next available slot otherwise.
00895         const int maxSlot = _metaEngine->getMaximumSaveSlot();
00896         for (int i = lastSlot; _nextFreeSaveSlot == -1 && i < maxSlot; ++i) {
00897             // Check that the save slot can be used for user saves.
00898             SaveStateDescriptor desc = _metaEngine->querySaveMetaInfos(_target.c_str(), i + 1);
00899             if (!desc.getWriteProtectedFlag()) {
00900                 _nextFreeSaveSlot = i + 1;
00901             }
00902         }
00903     }
00904 
00905     updateSaves();
00906 }
00907 
00908 void SaveLoadChooserGrid::reflowLayout() {
00909     // HACK: The page display is not available in low resolution layout. We
00910     // remove and readd the widget here to avoid our GUI from erroring out.
00911     removeWidget(_pageDisplay);
00912     if (g_gui.xmlEval()->getVar("Globals.ShowChooserPageDisplay") == 1) {
00913         _pageDisplay->init();
00914     }
00915 
00916     SaveLoadChooserDialog::reflowLayout();
00917     destroyButtons();
00918 
00919     // HACK: The whole code below really works around the fact, that we have
00920     // no easy way to dynamically layout widgets.
00921     const uint16 availableWidth = getWidth() - 20;
00922     int16 availableHeight;
00923 
00924     int16 x, y;
00925     int16 w;
00926     if (!g_gui.xmlEval()->getWidgetData("SaveLoadChooser.List", x, y, w, availableHeight))
00927         error("Could not load widget position for 'SaveLoadChooser.List'");
00928 
00929     const int16 buttonWidth = kThumbnailWidth + 6;
00930     const int16 buttonHeight = kThumbnailHeight2 + 6;
00931 
00932     const int16 containerFrameWidthAdd = 10;
00933     const int16 containerFrameHeightAdd = 0;
00934     const int16 containerWidth = buttonWidth + containerFrameWidthAdd;
00935     const int16 containerHeight = buttonHeight + kLineHeight + containerFrameHeightAdd;
00936 
00937     const int16 defaultSpacingHorizontal = 4;
00938     const int16 defaultSpacingVertical = 8;
00939     const int16 slotAreaWidth = containerWidth + defaultSpacingHorizontal;
00940     const int16 slotAreaHeight = containerHeight + defaultSpacingVertical;
00941 
00942     const uint oldEntriesPerPage = _entriesPerPage;
00943     _columns = MAX<uint>(1, availableWidth / slotAreaWidth);
00944     _lines = MAX<uint>(1, availableHeight / slotAreaHeight);
00945     _entriesPerPage = _columns * _lines;
00946 
00947     // In save mode the first button is always "New Save", thus we need to
00948     // adjust the entries per page here.
00949     if (_saveMode) {
00950         --_entriesPerPage;
00951     }
00952 
00953     // Recalculate the page number
00954     if (!_saveList.empty() && oldEntriesPerPage != 0) {
00955         if (_entriesPerPage != 0) {
00956             _curPage = (_curPage * oldEntriesPerPage) / _entriesPerPage;
00957         } else {
00958             _curPage = 0;
00959         }
00960     }
00961 
00962     const uint addX = _columns > 1 ? (availableWidth % slotAreaWidth) / (_columns - 1) : 0;
00963     //const uint addY = _lines > 1 ? (availableHeight % slotAreaHeight) / (_lines - 1) : 0;
00964 
00965     _buttons.reserve(_lines * _columns);
00966     y += defaultSpacingVertical / 2;
00967     for (uint curLine = 0; curLine < _lines; ++curLine, y += slotAreaHeight/* + addY*/) {
00968         for (uint curColumn = 0, curX = x + defaultSpacingHorizontal / 2; curColumn < _columns; ++curColumn, curX += slotAreaWidth + addX) {
00969             int dstY = containerFrameHeightAdd / 2;
00970             int dstX = containerFrameWidthAdd / 2;
00971 
00972             // In the save mode we will always create a new save button as the first button.
00973             if (_saveMode && curLine == 0 && curColumn == 0) {
00974                 _newSaveContainer = new ContainerWidget(this, curX, y, containerWidth, containerHeight);
00975                 ButtonWidget *newSave = new ButtonWidget(_newSaveContainer, dstX, dstY, buttonWidth, buttonHeight, _("New Save"), _("Create a new saved game"), kNewSaveCmd);
00976                 // In case no more slots are free, we will disable the new save button
00977                 if (_nextFreeSaveSlot == -1) {
00978                     newSave->setEnabled(false);
00979                 }
00980                 continue;
00981             }
00982 
00983             ContainerWidget *container = new ContainerWidget(this, curX, y, containerWidth, containerHeight);
00984             container->setVisible(false);
00985 
00986             // Command 0 cannot be used, since it won't be send. Thus we will adjust
00987             // command number here, if required. This is only the case for load mode
00988             // since for save mode, the first button used is index 1 anyway.
00989             uint buttonCmd = curLine * _columns + curColumn;
00990             if (!_saveMode) {
00991                 buttonCmd += 1;
00992             }
00993 
00994             PicButtonWidget *button = new PicButtonWidget(container, dstX, dstY, buttonWidth, buttonHeight, nullptr, buttonCmd);
00995             dstY += buttonHeight;
00996 
00997             StaticTextWidget *description = new StaticTextWidget(container, dstX, dstY, buttonWidth, kLineHeight, Common::String(), Graphics::kTextAlignLeft);
00998 
00999             _buttons.push_back(SlotButton(container, button, description));
01000         }
01001     }
01002 
01003     if (!_target.empty())
01004         updateSaves();
01005 }
01006 
01007 void SaveLoadChooserGrid::close() {
01008     // Save the current page.
01009     const int result = getResult();
01010     if (result >= 0 && result != _nextFreeSaveSlot) {
01011         // If the user selected a slot we use that one. We ignore new slots
01012         // here, since otherwise the dialog would reset to page 0 when the
01013         // user cancels the savename dialog.
01014         ConfMan.setInt("gui_saveload_last_pos", result);
01015     } else {
01016         // Otherwise save the first entry on the current page.
01017         // This is less precise than the solution above, since the number of
01018         // entries shown differs between save and load version of the dialog,
01019         // thus it might wrap to a different page than expected.
01020         // Similar things happen on resolution changes.
01021         // TODO: Should we ignore this here? Is the user likely to be
01022         // interested in having this page restored when he canceled?
01023         ConfMan.setInt("gui_saveload_last_pos", !_saveList.empty() ? _saveList[_curPage * _entriesPerPage].getSaveSlot() : 0);
01024     }
01025 
01026     SaveLoadChooserDialog::close();
01027     hideButtons();
01028 }
01029 
01030 int SaveLoadChooserGrid::runIntern() {
01031     int slot;
01032     do {
01033         const SaveLoadChooserType currentType = getType();
01034         const SaveLoadChooserType requestedType = getRequestedSaveLoadDialog(*_metaEngine);
01035 
01036         // Catch resolution changes when the save name dialog was open.
01037         if (currentType != requestedType) {
01038             setResult(kSwitchSaveLoadDialog);
01039             return kSwitchSaveLoadDialog;
01040         }
01041 
01042         slot = runModal();
01043     } while (_saveMode && slot >= 0 && !selectDescription());
01044 
01045     // Special case for new save games. We need to handle this here, since
01046     // we cannot handle it in close() without problems.
01047     if (slot == _nextFreeSaveSlot) {
01048         ConfMan.setInt("gui_saveload_last_pos", slot);
01049     }
01050 
01051     return slot;
01052 }
01053 
01054 bool SaveLoadChooserGrid::selectDescription() {
01055     _savenameDialog.setDescription(_resultString);
01056     _savenameDialog.setTargetSlot(getResult());
01057     if (_savenameDialog.runModal() == 0) {
01058         _resultString = _savenameDialog.getDescription();
01059         return true;
01060     } else {
01061         return false;
01062     }
01063 }
01064 
01065 void SaveLoadChooserGrid::destroyButtons() {
01066     if (_newSaveContainer) {
01067         removeWidget(_newSaveContainer);
01068         delete _newSaveContainer;
01069         _newSaveContainer = nullptr;
01070     }
01071 
01072     for (ButtonArray::iterator i = _buttons.begin(), end = _buttons.end(); i != end; ++i) {
01073         removeWidget(i->container);
01074         delete i->container;
01075     }
01076 
01077     _buttons.clear();
01078 }
01079 
01080 void SaveLoadChooserGrid::hideButtons() {
01081     for (ButtonArray::iterator i = _buttons.begin(), end = _buttons.end(); i != end; ++i) {
01082         i->button->setGfx(nullptr);
01083         i->setVisible(false);
01084     }
01085 }
01086 
01087 void SaveLoadChooserGrid::updateSaves() {
01088     hideButtons();
01089 
01090     for (uint i = _curPage * _entriesPerPage, curNum = 0; i < _saveList.size() && curNum < _entriesPerPage; ++i, ++curNum) {
01091         const uint saveSlot = _saveList[i].getSaveSlot();
01092 
01093         SaveStateDescriptor desc =  (_saveList[i].getLocked() ? _saveList[i] : _metaEngine->querySaveMetaInfos(_target.c_str(), saveSlot));
01094         SlotButton &curButton = _buttons[curNum];
01095         curButton.setVisible(true);
01096         const Graphics::Surface *thumbnail = desc.getThumbnail();
01097         if (thumbnail) {
01098             curButton.button->setGfx(desc.getThumbnail());
01099         } else {
01100             curButton.button->setGfx(kThumbnailWidth, kThumbnailHeight2, 0, 0, 0);
01101         }
01102         curButton.description->setLabel(Common::String::format("%d. %s", saveSlot, desc.getDescription().c_str()));
01103 
01104         Common::String tooltip(_("Name: "));
01105         tooltip += desc.getDescription();
01106 
01107         if (_saveDateSupport) {
01108             const Common::String &saveDate = desc.getSaveDate();
01109             if (!saveDate.empty()) {
01110                 tooltip += "\n";
01111                 tooltip +=  _("Date: ") + saveDate;
01112             }
01113 
01114             const Common::String &saveTime = desc.getSaveTime();
01115             if (!saveTime.empty()) {
01116                 tooltip += "\n";
01117                 tooltip += _("Time: ") + saveTime;
01118             }
01119         }
01120 
01121         if (_playTimeSupport) {
01122             const Common::String &playTime = desc.getPlayTime();
01123             if (!playTime.empty()) {
01124                 tooltip += "\n";
01125                 tooltip += _("Playtime: ") + playTime;
01126             }
01127         }
01128 
01129         curButton.button->setTooltip(tooltip);
01130 
01131         // In save mode we disable the button, when it's write protected.
01132         // TODO: Maybe we should not display it at all then?
01133         if (_saveMode && desc.getWriteProtectedFlag()) {
01134             curButton.button->setEnabled(false);
01135         } else {
01136             curButton.button->setEnabled(true);
01137         }
01138 
01139         //that would make it look "disabled" if slot is locked
01140         curButton.button->setEnabled(!desc.getLocked());
01141         curButton.description->setEnabled(!desc.getLocked());
01142     }
01143 
01144     const uint numPages = (_entriesPerPage != 0 && !_saveList.empty()) ? ((_saveList.size() + _entriesPerPage - 1) / _entriesPerPage) : 1;
01145     _pageDisplay->setLabel(Common::String::format("%u/%u", _curPage + 1, numPages));
01146 
01147     if (_curPage > 0)
01148         _prevButton->setEnabled(true);
01149     else
01150         _prevButton->setEnabled(false);
01151 
01152     if ((_curPage + 1) * _entriesPerPage < _saveList.size())
01153         _nextButton->setEnabled(true);
01154     else
01155         _nextButton->setEnabled(false);
01156 }
01157 
01158 SavenameDialog::SavenameDialog()
01159     : Dialog("SavenameDialog") {
01160     _title = new StaticTextWidget(this, "SavenameDialog.DescriptionText", Common::String());
01161 
01162     new ButtonWidget(this, "SavenameDialog.Cancel", _("Cancel"), nullptr, kCloseCmd);
01163     new ButtonWidget(this, "SavenameDialog.Ok", _("OK"), nullptr, kOKCmd);
01164 
01165     _description = new EditTextWidget(this, "SavenameDialog.Description", Common::String(), nullptr, 0, kOKCmd);
01166 
01167     _targetSlot = 0;
01168 }
01169 
01170 void SavenameDialog::setDescription(const Common::String &desc) {
01171     _description->setEditString(desc);
01172 }
01173 
01174 const Common::String &SavenameDialog::getDescription() {
01175     return _description->getEditString();
01176 }
01177 
01178 void SavenameDialog::open() {
01179     Dialog::open();
01180     setResult(-1);
01181 
01182     _title->setLabel(Common::String::format(_("Enter a description for slot %d:"), _targetSlot));
01183 }
01184 
01185 void SavenameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
01186     switch (cmd) {
01187     case kOKCmd:
01188         setResult(0);
01189         close();
01190         break;
01191 
01192     default:
01193         Dialog::handleCommand(sender, cmd, data);
01194     }
01195 }
01196 
01197 #endif // !DISABLE_SAVELOADCHOOSER_GRID
01198 
01199 } // End of namespace GUI


Generated on Sat May 30 2020 05:01:06 for ResidualVM by doxygen 1.7.1
curved edge   curved edge