mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-07 03:55:33 +00:00
FullscreenUI: Make save state selector a main window
More reliable, saves messing around with popups.
This commit is contained in:
parent
3bf5ded0d2
commit
9bcd738f5c
@ -174,6 +174,7 @@ enum class MainWindowType : u8
|
|||||||
GameList,
|
GameList,
|
||||||
Settings,
|
Settings,
|
||||||
PauseMenu,
|
PauseMenu,
|
||||||
|
SaveStateSelector,
|
||||||
Achievements,
|
Achievements,
|
||||||
Leaderboards,
|
Leaderboards,
|
||||||
};
|
};
|
||||||
@ -427,7 +428,8 @@ struct SaveStateListEntry
|
|||||||
{
|
{
|
||||||
std::string title;
|
std::string title;
|
||||||
std::string summary;
|
std::string summary;
|
||||||
std::string path;
|
std::string game_path;
|
||||||
|
std::string state_path;
|
||||||
std::unique_ptr<GPUTexture> preview_texture;
|
std::unique_ptr<GPUTexture> preview_texture;
|
||||||
time_t timestamp;
|
time_t timestamp;
|
||||||
s32 slot;
|
s32 slot;
|
||||||
@ -437,18 +439,14 @@ struct SaveStateListEntry
|
|||||||
static void InitializePlaceholderSaveStateListEntry(SaveStateListEntry* li, s32 slot, bool global);
|
static void InitializePlaceholderSaveStateListEntry(SaveStateListEntry* li, s32 slot, bool global);
|
||||||
static bool InitializeSaveStateListEntryFromSerial(SaveStateListEntry* li, const std::string& serial, s32 slot,
|
static bool InitializeSaveStateListEntryFromSerial(SaveStateListEntry* li, const std::string& serial, s32 slot,
|
||||||
bool global);
|
bool global);
|
||||||
static bool InitializeSaveStateListEntryFromPath(SaveStateListEntry* li, std::string path, s32 slot, bool global,
|
static bool InitializeSaveStateListEntryFromPath(SaveStateListEntry* li, std::string path, s32 slot, bool global);
|
||||||
std::string* media_path);
|
|
||||||
static void ClearSaveStateEntryList();
|
static void ClearSaveStateEntryList();
|
||||||
static u32 PopulateSaveStateListEntries(const std::string& serial,
|
static u32 PopulateSaveStateListEntries(const std::string& serial, std::optional<ExtendedSaveStateInfo> undo_save_state,
|
||||||
std::optional<ExtendedSaveStateInfo> undo_save_state);
|
bool is_loading);
|
||||||
static void OpenSaveStateSelector(const std::string& serial, const std::string& path, bool is_loading);
|
static void OpenSaveStateSelector(const std::string& serial, const std::string& path, bool is_loading);
|
||||||
static void CloseSaveStateSelector();
|
static void DrawSaveStateSelector();
|
||||||
static void DrawSaveStateSelector(bool is_loading);
|
|
||||||
static bool OpenLoadStateSelectorForGameResume(const GameList::Entry* entry);
|
static bool OpenLoadStateSelectorForGameResume(const GameList::Entry* entry);
|
||||||
static void DrawResumeStateSelector();
|
static void DrawResumeStateSelector();
|
||||||
static void DoLoadState(std::string path);
|
|
||||||
static void DoSaveState(s32 slot, bool global);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Game List
|
// Game List
|
||||||
@ -567,9 +565,6 @@ struct ALIGN_TO_CACHE_LINE UIState
|
|||||||
|
|
||||||
// Save State List
|
// Save State List
|
||||||
std::vector<SaveStateListEntry> save_state_selector_slots;
|
std::vector<SaveStateListEntry> save_state_selector_slots;
|
||||||
std::string save_state_selector_game_path;
|
|
||||||
s32 save_state_selector_submenu_index = -1;
|
|
||||||
bool save_state_selector_open = false;
|
|
||||||
bool save_state_selector_loading = true;
|
bool save_state_selector_loading = true;
|
||||||
|
|
||||||
// Lazily populated cover images.
|
// Lazily populated cover images.
|
||||||
@ -762,7 +757,7 @@ bool FullscreenUI::HasActiveWindow()
|
|||||||
|
|
||||||
bool FullscreenUI::AreAnyDialogsOpen()
|
bool FullscreenUI::AreAnyDialogsOpen()
|
||||||
{
|
{
|
||||||
return (s_state.save_state_selector_open || s_state.input_binding_type != InputBindingInfo::Type::Unknown ||
|
return (s_state.input_binding_type != InputBindingInfo::Type::Unknown ||
|
||||||
ImGuiFullscreen::IsAnyFixedPopupDialogOpen() || ImGuiFullscreen::IsChoiceDialogOpen() ||
|
ImGuiFullscreen::IsAnyFixedPopupDialogOpen() || ImGuiFullscreen::IsChoiceDialogOpen() ||
|
||||||
ImGuiFullscreen::IsInputDialogOpen() || ImGuiFullscreen::IsFileSelectorOpen() ||
|
ImGuiFullscreen::IsInputDialogOpen() || ImGuiFullscreen::IsFileSelectorOpen() ||
|
||||||
ImGuiFullscreen::IsMessageBoxDialogOpen() || ImGuiFullscreen::HasToast() ||
|
ImGuiFullscreen::IsMessageBoxDialogOpen() || ImGuiFullscreen::HasToast() ||
|
||||||
@ -968,7 +963,7 @@ void FullscreenUI::Shutdown(bool clear_state)
|
|||||||
|
|
||||||
Achievements::ClearUIState();
|
Achievements::ClearUIState();
|
||||||
ClearInputBindingVariables();
|
ClearInputBindingVariables();
|
||||||
CloseSaveStateSelector();
|
ClearSaveStateEntryList();
|
||||||
s_state.icon_image_map.clear();
|
s_state.icon_image_map.clear();
|
||||||
s_state.cover_image_map.clear();
|
s_state.cover_image_map.clear();
|
||||||
std::memset(s_state.controller_macro_expanded, 0, sizeof(s_state.controller_macro_expanded));
|
std::memset(s_state.controller_macro_expanded, 0, sizeof(s_state.controller_macro_expanded));
|
||||||
@ -1043,6 +1038,9 @@ void FullscreenUI::Render()
|
|||||||
case MainWindowType::PauseMenu:
|
case MainWindowType::PauseMenu:
|
||||||
DrawPauseMenu();
|
DrawPauseMenu();
|
||||||
break;
|
break;
|
||||||
|
case MainWindowType::SaveStateSelector:
|
||||||
|
DrawSaveStateSelector();
|
||||||
|
break;
|
||||||
case MainWindowType::Achievements:
|
case MainWindowType::Achievements:
|
||||||
Achievements::DrawAchievementsWindow();
|
Achievements::DrawAchievementsWindow();
|
||||||
break;
|
break;
|
||||||
@ -1057,8 +1055,6 @@ void FullscreenUI::Render()
|
|||||||
DrawAboutWindow();
|
DrawAboutWindow();
|
||||||
else if (IsFixedPopupDialogOpen(RESUME_STATE_SELECTOR_DIALOG_NAME))
|
else if (IsFixedPopupDialogOpen(RESUME_STATE_SELECTOR_DIALOG_NAME))
|
||||||
DrawResumeStateSelector();
|
DrawResumeStateSelector();
|
||||||
else if (s_state.save_state_selector_open)
|
|
||||||
DrawSaveStateSelector(s_state.save_state_selector_loading);
|
|
||||||
else if (s_state.input_binding_type != InputBindingInfo::Type::Unknown)
|
else if (s_state.input_binding_type != InputBindingInfo::Type::Unknown)
|
||||||
DrawInputBindingWindow();
|
DrawInputBindingWindow();
|
||||||
|
|
||||||
@ -1285,15 +1281,11 @@ void FullscreenUI::DoResume()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseSaveStateSelector();
|
|
||||||
|
|
||||||
SaveStateListEntry slentry;
|
SaveStateListEntry slentry;
|
||||||
if (!InitializeSaveStateListEntryFromPath(&slentry, std::move(path), -1, false,
|
if (!InitializeSaveStateListEntryFromPath(&slentry, std::move(path), -1, false))
|
||||||
&s_state.save_state_selector_game_path))
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
|
ClearSaveStateEntryList();
|
||||||
s_state.save_state_selector_slots.push_back(std::move(slentry));
|
s_state.save_state_selector_slots.push_back(std::move(slentry));
|
||||||
OpenFixedPopupDialog(RESUME_STATE_SELECTOR_DIALOG_NAME);
|
OpenFixedPopupDialog(RESUME_STATE_SELECTOR_DIALOG_NAME);
|
||||||
}
|
}
|
||||||
@ -6755,7 +6747,7 @@ void FullscreenUI::InitializePlaceholderSaveStateListEntry(SaveStateListEntry* l
|
|||||||
slot) :
|
slot) :
|
||||||
FSUI_STR("Quick Save");
|
FSUI_STR("Quick Save");
|
||||||
li->summary = FSUI_STR("No save present in this slot.");
|
li->summary = FSUI_STR("No save present in this slot.");
|
||||||
li->path = {};
|
li->state_path = {};
|
||||||
li->timestamp = 0;
|
li->timestamp = 0;
|
||||||
li->slot = slot;
|
li->slot = slot;
|
||||||
li->preview_texture = {};
|
li->preview_texture = {};
|
||||||
@ -6767,7 +6759,7 @@ bool FullscreenUI::InitializeSaveStateListEntryFromSerial(SaveStateListEntry* li
|
|||||||
{
|
{
|
||||||
const std::string path =
|
const std::string path =
|
||||||
(global ? System::GetGlobalSaveStateFileName(slot) : System::GetGameSaveStateFileName(serial, slot));
|
(global ? System::GetGlobalSaveStateFileName(slot) : System::GetGameSaveStateFileName(serial, slot));
|
||||||
if (!InitializeSaveStateListEntryFromPath(li, path.c_str(), slot, global, nullptr))
|
if (!InitializeSaveStateListEntryFromPath(li, path.c_str(), slot, global))
|
||||||
{
|
{
|
||||||
InitializePlaceholderSaveStateListEntry(li, slot, global);
|
InitializePlaceholderSaveStateListEntry(li, slot, global);
|
||||||
return false;
|
return false;
|
||||||
@ -6776,8 +6768,7 @@ bool FullscreenUI::InitializeSaveStateListEntryFromSerial(SaveStateListEntry* li
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FullscreenUI::InitializeSaveStateListEntryFromPath(SaveStateListEntry* li, std::string path, s32 slot, bool global,
|
bool FullscreenUI::InitializeSaveStateListEntryFromPath(SaveStateListEntry* li, std::string path, s32 slot, bool global)
|
||||||
std::string* media_path)
|
|
||||||
{
|
{
|
||||||
std::optional<ExtendedSaveStateInfo> ssi(System::GetExtendedSaveStateInfo(path.c_str()));
|
std::optional<ExtendedSaveStateInfo> ssi(System::GetExtendedSaveStateInfo(path.c_str()));
|
||||||
if (!ssi.has_value())
|
if (!ssi.has_value())
|
||||||
@ -6795,12 +6786,11 @@ bool FullscreenUI::InitializeSaveStateListEntryFromPath(SaveStateListEntry* li,
|
|||||||
li->summary = fmt::format(FSUI_FSTR("Saved {:%c}"), fmt::localtime(ssi->timestamp));
|
li->summary = fmt::format(FSUI_FSTR("Saved {:%c}"), fmt::localtime(ssi->timestamp));
|
||||||
li->timestamp = ssi->timestamp;
|
li->timestamp = ssi->timestamp;
|
||||||
li->slot = slot;
|
li->slot = slot;
|
||||||
li->path = std::move(path);
|
li->state_path = std::move(path);
|
||||||
|
li->game_path = std::move(ssi->media_path);
|
||||||
li->global = global;
|
li->global = global;
|
||||||
if (ssi->screenshot.IsValid())
|
if (ssi->screenshot.IsValid())
|
||||||
li->preview_texture = g_gpu_device->FetchAndUploadTextureImage(ssi->screenshot);
|
li->preview_texture = g_gpu_device->FetchAndUploadTextureImage(ssi->screenshot);
|
||||||
if (media_path)
|
|
||||||
*media_path = std::move(ssi->media_path);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -6816,7 +6806,7 @@ void FullscreenUI::ClearSaveStateEntryList()
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 FullscreenUI::PopulateSaveStateListEntries(const std::string& serial,
|
u32 FullscreenUI::PopulateSaveStateListEntries(const std::string& serial,
|
||||||
std::optional<ExtendedSaveStateInfo> undo_save_state)
|
std::optional<ExtendedSaveStateInfo> undo_save_state, bool is_loading)
|
||||||
{
|
{
|
||||||
ClearSaveStateEntryList();
|
ClearSaveStateEntryList();
|
||||||
|
|
||||||
@ -6835,7 +6825,7 @@ u32 FullscreenUI::PopulateSaveStateListEntries(const std::string& serial,
|
|||||||
for (s32 i = 1; i <= System::PER_GAME_SAVE_STATE_SLOTS; i++)
|
for (s32 i = 1; i <= System::PER_GAME_SAVE_STATE_SLOTS; i++)
|
||||||
{
|
{
|
||||||
SaveStateListEntry li;
|
SaveStateListEntry li;
|
||||||
if (InitializeSaveStateListEntryFromSerial(&li, serial, i, false) || !s_state.save_state_selector_loading)
|
if (InitializeSaveStateListEntryFromSerial(&li, serial, i, false) || !is_loading)
|
||||||
s_state.save_state_selector_slots.push_back(std::move(li));
|
s_state.save_state_selector_slots.push_back(std::move(li));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6843,7 +6833,7 @@ u32 FullscreenUI::PopulateSaveStateListEntries(const std::string& serial,
|
|||||||
for (s32 i = 1; i <= System::GLOBAL_SAVE_STATE_SLOTS; i++)
|
for (s32 i = 1; i <= System::GLOBAL_SAVE_STATE_SLOTS; i++)
|
||||||
{
|
{
|
||||||
SaveStateListEntry li;
|
SaveStateListEntry li;
|
||||||
if (InitializeSaveStateListEntryFromSerial(&li, serial, i, true) || !s_state.save_state_selector_loading)
|
if (InitializeSaveStateListEntryFromSerial(&li, serial, i, true) || !is_loading)
|
||||||
s_state.save_state_selector_slots.push_back(std::move(li));
|
s_state.save_state_selector_slots.push_back(std::move(li));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6856,15 +6846,15 @@ void FullscreenUI::OpenSaveStateSelector(const std::string& serial, const std::s
|
|||||||
{
|
{
|
||||||
// need to get the undo state, if any
|
// need to get the undo state, if any
|
||||||
Host::RunOnCPUThread([serial = serial, is_loading]() {
|
Host::RunOnCPUThread([serial = serial, is_loading]() {
|
||||||
std::optional<ExtendedSaveStateInfo> undo_state = System::GetUndoSaveStateInfo();
|
std::optional<ExtendedSaveStateInfo> undo_state;
|
||||||
|
if (is_loading)
|
||||||
|
undo_state = System::GetUndoSaveStateInfo();
|
||||||
GPUThread::RunOnThread([serial = std::move(serial), undo_state = std::move(undo_state), is_loading]() mutable {
|
GPUThread::RunOnThread([serial = std::move(serial), undo_state = std::move(undo_state), is_loading]() mutable {
|
||||||
s_state.save_state_selector_loading = is_loading;
|
if (PopulateSaveStateListEntries(serial, std::move(undo_state), is_loading) > 0)
|
||||||
s_state.save_state_selector_game_path = {};
|
|
||||||
if (PopulateSaveStateListEntries(serial, std::move(undo_state)) > 0)
|
|
||||||
{
|
{
|
||||||
s_state.current_main_window = MainWindowType::None;
|
s_state.save_state_selector_loading = is_loading;
|
||||||
s_state.save_state_selector_open = true;
|
s_state.current_main_window = MainWindowType::SaveStateSelector;
|
||||||
QueueResetFocus(FocusResetType::PopupOpened);
|
QueueResetFocus(FocusResetType::ViewChanged);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -6875,99 +6865,111 @@ void FullscreenUI::OpenSaveStateSelector(const std::string& serial, const std::s
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s_state.save_state_selector_loading = is_loading;
|
if (PopulateSaveStateListEntries(serial, std::nullopt, is_loading) > 0)
|
||||||
if (PopulateSaveStateListEntries(serial, std::nullopt) > 0)
|
|
||||||
{
|
{
|
||||||
s_state.save_state_selector_game_path = path;
|
s_state.save_state_selector_loading = is_loading;
|
||||||
s_state.save_state_selector_open = true;
|
s_state.current_main_window = MainWindowType::SaveStateSelector;
|
||||||
|
QueueResetFocus(FocusResetType::ViewChanged);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s_state.save_state_selector_game_path = {};
|
|
||||||
ShowToast({}, FSUI_STR("No save states found."), Host::OSD_INFO_DURATION);
|
ShowToast({}, FSUI_STR("No save states found."), Host::OSD_INFO_DURATION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullscreenUI::CloseSaveStateSelector()
|
void FullscreenUI::DrawSaveStateSelector()
|
||||||
{
|
{
|
||||||
if (s_state.save_state_selector_open)
|
static constexpr auto do_load_state = [](std::string game_path, std::string state_path) {
|
||||||
QueueResetFocus(FocusResetType::PopupClosed);
|
|
||||||
|
|
||||||
ClearSaveStateEntryList();
|
ClearSaveStateEntryList();
|
||||||
s_state.save_state_selector_open = false;
|
|
||||||
s_state.save_state_selector_loading = false;
|
|
||||||
s_state.save_state_selector_game_path = {};
|
|
||||||
|
|
||||||
if (IsFixedPopupDialogOpen(RESUME_STATE_SELECTOR_DIALOG_NAME))
|
if (GPUThread::HasGPUBackend())
|
||||||
CloseFixedPopupDialogImmediately();
|
{
|
||||||
|
ReturnToMainWindow();
|
||||||
|
|
||||||
|
Host::RunOnCPUThread([game_path = std::move(game_path), state_path = std::move(state_path)]() mutable {
|
||||||
|
if (System::IsValid())
|
||||||
|
{
|
||||||
|
if (state_path.empty())
|
||||||
|
{
|
||||||
|
// Loading undo state.
|
||||||
|
if (!System::UndoLoadState())
|
||||||
|
{
|
||||||
|
GPUThread::RunOnThread(
|
||||||
|
[]() { ShowToast(std::string(), TRANSLATE_STR("System", "Failed to undo load state.")); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullscreenUI::DrawSaveStateSelector(bool is_loading)
|
|
||||||
{
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
|
|
||||||
ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f));
|
|
||||||
ImGui::SetNextWindowSize(io.DisplaySize - LayoutScale(0.0f, LAYOUT_FOOTER_HEIGHT));
|
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 0.0f);
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.0f);
|
|
||||||
|
|
||||||
const char* window_title = is_loading ? FSUI_CSTR("Load State") : FSUI_CSTR("Save State");
|
|
||||||
ImGui::OpenPopup(window_title);
|
|
||||||
|
|
||||||
bool is_open = true;
|
|
||||||
const bool valid =
|
|
||||||
ImGui::BeginPopupModal(window_title, &is_open,
|
|
||||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
|
|
||||||
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBackground);
|
|
||||||
if (!valid || !is_open)
|
|
||||||
{
|
|
||||||
if (valid)
|
|
||||||
ImGui::EndPopup();
|
|
||||||
|
|
||||||
ImGui::PopStyleVar(5);
|
|
||||||
if (!is_open)
|
|
||||||
{
|
|
||||||
CloseSaveStateSelector();
|
|
||||||
ReturnToPreviousWindow();
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error error;
|
||||||
|
if (!System::LoadState(state_path.c_str(), &error, true, false))
|
||||||
|
{
|
||||||
|
GPUThread::RunOnThread([error_desc = error.TakeDescription()]() {
|
||||||
|
ShowToast(std::string(), fmt::format(TRANSLATE_FS("System", "Failed to load state: {}"), error_desc));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DoStartPath(std::move(game_path), std::move(state_path));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr auto do_save_state = [](s32 slot, bool global) {
|
||||||
|
ClearSaveStateEntryList();
|
||||||
|
ReturnToMainWindow();
|
||||||
|
|
||||||
|
Host::RunOnCPUThread([slot, global]() {
|
||||||
|
if (!System::IsValid())
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
|
std::string path(global ? System::GetGlobalSaveStateFileName(slot) :
|
||||||
|
System::GetGameSaveStateFileName(System::GetGameSerial(), slot));
|
||||||
|
Error error;
|
||||||
|
if (!System::SaveState(std::move(path), &error, g_settings.create_save_state_backups, false))
|
||||||
|
{
|
||||||
|
GPUThread::RunOnThread([error_desc = error.TakeDescription()]() {
|
||||||
|
ShowToast(std::string(), fmt::format(TRANSLATE_FS("System", "Failed to save state: {}"), error_desc));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
const ImVec2 heading_size =
|
const ImVec2 heading_size =
|
||||||
ImVec2(io.DisplaySize.x, LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY) +
|
ImVec2(io.DisplaySize.x, LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY) +
|
||||||
(LayoutScale(LAYOUT_MENU_BUTTON_Y_PADDING) * 2.0f) + LayoutScale(2.0f));
|
(LayoutScale(LAYOUT_MENU_BUTTON_Y_PADDING) * 2.0f) + LayoutScale(2.0f));
|
||||||
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ModAlpha(UIStyle.PrimaryColor, 0.9f));
|
|
||||||
|
|
||||||
bool closed = false;
|
bool closed = false;
|
||||||
bool was_close_not_back = false;
|
|
||||||
bool ignore_close_request = false;
|
// last state deleted?
|
||||||
if (ImGui::BeginChild("state_titlebar", heading_size, false, ImGuiWindowFlags_NavFlattened))
|
if (s_state.save_state_selector_slots.empty())
|
||||||
|
closed = true;
|
||||||
|
|
||||||
|
if (BeginFullscreenWindow(ImVec2(0.0f, 0.0f), heading_size, "##save_state_selector_title",
|
||||||
|
ModAlpha(UIStyle.PrimaryColor, GetBackgroundAlpha())))
|
||||||
{
|
{
|
||||||
BeginNavBar();
|
BeginNavBar();
|
||||||
if (NavButton(ICON_PF_NAVIGATION_BACK, true, true))
|
if (NavButton(ICON_PF_NAVIGATION_BACK, true, true))
|
||||||
closed = true;
|
closed = true;
|
||||||
|
|
||||||
NavTitle(is_loading ? FSUI_CSTR("Load State") : FSUI_CSTR("Save State"));
|
NavTitle(s_state.save_state_selector_loading ? FSUI_CSTR("Load State") : FSUI_CSTR("Save State"));
|
||||||
EndNavBar();
|
EndNavBar();
|
||||||
ImGui::EndChild();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PopStyleColor();
|
EndFullscreenWindow();
|
||||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ModAlpha(UIStyle.BackgroundColor, 0.9f));
|
|
||||||
ImGui::SetCursorPos(ImVec2(0.0f, heading_size.y));
|
|
||||||
|
|
||||||
if (IsFocusResetFromWindowChange())
|
if (IsFocusResetFromWindowChange())
|
||||||
ImGui::SetNextWindowScroll(ImVec2(0.0f, 0.0f));
|
ImGui::SetNextWindowScroll(ImVec2(0.0f, 0.0f));
|
||||||
|
|
||||||
if (ImGui::BeginChild("state_list",
|
if (BeginFullscreenWindow(
|
||||||
ImVec2(io.DisplaySize.x, io.DisplaySize.y - LayoutScale(LAYOUT_FOOTER_HEIGHT) - heading_size.y),
|
ImVec2(0.0f, heading_size.y),
|
||||||
false, ImGuiWindowFlags_NavFlattened))
|
ImVec2(io.DisplaySize.x, io.DisplaySize.y - heading_size.y - LayoutScale(LAYOUT_FOOTER_HEIGHT)),
|
||||||
|
"##save_state_selector_list", ModAlpha(UIStyle.BackgroundColor, GetBackgroundAlpha()), 0.0f,
|
||||||
|
ImVec2(ImGuiFullscreen::LAYOUT_MENU_WINDOW_X_PADDING, 0.0f)))
|
||||||
{
|
{
|
||||||
ResetFocusHere();
|
ResetFocusHere();
|
||||||
BeginMenuButtons();
|
BeginMenuButtons();
|
||||||
@ -6995,107 +6997,6 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading)
|
|||||||
for (u32 i = 0; i < s_state.save_state_selector_slots.size();)
|
for (u32 i = 0; i < s_state.save_state_selector_slots.size();)
|
||||||
{
|
{
|
||||||
SaveStateListEntry& entry = s_state.save_state_selector_slots[i];
|
SaveStateListEntry& entry = s_state.save_state_selector_slots[i];
|
||||||
if (static_cast<s32>(i) == s_state.save_state_selector_submenu_index)
|
|
||||||
{
|
|
||||||
// can't use a choice dialog here, because we're already in a modal...
|
|
||||||
ImGuiFullscreen::PushResetLayout();
|
|
||||||
ImGui::PushFont(UIStyle.LargeFont);
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f));
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
|
|
||||||
LayoutScale(LAYOUT_MENU_BUTTON_X_PADDING, LAYOUT_MENU_BUTTON_Y_PADDING));
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, UIStyle.PrimaryTextColor);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_TitleBg, UIStyle.PrimaryDarkColor);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, UIStyle.PrimaryColor);
|
|
||||||
|
|
||||||
const float width = LayoutScale(600.0f);
|
|
||||||
const float title_height = UIStyle.LargeFont->FontSize + ImGui::GetStyle().FramePadding.y * 2.0f +
|
|
||||||
ImGui::GetStyle().WindowPadding.y * 2.0f;
|
|
||||||
const float height =
|
|
||||||
title_height +
|
|
||||||
((LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY) + (LayoutScale(LAYOUT_MENU_BUTTON_Y_PADDING) * 2.0f)) *
|
|
||||||
3.0f);
|
|
||||||
ImGui::SetNextWindowSize(ImVec2(width, height));
|
|
||||||
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
|
||||||
ImGui::OpenPopup(entry.title.c_str());
|
|
||||||
|
|
||||||
bool removed = false;
|
|
||||||
if (ImGui::BeginPopupModal(entry.title.c_str(), &is_open,
|
|
||||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove))
|
|
||||||
{
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, UIStyle.BackgroundTextColor);
|
|
||||||
|
|
||||||
BeginMenuButtons();
|
|
||||||
|
|
||||||
if (MenuButtonWithoutSummary(is_loading ? FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Load State") :
|
|
||||||
FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Save State")))
|
|
||||||
{
|
|
||||||
if (is_loading)
|
|
||||||
DoLoadState(std::move(entry.path));
|
|
||||||
else
|
|
||||||
DoSaveState(entry.slot, entry.global);
|
|
||||||
|
|
||||||
closed = true;
|
|
||||||
was_close_not_back = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entry.path.empty() && MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_FOLDER_MINUS, "Delete Save")))
|
|
||||||
{
|
|
||||||
if (!FileSystem::FileExists(entry.path.c_str()))
|
|
||||||
{
|
|
||||||
ShowToast({}, fmt::format(FSUI_FSTR("{} does not exist."), ImGuiFullscreen::RemoveHash(entry.title)));
|
|
||||||
is_open = true;
|
|
||||||
}
|
|
||||||
else if (FileSystem::DeleteFile(entry.path.c_str()))
|
|
||||||
{
|
|
||||||
ShowToast({}, fmt::format(FSUI_FSTR("{} deleted."), ImGuiFullscreen::RemoveHash(entry.title)));
|
|
||||||
if (is_loading)
|
|
||||||
s_state.save_state_selector_slots.erase(s_state.save_state_selector_slots.begin() + i);
|
|
||||||
else
|
|
||||||
InitializePlaceholderSaveStateListEntry(&entry, entry.slot, entry.global);
|
|
||||||
|
|
||||||
removed = true;
|
|
||||||
|
|
||||||
if (s_state.save_state_selector_slots.empty())
|
|
||||||
{
|
|
||||||
closed = true;
|
|
||||||
was_close_not_back = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
is_open = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ShowToast({}, fmt::format(FSUI_FSTR("Failed to delete {}."), ImGuiFullscreen::RemoveHash(entry.title)));
|
|
||||||
is_open = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_WINDOW_CLOSE, "Close Menu")) || WantsToCloseMenu())
|
|
||||||
{
|
|
||||||
is_open = false;
|
|
||||||
ignore_close_request = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
EndMenuButtons();
|
|
||||||
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_open)
|
|
||||||
s_state.save_state_selector_submenu_index = -1;
|
|
||||||
|
|
||||||
ImGui::PopStyleColor(3);
|
|
||||||
ImGui::PopStyleVar(3);
|
|
||||||
ImGui::PopFont();
|
|
||||||
ImGuiFullscreen::PopResetLayout();
|
|
||||||
|
|
||||||
if (removed)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||||
if (window->SkipItems)
|
if (window->SkipItems)
|
||||||
@ -7153,20 +7054,74 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading)
|
|||||||
|
|
||||||
if (pressed)
|
if (pressed)
|
||||||
{
|
{
|
||||||
if (is_loading)
|
if (s_state.save_state_selector_loading)
|
||||||
DoLoadState(entry.path);
|
do_load_state(std::move(entry.game_path), std::move(entry.state_path));
|
||||||
else
|
else
|
||||||
DoSaveState(entry.slot, entry.global);
|
do_save_state(entry.slot, entry.global);
|
||||||
|
|
||||||
closed = true;
|
closed = true;
|
||||||
was_close_not_back = true;
|
|
||||||
}
|
}
|
||||||
else if (hovered &&
|
else if (hovered &&
|
||||||
(ImGui::IsItemClicked(ImGuiMouseButton_Right) ||
|
(ImGui::IsItemClicked(ImGuiMouseButton_Right) ||
|
||||||
ImGui::IsKeyPressed(ImGuiKey_NavGamepadInput, false) || ImGui::IsKeyPressed(ImGuiKey_F1, false)))
|
ImGui::IsKeyPressed(ImGuiKey_NavGamepadInput, false) || ImGui::IsKeyPressed(ImGuiKey_F1, false)))
|
||||||
{
|
{
|
||||||
CancelPendingMenuClose();
|
CancelPendingMenuClose();
|
||||||
s_state.save_state_selector_submenu_index = static_cast<s32>(i);
|
|
||||||
|
std::string title;
|
||||||
|
if (s_state.save_state_selector_loading)
|
||||||
|
title = FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Load State");
|
||||||
|
else
|
||||||
|
title = FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Save State");
|
||||||
|
|
||||||
|
ChoiceDialogOptions options;
|
||||||
|
options.reserve(3);
|
||||||
|
options.emplace_back(title, false);
|
||||||
|
if (!entry.state_path.empty())
|
||||||
|
options.emplace_back(FSUI_ICONSTR(ICON_FA_FOLDER_MINUS, "Delete Save"), false);
|
||||||
|
options.emplace_back(FSUI_ICONSTR(ICON_FA_WINDOW_CLOSE, "Close Menu"), false);
|
||||||
|
|
||||||
|
OpenChoiceDialog(
|
||||||
|
std::move(title), false, std::move(options),
|
||||||
|
[i](s32 index, const std::string& title, bool checked) mutable {
|
||||||
|
if (index < 0 || i >= s_state.save_state_selector_slots.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SaveStateListEntry& entry = s_state.save_state_selector_slots[i];
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
// load state
|
||||||
|
if (s_state.save_state_selector_loading)
|
||||||
|
do_load_state(std::move(entry.game_path), std::move(entry.state_path));
|
||||||
|
else
|
||||||
|
do_save_state(entry.slot, entry.global);
|
||||||
|
}
|
||||||
|
else if (!entry.state_path.empty() && index == 1)
|
||||||
|
{
|
||||||
|
// delete state
|
||||||
|
if (!FileSystem::FileExists(entry.state_path.c_str()))
|
||||||
|
{
|
||||||
|
ShowToast({}, fmt::format(FSUI_FSTR("{} does not exist."), ImGuiFullscreen::RemoveHash(entry.title)));
|
||||||
|
}
|
||||||
|
else if (FileSystem::DeleteFile(entry.state_path.c_str()))
|
||||||
|
{
|
||||||
|
ShowToast({}, fmt::format(FSUI_FSTR("{} deleted."), ImGuiFullscreen::RemoveHash(entry.title)));
|
||||||
|
|
||||||
|
// need to preserve the texture, since it's going to be drawn this frame
|
||||||
|
// TODO: do this with a transition for safety
|
||||||
|
g_gpu_device->RecycleTexture(std::move(entry.preview_texture));
|
||||||
|
|
||||||
|
if (s_state.save_state_selector_loading)
|
||||||
|
s_state.save_state_selector_slots.erase(s_state.save_state_selector_slots.begin() + i);
|
||||||
|
else
|
||||||
|
InitializePlaceholderSaveStateListEntry(&entry, entry.slot, entry.global);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ShowToast({},
|
||||||
|
fmt::format(FSUI_FSTR("Failed to delete {}."), ImGuiFullscreen::RemoveHash(entry.title)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7187,20 +7142,17 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading)
|
|||||||
|
|
||||||
EndMenuButtons();
|
EndMenuButtons();
|
||||||
SetWindowNavWrapping(true, true);
|
SetWindowNavWrapping(true, true);
|
||||||
ImGui::EndChild();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PopStyleColor();
|
EndFullscreenWindow();
|
||||||
|
|
||||||
ImGui::EndPopup();
|
|
||||||
ImGui::PopStyleVar(5);
|
|
||||||
|
|
||||||
if (IsGamepadInputSource())
|
if (IsGamepadInputSource())
|
||||||
{
|
{
|
||||||
SetFullscreenFooterText(
|
SetFullscreenFooterText(
|
||||||
std::array{std::make_pair(ICON_PF_XBOX_DPAD, FSUI_VSTR("Select State")),
|
std::array{std::make_pair(ICON_PF_XBOX_DPAD, FSUI_VSTR("Select State")),
|
||||||
std::make_pair(ICON_PF_BUTTON_Y, FSUI_VSTR("Delete State")),
|
std::make_pair(ICON_PF_BUTTON_Y, FSUI_VSTR("Delete State")),
|
||||||
std::make_pair(ICON_PF_BUTTON_A, is_loading ? FSUI_VSTR("Load State") : FSUI_VSTR("Save State")),
|
std::make_pair(ICON_PF_BUTTON_A, s_state.save_state_selector_loading ? FSUI_VSTR("Load State") :
|
||||||
|
FSUI_VSTR("Save State")),
|
||||||
std::make_pair(ICON_PF_BUTTON_B, FSUI_VSTR("Cancel"))},
|
std::make_pair(ICON_PF_BUTTON_B, FSUI_VSTR("Cancel"))},
|
||||||
GetBackgroundAlpha());
|
GetBackgroundAlpha());
|
||||||
}
|
}
|
||||||
@ -7210,17 +7162,15 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading)
|
|||||||
std::array{std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT,
|
std::array{std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT,
|
||||||
FSUI_VSTR("Select State")),
|
FSUI_VSTR("Select State")),
|
||||||
std::make_pair(ICON_PF_F1, FSUI_VSTR("Delete State")),
|
std::make_pair(ICON_PF_F1, FSUI_VSTR("Delete State")),
|
||||||
std::make_pair(ICON_PF_ENTER, is_loading ? FSUI_VSTR("Load State") : FSUI_VSTR("Save State")),
|
std::make_pair(ICON_PF_ENTER, s_state.save_state_selector_loading ? FSUI_VSTR("Load State") :
|
||||||
|
FSUI_VSTR("Save State")),
|
||||||
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Cancel"))},
|
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Cancel"))},
|
||||||
GetBackgroundAlpha());
|
GetBackgroundAlpha());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!ignore_close_request && WantsToCloseMenu()) || closed)
|
if ((!AreAnyDialogsOpen() && WantsToCloseMenu()) || closed)
|
||||||
{
|
{
|
||||||
CloseSaveStateSelector();
|
ClearSaveStateEntryList();
|
||||||
if (was_close_not_back)
|
|
||||||
ReturnToMainWindow();
|
|
||||||
else if (s_state.current_main_window != MainWindowType::GameList)
|
|
||||||
ReturnToPreviousWindow();
|
ReturnToPreviousWindow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7231,9 +7181,7 @@ bool FullscreenUI::OpenLoadStateSelectorForGameResume(const GameList::Entry* ent
|
|||||||
if (!InitializeSaveStateListEntryFromSerial(&slentry, entry->serial, -1, false))
|
if (!InitializeSaveStateListEntryFromSerial(&slentry, entry->serial, -1, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CloseSaveStateSelector();
|
|
||||||
s_state.save_state_selector_slots.push_back(std::move(slentry));
|
s_state.save_state_selector_slots.push_back(std::move(slentry));
|
||||||
s_state.save_state_selector_game_path = entry->path;
|
|
||||||
OpenFixedPopupDialog(RESUME_STATE_SELECTOR_DIALOG_NAME);
|
OpenFixedPopupDialog(RESUME_STATE_SELECTOR_DIALOG_NAME);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -7242,7 +7190,7 @@ void FullscreenUI::DrawResumeStateSelector()
|
|||||||
{
|
{
|
||||||
if (!BeginFixedPopupDialog(LayoutScale(30.0f), LayoutScale(40.0f), LayoutScale(820.0f, 625.0f)))
|
if (!BeginFixedPopupDialog(LayoutScale(30.0f), LayoutScale(40.0f), LayoutScale(820.0f, 625.0f)))
|
||||||
{
|
{
|
||||||
CloseSaveStateSelector();
|
ClearSaveStateEntryList();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7272,25 +7220,28 @@ void FullscreenUI::DrawResumeStateSelector()
|
|||||||
|
|
||||||
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_PLAY, "Load State")))
|
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_PLAY, "Load State")))
|
||||||
{
|
{
|
||||||
std::string game_path = std::move(s_state.save_state_selector_game_path);
|
std::string game_path = std::move(entry.game_path);
|
||||||
std::string state_path = std::move(entry.path);
|
std::string state_path = std::move(entry.state_path);
|
||||||
CloseSaveStateSelector();
|
ClearSaveStateEntryList();
|
||||||
|
CloseFixedPopupDialogImmediately();
|
||||||
DoStartPath(std::move(game_path), std::move(state_path));
|
DoStartPath(std::move(game_path), std::move(state_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_LIGHTBULB, "Clean Boot")))
|
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_LIGHTBULB, "Clean Boot")))
|
||||||
{
|
{
|
||||||
std::string game_path = std::move(s_state.save_state_selector_game_path);
|
std::string game_path = std::move(entry.game_path);
|
||||||
CloseSaveStateSelector();
|
ClearSaveStateEntryList();
|
||||||
|
CloseFixedPopupDialogImmediately();
|
||||||
DoStartPath(std::move(game_path));
|
DoStartPath(std::move(game_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_FOLDER_MINUS, "Delete State")))
|
if (MenuButtonWithoutSummary(FSUI_ICONSTR(ICON_FA_FOLDER_MINUS, "Delete State")))
|
||||||
{
|
{
|
||||||
if (FileSystem::DeleteFile(entry.path.c_str()))
|
if (FileSystem::DeleteFile(entry.state_path.c_str()))
|
||||||
{
|
{
|
||||||
std::string game_path = std::move(s_state.save_state_selector_game_path);
|
std::string game_path = std::move(entry.game_path);
|
||||||
CloseSaveStateSelector();
|
ClearSaveStateEntryList();
|
||||||
|
CloseFixedPopupDialogImmediately();
|
||||||
DoStartPath(std::move(game_path));
|
DoStartPath(std::move(game_path));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -7309,64 +7260,6 @@ void FullscreenUI::DrawResumeStateSelector()
|
|||||||
EndFixedPopupDialog();
|
EndFixedPopupDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullscreenUI::DoLoadState(std::string path)
|
|
||||||
{
|
|
||||||
std::string boot_path = std::move(s_state.save_state_selector_game_path);
|
|
||||||
CloseSaveStateSelector();
|
|
||||||
|
|
||||||
if (GPUThread::HasGPUBackend())
|
|
||||||
{
|
|
||||||
Host::RunOnCPUThread([boot_path = std::move(boot_path), path = std::move(path)]() mutable {
|
|
||||||
if (System::IsValid())
|
|
||||||
{
|
|
||||||
if (path.empty())
|
|
||||||
{
|
|
||||||
// Loading undo state.
|
|
||||||
if (!System::UndoLoadState())
|
|
||||||
{
|
|
||||||
GPUThread::RunOnThread(
|
|
||||||
[]() { ShowToast(std::string(), TRANSLATE_STR("System", "Failed to undo load state.")); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Error error;
|
|
||||||
if (!System::LoadState(path.c_str(), &error, true, false))
|
|
||||||
{
|
|
||||||
GPUThread::RunOnThread([error_desc = error.TakeDescription()]() {
|
|
||||||
ShowToast(std::string(), fmt::format(TRANSLATE_FS("System", "Failed to load state: {}"), error_desc));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DoStartPath(std::move(boot_path), std::move(path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FullscreenUI::DoSaveState(s32 slot, bool global)
|
|
||||||
{
|
|
||||||
CloseSaveStateSelector();
|
|
||||||
|
|
||||||
Host::RunOnCPUThread([slot, global]() {
|
|
||||||
if (!System::IsValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::string path(global ? System::GetGlobalSaveStateFileName(slot) :
|
|
||||||
System::GetGameSaveStateFileName(System::GetGameSerial(), slot));
|
|
||||||
Error error;
|
|
||||||
if (!System::SaveState(std::move(path), &error, g_settings.create_save_state_backups, false))
|
|
||||||
{
|
|
||||||
GPUThread::RunOnThread([error_desc = error.TakeDescription()]() {
|
|
||||||
ShowToast(std::string(), fmt::format(TRANSLATE_FS("System", "Failed to save state: {}"), error_desc));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void FullscreenUI::PopulateGameListEntryList()
|
void FullscreenUI::PopulateGameListEntryList()
|
||||||
{
|
{
|
||||||
const s32 sort = Host::GetBaseIntSettingValue("Main", "FullscreenUIGameSort", 0);
|
const s32 sort = Host::GetBaseIntSettingValue("Main", "FullscreenUIGameSort", 0);
|
||||||
|
@ -2426,6 +2426,7 @@ void ImGuiFullscreen::PopupDialog::CloseImmediately()
|
|||||||
{
|
{
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
ClearState();
|
ClearState();
|
||||||
|
QueueResetFocus(FocusResetType::PopupClosed);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user