diff --git a/pcsx2/ImGui/FullscreenUI.cpp b/pcsx2/ImGui/FullscreenUI.cpp index 1195054471..144b0f6558 100644 --- a/pcsx2/ImGui/FullscreenUI.cpp +++ b/pcsx2/ImGui/FullscreenUI.cpp @@ -5272,7 +5272,7 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading) const float t = std::min(std::abs(std::sin(ImGui::GetTime() * 0.75) * 1.1), 1.0f); ImGui::PushStyleColor(ImGuiCol_Border, ImGui::GetColorU32(ImGuiCol_Border, t)); - ImGui::RenderFrame(bb.Min, bb.Max, col, true, 0.0f); + ImGuiFullscreen::DrawMenuButtonFrame(bb.Min, bb.Max, col, true, 0.0f); ImGui::PopStyleColor(); } @@ -5889,7 +5889,7 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size) const float t = std::min(std::abs(std::sin(ImGui::GetTime() * 0.75) * 1.1), 1.0f); ImGui::PushStyleColor(ImGuiCol_Border, ImGui::GetColorU32(ImGuiCol_Border, t)); - ImGui::RenderFrame(bb.Min, bb.Max, col, true, 0.0f); + ImGuiFullscreen::DrawMenuButtonFrame(bb.Min, bb.Max, col, true, 0.0f); ImGui::PopStyleColor(); } diff --git a/pcsx2/ImGui/ImGuiFullscreen.cpp b/pcsx2/ImGui/ImGuiFullscreen.cpp index e0ee7e5da8..9532e86283 100644 --- a/pcsx2/ImGui/ImGuiFullscreen.cpp +++ b/pcsx2/ImGui/ImGuiFullscreen.cpp @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team + * Copyright (C) 2002-2023 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -17,8 +17,13 @@ #define IMGUI_DEFINE_MATH_OPERATORS -#include "ImGuiFullscreen.h" -#include "IconsFontAwesome5.h" +#include "fmt/core.h" +#include "Host.h" +#include "GS/Renderers/Common/GSDevice.h" +#include "GS/Renderers/Common/GSTexture.h" +#include "ImGui/ImGuiAnimated.h" +#include "ImGui/ImGuiFullscreen.h" + #include "common/Assertions.h" #include "common/Easing.h" #include "common/Image.h" @@ -28,12 +33,11 @@ #include "common/StringUtil.h" #include "common/Threading.h" #include "common/Timer.h" -#include "fmt/core.h" -#include "Host.h" -#include "GS/Renderers/Common/GSDevice.h" -#include "GS/Renderers/Common/GSTexture.h" + +#include "IconsFontAwesome5.h" #include "imgui_internal.h" #include "imgui_stdlib.h" + #include #include #include @@ -44,6 +48,8 @@ namespace ImGuiFullscreen { using MessageDialogCallbackVariant = std::variant; + static constexpr float MENU_BACKGROUND_ANIMATION_TIME = 0.5f; + static std::optional LoadTextureImage(const char* path); static std::shared_ptr UploadTexture(const char* path, const Common::RGBA8Image& image); static void TextureLoaderThread(); @@ -123,6 +129,12 @@ namespace ImGuiFullscreen static std::array s_message_dialog_buttons; static MessageDialogCallbackVariant s_message_dialog_callback; + static ImAnimatedVec2 s_menu_button_frame_min_animated; + static ImAnimatedVec2 s_menu_button_frame_max_animated; + static bool s_had_hovered_menu_item = false; + static bool s_has_hovered_menu_item = false; + static bool s_rendered_menu_item_border = false; + struct FileSelectorItem { FileSelectorItem() = default; @@ -209,6 +221,7 @@ bool ImGuiFullscreen::Initialize(const char* placeholder_image_path) s_texture_load_thread_quit.store(false, std::memory_order_release); s_texture_load_thread.Start(TextureLoaderThread); + ResetMenuButtonFrame(); return true; } @@ -490,6 +503,9 @@ void ImGuiFullscreen::EndLayout() DrawToast(); PopResetLayout(); + + s_rendered_menu_item_border = false; + s_had_hovered_menu_item = std::exchange(s_has_hovered_menu_item, false); } void ImGuiFullscreen::PushResetLayout() @@ -681,6 +697,26 @@ void ImGuiFullscreen::EndFullscreenWindow() ImGui::PopStyleColor(); } +void ImGuiFullscreen::PrerenderMenuButtonBorder() +{ + if (!s_had_hovered_menu_item) + return; + + // updating might finish the animation + const ImVec2 min = s_menu_button_frame_min_animated.UpdateAndGetValue(); + const ImVec2 max = s_menu_button_frame_max_animated.UpdateAndGetValue(); + const ImU32 col = ImGui::GetColorU32(ImGuiCol_ButtonHovered); + + const float t = std::min(std::abs(std::sin(ImGui::GetTime() * 0.75) * 1.1), 1.0f); + ImGui::PushStyleColor(ImGuiCol_Border, ImGui::GetColorU32(ImGuiCol_Border, t)); + + ImGui::RenderFrame(min, max, col, true, 0.0f); + + ImGui::PopStyleColor(); + + s_rendered_menu_item_border = true; +} + void ImGuiFullscreen::BeginMenuButtons(u32 num_items, float y_align, float x_padding, float y_padding, float item_height) { s_menu_button_index = 0; @@ -698,6 +734,8 @@ void ImGuiFullscreen::BeginMenuButtons(u32 num_items, float y_align, float x_pad if (window_height > total_size) ImGui::SetCursorPosY((window_height - total_size) * y_align); } + + PrerenderMenuButtonBorder(); } void ImGuiFullscreen::EndMenuButtons() @@ -735,6 +773,47 @@ void ImGuiFullscreen::GetMenuButtonFrameBounds(float height, ImVec2* pos, ImVec2 *size = ImVec2(window->WorkRect.GetWidth(), LayoutScale(height) + ImGui::GetStyle().FramePadding.y * 2.0f); } +void ImGuiFullscreen::DrawMenuButtonFrame(const ImVec2& p_min, const ImVec2& p_max, ImU32 fill_col, + bool border /* = true */, float rounding /* = 0.0f */) +{ + ImVec2 frame_min = p_min; + ImVec2 frame_max = p_max; + + if (ImGui::GetIO().NavVisible && ImGui::GetHoveredID() != ImGui::GetItemID()) + { + if (!s_had_hovered_menu_item) + { + s_menu_button_frame_min_animated.Reset(frame_min); + s_menu_button_frame_max_animated.Reset(frame_max); + s_has_hovered_menu_item = true; + } + else + { + if (frame_min.x != s_menu_button_frame_min_animated.GetEndValue().x || + frame_min.y != s_menu_button_frame_min_animated.GetEndValue().y) + { + s_menu_button_frame_min_animated.Start(s_menu_button_frame_min_animated.GetCurrentValue(), frame_min, + MENU_BACKGROUND_ANIMATION_TIME); + } + if (frame_max.x != s_menu_button_frame_max_animated.GetEndValue().x || + frame_max.y != s_menu_button_frame_max_animated.GetEndValue().x) + { + s_menu_button_frame_max_animated.Start(s_menu_button_frame_max_animated.GetCurrentValue(), frame_max, + MENU_BACKGROUND_ANIMATION_TIME); + } + frame_min = s_menu_button_frame_min_animated.UpdateAndGetValue(); + frame_max = s_menu_button_frame_max_animated.UpdateAndGetValue(); + s_has_hovered_menu_item = true; + } + } + + if (!s_rendered_menu_item_border) + { + s_rendered_menu_item_border = true; + ImGui::RenderFrame(frame_min, frame_max, fill_col, border, rounding); + } +} + bool ImGuiFullscreen::MenuButtonFrame( const char* str_id, bool enabled, float height, bool* visible, bool* hovered, ImRect* bb, ImGuiButtonFlags flags, float hover_alpha) { @@ -785,7 +864,7 @@ bool ImGuiFullscreen::MenuButtonFrame( const float t = std::min(std::abs(std::sin(ImGui::GetTime() * 0.75) * 1.1), 1.0f); ImGui::PushStyleColor(ImGuiCol_Border, ImGui::GetColorU32(ImGuiCol_Border, t)); - ImGui::RenderFrame(bb->Min, bb->Max, col, true, 0.0f); + DrawMenuButtonFrame(bb->Min, bb->Max, col, true, 0.0f); ImGui::PopStyleColor(); } @@ -813,6 +892,12 @@ bool ImGuiFullscreen::MenuButtonFrame(const char* str_id, bool enabled, float he return result; } +void ImGuiFullscreen::ResetMenuButtonFrame() +{ + s_had_hovered_menu_item = false; + s_has_hovered_menu_item = false; +} + void ImGuiFullscreen::MenuHeading(const char* title, bool draw_line /*= true*/) { const float line_thickness = draw_line ? LayoutScale(1.0f) : 0.0f; @@ -1065,7 +1150,7 @@ bool ImGuiFullscreen::FloatingButton(const char* text, float x, float y, float w const float t = std::min(std::abs(std::sin(ImGui::GetTime() * 0.75) * 1.1), 1.0f); const ImU32 col = ImGui::GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered, 1.0f); ImGui::PushStyleColor(ImGuiCol_Border, ImGui::GetColorU32(ImGuiCol_Border, t)); - ImGui::RenderFrame(bb.Min, bb.Max, col, true, 0.0f); + DrawMenuButtonFrame(bb.Min, bb.Max, col, true, 0.0f); ImGui::PopStyleColor(); } } @@ -1556,7 +1641,7 @@ bool ImGuiFullscreen::NavButton(const char* title, bool is_active, bool enabled if (hovered) { const ImU32 col = ImGui::GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered, 1.0f); - ImGui::RenderFrame(bb.Min, bb.Max, col, true, 0.0f); + DrawMenuButtonFrame(bb.Min, bb.Max, col, true, 0.0f); } } else @@ -1633,7 +1718,7 @@ bool ImGuiFullscreen::NavTab(const char* title, bool is_active, bool enabled /* hovered ? ImGui::GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered, 1.0f) : ImGui::GetColorU32(is_active ? background : ImVec4(background.x, background.y, background.z, 0.5f)); - ImGui::RenderFrame(bb.Min, bb.Max, col, true, 0.0f); + DrawMenuButtonFrame(bb.Min, bb.Max, col, true, 0.0f); #if 0 // This looks a bit rubbish... but left it here if someone thinks they can improve it. diff --git a/pcsx2/ImGui/ImGuiFullscreen.h b/pcsx2/ImGui/ImGuiFullscreen.h index 1deff01906..0b6a414dc3 100644 --- a/pcsx2/ImGui/ImGuiFullscreen.h +++ b/pcsx2/ImGui/ImGuiFullscreen.h @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team + * Copyright (C) 2002-2023 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -151,12 +151,15 @@ namespace ImGuiFullscreen const ImVec4& background = HEX_TO_IMVEC4(0x212121, 0xFF), float rounding = 0.0f, float padding = 0.0f, ImGuiWindowFlags flags = 0); void EndFullscreenWindow(); + void PrerenderMenuButtonBorder(); void BeginMenuButtons(u32 num_items = 0, float y_align = 0.0f, float x_padding = LAYOUT_MENU_BUTTON_X_PADDING, float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING, float item_height = LAYOUT_MENU_BUTTON_HEIGHT); void EndMenuButtons(); void GetMenuButtonFrameBounds(float height, ImVec2* pos, ImVec2* size); bool MenuButtonFrame(const char* str_id, bool enabled, float height, bool* visible, bool* hovered, ImVec2* min, ImVec2* max, ImGuiButtonFlags flags = 0, float hover_alpha = 1.0f); + void DrawMenuButtonFrame(const ImVec2& p_min, const ImVec2& p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); + void ResetMenuButtonFrame(); void MenuHeading(const char* title, bool draw_line = true); bool MenuHeadingButton(const char* title, const char* value = nullptr, bool enabled = true, bool draw_line = true); bool ActiveButton(const char* title, bool is_active, bool enabled = true, float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY,