ImGuiOverlays: Add animation to save state selector

pull/3782/head
Stenzek 1 month ago
parent b25e2358b8
commit 0bf64996cf
No known key found for this signature in database

@ -944,11 +944,14 @@ static void InitializeListEntry(ListEntry* li, ExtendedSaveStateInfo* ssi, const
static void DestroyTextures();
static void RefreshHotkeyLegend();
static void CloseImmediately();
static void Draw();
static void ShowSlotOSDMessage();
static constexpr const char* DATE_TIME_FORMAT =
TRANSLATE_NOOP("SaveStateSelectorUI", "Saved at {0:%H:%M} on {0:%a} {0:%Y/%m/%d}.");
static constexpr float OPEN_ANIMATION_TIME = 0.2f;
static constexpr float CLOSE_ANIMATION_TIME = 0.1f;
namespace {
@ -968,11 +971,13 @@ struct State
float open_time = 0.0f;
float close_time = 0.0f;
float animation_time_remaining = 0.0f;
ImAnimatedFloat scroll_animated;
ImAnimatedFloat background_animated;
bool is_open = false;
bool is_closing = false;
};
} // namespace
@ -992,12 +997,23 @@ void SaveStateSelectorUI::Open(float open_time /* = DEFAULT_OPEN_TIME */)
s_state.close_time = open_time;
if (s_state.is_open)
{
// Abort close.
if (s_state.is_closing)
{
s_state.animation_time_remaining = 0.0f;
s_state.is_closing = false;
}
return;
}
if (!s_state.placeholder_texture)
s_state.placeholder_texture = FullscreenUI::LoadTexture("no-save.png");
s_state.is_open = true;
s_state.is_closing = false;
s_state.animation_time_remaining = FullscreenUI::UIStyle.Animations ? OPEN_ANIMATION_TIME : 0.0f;
s_state.global_slots_enabled = System::AreGlobalSaveStatesEnabled();
RefreshList();
RefreshHotkeyLegend();
@ -1006,14 +1022,27 @@ void SaveStateSelectorUI::Open(float open_time /* = DEFAULT_OPEN_TIME */)
{
FullscreenUI::ShowToast(OSDMessageType::Info, {},
TRANSLATE_STR("SaveStateSelectorUI", "No save state slots available."));
Close();
CloseImmediately();
}
}
void SaveStateSelectorUI::Close()
{
if (!s_state.is_open || s_state.is_closing)
return;
s_state.animation_time_remaining = FullscreenUI::UIStyle.Animations ? CLOSE_ANIMATION_TIME : 0.0f;
s_state.is_closing = true;
if (s_state.animation_time_remaining <= 0.0f)
CloseImmediately();
}
void SaveStateSelectorUI::CloseImmediately()
{
ClearList();
s_state.is_open = false;
s_state.is_closing = false;
s_state.animation_time_remaining = 0.0f;
s_state.load_legend = {};
s_state.save_legend = {};
s_state.prev_legend = {};
@ -1101,7 +1130,7 @@ void SaveStateSelectorUI::ClearList()
void SaveStateSelectorUI::DestroyTextures()
{
Close();
CloseImmediately();
for (ListEntry& entry : s_state.slots)
{
@ -1146,7 +1175,14 @@ void SaveStateSelectorUI::SelectNextSlot(bool open_selector)
if (!s_state.is_open)
Open();
else
{
s_state.open_time = 0.0f; // stay open for the full duration
if (s_state.is_closing)
{
s_state.animation_time_remaining = 0.0f;
s_state.is_closing = false;
}
}
}
else
{
@ -1170,7 +1206,14 @@ void SaveStateSelectorUI::SelectPreviousSlot(bool open_selector)
if (!s_state.is_open)
Open();
else
{
s_state.open_time = 0.0f; // stay open for the full duration
if (s_state.is_closing)
{
s_state.animation_time_remaining = 0.0f;
s_state.is_closing = false;
}
}
}
else
{
@ -1232,7 +1275,36 @@ void SaveStateSelectorUI::Draw()
const float width = LayoutScale(640.0f);
const float height = LayoutScale(480.0f);
float alpha = 1.0f;
float position_offset = 0.0f;
if (s_state.animation_time_remaining > 0.0f)
{
s_state.animation_time_remaining -= io.DeltaTime;
if (s_state.animation_time_remaining <= 0.0f)
{
s_state.animation_time_remaining = 0.0f;
if (s_state.is_closing)
{
CloseImmediately();
return;
}
}
else if (s_state.is_closing)
{
const float fract = s_state.animation_time_remaining / CLOSE_ANIMATION_TIME;
alpha = fract;
position_offset = ImCeil(LayoutScale(20.0f) * (1.0f - fract));
}
else
{
const float fract = Easing::InExpo(s_state.animation_time_remaining / OPEN_ANIMATION_TIME);
alpha = 1.0f - fract;
position_offset = ImCeil(LayoutScale(50.0f) * fract);
}
}
const float padding_and_rounding = LayoutScale(18.0f);
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, padding_and_rounding);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(padding_and_rounding, padding_and_rounding));
ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarSize, LayoutScale(14.0f));
@ -1244,7 +1316,7 @@ void SaveStateSelectorUI::Draw()
ImGui::PushStyleColor(ImGuiCol_WindowBg, DarkerColor(UIStyle.PopupBackgroundColor));
ImGui::PushStyleColor(ImGuiCol_Text, UIStyle.BackgroundTextColor);
ImGui::SetNextWindowSize(ImVec2(width, height), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), ImGuiCond_Always,
ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f + position_offset), ImGuiCond_Always,
ImVec2(0.5f, 0.5f));
if (FullscreenUI::BeginBlurWindow("##save_state_selector", nullptr,
@ -1391,20 +1463,23 @@ void SaveStateSelectorUI::Draw()
}
ImGui::End();
ImGui::PopStyleVar(6);
ImGui::PopStyleVar(7);
ImGui::PopStyleColor(4);
// auto-close
s_state.open_time += io.DeltaTime;
if (s_state.open_time >= s_state.close_time)
{
Close();
}
else if (ImGui::IsKeyPressed(ImGuiKey_Escape))
if (!s_state.is_closing)
{
// Need to cancel the hotkey bindings, otherwise the pause menu will open.
InputManager::ClearBindStateFromSource(InputManager::MakeHostKeyboardKey(0));
Close();
s_state.open_time += io.DeltaTime;
if (s_state.open_time >= s_state.close_time)
{
Close();
}
else if (ImGui::IsKeyPressed(ImGuiKey_Escape))
{
// Need to cancel the hotkey bindings, otherwise the pause menu will open.
InputManager::ClearBindStateFromSource(InputManager::MakeHostKeyboardKey(0));
Close();
}
}
}

Loading…
Cancel
Save