ImGuiOverlays: Pack SaveStateSelectorUI state

This commit is contained in:
Stenzek 2024-12-09 15:35:04 +10:00
parent 8bb013540d
commit a1928de4d0
No known key found for this signature in database
1 changed files with 97 additions and 84 deletions

View File

@ -827,66 +827,76 @@ static std::string GetCurrentSlotPath();
static constexpr const char* DATE_TIME_FORMAT = static constexpr const char* DATE_TIME_FORMAT =
TRANSLATE_NOOP("SaveStateSelectorUI", "Saved at {0:%H:%M} on {0:%a} {0:%Y/%m/%d}."); TRANSLATE_NOOP("SaveStateSelectorUI", "Saved at {0:%H:%M} on {0:%a} {0:%Y/%m/%d}.");
static std::shared_ptr<GPUTexture> s_placeholder_texture; namespace {
static std::string s_load_legend; struct ALIGN_TO_CACHE_LINE State
static std::string s_save_legend; {
static std::string s_prev_legend; std::shared_ptr<GPUTexture> placeholder_texture;
static std::string s_next_legend;
static llvm::SmallVector<ListEntry, System::PER_GAME_SAVE_STATE_SLOTS + System::GLOBAL_SAVE_STATE_SLOTS> s_slots; std::string load_legend;
static s32 s_current_slot = 0; std::string save_legend;
static bool s_current_slot_global = false; std::string prev_legend;
std::string next_legend;
static float s_open_time = 0.0f; llvm::SmallVector<ListEntry, System::PER_GAME_SAVE_STATE_SLOTS + System::GLOBAL_SAVE_STATE_SLOTS> slots;
static float s_close_time = 0.0f; s32 current_slot = 0;
bool current_slot_global = false;
static ImAnimatedFloat s_scroll_animated; float open_time = 0.0f;
static ImAnimatedFloat s_background_animated; float close_time = 0.0f;
ImAnimatedFloat scroll_animated;
ImAnimatedFloat background_animated;
bool is_open = false;
};
} // namespace
static State s_state;
static bool s_open = false;
} // namespace SaveStateSelectorUI } // namespace SaveStateSelectorUI
bool SaveStateSelectorUI::IsOpen() bool SaveStateSelectorUI::IsOpen()
{ {
return s_open; return s_state.is_open;
} }
void SaveStateSelectorUI::Open(float open_time /* = DEFAULT_OPEN_TIME */) void SaveStateSelectorUI::Open(float open_time /* = DEFAULT_OPEN_TIME */)
{ {
const std::string& serial = System::GetGameSerial(); const std::string& serial = System::GetGameSerial();
s_open_time = 0.0f; s_state.open_time = 0.0f;
s_close_time = open_time; s_state.close_time = open_time;
if (s_open) if (s_state.is_open)
return; return;
if (!s_placeholder_texture) if (!s_state.placeholder_texture)
s_placeholder_texture = ImGuiFullscreen::LoadTexture("no-save.png"); s_state.placeholder_texture = ImGuiFullscreen::LoadTexture("no-save.png");
s_open = true; s_state.is_open = true;
RefreshList(serial); RefreshList(serial);
RefreshHotkeyLegend(); RefreshHotkeyLegend();
} }
void SaveStateSelectorUI::Close() void SaveStateSelectorUI::Close()
{ {
s_open = false; s_state.is_open = false;
s_load_legend = {}; s_state.load_legend = {};
s_save_legend = {}; s_state.save_legend = {};
s_prev_legend = {}; s_state.prev_legend = {};
s_next_legend = {}; s_state.next_legend = {};
} }
void SaveStateSelectorUI::RefreshList(const std::string& serial) void SaveStateSelectorUI::RefreshList(const std::string& serial)
{ {
for (ListEntry& entry : s_slots) for (ListEntry& entry : s_state.slots)
{ {
if (entry.preview_texture) if (entry.preview_texture)
g_gpu_device->RecycleTexture(std::move(entry.preview_texture)); g_gpu_device->RecycleTexture(std::move(entry.preview_texture));
} }
s_slots.clear(); s_state.slots.clear();
if (System::IsShutdown()) if (System::IsShutdown())
return; return;
@ -904,16 +914,16 @@ void SaveStateSelectorUI::RefreshList(const std::string& serial)
else else
InitializePlaceholderListEntry(&li, std::move(path), i, false); InitializePlaceholderListEntry(&li, std::move(path), i, false);
s_slots.push_back(std::move(li)); s_state.slots.push_back(std::move(li));
} }
} }
else else
{ {
// reset slot if it's not global // reset slot if it's not global
if (!s_current_slot_global) if (!s_state.current_slot_global)
{ {
s_current_slot = 0; s_state.current_slot = 0;
s_current_slot_global = true; s_state.current_slot_global = true;
} }
} }
@ -928,7 +938,7 @@ void SaveStateSelectorUI::RefreshList(const std::string& serial)
else else
InitializePlaceholderListEntry(&li, std::move(path), i, true); InitializePlaceholderListEntry(&li, std::move(path), i, true);
s_slots.push_back(std::move(li)); s_state.slots.push_back(std::move(li));
} }
} }
@ -938,33 +948,33 @@ void SaveStateSelectorUI::Clear()
// big picture UI, in which case we have to delete them here... // big picture UI, in which case we have to delete them here...
ClearList(); ClearList();
s_current_slot = 0; s_state.current_slot = 0;
s_current_slot_global = false; s_state.current_slot_global = false;
s_scroll_animated.Reset(0.0f); s_state.scroll_animated.Reset(0.0f);
s_background_animated.Reset(0.0f); s_state.background_animated.Reset(0.0f);
} }
void SaveStateSelectorUI::ClearList() void SaveStateSelectorUI::ClearList()
{ {
for (ListEntry& li : s_slots) for (ListEntry& li : s_state.slots)
{ {
if (li.preview_texture) if (li.preview_texture)
g_gpu_device->RecycleTexture(std::move(li.preview_texture)); g_gpu_device->RecycleTexture(std::move(li.preview_texture));
} }
s_slots.clear(); s_state.slots.clear();
} }
void SaveStateSelectorUI::DestroyTextures() void SaveStateSelectorUI::DestroyTextures()
{ {
Close(); Close();
for (ListEntry& entry : s_slots) for (ListEntry& entry : s_state.slots)
{ {
if (entry.preview_texture) if (entry.preview_texture)
g_gpu_device->RecycleTexture(std::move(entry.preview_texture)); g_gpu_device->RecycleTexture(std::move(entry.preview_texture));
} }
s_placeholder_texture.reset(); s_state.placeholder_texture.reset();
} }
void SaveStateSelectorUI::RefreshHotkeyLegend() void SaveStateSelectorUI::RefreshHotkeyLegend()
@ -974,33 +984,34 @@ void SaveStateSelectorUI::RefreshHotkeyLegend()
return fmt::format("{} - {}", binding, caption); return fmt::format("{} - {}", binding, caption);
}; };
s_load_legend = format_legend_entry(Host::GetSmallStringSettingValue("Hotkeys", "LoadSelectedSaveState"), s_state.load_legend = format_legend_entry(Host::GetSmallStringSettingValue("Hotkeys", "LoadSelectedSaveState"),
TRANSLATE_SV("SaveStateSelectorUI", "Load")); TRANSLATE_SV("SaveStateSelectorUI", "Load"));
s_save_legend = format_legend_entry(Host::GetSmallStringSettingValue("Hotkeys", "SaveSelectedSaveState"), s_state.save_legend = format_legend_entry(Host::GetSmallStringSettingValue("Hotkeys", "SaveSelectedSaveState"),
TRANSLATE_SV("SaveStateSelectorUI", "Save")); TRANSLATE_SV("SaveStateSelectorUI", "Save"));
s_prev_legend = format_legend_entry(Host::GetSmallStringSettingValue("Hotkeys", "SelectPreviousSaveStateSlot"), s_state.prev_legend = format_legend_entry(Host::GetSmallStringSettingValue("Hotkeys", "SelectPreviousSaveStateSlot"),
TRANSLATE_SV("SaveStateSelectorUI", "Select Previous")); TRANSLATE_SV("SaveStateSelectorUI", "Select Previous"));
s_next_legend = format_legend_entry(Host::GetSmallStringSettingValue("Hotkeys", "SelectNextSaveStateSlot"), s_state.next_legend = format_legend_entry(Host::GetSmallStringSettingValue("Hotkeys", "SelectNextSaveStateSlot"),
TRANSLATE_SV("SaveStateSelectorUI", "Select Next")); TRANSLATE_SV("SaveStateSelectorUI", "Select Next"));
} }
void SaveStateSelectorUI::SelectNextSlot(bool open_selector) void SaveStateSelectorUI::SelectNextSlot(bool open_selector)
{ {
const s32 total_slots = s_current_slot_global ? System::GLOBAL_SAVE_STATE_SLOTS : System::PER_GAME_SAVE_STATE_SLOTS; const s32 total_slots =
s_current_slot++; s_state.current_slot_global ? System::GLOBAL_SAVE_STATE_SLOTS : System::PER_GAME_SAVE_STATE_SLOTS;
if (s_current_slot >= total_slots) s_state.current_slot++;
if (s_state.current_slot >= total_slots)
{ {
if (!System::GetGameSerial().empty()) if (!System::GetGameSerial().empty())
s_current_slot_global ^= true; s_state.current_slot_global ^= true;
s_current_slot -= total_slots; s_state.current_slot -= total_slots;
} }
if (open_selector) if (open_selector)
{ {
if (!s_open) if (!s_state.is_open)
Open(); Open();
s_open_time = 0.0f; s_state.open_time = 0.0f;
} }
else else
{ {
@ -1010,20 +1021,21 @@ void SaveStateSelectorUI::SelectNextSlot(bool open_selector)
void SaveStateSelectorUI::SelectPreviousSlot(bool open_selector) void SaveStateSelectorUI::SelectPreviousSlot(bool open_selector)
{ {
s_current_slot--; s_state.current_slot--;
if (s_current_slot < 0) if (s_state.current_slot < 0)
{ {
if (!System::GetGameSerial().empty()) if (!System::GetGameSerial().empty())
s_current_slot_global ^= true; s_state.current_slot_global ^= true;
s_current_slot += s_current_slot_global ? System::GLOBAL_SAVE_STATE_SLOTS : System::PER_GAME_SAVE_STATE_SLOTS; s_state.current_slot +=
s_state.current_slot_global ? System::GLOBAL_SAVE_STATE_SLOTS : System::PER_GAME_SAVE_STATE_SLOTS;
} }
if (open_selector) if (open_selector)
{ {
if (!s_open) if (!s_state.is_open)
Open(); Open();
s_open_time = 0.0f; s_state.open_time = 0.0f;
} }
else else
{ {
@ -1103,9 +1115,9 @@ void SaveStateSelectorUI::Draw()
const float item_height = std::floor(image_size.y + padding * 2.0f); const float item_height = std::floor(image_size.y + padding * 2.0f);
const float text_indent = image_size.x + padding + padding; const float text_indent = image_size.x + padding + padding;
for (size_t i = 0; i < s_slots.size(); i++) for (size_t i = 0; i < s_state.slots.size(); i++)
{ {
const ListEntry& entry = s_slots[i]; const ListEntry& entry = s_state.slots[i];
const float y_start = item_height * static_cast<float>(i); const float y_start = item_height * static_cast<float>(i);
if (entry.slot == current_slot && entry.global == current_slot_global) if (entry.slot == current_slot && entry.global == current_slot_global)
@ -1124,19 +1136,20 @@ void SaveStateSelectorUI::Draw()
else if (item_rect.Max.y > window_rect.Max.y) else if (item_rect.Max.y > window_rect.Max.y)
scroll_target = (ImGui::GetScrollY() + (item_rect.Max.y - window_rect.Max.y)); scroll_target = (ImGui::GetScrollY() + (item_rect.Max.y - window_rect.Max.y));
if (scroll_target != s_scroll_animated.GetEndValue()) if (scroll_target != s_state.scroll_animated.GetEndValue())
s_scroll_animated.Start(ImGui::GetScrollY(), scroll_target, SCROLL_ANIMATION_TIME); s_state.scroll_animated.Start(ImGui::GetScrollY(), scroll_target, SCROLL_ANIMATION_TIME);
} }
if (s_scroll_animated.IsActive()) if (s_state.scroll_animated.IsActive())
ImGui::SetScrollY(s_scroll_animated.UpdateAndGetValue()); ImGui::SetScrollY(s_state.scroll_animated.UpdateAndGetValue());
if (s_background_animated.GetEndValue() != p_start.y) if (s_state.background_animated.GetEndValue() != p_start.y)
s_background_animated.Start(s_background_animated.UpdateAndGetValue(), p_start.y, BG_ANIMATION_TIME); s_state.background_animated.Start(s_state.background_animated.UpdateAndGetValue(), p_start.y,
BG_ANIMATION_TIME);
ImVec2 highlight_pos; ImVec2 highlight_pos;
if (s_background_animated.IsActive()) if (s_state.background_animated.IsActive())
highlight_pos = ImVec2(p_start.x, s_background_animated.UpdateAndGetValue()); highlight_pos = ImVec2(p_start.x, s_state.background_animated.UpdateAndGetValue());
else else
highlight_pos = p_start; highlight_pos = p_start;
@ -1146,7 +1159,7 @@ void SaveStateSelectorUI::Draw()
} }
if (GPUTexture* preview_texture = if (GPUTexture* preview_texture =
entry.preview_texture ? entry.preview_texture.get() : s_placeholder_texture.get()) entry.preview_texture ? entry.preview_texture.get() : s_state.placeholder_texture.get())
{ {
ImGui::SetCursorPosY(y_start + padding); ImGui::SetCursorPosY(y_start + padding);
ImGui::SetCursorPosX(padding); ImGui::SetCursorPosX(padding);
@ -1184,13 +1197,13 @@ void SaveStateSelectorUI::Draw()
if (ImGui::BeginTable("table", 2)) if (ImGui::BeginTable("table", 2))
{ {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextUnformatted(s_load_legend.c_str()); ImGui::TextUnformatted(s_state.load_legend.c_str());
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextUnformatted(s_prev_legend.c_str()); ImGui::TextUnformatted(s_state.prev_legend.c_str());
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextUnformatted(s_save_legend.c_str()); ImGui::TextUnformatted(s_state.save_legend.c_str());
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextUnformatted(s_next_legend.c_str()); ImGui::TextUnformatted(s_state.next_legend.c_str());
ImGui::EndTable(); ImGui::EndTable();
} }
@ -1204,8 +1217,8 @@ void SaveStateSelectorUI::Draw()
ImGui::PopStyleColor(); ImGui::PopStyleColor();
// auto-close // auto-close
s_open_time += io.DeltaTime; s_state.open_time += io.DeltaTime;
if (s_open_time >= s_close_time) if (s_state.open_time >= s_state.close_time)
{ {
Close(); Close();
} }
@ -1219,25 +1232,25 @@ void SaveStateSelectorUI::Draw()
s32 SaveStateSelectorUI::GetCurrentSlot() s32 SaveStateSelectorUI::GetCurrentSlot()
{ {
return s_current_slot + 1; return s_state.current_slot + 1;
} }
bool SaveStateSelectorUI::IsCurrentSlotGlobal() bool SaveStateSelectorUI::IsCurrentSlotGlobal()
{ {
return s_current_slot_global; return s_state.current_slot_global;
} }
std::string SaveStateSelectorUI::GetCurrentSlotPath() std::string SaveStateSelectorUI::GetCurrentSlotPath()
{ {
std::string filename; std::string filename;
if (!s_current_slot_global) if (!s_state.current_slot_global)
{ {
if (const std::string& serial = System::GetGameSerial(); !serial.empty()) if (const std::string& serial = System::GetGameSerial(); !serial.empty())
filename = System::GetGameSaveStateFileName(serial, s_current_slot + 1); filename = System::GetGameSaveStateFileName(serial, s_state.current_slot + 1);
} }
else else
{ {
filename = System::GetGlobalSaveStateFileName(s_current_slot + 1); filename = System::GetGlobalSaveStateFileName(s_state.current_slot + 1);
} }
return filename; return filename;
@ -1312,7 +1325,7 @@ void ImGuiManager::RenderOverlayWindows()
const System::State state = System::GetState(); const System::State state = System::GetState();
if (state != System::State::Shutdown) if (state != System::State::Shutdown)
{ {
if (SaveStateSelectorUI::s_open) if (SaveStateSelectorUI::s_state.is_open)
SaveStateSelectorUI::Draw(); SaveStateSelectorUI::Draw();
} }
} }