From 435865b45df834115f4154c210f38c17c842d352 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin <stenzek@gmail.com> Date: Wed, 30 Jun 2021 19:12:56 +1000 Subject: [PATCH] FullscreenUI: Redesign settings window --- src/frontend-common/common_host_interface.cpp | 2 + src/frontend-common/fullscreen_ui.cpp | 84 ++++++++---- src/frontend-common/imgui_fullscreen.cpp | 128 ++++++++++++++++++ src/frontend-common/imgui_fullscreen.h | 8 ++ 4 files changed, 199 insertions(+), 23 deletions(-) diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp index 24ef201a8..9d43a44b2 100644 --- a/src/frontend-common/common_host_interface.cpp +++ b/src/frontend-common/common_host_interface.cpp @@ -540,6 +540,7 @@ bool CommonHostInterface::CreateHostDisplayResources() ImGui::GetIO().DisplaySize.x = static_cast<float>(m_display->GetWindowWidth()); ImGui::GetIO().DisplaySize.y = static_cast<float>(m_display->GetWindowHeight()); ImGui::GetStyle() = ImGuiStyle(); + ImGui::GetStyle().WindowMinSize = ImVec2(1.0f, 1.0f); ImGui::StyleColorsDarker(); ImGui::GetStyle().ScaleAllSizes(framebuffer_scale); @@ -603,6 +604,7 @@ void CommonHostInterface::OnHostDisplayResized() { ImGui::GetIO().DisplayFramebufferScale = ImVec2(new_scale, new_scale); ImGui::GetStyle() = ImGuiStyle(); + ImGui::GetStyle().WindowMinSize = ImVec2(1.0f, 1.0f); ImGui::StyleColorsDarker(); ImGui::GetStyle().ScaleAllSizes(new_scale); ImGuiFullscreen::ResetFonts(); diff --git a/src/frontend-common/fullscreen_ui.cpp b/src/frontend-common/fullscreen_ui.cpp index 3a95e84a5..d91cbfbe2 100644 --- a/src/frontend-common/fullscreen_ui.cpp +++ b/src/frontend-common/fullscreen_ui.cpp @@ -53,6 +53,7 @@ using ImGuiFullscreen::BeginFullscreenColumns; using ImGuiFullscreen::BeginFullscreenColumnWindow; using ImGuiFullscreen::BeginFullscreenWindow; using ImGuiFullscreen::BeginMenuButtons; +using ImGuiFullscreen::BeginNavBar; using ImGuiFullscreen::CloseChoiceDialog; using ImGuiFullscreen::CloseFileSelector; using ImGuiFullscreen::DPIScale; @@ -60,6 +61,7 @@ using ImGuiFullscreen::EndFullscreenColumns; using ImGuiFullscreen::EndFullscreenColumnWindow; using ImGuiFullscreen::EndFullscreenWindow; using ImGuiFullscreen::EndMenuButtons; +using ImGuiFullscreen::EndNavBar; using ImGuiFullscreen::EnumChoiceButton; using ImGuiFullscreen::FloatingButton; using ImGuiFullscreen::LayoutScale; @@ -69,9 +71,12 @@ using ImGuiFullscreen::MenuButtonWithValue; using ImGuiFullscreen::MenuHeading; using ImGuiFullscreen::MenuHeadingButton; using ImGuiFullscreen::MenuImageButton; +using ImGuiFullscreen::NavButton; +using ImGuiFullscreen::NavTitle; using ImGuiFullscreen::OpenChoiceDialog; using ImGuiFullscreen::OpenFileSelector; using ImGuiFullscreen::RangeButton; +using ImGuiFullscreen::RightAlignNavButtons; using ImGuiFullscreen::ToggleButton; namespace FullscreenUI { @@ -1274,36 +1279,69 @@ static bool WantsToCloseMenu() void DrawSettingsWindow() { - BeginFullscreenColumns(); + ImGuiIO& io = ImGui::GetIO(); + ImVec2 heading_size = ImVec2( + io.DisplaySize.x, LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + LAYOUT_MENU_BUTTON_Y_PADDING * 2.0f + 2.0f)); - if (BeginFullscreenColumnWindow(0.0f, 300.0f, "settings_category", ImVec4(0.18f, 0.18f, 0.18f, 1.00f))) + if (BeginFullscreenWindow(ImVec2(0.0f, ImGuiFullscreen::g_menu_bar_size), heading_size, "settings_category", + ImVec4(0.18f, 0.18f, 0.18f, 1.00f))) { - static constexpr std::array<const char*, static_cast<u32>(SettingsPage::Count)> titles = { - {ICON_FA_WINDOW_MAXIMIZE " Interface Settings", ICON_FA_LIST " Game List Settings", - ICON_FA_HDD " Console Settings", ICON_FA_SLIDERS_H " Emulation Settings", ICON_FA_MICROCHIP " BIOS Settings", - ICON_FA_GAMEPAD " Controller Settings", ICON_FA_KEYBOARD " Hotkey Settings", - ICON_FA_SD_CARD " Memory Card Settings", ICON_FA_TV " Display Settings", - ICON_FA_MAGIC " Enhancement Settings", ICON_FA_HEADPHONES " Audio Settings", - ICON_FA_TROPHY " Achievements Settings", ICON_FA_EXCLAMATION_TRIANGLE " Advanced Settings"}}; + static constexpr float ITEM_WIDTH = 22.0f; - BeginMenuButtons(); - for (u32 i = 0; i < static_cast<u32>(titles.size()); i++) + static constexpr std::array<const char*, static_cast<u32>(SettingsPage::Count)> icons = { + {ICON_FA_WINDOW_MAXIMIZE, ICON_FA_LIST, ICON_FA_HDD, ICON_FA_SLIDERS_H, ICON_FA_MICROCHIP, ICON_FA_GAMEPAD, + ICON_FA_KEYBOARD, ICON_FA_SD_CARD, ICON_FA_TV, ICON_FA_MAGIC, ICON_FA_HEADPHONES, ICON_FA_TROPHY, + ICON_FA_EXCLAMATION_TRIANGLE}}; + + static constexpr std::array<const char*, static_cast<u32>(SettingsPage::Count)> titles = { + {"Interface Settings", "Game List Settings", "Console Settings", "Emulation Settings", "BIOS Settings", + "Controller Settings", "Hotkey Settings", "Memory Card Settings", "Display Settings", "Audio Settings", + "Enhancement Settings", "Achievements Settings", "Advanced Settings"}}; + + BeginNavBar(); + + if (ImGui::IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_Pressed)) { - if (ActiveButton(titles[i], s_settings_page == static_cast<SettingsPage>(i))) - s_settings_page = static_cast<SettingsPage>(i); + s_settings_page = static_cast<SettingsPage>((s_settings_page == static_cast<SettingsPage>(0)) ? + (static_cast<u32>(SettingsPage::Count) - 1) : + (static_cast<u32>(s_settings_page) - 1)); + } + else if (ImGui::IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_Pressed)) + { + s_settings_page = + static_cast<SettingsPage>((static_cast<u32>(s_settings_page) + 1) % static_cast<u32>(SettingsPage::Count)); } - ImGui::SetCursorPosY(ImGui::GetWindowHeight() - LayoutScale(50.0f)); - if (ActiveButton(ICON_FA_BACKWARD " Back", false) || WantsToCloseMenu()) + if (NavButton(ICON_FA_BACKWARD, false, true)) ReturnToMainWindow(); - EndMenuButtons(); + NavTitle(titles[static_cast<u32>(s_settings_page)]); + + RightAlignNavButtons(static_cast<u32>(titles.size()), ITEM_WIDTH, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); + + for (u32 i = 0; i < static_cast<u32>(titles.size()); i++) + { + if (NavButton(icons[i], s_settings_page == static_cast<SettingsPage>(i), true, ITEM_WIDTH, + LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY)) + { + s_settings_page = static_cast<SettingsPage>(i); + } + } + + EndNavBar(); } - EndFullscreenColumnWindow(); + EndFullscreenWindow(); - if (BeginFullscreenColumnWindow(300.0f, LAYOUT_SCREEN_WIDTH, "settings_parent")) + if (BeginFullscreenWindow(ImVec2(0.0f, ImGuiFullscreen::g_menu_bar_size + heading_size.y), + ImVec2(io.DisplaySize.x, io.DisplaySize.y - heading_size.y), "settings_parent")) { + if (ImGui::IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) + { + if (ImGui::IsWindowFocused()) + ReturnToMainWindow(); + } + bool settings_changed = false; switch (s_settings_page) @@ -2535,9 +2573,7 @@ void DrawSettingsWindow() s_host_interface->RunLater(SaveAndApplySettings); } - EndFullscreenColumnWindow(); - - EndFullscreenColumns(); + EndFullscreenWindow(); } void DrawQuickMenu(MainWindowType type) @@ -4732,8 +4768,8 @@ bool SetControllerNavInput(FrontendCommon::ControllerNavigationButton button, bo io.KeysDown[io.KeyMap[imkey]] = value; \ } - MAP_KEY(FrontendCommon::ControllerNavigationButton::LeftShoulder, ImGuiKey_PageUp); - MAP_KEY(FrontendCommon::ControllerNavigationButton::RightShoulder, ImGuiKey_PageDown); + // MAP_KEY(FrontendCommon::ControllerNavigationButton::LeftTrigger, ImGuiKey_PageUp); + // MAP_KEY(FrontendCommon::ControllerNavigationButton::RightTrigger, ImGuiKey_PageDown); #undef MAP_KEY @@ -4755,6 +4791,8 @@ void SetImGuiNavInputs() MAP_BUTTON(FrontendCommon::ControllerNavigationButton::DPadRight, ImGuiNavInput_DpadRight); MAP_BUTTON(FrontendCommon::ControllerNavigationButton::DPadUp, ImGuiNavInput_DpadUp); MAP_BUTTON(FrontendCommon::ControllerNavigationButton::DPadDown, ImGuiNavInput_DpadDown); + MAP_BUTTON(FrontendCommon::ControllerNavigationButton::LeftShoulder, ImGuiNavInput_FocusPrev); + MAP_BUTTON(FrontendCommon::ControllerNavigationButton::RightShoulder, ImGuiNavInput_FocusNext); #undef MAP_BUTTON } diff --git a/src/frontend-common/imgui_fullscreen.cpp b/src/frontend-common/imgui_fullscreen.cpp index a32330814..04b939a9d 100644 --- a/src/frontend-common/imgui_fullscreen.cpp +++ b/src/frontend-common/imgui_fullscreen.cpp @@ -987,6 +987,134 @@ bool EnumChoiceButtonImpl(const char* title, const char* summary, s32* value_poi return changed; } +void BeginNavBar(float x_padding /*= LAYOUT_MENU_BUTTON_X_PADDING*/, float y_padding /*= LAYOUT_MENU_BUTTON_Y_PADDING*/) +{ + s_menu_button_index = 0; + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(x_padding, y_padding)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, LayoutScale(1.0f, 1.0f)); +} + +void EndNavBar() +{ + ImGui::PopStyleVar(4); +} + +void NavTitle(const char* title, float height /*= LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY*/, + ImFont* font /*= g_large_font*/) +{ + ImGuiWindow* window = ImGui::GetCurrentWindow(); + if (window->SkipItems) + return; + + s_menu_button_index++; + + const ImVec2 text_size(font->CalcTextSizeA(font->FontSize, std::numeric_limits<float>::max(), 0.0f, title)); + const ImVec2 pos(window->DC.CursorPos); + const ImGuiStyle& style = ImGui::GetStyle(); + const ImVec2 size = ImVec2(text_size.x, LayoutScale(height) + style.FramePadding.y * 2.0f); + + ImGui::ItemSize( + ImVec2(size.x + style.FrameBorderSize + style.ItemSpacing.x, size.y + style.FrameBorderSize + style.ItemSpacing.y)); + ImGui::SameLine(); + + ImRect bb(pos, pos + size); + if (ImGui::IsClippedEx(bb, 0, false)) + return; + + bb.Min.y += style.FramePadding.y; + bb.Max.y -= style.FramePadding.y; + + ImGui::PushFont(font); + ImGui::RenderTextClipped(bb.Min, bb.Max, title, nullptr, nullptr, ImVec2(0.0f, 0.0f), &bb); + ImGui::PopFont(); +} + +void RightAlignNavButtons(u32 num_items /*= 0*/, float item_width /*= LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY*/, + float item_height /*= LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY*/) +{ + ImGuiWindow* window = ImGui::GetCurrentWindow(); + const ImVec2 window_size(ImGui::GetWindowSize()); + const ImGuiStyle& style = ImGui::GetStyle(); + + const float total_item_width = + style.FramePadding.x * 2.0f + style.FrameBorderSize + style.ItemSpacing.x + LayoutScale(item_width); + const float margin = total_item_width * static_cast<float>(num_items); + ImGui::SetCursorPosX(window->InnerClipRect.Max.x - margin - style.FramePadding.x); +} + +bool NavButton(const char* title, bool is_active, bool enabled /* = true */, float width /* = -1.0f */, + float height /* = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY */, ImFont* font /* = g_large_font */) +{ + ImGuiWindow* window = ImGui::GetCurrentWindow(); + if (window->SkipItems) + return false; + + s_menu_button_index++; + + const ImVec2 text_size(font->CalcTextSizeA(font->FontSize, std::numeric_limits<float>::max(), 0.0f, title)); + const ImVec2 pos(window->DC.CursorPos); + const ImGuiStyle& style = ImGui::GetStyle(); + const ImVec2 size = ImVec2(((width < 0.0f) ? text_size.x : LayoutScale(width)) + style.FramePadding.x * 2.0f, + LayoutScale(height) + style.FramePadding.y * 2.0f); + + ImGui::ItemSize( + ImVec2(size.x + style.FrameBorderSize + style.ItemSpacing.x, size.y + style.FrameBorderSize + style.ItemSpacing.y)); + ImGui::SameLine(); + + ImRect bb(pos, pos + size); + const ImGuiID id = window->GetID(title); + if (enabled) + { + if (!ImGui::ItemAdd(bb, id)) + return false; + } + else + { + if (ImGui::IsClippedEx(bb, id, false)) + return false; + } + + bool held; + bool pressed; + bool hovered; + if (enabled) + { + pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, 0); + if (hovered) + { + const ImU32 col = ImGui::GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered, 1.0f); + ImGui::RenderFrame(bb.Min, bb.Max, col, true, 0.0f); + } + } + else + { + pressed = false; + held = false; + hovered = false; + } + + bb.Min += style.FramePadding; + bb.Max -= style.FramePadding; + + if (!enabled || is_active) + { + ImGui::PushStyleColor(ImGuiCol_Text, is_active ? ImGui::GetColorU32(UITextHighlightColor()) : + ImGui::GetColorU32(ImGuiCol_TextDisabled)); + } + + ImGui::PushFont(font); + ImGui::RenderTextClipped(bb.Min, bb.Max, title, nullptr, nullptr, ImVec2(0.0f, 0.0f), &bb); + ImGui::PopFont(); + + if (!enabled || is_active) + ImGui::PopStyleColor(); + + return pressed; +} + struct FileSelectorItem { FileSelectorItem() = default; diff --git a/src/frontend-common/imgui_fullscreen.h b/src/frontend-common/imgui_fullscreen.h index b75a87575..94923b013 100644 --- a/src/frontend-common/imgui_fullscreen.h +++ b/src/frontend-common/imgui_fullscreen.h @@ -231,6 +231,14 @@ static ALWAYS_INLINE bool EnumChoiceButton(const char* title, const char* summar } } +void BeginNavBar(float x_padding = LAYOUT_MENU_BUTTON_X_PADDING, float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING); +void EndNavBar(); +void NavTitle(const char* title, float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, ImFont* font = g_large_font); +void RightAlignNavButtons(u32 num_items = 0, float item_width = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, + float item_height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); +bool NavButton(const char* title, bool is_active, bool enabled = true, float width = -1.0f, + float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, ImFont* font = g_large_font); + using FileSelectorCallback = std::function<void(const std::string& path)>; using FileSelectorFilters = std::vector<std::string>; bool IsFileSelectorOpen();