From 4907003d3cd65eac5adf1c33fe1fc5b3abb12607 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 1 Oct 2022 23:29:29 +1000 Subject: [PATCH] Qt: Add Delete Save States to load menu --- pcsx2-qt/MainWindow.cpp | 27 +++++++++++++++++++++++++-- pcsx2-qt/MainWindow.h | 5 ----- pcsx2/Frontend/FullscreenUI.cpp | 4 +--- pcsx2/VMManager.cpp | 22 ++++++++++++++++++++++ pcsx2/VMManager.h | 6 ++++++ 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/pcsx2-qt/MainWindow.cpp b/pcsx2-qt/MainWindow.cpp index d749d7f669..f56b2786a1 100644 --- a/pcsx2-qt/MainWindow.cpp +++ b/pcsx2-qt/MainWindow.cpp @@ -2395,6 +2395,7 @@ void MainWindow::populateLoadStateMenu(QMenu* menu, const QString& filename, con return; const bool is_right_click_menu = (menu != m_ui.menuLoadState); + bool has_any_states = false; QAction* action = menu->addAction(is_right_click_menu ? tr("Load State File...") : tr("Load From File...")); connect(action, &QAction::triggered, [this, filename]() { @@ -2405,6 +2406,8 @@ void MainWindow::populateLoadStateMenu(QMenu* menu, const QString& filename, con loadSaveStateFile(filename, path); }); + QAction* delete_save_states_action = menu->addAction(tr("Delete Save States...")); + // don't include undo in the right click menu if (!is_right_click_menu) { @@ -2427,10 +2430,11 @@ void MainWindow::populateLoadStateMenu(QMenu* menu, const QString& filename, con // Make bold to indicate it's the default choice when double-clicking QtUtils::MarkActionAsDefault(action); + has_any_states = true; } } - for (s32 i = 1; i <= NUM_SAVE_STATE_SLOTS; i++) + for (s32 i = 1; i <= VMManager::NUM_SAVE_STATE_SLOTS; i++) { FILESYSTEM_STAT_DATA sd; state_filename = VMManager::GetSaveStateFileName(game_serial_utf8.constData(), crc, i); @@ -2439,6 +2443,25 @@ void MainWindow::populateLoadStateMenu(QMenu* menu, const QString& filename, con action = menu->addAction(tr("Load Slot %1 (%2)").arg(i).arg(formatTimestampForSaveStateMenu(sd.ModificationTime))); connect(action, &QAction::triggered, [this, i]() { loadSaveStateSlot(i); }); + has_any_states = true; + } + + delete_save_states_action->setEnabled(has_any_states); + if (has_any_states) + { + connect(delete_save_states_action, &QAction::triggered, this, [this, serial, crc] { + if (QMessageBox::warning( + this, tr("Delete Save States"), + tr("Are you sure you want to delete all save states for %1?\n\nThe saves will not be recoverable.") + .arg(serial), + QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes) + { + return; + } + + const u32 deleted = VMManager::DeleteSaveStates(serial.toUtf8().constData(), crc, true); + QMessageBox::information(this, tr("Delete Save States"), tr("%1 save states deleted.").arg(deleted)); + }); } } @@ -2458,7 +2481,7 @@ void MainWindow::populateSaveStateMenu(QMenu* menu, const QString& serial, quint menu->addSeparator(); const QByteArray game_serial_utf8(serial.toUtf8()); - for (s32 i = 1; i <= NUM_SAVE_STATE_SLOTS; i++) + for (s32 i = 1; i <= VMManager::NUM_SAVE_STATE_SLOTS; i++) { std::string filename(VMManager::GetSaveStateFileName(game_serial_utf8.constData(), crc, i)); FILESYSTEM_STAT_DATA sd; diff --git a/pcsx2-qt/MainWindow.h b/pcsx2-qt/MainWindow.h index 00b8bce6c3..2b4e1d2008 100644 --- a/pcsx2-qt/MainWindow.h +++ b/pcsx2-qt/MainWindow.h @@ -175,11 +175,6 @@ protected: void dropEvent(QDropEvent* event) override; private: - enum : s32 - { - NUM_SAVE_STATE_SLOTS = 10, - }; - static void setStyleFromSettings(); static void setIconThemeFromStyle(); diff --git a/pcsx2/Frontend/FullscreenUI.cpp b/pcsx2/Frontend/FullscreenUI.cpp index c8cf272754..ff27312b8b 100644 --- a/pcsx2/Frontend/FullscreenUI.cpp +++ b/pcsx2/Frontend/FullscreenUI.cpp @@ -61,8 +61,6 @@ #include "Frontend/Achievements.h" #endif -static constexpr s32 MAX_SAVE_STATE_SLOTS = 10; - using ImGuiFullscreen::g_large_font; using ImGuiFullscreen::g_layout_padding_left; using ImGuiFullscreen::g_layout_padding_top; @@ -3841,7 +3839,7 @@ u32 FullscreenUI::PopulateSaveStateListEntries(const std::string& title, const s { ClearSaveStateEntryList(); - for (s32 i = 0; i <= MAX_SAVE_STATE_SLOTS; i++) + for (s32 i = 0; i <= VMManager::NUM_SAVE_STATE_SLOTS; i++) { SaveStateListEntry li; if (InitializeSaveStateListEntry(&li, title, serial, crc, i) || !s_save_state_selector_loading) diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index 4f43dcd7e4..d72ec75444 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -1275,6 +1275,28 @@ void VMManager::WaitForSaveStateFlush() } } +u32 VMManager::DeleteSaveStates(const char* game_serial, u32 game_crc, bool also_backups /* = true */) +{ + WaitForSaveStateFlush(); + + u32 deleted = 0; + for (s32 i = -1; i <= NUM_SAVE_STATE_SLOTS; i++) + { + std::string filename(GetSaveStateFileName(game_serial, game_crc, i)); + if (FileSystem::FileExists(filename.c_str()) && FileSystem::DeleteFilePath(filename.c_str())) + deleted++; + + if (also_backups) + { + filename += ".backup"; + if (FileSystem::FileExists(filename.c_str()) && FileSystem::DeleteFilePath(filename.c_str())) + deleted++; + } + } + + return deleted; +} + bool VMManager::LoadState(const char* filename) { #ifdef ENABLE_ACHIEVEMENTS diff --git a/pcsx2/VMManager.h b/pcsx2/VMManager.h index 52ce7e2db7..4e4f180703 100644 --- a/pcsx2/VMManager.h +++ b/pcsx2/VMManager.h @@ -52,6 +52,9 @@ struct VMBootParameters namespace VMManager { + /// The number of usable save state slots. + static constexpr s32 NUM_SAVE_STATE_SLOTS = 10; + /// Makes sure that AVX2 is available if we were compiled with it. bool PerformEarlyHardwareChecks(const char** error); @@ -127,6 +130,9 @@ namespace VMManager /// Waits until all compressing save states have finished saving to disk. void WaitForSaveStateFlush(); + /// Removes all save states for the specified serial and crc. Returns the number of files deleted. + u32 DeleteSaveStates(const char* game_serial, u32 game_crc, bool also_backups = true); + /// Returns the current limiter mode. LimiterModeType GetLimiterMode();