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

saveloadmenu.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
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 "engines/stark/ui/menu/saveloadmenu.h"
00024 
00025 #include "engines/stark/services/services.h"
00026 #include "engines/stark/services/userinterface.h"
00027 #include "engines/stark/services/stateprovider.h"
00028 #include "engines/stark/services/global.h"
00029 #include "engines/stark/services/settings.h"
00030 #include "engines/stark/services/gamechapter.h"
00031 #include "engines/stark/services/gamemessage.h"
00032 
00033 #include "engines/stark/gfx/driver.h"
00034 #include "engines/stark/gfx/texture.h"
00035 #include "engines/stark/gfx/surfacerenderer.h"
00036 
00037 #include "engines/stark/stark.h"
00038 #include "engines/stark/savemetadata.h"
00039 
00040 #include "engines/engine.h"
00041 
00042 #include "common/config-manager.h"
00043 #include "common/savefile.h"
00044 
00045 #include "gui/message.h"
00046 
00047 namespace Stark {
00048 
00049 const Color SaveDataWidget::_outlineColor = Color(0x1E, 0x1E, 0x96);
00050 const Color SaveDataWidget::_textColor    = Color(0x5C, 0x48, 0x3D);
00051 
00052 SaveLoadMenuScreen::SaveLoadMenuScreen(Gfx::Driver *gfx, Cursor *cursor, Screen::Name screenName) :
00053         StaticLocationScreen(gfx, cursor, "LoadSaveLocation", screenName),
00054         _page(0),
00055         _maxPage(10) {
00056 }
00057 
00058 SaveLoadMenuScreen::~SaveLoadMenuScreen() {
00059 }
00060 
00061 void SaveLoadMenuScreen::open() {
00062     StaticLocationScreen::open();
00063 
00064     _maxPage = computeMaxPage();
00065 
00066     _page = StarkSettings->getIntSetting(Settings::kSaveLoadPage);
00067     if (_page > _maxPage) {
00068         _page = _maxPage;
00069     }
00070 
00071     _widgets.push_back(new StaticLocationWidget(
00072             "loadsavebg",
00073             nullptr,
00074             nullptr));
00075     
00076     _widgets.push_back(new StaticLocationWidget(
00077             "back to index",
00078             CLICK_HANDLER(SaveLoadMenuScreen, backHandler),
00079             nullptr));
00080     _widgets.back()->setupSounds(0, 1);
00081     
00082     _widgets.push_back(new StaticLocationWidget(
00083             "Cancel",
00084             CLICK_HANDLER(SaveLoadMenuScreen, backHandler),
00085             nullptr));
00086     _widgets.back()->setupSounds(0, 1);
00087     
00088     _widgets.push_back(new StaticLocationWidget(
00089             "SaveText",
00090             nullptr,
00091             nullptr));
00092     
00093     _widgets.push_back(new StaticLocationWidget(
00094             "LoadText",
00095             nullptr,
00096             nullptr));
00097     
00098     _widgets.push_back(new StaticLocationWidget(
00099             "Back",
00100             CLICK_HANDLER(SaveLoadMenuScreen, prevPageHandler),
00101             nullptr));
00102     _widgets.back()->setupSounds(0, 1);
00103     _widgets.back()->setTextColor(Color(0, 0, 0));
00104     _widgets.back()->setVisible(_page > 0);
00105     
00106     _widgets.push_back(new StaticLocationWidget(
00107             "Next",
00108             CLICK_HANDLER(SaveLoadMenuScreen, nextPageHandler),
00109             nullptr));
00110     _widgets.back()->setupSounds(0, 1);
00111     _widgets.back()->setTextColor(Color(0, 0, 0));
00112     _widgets.back()->setVisible(_page < _maxPage);
00113 
00114     loadSaveData(_page);
00115 }
00116 
00117 void SaveLoadMenuScreen::close() {
00118     ConfMan.flushToDisk();
00119     StaticLocationScreen::close();
00120 }
00121 
00122 int SaveLoadMenuScreen::computeMaxPage() {
00123     const char *target = ConfMan.getActiveDomainName().c_str();
00124 
00125     int maxSlot = 0;
00126     Common::StringArray saves = StarkEngine::listSaveNames(target);
00127     for (Common::StringArray::const_iterator filename = saves.begin(); filename != saves.end(); filename++) {
00128         int slot = StarkEngine::getSaveNameSlot(target, *filename);
00129 
00130         if (slot > maxSlot) {
00131             maxSlot = slot;
00132         }
00133     }
00134 
00135     // Allow using one more page than the last page with saves
00136     int maxPage = CLIP((maxSlot / _slotPerPage) + 1, 0, 110);
00137     if (maxPage < 10) {
00138         maxPage = 10;
00139     }
00140 
00141     return maxPage;
00142 }
00143 
00144 void SaveLoadMenuScreen::backHandler() {
00145     StarkUserInterface->backPrevScreen();
00146 }
00147 
00148 void SaveLoadMenuScreen::checkError(Common::Error error) {
00149     if (error.getCode() != Common::kNoError) {
00150         GUI::MessageDialog dialog(error.getDesc());
00151         dialog.runModal();
00152     }
00153 }
00154 
00155 void SaveLoadMenuScreen::removeSaveDataWidgets() {
00156     assert(_widgets.size() == 7 + _slotPerPage);
00157 
00158     for (int i = 0; i < _slotPerPage; ++i) {
00159         delete _widgets.back();
00160         _widgets.pop_back();
00161     }
00162 }
00163 
00164 void SaveLoadMenuScreen::loadSaveData(int page) {
00165     for (int i = 0; i < _slotPerPage; ++i) {
00166         _widgets.push_back(new SaveDataWidget(i + page * _slotPerPage, _gfx, this));
00167     }
00168 }
00169 
00170 void SaveLoadMenuScreen::changePage(int page) {
00171     assert(page >= 0 && page <= _maxPage);
00172 
00173     removeSaveDataWidgets();
00174     loadSaveData(page);
00175 
00176     _widgets[kWidgetBack]->setVisible(page > 0);
00177     _widgets[kWidgetNext]->setVisible(page < _maxPage);
00178 
00179     StarkSettings->setIntSetting(Settings::kSaveLoadPage, page);
00180     _page = page;
00181 }
00182 
00183 void SaveMenuScreen::open() {
00184     SaveLoadMenuScreen::open();
00185     _widgets[kWidgetLoadText]->setVisible(false);
00186 }
00187 
00188 void SaveMenuScreen::onWidgetSelected(SaveDataWidget *widget) {
00189     if (widget->hasSave()) {
00190         _slotToSaveAfterConfirm = widget;
00191 
00192         Common::String format = StarkGameMessage->getTextByKey(GameMessage::kOverwriteSave);
00193         Common::String prompt = Common::String::format(format.c_str(), widget->getName().c_str());
00194 
00195         StarkUserInterface->confirm(prompt, this, &SaveMenuScreen::saveConfirmSlot);
00196     } else {
00197         saveGameToSlot(widget);
00198     }
00199 }
00200 
00201 void SaveMenuScreen::saveConfirmSlot() {
00202     assert(_slotToSaveAfterConfirm);
00203 
00204     saveGameToSlot(_slotToSaveAfterConfirm);
00205     _slotToSaveAfterConfirm = nullptr;
00206 }
00207 
00208 void SaveMenuScreen::saveGameToSlot(SaveDataWidget *widget) {
00209     checkError(g_engine->saveGameState(widget->getSlot(), StarkGameChapter->getCurrentChapterTitle()));
00210 
00211     // Freeze the screen for a while to let the user notice the change
00212     widget->loadSaveDataElements();
00213     render();
00214     StarkGfx->flipBuffer();
00215     g_system->delayMillis(100);
00216     render();
00217     StarkGfx->flipBuffer();
00218 
00219     StarkUserInterface->backPrevScreen();
00220 }
00221 
00222 void LoadMenuScreen::open() {
00223     SaveLoadMenuScreen::open();
00224     _widgets[kWidgetSaveText]->setVisible(false);
00225 }
00226 
00227 void LoadMenuScreen::onWidgetSelected(SaveDataWidget *widget) {
00228     if (!StarkGlobal->getCurrent()) {
00229         checkError(g_engine->loadGameState(widget->getSlot()));
00230     } else {
00231         _slotToLoadAfterConfirm = widget->getSlot();
00232         StarkUserInterface->confirm(GameMessage::kEndAndLoad, this, &LoadMenuScreen::loadConfirmSlot);
00233     }
00234 }
00235 
00236 void LoadMenuScreen::loadConfirmSlot() {
00237     assert(_slotToLoadAfterConfirm >= 0);
00238 
00239     checkError(g_engine->loadGameState(_slotToLoadAfterConfirm));
00240     _slotToLoadAfterConfirm = -1;
00241 }
00242 
00243 SaveDataWidget::SaveDataWidget(int slot, Gfx::Driver *gfx, SaveLoadMenuScreen *screen) :
00244         StaticLocationWidget(nullptr, nullptr, nullptr),
00245         _slot(slot),
00246         _screen(screen),
00247         _thumbWidth(StarkUserInterface->kThumbnailWidth),
00248         _thumbHeight(StarkUserInterface->kThumbnailHeight),
00249         _texture(gfx->createTexture()),
00250         _outline(gfx->createTexture()),
00251         _surfaceRenderer(gfx->createSurfaceRenderer()),
00252         _textDesc(gfx),
00253         _textTime(gfx),
00254         _isMouseHovered(false),
00255         _hasSave(false),
00256         _name() {
00257     // Load from the save data
00258     loadSaveDataElements();
00259 
00260     _textDesc.setColor(_textColor);
00261     _textDesc.setFont(FontProvider::kCustomFont, 3);
00262 
00263     _textTime.setColor(_textColor);
00264     _textTime.setFont(FontProvider::kCustomFont, 3);
00265 
00266     Graphics::PixelFormat pixelFormat = Gfx::Driver::getRGBAPixelFormat();
00267     uint32 outlineColor = pixelFormat.ARGBToColor(
00268             _outlineColor.a, _outlineColor.r, _outlineColor.g, _outlineColor.b
00269     );
00270 
00271     // Create the outline texture
00272     Graphics::Surface lineSurface;
00273     lineSurface.create(_thumbWidth, _thumbHeight, pixelFormat);
00274     lineSurface.drawThickLine(0, 0, _thumbWidth - 1, 0, 2, 2, outlineColor);
00275     lineSurface.drawThickLine(0, 0, 0, _thumbHeight - 1, 2, 2, outlineColor);
00276     lineSurface.drawThickLine(_thumbWidth - 2, 0, _thumbWidth - 2, _thumbHeight - 2, 2, 2, outlineColor);
00277     lineSurface.drawThickLine(0, _thumbHeight - 2, _thumbWidth - 2, _thumbHeight - 2, 2, 2, outlineColor);
00278 
00279     _outline->update(&lineSurface);
00280     lineSurface.free();
00281 
00282     // Set the position
00283     _thumbPos.x = 41 + (_slot % SaveLoadMenuScreen::_slotPerRow) * (_thumbWidth + 39);
00284     _thumbPos.y = 61 + (_slot % SaveLoadMenuScreen::_slotPerPage / SaveLoadMenuScreen::_slotPerColumn) * (_thumbHeight + 38);
00285 
00286     _textDescPos.x = _thumbPos.x;
00287     _textDescPos.y = _thumbPos.y + _thumbHeight + 2;
00288 
00289     _textTimePos.x = _thumbPos.x;
00290     _textTimePos.y = _textDescPos.y + 12;
00291 }
00292 
00293 SaveDataWidget::~SaveDataWidget() {
00294     delete _texture;
00295     delete _outline;
00296     delete _surfaceRenderer;
00297 }
00298 
00299 void SaveDataWidget::render() {
00300     _surfaceRenderer->render(_texture, _thumbPos);
00301     _textDesc.render(_textDescPos);
00302     _textTime.render(_textTimePos);
00303     if (_isMouseHovered) {
00304         _surfaceRenderer->render(_outline, _thumbPos);
00305     }
00306 }
00307 
00308 bool SaveDataWidget::isMouseInside(const Common::Point &mousePos) const {
00309     return mousePos.x >= _thumbPos.x && mousePos.x <= _thumbPos.x + _thumbWidth &&
00310            mousePos.y >= _thumbPos.y && mousePos.y <= _thumbPos.y + _thumbHeight;
00311 }
00312 
00313 void SaveDataWidget::onClick() {
00314     StaticLocationWidget::onClick();
00315     _screen->onWidgetSelected(this);
00316 }
00317 
00318 void SaveDataWidget::onMouseMove(const Common::Point &mousePos) {
00319     StaticLocationWidget::onMouseMove(mousePos);
00320     _isMouseHovered = isMouseInside(mousePos);
00321 }
00322 
00323 void SaveDataWidget::onScreenChanged() {
00324     StaticLocationWidget::onScreenChanged();
00325     _textDesc.resetTexture();
00326     _textTime.resetTexture();
00327 }
00328 
00329 void SaveDataWidget::loadSaveDataElements() {
00330     Common::String filename = StarkEngine::formatSaveName(ConfMan.getActiveDomainName().c_str(), _slot);
00331     Common::InSaveFile *save = g_system->getSavefileManager()->openForLoading(filename);
00332     if (save) {
00333         _hasSave = true;
00334 
00335         SaveMetadata metadata;
00336         StateReadStream stream(save);
00337         Common::ErrorCode metadataErrorCode = metadata.read(&stream, filename);
00338         if (metadataErrorCode != Common::kNoError) {
00339             error("Unable to read save metadata with error code %d.", metadataErrorCode);
00340         }
00341 
00342         // Obtain the thumbnail
00343         if (metadata.version >= 9) {
00344             Graphics::Surface *thumb = metadata.readGameScreenThumbnail(&stream);
00345             _texture->update(thumb);
00346             _texture->setSamplingFilter(StarkSettings->getImageSamplingFilter());
00347 
00348             thumb->free();
00349             delete thumb;
00350         }
00351 
00352         // Obtain the text
00353         Common::String desc = metadata.description;
00354         Common::String time = Common::String::format("%02d:%02d:%02d %02d/%02d/%02d",
00355                 metadata.saveHour, metadata.saveMinute, metadata.saveSecond,
00356                 metadata.saveMonth, metadata.saveDay, metadata.saveYear % 100);
00357 
00358         _textDesc.setText(desc);
00359         _textTime.setText(time);
00360         _name = desc + " " + time;
00361     } else {
00362         _hasSave = false;
00363         setVisible(_screen->isSaveMenu());
00364     }
00365 }
00366 
00367 } // End of namespace Stark


Generated on Sat Dec 7 2019 05:00:40 for ResidualVM by doxygen 1.7.1
curved edge   curved edge