Qt: Implement save state menus
This commit is contained in:
parent
97ea851097
commit
1ce1e016ae
|
@ -22,7 +22,6 @@ MainWindow::MainWindow(QtHostInterface* host_interface) : QMainWindow(nullptr),
|
|||
m_ui.setupUi(this);
|
||||
setupAdditionalUi();
|
||||
connectSignals();
|
||||
populateLoadSaveStateMenus(QString());
|
||||
|
||||
resize(750, 690);
|
||||
}
|
||||
|
@ -136,7 +135,7 @@ void MainWindow::onSystemPerformanceCountersUpdated(float speed, float fps, floa
|
|||
|
||||
void MainWindow::onRunningGameChanged(QString filename, QString game_code, QString game_title)
|
||||
{
|
||||
populateLoadSaveStateMenus(game_code);
|
||||
m_host_interface->populateSaveStateMenus(game_code.toStdString().c_str(), m_ui.menuLoadState, m_ui.menuSaveState);
|
||||
if (game_title.isEmpty())
|
||||
setWindowTitle(tr("DuckStation"));
|
||||
else
|
||||
|
@ -367,14 +366,16 @@ void MainWindow::connectSignals()
|
|||
if (!entry)
|
||||
{
|
||||
m_ui.statusBar->clearMessage();
|
||||
populateLoadSaveStateMenus(QString());
|
||||
m_host_interface->populateSaveStateMenus("", m_ui.menuLoadState, m_ui.menuSaveState);
|
||||
return;
|
||||
}
|
||||
|
||||
m_ui.statusBar->showMessage(QString::fromStdString(entry->path));
|
||||
populateLoadSaveStateMenus(QString::fromStdString(entry->code));
|
||||
m_host_interface->populateSaveStateMenus(entry->code.c_str(), m_ui.menuLoadState, m_ui.menuSaveState);
|
||||
});
|
||||
|
||||
m_host_interface->populateSaveStateMenus(nullptr, m_ui.menuLoadState, m_ui.menuSaveState);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowVRAM, "Debug/ShowVRAM");
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugDumpCPUtoVRAMCopies,
|
||||
"Debug/DumpCPUToVRAMCopies");
|
||||
|
@ -443,39 +444,6 @@ void MainWindow::updateDebugMenuGPURenderer()
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::populateLoadSaveStateMenus(QString game_code)
|
||||
{
|
||||
static constexpr int NUM_SAVE_STATE_SLOTS = 10;
|
||||
|
||||
QMenu* const load_menu = m_ui.menuLoadState;
|
||||
QMenu* const save_menu = m_ui.menuSaveState;
|
||||
|
||||
load_menu->clear();
|
||||
save_menu->clear();
|
||||
|
||||
load_menu->addAction(tr("Resume State"));
|
||||
load_menu->addSeparator();
|
||||
|
||||
for (int i = 0; i < NUM_SAVE_STATE_SLOTS; i++)
|
||||
{
|
||||
// TODO: Do we want to test for the existance of these on disk here?
|
||||
load_menu->addAction(tr("Global Save %1 (2020-01-01 00:01:02)").arg(i + 1));
|
||||
save_menu->addAction(tr("Global Save %1").arg(i + 1));
|
||||
}
|
||||
|
||||
if (!game_code.isEmpty())
|
||||
{
|
||||
load_menu->addSeparator();
|
||||
save_menu->addSeparator();
|
||||
|
||||
for (int i = 0; i < NUM_SAVE_STATE_SLOTS; i++)
|
||||
{
|
||||
load_menu->addAction(tr("Game Save %1 (2020-01-01 00:01:02)").arg(i + 1));
|
||||
save_menu->addAction(tr("Game Save %1").arg(i + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
m_host_interface->powerOffSystem(true, true);
|
||||
|
|
|
@ -54,7 +54,6 @@ private:
|
|||
void doSettings(SettingsDialog::Category category = SettingsDialog::Category::Count);
|
||||
void updateDebugMenuCPUExecutionMode();
|
||||
void updateDebugMenuGPURenderer();
|
||||
void populateLoadSaveStateMenus(QString game_code);
|
||||
|
||||
Ui::MainWindow m_ui;
|
||||
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
#include "qtsettingsinterface.h"
|
||||
#include "qtutils.h"
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QEventLoop>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <memory>
|
||||
Log_SetChannel(QtHostInterface);
|
||||
|
@ -354,15 +356,22 @@ std::vector<QtHostInterface::HotkeyInfo> QtHostInterface::getHotkeyList() const
|
|||
{QStringLiteral("DecreaseResolutionScale"), QStringLiteral("Decrease Resolution Scale"),
|
||||
QStringLiteral("Graphics")}};
|
||||
|
||||
for (u32 i = 1; i <= NUM_SAVE_STATE_HOTKEYS; i++)
|
||||
for (u32 global_i = 0; global_i < 2; global_i++)
|
||||
{
|
||||
hotkeys.push_back(
|
||||
{QStringLiteral("LoadState%1").arg(i), QStringLiteral("Load State %1").arg(i), QStringLiteral("Save States")});
|
||||
const bool global = ConvertToBoolUnchecked(global_i);
|
||||
const u32 count = global ? GLOBAL_SAVE_STATE_SLOTS : PER_GAME_SAVE_STATE_SLOTS;
|
||||
for (u32 i = 1; i <= count; i++)
|
||||
{
|
||||
hotkeys.push_back({QStringLiteral("Load%1State%2").arg(global ? "Global" : "Game").arg(i),
|
||||
QStringLiteral("Load %1 State %2").arg(global ? tr("Global") : tr("Game")).arg(i),
|
||||
QStringLiteral("Save States")});
|
||||
}
|
||||
for (u32 i = 1; i <= NUM_SAVE_STATE_HOTKEYS; i++)
|
||||
for (u32 slot = 1; slot <= count; slot++)
|
||||
{
|
||||
hotkeys.push_back(
|
||||
{QStringLiteral("SaveState%1").arg(i), QStringLiteral("Save State %1").arg(i), QStringLiteral("Save States")});
|
||||
hotkeys.push_back({QStringLiteral("Save%1State%2").arg(global ? "Global" : "Game").arg(slot),
|
||||
QStringLiteral("Save %1 State %2").arg(global ? tr("Global") : tr("Game")).arg(slot),
|
||||
QStringLiteral("Save States")});
|
||||
}
|
||||
}
|
||||
|
||||
return hotkeys;
|
||||
|
@ -408,18 +417,22 @@ void QtHostInterface::updateHotkeyInputMap()
|
|||
ModifyResolutionScale(-1);
|
||||
});
|
||||
|
||||
for (u32 i = 1; i <= NUM_SAVE_STATE_HOTKEYS; i++)
|
||||
for (u32 global_i = 0; global_i < 2; global_i++)
|
||||
{
|
||||
hk(QStringLiteral("LoadState%1").arg(i), [this, i](bool pressed) {
|
||||
const bool global = ConvertToBoolUnchecked(global_i);
|
||||
const u32 count = global ? GLOBAL_SAVE_STATE_SLOTS : PER_GAME_SAVE_STATE_SLOTS;
|
||||
for (u32 slot = 1; slot <= count; slot++)
|
||||
{
|
||||
hk(QStringLiteral("Load%1State%2").arg(global ? "Global" : "Game").arg(slot), [this, global, slot](bool pressed) {
|
||||
if (!pressed)
|
||||
HostInterface::LoadState(StringUtil::StdStringFromFormat("savestate_%u.bin", i).c_str());
|
||||
loadState(global, slot);
|
||||
});
|
||||
|
||||
hk(QStringLiteral("SaveState%1").arg(i), [this, i](bool pressed) {
|
||||
hk(QStringLiteral("Save%1State%2").arg(global ? "Global" : "Game").arg(slot), [this, global, slot](bool pressed) {
|
||||
if (!pressed)
|
||||
HostInterface::SaveState(StringUtil::StdStringFromFormat("savestate_%u.bin", i).c_str());
|
||||
saveState(global, slot);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QtHostInterface::addButtonToInputMap(const QString& binding, InputButtonHandler handler)
|
||||
|
@ -555,6 +568,106 @@ void QtHostInterface::createAudioStream()
|
|||
}
|
||||
}
|
||||
|
||||
void QtHostInterface::populateSaveStateMenus(const char* game_code, QMenu* load_menu, QMenu* save_menu)
|
||||
{
|
||||
const std::vector<SaveStateInfo> available_states(GetAvailableSaveStates(game_code));
|
||||
|
||||
load_menu->clear();
|
||||
if (!available_states.empty())
|
||||
{
|
||||
bool last_global = available_states.front().global;
|
||||
for (const SaveStateInfo& ssi : available_states)
|
||||
{
|
||||
const s32 slot = ssi.slot;
|
||||
const bool global = ssi.global;
|
||||
const QDateTime timestamp(QDateTime::fromSecsSinceEpoch(static_cast<qint64>(ssi.timestamp)));
|
||||
const QString path(QString::fromStdString(ssi.path));
|
||||
|
||||
QString title = tr("%1 Save %2 (%3)")
|
||||
.arg(global ? tr("Global") : tr("Game"))
|
||||
.arg(slot)
|
||||
.arg(timestamp.toString(Qt::SystemLocaleShortDate));
|
||||
|
||||
if (global != last_global)
|
||||
{
|
||||
load_menu->addSeparator();
|
||||
last_global = global;
|
||||
}
|
||||
|
||||
QAction* action = load_menu->addAction(title);
|
||||
connect(action, &QAction::triggered, [this, path]() { loadState(path); });
|
||||
}
|
||||
}
|
||||
|
||||
save_menu->clear();
|
||||
if (game_code && std::strlen(game_code) > 0)
|
||||
{
|
||||
for (s32 i = 1; i <= PER_GAME_SAVE_STATE_SLOTS; i++)
|
||||
{
|
||||
QAction* action = save_menu->addAction(tr("Game Save %1").arg(i));
|
||||
connect(action, &QAction::triggered, [this, i]() { saveState(i, false); });
|
||||
}
|
||||
|
||||
save_menu->addSeparator();
|
||||
}
|
||||
|
||||
for (s32 i = 1; i <= GLOBAL_SAVE_STATE_SLOTS; i++)
|
||||
{
|
||||
QAction* action = save_menu->addAction(tr("Global Save %1").arg(i));
|
||||
connect(action, &QAction::triggered, [this, i]() { saveState(i, true); });
|
||||
}
|
||||
}
|
||||
|
||||
void QtHostInterface::loadState(QString filename)
|
||||
{
|
||||
if (!isOnWorkerThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "loadState", Qt::QueuedConnection, Q_ARG(QString, filename));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_system)
|
||||
LoadState(filename.toStdString().c_str());
|
||||
else
|
||||
doBootSystem(QString(), filename);
|
||||
}
|
||||
|
||||
void QtHostInterface::loadState(bool global, qint32 slot)
|
||||
{
|
||||
if (!isOnWorkerThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "loadState", Qt::QueuedConnection, Q_ARG(bool, global), Q_ARG(qint32, slot));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_system)
|
||||
{
|
||||
LoadState(slot, global);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!global)
|
||||
{
|
||||
// can't load a non-global system without a game code
|
||||
return;
|
||||
}
|
||||
|
||||
loadState(QString::fromStdString(GetGlobalSaveStateFileName(slot)));
|
||||
}
|
||||
|
||||
void QtHostInterface::saveState(bool global, qint32 slot, bool block_until_done /* = false */)
|
||||
{
|
||||
if (!isOnWorkerThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "saveState", block_until_done ? Qt::BlockingQueuedConnection : Qt::QueuedConnection,
|
||||
Q_ARG(bool, global), Q_ARG(qint32, slot), Q_ARG(bool, block_until_done));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_system)
|
||||
SaveState(global, slot);
|
||||
}
|
||||
|
||||
void QtHostInterface::createThread()
|
||||
{
|
||||
m_original_thread = QThread::currentThread();
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
class ByteStream;
|
||||
|
||||
class QEventLoop;
|
||||
class QMenu;
|
||||
class QWidget;
|
||||
|
||||
class GameList;
|
||||
|
@ -61,6 +62,8 @@ public:
|
|||
};
|
||||
std::vector<HotkeyInfo> getHotkeyList() const;
|
||||
|
||||
void populateSaveStateMenus(const char* game_code, QMenu* load_menu, QMenu* save_menu);
|
||||
|
||||
Q_SIGNALS:
|
||||
void errorReported(QString message);
|
||||
void messageReported(QString message);
|
||||
|
@ -81,6 +84,9 @@ public Q_SLOTS:
|
|||
void resetSystem();
|
||||
void pauseSystem(bool paused);
|
||||
void changeDisc(QString new_disc_filename);
|
||||
void loadState(QString filename);
|
||||
void loadState(bool global, qint32 slot);
|
||||
void saveState(bool global, qint32 slot, bool block_until_done = false);
|
||||
|
||||
private Q_SLOTS:
|
||||
void doStopThread();
|
||||
|
@ -97,11 +103,6 @@ protected:
|
|||
private:
|
||||
using InputButtonHandler = std::function<void(bool)>;
|
||||
|
||||
enum : u32
|
||||
{
|
||||
NUM_SAVE_STATE_HOTKEYS = 8
|
||||
};
|
||||
|
||||
class Thread : public QThread
|
||||
{
|
||||
public:
|
||||
|
|
Loading…
Reference in New Issue