2013-11-05 19:50:24 +01:00
|
|
|
#include "savegamedialog.hpp"
|
2014-01-24 17:49:16 +01:00
|
|
|
|
2015-08-19 10:05:08 -04:00
|
|
|
#include <iomanip>
|
|
|
|
#include <sstream>
|
|
|
|
|
2015-01-10 02:50:43 +01:00
|
|
|
#include <MyGUI_ComboBox.h>
|
|
|
|
#include <MyGUI_ImageBox.h>
|
|
|
|
#include <MyGUI_InputManager.h>
|
2017-04-21 09:40:25 +04:00
|
|
|
#include <MyGUI_LanguageManager.h>
|
2015-01-10 02:50:43 +01:00
|
|
|
|
2015-05-28 02:34:38 +02:00
|
|
|
#include <osg/Texture2D>
|
|
|
|
#include <osgDB/ReadFile>
|
|
|
|
|
2018-08-14 23:05:43 +04:00
|
|
|
#include <components/debug/debuglog.hpp>
|
|
|
|
|
2015-05-28 02:34:38 +02:00
|
|
|
#include <components/myguiplatform/myguitexture.hpp>
|
|
|
|
|
2022-08-03 00:00:54 +02:00
|
|
|
#include <components/misc/strings/lower.hpp>
|
2013-11-26 10:37:58 +01:00
|
|
|
|
|
|
|
#include <components/settings/settings.hpp>
|
|
|
|
|
2022-07-03 00:02:29 +02:00
|
|
|
#include <components/files/conversion.hpp>
|
2015-05-28 02:34:38 +02:00
|
|
|
#include <components/files/memorystream.hpp>
|
2022-06-11 23:38:09 +02:00
|
|
|
#include <components/misc/timeconvert.hpp>
|
2015-05-28 02:34:38 +02:00
|
|
|
|
2022-09-05 19:35:15 +02:00
|
|
|
#include <components/esm3/loadclas.hpp>
|
|
|
|
|
2013-11-21 20:24:58 +01:00
|
|
|
#include "../mwbase/environment.hpp"
|
2013-11-26 12:47:30 +01:00
|
|
|
#include "../mwbase/statemanager.hpp"
|
2014-01-21 14:50:58 +01:00
|
|
|
#include "../mwbase/windowmanager.hpp"
|
|
|
|
#include "../mwbase/world.hpp"
|
2014-12-19 11:26:54 +01:00
|
|
|
#include "../mwworld/esmstore.hpp"
|
2013-11-21 20:24:58 +01:00
|
|
|
|
|
|
|
#include "../mwstate/character.hpp"
|
|
|
|
|
2014-01-26 15:43:26 +01:00
|
|
|
#include "confirmationdialog.hpp"
|
2022-08-28 15:06:31 +02:00
|
|
|
#include "ustring.hpp"
|
2014-01-26 15:43:26 +01:00
|
|
|
|
2013-11-05 19:50:24 +01:00
|
|
|
namespace MWGui
|
|
|
|
{
|
|
|
|
SaveGameDialog::SaveGameDialog()
|
|
|
|
: WindowModal("openmw_savegame_dialog.layout")
|
2013-11-21 20:24:58 +01:00
|
|
|
, mSaving(true)
|
2018-10-09 10:21:12 +04:00
|
|
|
, mCurrentCharacter(nullptr)
|
|
|
|
, mCurrentSlot(nullptr)
|
2013-11-05 19:50:24 +01:00
|
|
|
{
|
|
|
|
getWidget(mScreenshot, "Screenshot");
|
|
|
|
getWidget(mCharacterSelection, "SelectCharacter");
|
|
|
|
getWidget(mInfoText, "InfoText");
|
|
|
|
getWidget(mOkButton, "OkButton");
|
|
|
|
getWidget(mCancelButton, "CancelButton");
|
2014-06-10 02:27:38 +02:00
|
|
|
getWidget(mDeleteButton, "DeleteButton");
|
2013-11-05 19:50:24 +01:00
|
|
|
getWidget(mSaveList, "SaveList");
|
|
|
|
getWidget(mSaveNameEdit, "SaveNameEdit");
|
|
|
|
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onOkButtonClicked);
|
|
|
|
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked);
|
2014-06-10 02:27:38 +02:00
|
|
|
mDeleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteButtonClicked);
|
2017-10-04 17:47:42 +02:00
|
|
|
mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected);
|
|
|
|
mCharacterSelection->eventComboAccept += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterAccept);
|
2013-11-21 20:24:58 +01:00
|
|
|
mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected);
|
2014-04-28 20:57:45 +02:00
|
|
|
mSaveList->eventListMouseItemActivate += MyGUI::newDelegate(this, &SaveGameDialog::onSlotMouseClick);
|
2014-01-25 22:30:25 +01:00
|
|
|
mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated);
|
2014-08-17 20:41:23 +02:00
|
|
|
mSaveList->eventKeyButtonPressed += MyGUI::newDelegate(this, &SaveGameDialog::onKeyButtonPressed);
|
2014-01-26 15:22:31 +01:00
|
|
|
mSaveNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onEditSelectAccept);
|
2014-01-26 15:43:26 +01:00
|
|
|
mSaveNameEdit->eventEditTextChange += MyGUI::newDelegate(this, &SaveGameDialog::onSaveNameChanged);
|
2017-09-27 13:43:33 +02:00
|
|
|
|
|
|
|
// To avoid accidental deletions
|
|
|
|
mDeleteButton->setNeedKeyFocus(false);
|
2014-01-25 22:30:25 +01:00
|
|
|
}
|
2013-11-05 19:50:24 +01:00
|
|
|
|
2014-01-25 22:30:25 +01:00
|
|
|
void SaveGameDialog::onSlotActivated(MyGUI::ListBox* sender, size_t pos)
|
|
|
|
{
|
|
|
|
onSlotSelected(sender, pos);
|
2014-01-26 15:43:26 +01:00
|
|
|
accept();
|
|
|
|
}
|
|
|
|
|
2014-04-28 20:57:45 +02:00
|
|
|
void SaveGameDialog::onSlotMouseClick(MyGUI::ListBox* sender, size_t pos)
|
|
|
|
{
|
|
|
|
onSlotSelected(sender, pos);
|
|
|
|
|
2014-04-29 13:04:09 +02:00
|
|
|
if (pos != MyGUI::ITEM_NONE && MyGUI::InputManager::getInstance().isShiftPressed())
|
2014-06-10 02:27:38 +02:00
|
|
|
confirmDeleteSave();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SaveGameDialog::confirmDeleteSave()
|
|
|
|
{
|
|
|
|
ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog();
|
2015-06-04 20:31:28 +02:00
|
|
|
dialog->askForConfirmation("#{sMessage3}");
|
2014-06-10 02:27:38 +02:00
|
|
|
dialog->eventOkClicked.clear();
|
|
|
|
dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotConfirmed);
|
|
|
|
dialog->eventCancelClicked.clear();
|
2017-10-15 17:01:57 +02:00
|
|
|
dialog->eventCancelClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotCancel);
|
2014-04-28 20:57:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void SaveGameDialog::onDeleteSlotConfirmed()
|
|
|
|
{
|
|
|
|
MWBase::Environment::get().getStateManager()->deleteGame(mCurrentCharacter, mCurrentSlot);
|
|
|
|
mSaveList->removeItemAt(mSaveList->getIndexSelected());
|
2016-03-29 01:26:55 +02:00
|
|
|
onSlotSelected(mSaveList, mSaveList->getIndexSelected());
|
2019-06-09 02:08:09 +03:00
|
|
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
|
2014-04-28 20:57:45 +02:00
|
|
|
|
2016-03-29 01:26:55 +02:00
|
|
|
if (mSaveList->getItemCount() == 0)
|
2014-04-28 20:57:45 +02:00
|
|
|
{
|
2016-03-29 01:26:55 +02:00
|
|
|
size_t previousIndex = mCharacterSelection->getIndexSelected();
|
2018-10-09 10:21:12 +04:00
|
|
|
mCurrentCharacter = nullptr;
|
2016-09-18 19:25:51 +02:00
|
|
|
mCharacterSelection->removeItemAt(previousIndex);
|
2016-03-29 01:26:55 +02:00
|
|
|
if (mCharacterSelection->getItemCount())
|
|
|
|
{
|
|
|
|
size_t nextCharacter = std::min(previousIndex, mCharacterSelection->getItemCount() - 1);
|
|
|
|
mCharacterSelection->setIndexSelected(nextCharacter);
|
|
|
|
onCharacterSelected(mCharacterSelection, nextCharacter);
|
|
|
|
}
|
2016-09-18 19:25:51 +02:00
|
|
|
else
|
2023-01-06 17:34:27 +04:00
|
|
|
mCharacterSelection->setIndexSelected(MyGUI::ITEM_NONE);
|
2014-04-28 20:57:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-27 13:32:46 +02:00
|
|
|
void SaveGameDialog::onDeleteSlotCancel()
|
|
|
|
{
|
2019-06-09 02:08:09 +03:00
|
|
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
|
2017-09-27 13:32:46 +02:00
|
|
|
}
|
|
|
|
|
2014-01-26 15:43:26 +01:00
|
|
|
void SaveGameDialog::onSaveNameChanged(MyGUI::EditBox* sender)
|
|
|
|
{
|
|
|
|
// This might have previously been a save slot from the list. If so, that is no longer the case
|
|
|
|
mSaveList->setIndexSelected(MyGUI::ITEM_NONE);
|
|
|
|
onSlotSelected(mSaveList, MyGUI::ITEM_NONE);
|
2013-11-05 19:50:24 +01:00
|
|
|
}
|
|
|
|
|
2014-01-26 15:22:31 +01:00
|
|
|
void SaveGameDialog::onEditSelectAccept(MyGUI::EditBox* sender)
|
|
|
|
{
|
2014-01-26 15:43:26 +01:00
|
|
|
accept();
|
2018-09-10 12:55:00 +04:00
|
|
|
|
|
|
|
// To do not spam onEditSelectAccept() again and again
|
|
|
|
MWBase::Environment::get().getWindowManager()->injectKeyRelease(MyGUI::KeyCode::None);
|
2014-01-26 15:22:31 +01:00
|
|
|
}
|
|
|
|
|
2020-06-17 11:09:17 +04:00
|
|
|
void SaveGameDialog::onClose()
|
|
|
|
{
|
|
|
|
mSaveList->setIndexSelected(MyGUI::ITEM_NONE);
|
|
|
|
|
|
|
|
WindowModal::onClose();
|
|
|
|
}
|
|
|
|
|
2017-09-22 17:10:53 +02:00
|
|
|
void SaveGameDialog::onOpen()
|
2013-11-05 19:50:24 +01:00
|
|
|
{
|
2017-09-22 17:10:53 +02:00
|
|
|
WindowModal::onOpen();
|
2013-11-21 20:24:58 +01:00
|
|
|
|
2013-11-24 15:19:56 +01:00
|
|
|
mSaveNameEdit->setCaption("");
|
2014-01-29 17:26:18 +01:00
|
|
|
if (mSaving)
|
2019-06-09 02:08:09 +03:00
|
|
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveNameEdit);
|
2017-10-04 17:47:42 +02:00
|
|
|
else
|
2019-06-09 02:08:09 +03:00
|
|
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
|
2013-11-24 15:19:56 +01:00
|
|
|
|
2013-11-05 19:50:24 +01:00
|
|
|
center();
|
2013-11-21 20:24:58 +01:00
|
|
|
|
2014-04-28 20:57:45 +02:00
|
|
|
mCharacterSelection->setCaption("");
|
|
|
|
mCharacterSelection->removeAllItems();
|
2018-10-09 10:21:12 +04:00
|
|
|
mCurrentCharacter = nullptr;
|
|
|
|
mCurrentSlot = nullptr;
|
2014-04-28 20:57:45 +02:00
|
|
|
mSaveList->removeAllItems();
|
2014-06-10 02:47:02 +02:00
|
|
|
onSlotSelected(mSaveList, MyGUI::ITEM_NONE);
|
2014-04-28 20:57:45 +02:00
|
|
|
|
2013-11-21 20:24:58 +01:00
|
|
|
MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager();
|
|
|
|
if (mgr->characterBegin() == mgr->characterEnd())
|
|
|
|
return;
|
|
|
|
|
2016-03-14 00:00:11 +01:00
|
|
|
mCurrentCharacter = mgr->getCurrentCharacter();
|
2013-11-21 20:24:58 +01:00
|
|
|
|
2013-11-26 10:37:58 +01:00
|
|
|
std::string directory = Misc::StringUtils::lowerCase(Settings::Manager::getString("character", "Saves"));
|
|
|
|
|
2014-06-02 19:47:39 +02:00
|
|
|
size_t selectedIndex = MyGUI::ITEM_NONE;
|
2014-03-30 20:07:43 +02:00
|
|
|
|
2013-11-21 20:24:58 +01:00
|
|
|
for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it)
|
|
|
|
{
|
2013-11-24 15:05:00 +01:00
|
|
|
if (it->begin() != it->end())
|
|
|
|
{
|
2022-09-15 22:41:17 +02:00
|
|
|
const ESM::SavedGame& signature = it->getSignature();
|
|
|
|
|
2013-11-24 15:05:00 +01:00
|
|
|
std::stringstream title;
|
2022-09-15 22:41:17 +02:00
|
|
|
title << signature.mPlayerName;
|
2014-03-27 22:32:42 +01:00
|
|
|
|
|
|
|
// For a custom class, we will not find it in the store (unless we loaded the savegame first).
|
|
|
|
// Fall back to name stored in savegame header in that case.
|
2022-08-28 15:06:31 +02:00
|
|
|
std::string_view className;
|
2022-09-15 22:41:17 +02:00
|
|
|
if (signature.mPlayerClassId.empty())
|
|
|
|
className = signature.mPlayerClassName;
|
2014-03-27 22:32:42 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// Find the localised name for this class from the store
|
2022-09-15 22:41:17 +02:00
|
|
|
const ESM::Class* class_
|
|
|
|
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().search(
|
|
|
|
signature.mPlayerClassId);
|
2014-05-28 21:08:20 +02:00
|
|
|
if (class_)
|
|
|
|
className = class_->mName;
|
|
|
|
else
|
|
|
|
className = "?"; // From an older savegame format that did not support custom classes properly.
|
2014-03-27 22:32:42 +01:00
|
|
|
}
|
|
|
|
|
2022-09-15 22:41:17 +02:00
|
|
|
title << " (#{sLevel} " << signature.mPlayerLevel << " "
|
|
|
|
<< MyGUI::TextIterator::toTagsString(toUString(className)) << ")";
|
2013-11-21 20:24:58 +01:00
|
|
|
|
2017-04-21 09:40:25 +04:00
|
|
|
mCharacterSelection->addItem(MyGUI::LanguageManager::getInstance().replaceTags(title.str()));
|
2013-11-21 20:24:58 +01:00
|
|
|
|
2013-11-26 10:37:58 +01:00
|
|
|
if (mCurrentCharacter == &*it
|
2013-12-03 15:19:13 +01:00
|
|
|
|| (!mCurrentCharacter && !mSaving
|
|
|
|
&& directory
|
|
|
|
== Misc::StringUtils::lowerCase(
|
2022-07-03 00:02:29 +02:00
|
|
|
Files::pathToUnicodeString(it->begin()->mPath.parent_path().filename()))))
|
2013-11-30 11:08:41 +01:00
|
|
|
{
|
|
|
|
mCurrentCharacter = &*it;
|
2014-03-30 20:07:43 +02:00
|
|
|
selectedIndex = mCharacterSelection->getItemCount() - 1;
|
2013-11-30 11:08:41 +01:00
|
|
|
}
|
2013-11-24 15:05:00 +01:00
|
|
|
}
|
2013-11-21 20:24:58 +01:00
|
|
|
}
|
|
|
|
|
2014-03-30 20:07:43 +02:00
|
|
|
mCharacterSelection->setIndexSelected(selectedIndex);
|
2014-06-10 18:31:39 +02:00
|
|
|
if (selectedIndex == MyGUI::ITEM_NONE)
|
2022-12-22 18:53:49 +01:00
|
|
|
mCharacterSelection->setCaptionWithReplacing("#{OMWEngine:SelectCharacter}");
|
2014-03-30 20:07:43 +02:00
|
|
|
|
2013-11-21 20:24:58 +01:00
|
|
|
fillSaveList();
|
2013-11-05 19:50:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void SaveGameDialog::setLoadOrSave(bool load)
|
|
|
|
{
|
2013-11-21 20:24:58 +01:00
|
|
|
mSaving = !load;
|
2013-11-05 19:50:24 +01:00
|
|
|
mSaveNameEdit->setVisible(!load);
|
|
|
|
mCharacterSelection->setUserString("Hidden", load ? "false" : "true");
|
|
|
|
mCharacterSelection->setVisible(load);
|
|
|
|
|
2014-06-10 02:27:38 +02:00
|
|
|
mDeleteButton->setUserString("Hidden", load ? "false" : "true");
|
|
|
|
mDeleteButton->setVisible(load);
|
|
|
|
|
2013-11-21 20:24:58 +01:00
|
|
|
if (!load)
|
|
|
|
{
|
2016-03-14 00:00:11 +01:00
|
|
|
mCurrentCharacter = MWBase::Environment::get().getStateManager()->getCurrentCharacter();
|
2013-11-21 20:24:58 +01:00
|
|
|
}
|
|
|
|
|
2013-11-05 19:50:24 +01:00
|
|
|
center();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SaveGameDialog::onCancelButtonClicked(MyGUI::Widget* sender)
|
|
|
|
{
|
2017-09-23 12:18:39 +02:00
|
|
|
setVisible(false);
|
2013-11-05 19:50:24 +01:00
|
|
|
}
|
|
|
|
|
2014-06-10 02:27:38 +02:00
|
|
|
void SaveGameDialog::onDeleteButtonClicked(MyGUI::Widget* sender)
|
|
|
|
{
|
|
|
|
if (mCurrentSlot)
|
|
|
|
confirmDeleteSave();
|
|
|
|
}
|
|
|
|
|
2014-01-26 15:43:26 +01:00
|
|
|
void SaveGameDialog::onConfirmationGiven()
|
|
|
|
{
|
|
|
|
accept(true);
|
|
|
|
}
|
|
|
|
|
2017-09-27 13:32:46 +02:00
|
|
|
void SaveGameDialog::onConfirmationCancel()
|
|
|
|
{
|
2019-06-09 02:08:09 +03:00
|
|
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
|
2017-09-27 13:32:46 +02:00
|
|
|
}
|
|
|
|
|
2014-01-26 15:43:26 +01:00
|
|
|
void SaveGameDialog::accept(bool reallySure)
|
2013-11-05 19:50:24 +01:00
|
|
|
{
|
2013-11-21 20:24:58 +01:00
|
|
|
if (mSaving)
|
|
|
|
{
|
2014-01-26 15:43:26 +01:00
|
|
|
// If overwriting an existing slot, ask for confirmation first
|
2018-10-09 10:21:12 +04:00
|
|
|
if (mCurrentSlot != nullptr && !reallySure)
|
2014-01-26 15:43:26 +01:00
|
|
|
{
|
|
|
|
ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog();
|
2015-06-04 20:31:28 +02:00
|
|
|
dialog->askForConfirmation("#{sMessage4}");
|
2014-01-26 15:43:26 +01:00
|
|
|
dialog->eventOkClicked.clear();
|
|
|
|
dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationGiven);
|
|
|
|
dialog->eventCancelClicked.clear();
|
2017-09-27 13:32:46 +02:00
|
|
|
dialog->eventCancelClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationCancel);
|
2014-01-26 15:43:26 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-08-19 14:31:25 +04:00
|
|
|
if (mSaveNameEdit->getCaption().empty())
|
2014-01-26 15:28:05 +01:00
|
|
|
{
|
|
|
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}");
|
|
|
|
return;
|
|
|
|
}
|
2014-05-02 11:26:05 +02:00
|
|
|
}
|
2017-03-27 23:10:57 +04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
MWBase::StateManager::State state = MWBase::Environment::get().getStateManager()->getState();
|
|
|
|
|
|
|
|
// If game is running, ask for confirmation first
|
|
|
|
if (state == MWBase::StateManager::State_Running && !reallySure)
|
|
|
|
{
|
|
|
|
ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog();
|
|
|
|
dialog->askForConfirmation("#{sMessage1}");
|
|
|
|
dialog->eventOkClicked.clear();
|
|
|
|
dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationGiven);
|
|
|
|
dialog->eventCancelClicked.clear();
|
2017-09-27 13:32:46 +02:00
|
|
|
dialog->eventCancelClicked += MyGUI::newDelegate(this, &SaveGameDialog::onConfirmationCancel);
|
2017-03-27 23:10:57 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2014-05-02 11:26:05 +02:00
|
|
|
|
|
|
|
setVisible(false);
|
|
|
|
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_MainMenu);
|
|
|
|
|
|
|
|
if (mSaving)
|
|
|
|
{
|
2017-08-19 14:31:25 +04:00
|
|
|
MWBase::Environment::get().getStateManager()->saveGame(mSaveNameEdit->getCaption(), mCurrentSlot);
|
2013-11-21 20:24:58 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-06-10 02:47:02 +02:00
|
|
|
assert(mCurrentCharacter && mCurrentSlot);
|
2022-06-19 13:28:33 +02:00
|
|
|
MWBase::Environment::get().getStateManager()->loadGame(mCurrentCharacter, mCurrentSlot->mPath);
|
2013-11-21 20:24:58 +01:00
|
|
|
}
|
2013-11-05 19:50:24 +01:00
|
|
|
}
|
|
|
|
|
2014-08-17 20:41:23 +02:00
|
|
|
void SaveGameDialog::onKeyButtonPressed(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char character)
|
|
|
|
{
|
|
|
|
if (key == MyGUI::KeyCode::Delete && mCurrentSlot)
|
|
|
|
confirmDeleteSave();
|
|
|
|
}
|
|
|
|
|
2014-01-26 15:43:26 +01:00
|
|
|
void SaveGameDialog::onOkButtonClicked(MyGUI::Widget* sender)
|
|
|
|
{
|
|
|
|
accept();
|
|
|
|
}
|
|
|
|
|
2013-11-21 20:24:58 +01:00
|
|
|
void SaveGameDialog::onCharacterSelected(MyGUI::ComboBox* sender, size_t pos)
|
|
|
|
{
|
|
|
|
MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager();
|
|
|
|
|
|
|
|
unsigned int i = 0;
|
2018-10-09 10:21:12 +04:00
|
|
|
const MWState::Character* character = nullptr;
|
2013-11-21 20:24:58 +01:00
|
|
|
for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it, ++i)
|
|
|
|
{
|
|
|
|
if (i == pos)
|
|
|
|
character = &*it;
|
|
|
|
}
|
|
|
|
assert(character && "Can't find selected character");
|
|
|
|
|
|
|
|
mCurrentCharacter = character;
|
2018-10-09 10:21:12 +04:00
|
|
|
mCurrentSlot = nullptr;
|
2013-11-21 20:24:58 +01:00
|
|
|
fillSaveList();
|
|
|
|
}
|
|
|
|
|
2017-10-04 17:47:42 +02:00
|
|
|
void SaveGameDialog::onCharacterAccept(MyGUI::ComboBox* sender, size_t pos)
|
|
|
|
{
|
|
|
|
// Give key focus to save list so we can confirm the selection with Enter
|
2019-06-09 02:08:09 +03:00
|
|
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
|
2017-10-04 17:47:42 +02:00
|
|
|
}
|
|
|
|
|
2013-11-21 20:24:58 +01:00
|
|
|
void SaveGameDialog::fillSaveList()
|
|
|
|
{
|
|
|
|
mSaveList->removeAllItems();
|
|
|
|
if (!mCurrentCharacter)
|
|
|
|
return;
|
|
|
|
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it)
|
|
|
|
{
|
2013-11-24 15:19:56 +01:00
|
|
|
mSaveList->addItem(it->mProfile.mDescription);
|
2013-11-21 20:24:58 +01:00
|
|
|
}
|
2014-05-21 16:36:55 +02:00
|
|
|
// When loading, Auto-select the first save, if there is one
|
|
|
|
if (mSaveList->getItemCount() && !mSaving)
|
|
|
|
{
|
|
|
|
mSaveList->setIndexSelected(0);
|
|
|
|
onSlotSelected(mSaveList, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
onSlotSelected(mSaveList, MyGUI::ITEM_NONE);
|
2013-11-21 20:24:58 +01:00
|
|
|
}
|
|
|
|
|
2015-08-19 13:23:40 -04:00
|
|
|
std::string formatTimeplayed(const double timeInSeconds)
|
2015-08-19 10:05:08 -04:00
|
|
|
{
|
2015-08-19 13:23:40 -04:00
|
|
|
int timePlayed = (int)floor(timeInSeconds);
|
|
|
|
int days = timePlayed / 60 / 60 / 24;
|
|
|
|
int hours = (timePlayed / 60 / 60) % 24;
|
|
|
|
int minutes = (timePlayed / 60) % 60;
|
|
|
|
int seconds = timePlayed % 60;
|
2015-08-19 10:05:08 -04:00
|
|
|
|
|
|
|
std::stringstream stream;
|
|
|
|
stream << std::setfill('0') << std::setw(2) << days << ":";
|
|
|
|
stream << std::setfill('0') << std::setw(2) << hours << ":";
|
|
|
|
stream << std::setfill('0') << std::setw(2) << minutes << ":";
|
|
|
|
stream << std::setfill('0') << std::setw(2) << seconds;
|
|
|
|
return stream.str();
|
|
|
|
}
|
|
|
|
|
2013-11-21 20:24:58 +01:00
|
|
|
void SaveGameDialog::onSlotSelected(MyGUI::ListBox* sender, size_t pos)
|
|
|
|
{
|
2014-06-10 02:47:02 +02:00
|
|
|
mOkButton->setEnabled(pos != MyGUI::ITEM_NONE || mSaving);
|
|
|
|
mDeleteButton->setEnabled(pos != MyGUI::ITEM_NONE);
|
|
|
|
|
2014-12-18 03:24:10 +01:00
|
|
|
if (pos == MyGUI::ITEM_NONE || !mCurrentCharacter)
|
2013-11-21 20:24:58 +01:00
|
|
|
{
|
2018-10-09 10:21:12 +04:00
|
|
|
mCurrentSlot = nullptr;
|
2013-11-21 20:24:58 +01:00
|
|
|
mInfoText->setCaption("");
|
2014-01-24 17:49:16 +01:00
|
|
|
mScreenshot->setImageTexture("");
|
2013-11-21 20:24:58 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-01-26 15:43:26 +01:00
|
|
|
if (mSaving)
|
|
|
|
mSaveNameEdit->setCaption(sender->getItemNameAt(pos));
|
|
|
|
|
2018-10-09 10:21:12 +04:00
|
|
|
mCurrentSlot = nullptr;
|
2013-11-21 20:24:58 +01:00
|
|
|
unsigned int i = 0;
|
|
|
|
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end();
|
|
|
|
++it, ++i)
|
|
|
|
{
|
|
|
|
if (i == pos)
|
2014-04-28 20:57:45 +02:00
|
|
|
mCurrentSlot = &*it;
|
2013-11-21 20:24:58 +01:00
|
|
|
}
|
2014-09-28 12:44:47 +02:00
|
|
|
if (!mCurrentSlot)
|
|
|
|
throw std::runtime_error("Can't find selected slot");
|
2013-11-21 20:24:58 +01:00
|
|
|
|
|
|
|
std::stringstream text;
|
|
|
|
|
2022-09-24 16:20:42 +02:00
|
|
|
text << Misc::fileTimeToString(mCurrentSlot->mTimeStamp, "%Y.%m.%d %T") << "\n";
|
2015-12-07 21:24:30 +01:00
|
|
|
|
2015-08-16 01:50:44 +02:00
|
|
|
text << "#{sLevel} " << mCurrentSlot->mProfile.mPlayerLevel << "\n";
|
2015-08-16 01:55:14 +02:00
|
|
|
text << "#{sCell=" << mCurrentSlot->mProfile.mPlayerCell << "}\n";
|
2013-11-21 20:24:58 +01:00
|
|
|
|
2014-04-28 20:57:45 +02:00
|
|
|
int hour = int(mCurrentSlot->mProfile.mInGameTime.mGameHour);
|
2013-11-21 20:24:58 +01:00
|
|
|
bool pm = hour >= 12;
|
|
|
|
if (hour >= 13)
|
|
|
|
hour -= 12;
|
|
|
|
if (hour == 0)
|
|
|
|
hour = 12;
|
|
|
|
|
2014-04-28 20:57:45 +02:00
|
|
|
text << mCurrentSlot->mProfile.mInGameTime.mDay << " "
|
|
|
|
<< MWBase::Environment::get().getWorld()->getMonthName(mCurrentSlot->mProfile.mInGameTime.mMonth) << " "
|
2015-08-19 11:31:43 -04:00
|
|
|
<< hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}");
|
2015-08-19 10:05:08 -04:00
|
|
|
|
2015-08-19 11:31:43 -04:00
|
|
|
if (Settings::Manager::getBool("timeplayed", "Saves"))
|
|
|
|
{
|
2022-07-04 21:45:44 +04:00
|
|
|
text << "\n"
|
2022-12-22 18:53:49 +01:00
|
|
|
<< "#{OMWEngine:TimePlayed}: " << formatTimeplayed(mCurrentSlot->mProfile.mTimePlayed);
|
2015-08-19 11:31:43 -04:00
|
|
|
}
|
2013-11-21 20:24:58 +01:00
|
|
|
|
|
|
|
mInfoText->setCaptionWithReplacing(text.str());
|
2015-05-28 02:34:38 +02:00
|
|
|
|
2022-09-07 16:18:33 +03:00
|
|
|
// Reset the image for the case we're unable to recover a screenshot
|
|
|
|
mScreenshotTexture.reset();
|
|
|
|
mScreenshot->setRenderItemTexture(nullptr);
|
|
|
|
mScreenshot->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f));
|
2015-05-28 02:34:38 +02:00
|
|
|
|
2014-01-24 17:49:16 +01:00
|
|
|
// Decode screenshot
|
2015-05-28 02:34:38 +02:00
|
|
|
const std::vector<char>& data = mCurrentSlot->mProfile.mScreenshot;
|
2022-09-02 07:04:02 +03:00
|
|
|
if (!data.size())
|
|
|
|
{
|
2022-08-20 00:26:23 +02:00
|
|
|
Log(Debug::Warning) << "Selected save file '" << Files::pathToUnicodeString(mCurrentSlot->mPath.filename())
|
|
|
|
<< "' has no savegame screenshot";
|
2022-09-02 07:04:02 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Files::IMemStream instream(data.data(), data.size());
|
2015-05-28 02:34:38 +02:00
|
|
|
|
|
|
|
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg");
|
|
|
|
if (!readerwriter)
|
|
|
|
{
|
2022-09-02 19:37:00 +03:00
|
|
|
Log(Debug::Error) << "Can't open savegame screenshot, no jpg readerwriter found";
|
2015-05-28 02:34:38 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(instream);
|
|
|
|
if (!result.success())
|
2014-01-24 17:49:16 +01:00
|
|
|
{
|
2022-09-02 19:37:00 +03:00
|
|
|
Log(Debug::Error) << "Failed to read savegame screenshot: " << result.message() << " code "
|
|
|
|
<< result.status();
|
2015-05-28 02:34:38 +02:00
|
|
|
return;
|
2014-01-24 17:49:16 +01:00
|
|
|
}
|
|
|
|
|
2015-05-28 02:34:38 +02:00
|
|
|
osg::ref_ptr<osg::Texture2D> texture(new osg::Texture2D);
|
|
|
|
texture->setImage(result.getImage());
|
2021-08-04 17:49:57 -07:00
|
|
|
texture->setInternalFormat(GL_RGB);
|
2015-05-28 02:34:38 +02:00
|
|
|
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
|
|
|
|
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
|
|
|
|
texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
|
|
|
|
texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
|
|
|
|
texture->setResizeNonPowerOfTwoHint(false);
|
|
|
|
texture->setUnRefImageDataAfterApply(true);
|
|
|
|
|
2022-05-29 13:24:48 +02:00
|
|
|
mScreenshotTexture = std::make_unique<osgMyGUI::OSGTexture>(texture);
|
2015-05-28 02:34:38 +02:00
|
|
|
mScreenshot->setRenderItemTexture(mScreenshotTexture.get());
|
2013-11-21 20:24:58 +01:00
|
|
|
}
|
2013-11-05 19:50:24 +01:00
|
|
|
}
|