FullscreenUI: Add floating nav bar widgets

pull/3658/head
Stenzek 10 months ago
parent e2fc40c407
commit 56d8750f41
No known key found for this signature in database

@ -42,3 +42,5 @@
#define ICON_EMOJI_CLOCK_FIVE_OCLOCK "\xf0\x9f\x95\x94" #define ICON_EMOJI_CLOCK_FIVE_OCLOCK "\xf0\x9f\x95\x94"
#define ICON_EMOJI_DESKTOP_COMPUTER "\xf0\x9f\x96\xa5" #define ICON_EMOJI_DESKTOP_COMPUTER "\xf0\x9f\x96\xa5"
#define ICON_EMOJI_INDEX_DIVIDERS "\xf0\x9f\x97\x82" #define ICON_EMOJI_INDEX_DIVIDERS "\xf0\x9f\x97\x82"
#define ICON_EMOJI_CLIPBOARD "\xf0\x9f\x93\x8b"
#define ICON_EMOJI_NOTEBOOK "\xf0\x9f\x93\x99"

@ -50,7 +50,6 @@ LOG_CHANNEL(FullscreenUI);
namespace FullscreenUI { namespace FullscreenUI {
static constexpr float MENU_BACKGROUND_ANIMATION_TIME = 0.5f; static constexpr float MENU_BACKGROUND_ANIMATION_TIME = 0.5f;
static constexpr float MENU_ITEM_BORDER_ROUNDING = 10.0f;
static constexpr float SMOOTH_SCROLLING_SPEED = 3.5f; static constexpr float SMOOTH_SCROLLING_SPEED = 3.5f;
static constexpr u32 LOADING_PROGRESS_SAMPLE_COUNT = 30; static constexpr u32 LOADING_PROGRESS_SAMPLE_COUNT = 30;
@ -1572,7 +1571,7 @@ void FullscreenUI::PrerenderMenuButtonBorder()
const float t = static_cast<float>(std::min(std::abs(std::sin(ImGui::GetTime() * 0.75) * 1.1), 1.0)); const float t = static_cast<float>(std::min(std::abs(std::sin(ImGui::GetTime() * 0.75) * 1.1), 1.0));
ImGui::PushStyleColor(ImGuiCol_Border, ImGui::GetColorU32(ImGuiCol_Border, t)); ImGui::PushStyleColor(ImGuiCol_Border, ImGui::GetColorU32(ImGuiCol_Border, t));
ImGui::RenderFrame(min, max, col, true, LayoutScale(MENU_ITEM_BORDER_ROUNDING)); ImGui::RenderFrame(min, max, col, true, LayoutScale(LAYOUT_MENU_ITEM_BORDER_ROUNDING));
ImGui::PopStyleColor(); ImGui::PopStyleColor();
@ -1773,7 +1772,7 @@ void FullscreenUI::DrawMenuButtonFrame(const ImVec2& p_min, const ImVec2& p_max,
if (!s_state.rendered_menu_item_border) if (!s_state.rendered_menu_item_border)
{ {
s_state.rendered_menu_item_border = true; s_state.rendered_menu_item_border = true;
ImGui::RenderFrame(frame_min, frame_max, fill_col, border, LayoutScale(MENU_ITEM_BORDER_ROUNDING)); ImGui::RenderFrame(frame_min, frame_max, fill_col, border, LayoutScale(LAYOUT_MENU_ITEM_BORDER_ROUNDING));
} }
} }
@ -2324,17 +2323,21 @@ bool FullscreenUI::FloatingButton(std::string_view text, float x, float y, float
else if (anchor_x == -0.5f) else if (anchor_x == -0.5f)
x -= (width * 0.5f); x -= (width * 0.5f);
else if (anchor_x == 0.5f) else if (anchor_x == 0.5f)
x = (window_size.x * 0.5f) - (width * 0.5f) - x; x = (window_size.x * 0.5f) - (width * 0.5f) - LayoutScale(x);
else if (anchor_x == 1.0f) else if (anchor_x == 1.0f)
x = window_size.x - width - x; x = window_size.x - width - LayoutScale(x);
else
x = LayoutScale(x);
if (anchor_y == -1.0f) if (anchor_y == -1.0f)
y -= height; y -= height;
else if (anchor_y == -0.5f) else if (anchor_y == -0.5f)
y -= (height * 0.5f); y -= (height * 0.5f);
else if (anchor_y == 0.5f) else if (anchor_y == 0.5f)
y = (window_size.y * 0.5f) - (height * 0.5f) - y; y = (window_size.y * 0.5f) - (height * 0.5f) - LayoutScale(y);
else if (anchor_y == 1.0f) else if (anchor_y == 1.0f)
y = window_size.y - height - y; y = window_size.y - height - LayoutScale(y);
else
y = LayoutScale(y);
if (out_position) if (out_position)
*out_position = ImVec2(x, y); *out_position = ImVec2(x, y);
@ -2679,7 +2682,7 @@ void FullscreenUI::BeginHorizontalMenuButtons(u32 num_items, float max_item_widt
for (u32 i = 0; i < num_items; i++) for (u32 i = 0; i < num_items; i++)
{ {
ImGui::RenderFrame(current_pos, current_pos + s_state.horizontal_menu_button_size, frame_background, false, ImGui::RenderFrame(current_pos, current_pos + s_state.horizontal_menu_button_size, frame_background, false,
LayoutScale(MENU_ITEM_BORDER_ROUNDING)); LayoutScale(LAYOUT_MENU_ITEM_BORDER_ROUNDING));
current_pos.x += s_state.horizontal_menu_button_size.x + style.ItemSpacing.x; current_pos.x += s_state.horizontal_menu_button_size.x + style.ItemSpacing.x;
} }
@ -2801,17 +2804,24 @@ void FullscreenUI::NavTitle(std::string_view title)
ImGui::GetColorU32(ImGuiCol_Text), title, &text_size, ImVec2(0.0f, 0.0f), 0.0f, &bb); ImGui::GetColorU32(ImGuiCol_Text), title, &text_size, ImVec2(0.0f, 0.0f), 0.0f, &bb);
} }
void FullscreenUI::RightAlignNavButtons(u32 num_items /*= 0*/) void FullscreenUI::RightAlignNavButtons(u32 num_items)
{ {
ImGuiWindow* window = ImGui::GetCurrentWindow(); ImGuiWindow* window = ImGui::GetCurrentWindow();
const ImGuiStyle& style = ImGui::GetStyle(); const ImGuiStyle& style = ImGui::GetStyle();
const float total_item_width = style.FramePadding.x * 2.0f + style.FrameBorderSize + style.ItemSpacing.x + const float total_item_width = style.FramePadding.x * 2.0f + style.FrameBorderSize + style.ItemSpacing.x +
LayoutScale(LAYOUT_LARGE_FONT_SIZE - 1.0f); LayoutScale(LAYOUT_LARGE_FONT_SIZE - 1.0f);
const float margin = total_item_width * static_cast<float>(num_items); const float margin = total_item_width * static_cast<float>(num_items);
ImGui::SetCursorPosX(window->InnerClipRect.Max.x - margin - style.FramePadding.x); ImGui::SetCursorPosX(window->InnerClipRect.Max.x - margin - style.FramePadding.x);
} }
void FullscreenUI::RightAlignNavButtons(float total_width)
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
const ImGuiStyle& style = ImGui::GetStyle();
ImGui::SetCursorPosX(window->InnerClipRect.Max.x - total_width - style.FramePadding.x);
}
bool FullscreenUI::NavButton(std::string_view title, bool is_active, bool enabled /* = true */) bool FullscreenUI::NavButton(std::string_view title, bool is_active, bool enabled /* = true */)
{ {
ImGuiWindow* window = ImGui::GetCurrentWindow(); ImGuiWindow* window = ImGui::GetCurrentWindow();
@ -2925,7 +2935,7 @@ bool FullscreenUI::NavTab(std::string_view title, bool is_active, bool enabled,
{ {
const ImU32 col = hovered ? ImGui::GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered, 1.0f) : const ImU32 col = hovered ? ImGui::GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered, 1.0f) :
ImGui::GetColorU32(DarkerColor(style.Colors[ImGuiCol_ButtonHovered])); ImGui::GetColorU32(DarkerColor(style.Colors[ImGuiCol_ButtonHovered]));
ImGui::RenderFrame(bb.Min, bb.Max, col, true, LayoutScale(MENU_ITEM_BORDER_ROUNDING)); ImGui::RenderFrame(bb.Min, bb.Max, col, true, LayoutScale(LAYOUT_MENU_ITEM_BORDER_ROUNDING));
} }
const ImVec2 pad(std::max((size.x - text_size.x) * 0.5f, 0.0f), std::max((size.y - text_size.y) * 0.5f, 0.0f)); const ImVec2 pad(std::max((size.x - text_size.x) * 0.5f, 0.0f), std::max((size.y - text_size.y) * 0.5f, 0.0f));
@ -2940,6 +2950,170 @@ bool FullscreenUI::NavTab(std::string_view title, bool is_active, bool enabled,
return pressed; return pressed;
} }
bool FullscreenUI::BeginFloatingNavBar(float x, float y, float items_width,
float font_size /* = UIStyle.LargeFontSize */, float anchor_x /* = 0.0f */,
float anchor_y /* = 0.0f */,
float x_padding /* = LAYOUT_MENU_BUTTON_X_PADDING */,
float y_padding /* = LAYOUT_MENU_BUTTON_Y_PADDING */)
{
if (ImGui::GetCurrentWindowRead()->SkipItems)
return false;
const ImVec2 padding = LayoutScale(x_padding, y_padding);
const float width = (padding.x * 2.0f) + items_width;
const float height = (padding.y * 2.0f) + font_size;
const ImVec2 window_size = ImGui::GetWindowSize();
ImVec2 local_pos = LayoutScale(x, y);
if (anchor_x == -1.0f)
local_pos.x -= width;
else if (anchor_x == -0.5f)
local_pos.x -= (width * 0.5f);
else if (anchor_x == 0.5f)
local_pos.x = (window_size.x * 0.5f) - (width * 0.5f) - local_pos.x;
else if (anchor_x == 1.0f)
local_pos.x = window_size.x - width - local_pos.x;
if (anchor_y == -1.0f)
local_pos.y -= height;
else if (anchor_y == -0.5f)
local_pos.y -= (height * 0.5f);
else if (anchor_y == 0.5f)
local_pos.y = (window_size.y * 0.5f) - (height * 0.5f) - local_pos.y;
else if (anchor_y == 1.0f)
local_pos.y = window_size.y - height - local_pos.y;
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(x_padding, y_padding));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, LayoutScale(1.0f, 0.0f));
PushPrimaryColor();
const ImGuiStyle& style = ImGui::GetStyle();
const ImVec2 nav_pos = ImGui::GetWindowPos() + local_pos;
const ImVec2 nav_size = ImVec2(items_width, font_size + style.FramePadding.y * 2.0f);
ImGui::GetWindowDrawList()->AddRectFilled(nav_pos, nav_pos + nav_size,
ImGui::GetColorU32(ModAlpha(UIStyle.BackgroundHighlight, 0.4f)),
LayoutScale(LAYOUT_MENU_ITEM_BORDER_ROUNDING));
ImGui::SetCursorPos(local_pos);
return true;
}
void FullscreenUI::EndFloatingNavBar()
{
PopPrimaryColor();
ImGui::PopStyleVar(4);
}
float FullscreenUI::CalcFloatingNavBarButtonWidth(std::string_view title, float icon_size /* = UIStyle.LargeFontSize */,
float font_size /* = UIStyle.LargeFontSize */,
float font_weight /* = UIStyle.BoldFontWeight */,
float x_padding /* = LAYOUT_MENU_BUTTON_X_PADDING */)
{
float text_width;
if (!title.empty())
{
const ImVec2 text_size = UIStyle.Font->CalcTextSizeA(font_size, font_weight, std::numeric_limits<float>::max(),
0.0f, IMSTR_START_END(title));
text_width = text_size.x;
if (icon_size > 0.0f)
{
text_width +=
(UIStyle.Font->CalcTextSizeA(font_size, font_weight, std::numeric_limits<float>::max(), 0.0f, " ").x * 2.0f);
}
}
else
{
text_width = 0.0f;
}
return icon_size + text_width + (LayoutScale(x_padding) * 2.0f) + /* spacing */ LayoutScale(1.0f);
}
bool FullscreenUI::FloatingNavBarIcon(std::string_view title, ImTextureID image, bool is_active,
float image_size /* = UIStyle.LargeFontSize */,
float font_size /* = UIStyle.LargeFontSize */,
float font_weight /* = UIStyle.BoldFontWeight */, bool enabled /* = true */,
const ImVec2& uv0 /* = ImVec2(0.0f, 0.0f) */,
const ImVec2& uv1 /* = ImVec2(1.0f, 1.0f) */)
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems)
return false;
const ImVec2 text_size = !title.empty() ?
UIStyle.Font->CalcTextSizeA(font_size, font_weight, std::numeric_limits<float>::max(),
0.0f, IMSTR_START_END(title)) :
ImVec2();
const float text_space_size =
(!title.empty() && image) ?
(UIStyle.Font->CalcTextSizeA(font_size, font_weight, std::numeric_limits<float>::max(), 0.0f, " ").x * 2.0f) :
0.0f;
const ImVec2 pos(window->DC.CursorPos);
const ImGuiStyle& style = ImGui::GetStyle();
const ImVec2 size = ImVec2(image_size + text_space_size + text_size.x + style.FramePadding.x * 2.0f,
text_size.y + 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(IMSTR_START_END(title));
if (enabled)
{
// bit contradictory - we don't want this button to be used for *gamepad* navigation, since they're usually
// activated with the bumpers and/or the back button.
if (!ImGui::ItemAdd(bb, id, nullptr, ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus))
return false;
}
else
{
if (ImGui::IsClippedEx(bb, id))
return false;
}
bool held;
bool pressed;
bool hovered;
if (enabled)
{
pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus);
if (hovered || is_active)
{
// Intentionally no animation here.
const ImU32 col = ImGui::GetColorU32((hovered && !held) ? ImGuiCol_ButtonHovered : ImGuiCol_ButtonActive, 1.0f);
ImGui::RenderFrame(bb.Min, bb.Max, col, false, LayoutScale(LAYOUT_MENU_ITEM_BORDER_ROUNDING));
}
}
else
{
pressed = false;
held = false;
hovered = false;
}
bb.Min += style.FramePadding;
bb.Max -= style.FramePadding;
if (image)
{
const ImVec2& image_min = bb.Min;
const ImVec2 image_max = image_min + ImVec2(image_size, image_size);
ImGui::GetWindowDrawList()->AddImage(image, image_min, image_max, uv0, uv1,
ImGui::GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled));
bb.Min.x = image_max.x + text_space_size;
}
RenderShadowedTextClipped(
UIStyle.Font, font_size, font_weight, bb.Min, bb.Max,
ImGui::GetColorU32(enabled ? (is_active ? ImGuiCol_Text : ImGuiCol_TextDisabled) : ImGuiCol_ButtonHovered), title,
&text_size, ImVec2(0.0f, 0.0f), 0.0f, &bb);
return pressed;
}
bool FullscreenUI::BeginHorizontalMenu(const char* name, const ImVec2& position, const ImVec2& size, bool FullscreenUI::BeginHorizontalMenu(const char* name, const ImVec2& position, const ImVec2& size,
const ImVec4& bg_color, u32 num_items) const ImVec4& bg_color, u32 num_items)
{ {
@ -3556,7 +3730,7 @@ void FullscreenUI::ChoiceDialog::Draw()
ImGui::RenderFrame(pos, pos + bb.frame_bb.GetSize(), ImGui::RenderFrame(pos, pos + bb.frame_bb.GetSize(),
ImGui::GetColorU32(DarkerColor(UIStyle.PopupBackgroundColor, 0.6f)), false, ImGui::GetColorU32(DarkerColor(UIStyle.PopupBackgroundColor, 0.6f)), false,
LayoutScale(MENU_ITEM_BORDER_ROUNDING)); LayoutScale(LAYOUT_MENU_ITEM_BORDER_ROUNDING));
break; break;
} }
} }
@ -5195,7 +5369,7 @@ void FullscreenUI::UpdateTheme()
UIStyle.PrimaryLightColor = HEX_TO_IMVEC4(0x235cd9, 0xff); UIStyle.PrimaryLightColor = HEX_TO_IMVEC4(0x235cd9, 0xff);
UIStyle.PrimaryDarkColor = HEX_TO_IMVEC4(0x1d2953, 0xff); UIStyle.PrimaryDarkColor = HEX_TO_IMVEC4(0x1d2953, 0xff);
UIStyle.PrimaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff); UIStyle.PrimaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIStyle.DisabledColor = HEX_TO_IMVEC4(0x999999, 0xff); UIStyle.DisabledColor = HEX_TO_IMVEC4(0x444444, 0xff);
UIStyle.TextHighlightColor = HEX_TO_IMVEC4(0x8e8e8e, 0xff); UIStyle.TextHighlightColor = HEX_TO_IMVEC4(0x8e8e8e, 0xff);
UIStyle.PrimaryLineColor = HEX_TO_IMVEC4(0x000000, 0xff); UIStyle.PrimaryLineColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIStyle.SecondaryColor = HEX_TO_IMVEC4(0x2a3e78, 0xff); UIStyle.SecondaryColor = HEX_TO_IMVEC4(0x2a3e78, 0xff);

@ -54,6 +54,7 @@ inline constexpr float LAYOUT_MENU_WINDOW_X_PADDING = 12.0f;
inline constexpr float LAYOUT_MENU_WINDOW_Y_PADDING = 12.0f; inline constexpr float LAYOUT_MENU_WINDOW_Y_PADDING = 12.0f;
inline constexpr float LAYOUT_MENU_ITEM_TITLE_SUMMARY_SPACING = 6.0f; inline constexpr float LAYOUT_MENU_ITEM_TITLE_SUMMARY_SPACING = 6.0f;
inline constexpr float LAYOUT_MENU_ITEM_EXTRA_HEIGHT = 2.0f; inline constexpr float LAYOUT_MENU_ITEM_EXTRA_HEIGHT = 2.0f;
static constexpr float LAYOUT_MENU_ITEM_BORDER_ROUNDING = 10.0f;
inline constexpr float LAYOUT_FOOTER_PADDING = 10.0f; inline constexpr float LAYOUT_FOOTER_PADDING = 10.0f;
inline constexpr float LAYOUT_FOOTER_HEIGHT = LAYOUT_MEDIUM_FONT_SIZE + LAYOUT_FOOTER_PADDING * 2.0f; inline constexpr float LAYOUT_FOOTER_HEIGHT = LAYOUT_MEDIUM_FONT_SIZE + LAYOUT_FOOTER_PADDING * 2.0f;
inline constexpr float LAYOUT_HORIZONTAL_MENU_HEIGHT = 320.0f; inline constexpr float LAYOUT_HORIZONTAL_MENU_HEIGHT = 320.0f;
@ -426,10 +427,23 @@ bool HorizontalMenuButton(std::string_view title, bool enabled = true,
void BeginNavBar(float x_padding = LAYOUT_MENU_BUTTON_X_PADDING, float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING); void BeginNavBar(float x_padding = LAYOUT_MENU_BUTTON_X_PADDING, float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING);
void EndNavBar(); void EndNavBar();
void NavTitle(std::string_view title); void NavTitle(std::string_view title);
void RightAlignNavButtons(u32 num_items = 0); void RightAlignNavButtons(u32 num_items);
void RightAlignNavButtons(float total_width);
bool NavButton(std::string_view title, bool is_active, bool enabled = true); bool NavButton(std::string_view title, bool is_active, bool enabled = true);
bool NavTab(std::string_view title, bool is_active, bool enabled, float width); bool NavTab(std::string_view title, bool is_active, bool enabled, float width);
bool BeginFloatingNavBar(float x, float y, float items_width, float font_size = UIStyle.LargeFontSize,
float anchor_x = 0.0f, float anchor_y = 0.0f, float x_padding = LAYOUT_MENU_BUTTON_X_PADDING,
float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING);
void EndFloatingNavBar();
float CalcFloatingNavBarButtonWidth(std::string_view title, float icon_size = UIStyle.LargeFontSize,
float font_size = UIStyle.LargeFontSize, float font_weight = UIStyle.BoldFontWeight,
float x_padding = LAYOUT_MENU_BUTTON_X_PADDING);
bool FloatingNavBarIcon(std::string_view title, ImTextureID image, bool is_active,
float image_size = UIStyle.LargeFontSize, float font_size = UIStyle.LargeFontSize,
float font_weight = UIStyle.BoldFontWeight, bool enabled = true,
const ImVec2& uv0 = ImVec2(0.0f, 0.0f), const ImVec2& uv1 = ImVec2(1.0f, 1.0f));
bool BeginHorizontalMenu(const char* name, const ImVec2& position, const ImVec2& size, const ImVec4& bg_color, bool BeginHorizontalMenu(const char* name, const ImVec2& position, const ImVec2& size, const ImVec4& bg_color,
u32 num_items); u32 num_items);
void EndHorizontalMenu(); void EndHorizontalMenu();

Loading…
Cancel
Save