diff --git a/src/core/achievements.cpp b/src/core/achievements.cpp index 45d4439f9..61b3c3580 100644 --- a/src/core/achievements.cpp +++ b/src/core/achievements.cpp @@ -2315,8 +2315,7 @@ void Achievements::DrawGameOverlays() const float spacing = LayoutScale(10.0f); const float padding = LayoutScale(10.0f); const float rounding = LayoutScale(10.0f); - const ImVec2 image_size = - LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT); + const ImVec2 image_size = LayoutScale(50.0f, 50.0f); const ImGuiIO& io = ImGui::GetIO(); ImVec2 position = ImVec2(io.DisplaySize.x - margin, io.DisplaySize.y - margin); ImDrawList* dl = ImGui::GetBackgroundDrawList(); @@ -2695,114 +2694,103 @@ void Achievements::DrawAchievementsWindow() const float heading_height = LayoutScale(heading_height_unscaled); bool close_window = false; - if (ImGuiFullscreen::BeginFullscreenWindow( - ImVec2(), ImVec2(display_size.x, heading_height), "achievements_heading", heading_background, 0.0f, ImVec2(), - ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoScrollWithMouse)) + if (ImGuiFullscreen::BeginFullscreenWindow(ImVec2(), ImVec2(display_size.x, heading_height), "achievements_heading", + heading_background, 0.0f, ImVec2(10.0f, 10.0f), + ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_NoScrollWithMouse)) { - ImRect bb; - bool visible, hovered; - ImGuiFullscreen::MenuButtonFrame("achievements_heading", false, heading_height_unscaled, &visible, &hovered, - &bb.Min, &bb.Max, 0, heading_alpha); - if (visible) + const ImVec2 pos = ImGui::GetCursorScreenPos() + ImGui::GetStyle().FramePadding; + const float spacing = LayoutScale(10.0f); + const float image_size = LayoutScale(85.0f); + + if (!s_state.game_icon.empty()) { - const float padding = LayoutScale(10.0f); - const float spacing = LayoutScale(10.0f); - const float image_height = LayoutScale(85.0f); - - const ImVec2 icon_min(bb.Min + ImVec2(padding, padding)); - const ImVec2 icon_max(icon_min + ImVec2(image_height, image_height)); - - if (!s_state.game_icon.empty()) + GPUTexture* badge = ImGuiFullscreen::GetCachedTextureAsync(s_state.game_icon); + if (badge) { - GPUTexture* badge = ImGuiFullscreen::GetCachedTextureAsync(s_state.game_icon); - if (badge) - { - ImGui::GetWindowDrawList()->AddImage(badge, icon_min, icon_max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), - IM_COL32(255, 255, 255, 255)); - } + ImGui::GetWindowDrawList()->AddImage(badge, pos, pos + ImVec2(image_size, image_size), ImVec2(0.0f, 0.0f), + ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); } + } - float left = bb.Min.x + padding + image_height + spacing; - float right = bb.Max.x - padding; - float top = bb.Min.y + padding; - ImDrawList* dl = ImGui::GetWindowDrawList(); - SmallString text; - ImVec2 text_size; + float left = pos.x + image_size + spacing; + float right = pos.x + ImGuiFullscreen::GetMenuButtonAvailableWidth(); + float top = pos.y; + ImDrawList* dl = ImGui::GetWindowDrawList(); + SmallString text; + ImVec2 text_size; - close_window = (ImGuiFullscreen::FloatingButton(ICON_FA_SQUARE_XMARK, 10.0f, 10.0f, 1.0f, 0.0f, true) || - ImGuiFullscreen::WantsToCloseMenu()); + close_window = (ImGuiFullscreen::FloatingButton(ICON_FA_SQUARE_XMARK, 10.0f, 10.0f, 1.0f, 0.0f, true) || + ImGuiFullscreen::WantsToCloseMenu()); - const ImRect title_bb(ImVec2(left, top), ImVec2(right, top + UIStyle.LargeFontSize)); - text.assign(s_state.game_title); + const ImRect title_bb(ImVec2(left, top), ImVec2(right, top + UIStyle.LargeFontSize)); + text.assign(s_state.game_title); - if (rc_client_get_hardcore_enabled(s_state.client)) - text.append(TRANSLATE_SV("Achievements", " (Hardcore Mode)")); + if (rc_client_get_hardcore_enabled(s_state.client)) + text.append(TRANSLATE_SV("Achievements", " (Hardcore Mode)")); - top += UIStyle.LargeFontSize + spacing; + top += UIStyle.LargeFontSize + spacing; - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, title_bb.Min, title_bb.Max, - ImGui::GetColorU32(ImGuiCol_Text), text, nullptr, ImVec2(0.0f, 0.0f), 0.0f, &title_bb); + RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, title_bb.Min, title_bb.Max, + ImGui::GetColorU32(ImGuiCol_Text), text, nullptr, ImVec2(0.0f, 0.0f), 0.0f, &title_bb); - const ImRect summary_bb(ImVec2(left, top), ImVec2(right, top + UIStyle.MediumFontSize)); - if (s_state.game_summary.num_core_achievements > 0) + const ImRect summary_bb(ImVec2(left, top), ImVec2(right, top + UIStyle.MediumFontSize)); + if (s_state.game_summary.num_core_achievements > 0) + { + if (s_state.game_summary.num_unlocked_achievements == s_state.game_summary.num_core_achievements) { - if (s_state.game_summary.num_unlocked_achievements == s_state.game_summary.num_core_achievements) - { - text = TRANSLATE_PLURAL_SSTR("Achievements", "You have unlocked all achievements and earned %n points!", - "Point count", s_state.game_summary.points_unlocked); - } - else - { - text.format(TRANSLATE_FS("Achievements", - "You have unlocked {0} of {1} achievements, earning {2} of {3} possible points."), - s_state.game_summary.num_unlocked_achievements, s_state.game_summary.num_core_achievements, - s_state.game_summary.points_unlocked, s_state.game_summary.points_core); - } + text = TRANSLATE_PLURAL_SSTR("Achievements", "You have unlocked all achievements and earned %n points!", + "Point count", s_state.game_summary.points_unlocked); } else { - text.assign(TRANSLATE_SV("Achievements", "This game has no achievements.")); + text.format(TRANSLATE_FS("Achievements", + "You have unlocked {0} of {1} achievements, earning {2} of {3} possible points."), + s_state.game_summary.num_unlocked_achievements, s_state.game_summary.num_core_achievements, + s_state.game_summary.points_unlocked, s_state.game_summary.points_core); } + } + else + { + text.assign(TRANSLATE_SV("Achievements", "This game has no achievements.")); + } - top += UIStyle.MediumFontSize + spacing; + top += UIStyle.MediumFontSize + spacing; - RenderShadowedTextClipped( - UIStyle.Font, UIStyle.MediumFontSize, UIStyle.BoldFontWeight, summary_bb.Min, summary_bb.Max, - ImGui::GetColorU32(ImGuiFullscreen::DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text])), text, nullptr, - ImVec2(0.0f, 0.0f), 0.0f, &summary_bb); + RenderShadowedTextClipped(UIStyle.Font, UIStyle.MediumFontSize, UIStyle.BoldFontWeight, summary_bb.Min, + summary_bb.Max, + ImGui::GetColorU32(ImGuiFullscreen::DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text])), + text, nullptr, ImVec2(0.0f, 0.0f), 0.0f, &summary_bb); - if (s_state.game_summary.num_core_achievements > 0) + if (s_state.game_summary.num_core_achievements > 0) + { + const float progress_height = LayoutScale(20.0f); + const float progress_rounding = LayoutScale(5.0f); + const ImRect progress_bb(ImVec2(left, top), ImVec2(right, top + progress_height)); + const float fraction = static_cast(s_state.game_summary.num_unlocked_achievements) / + static_cast(s_state.game_summary.num_core_achievements); + dl->AddRectFilled(progress_bb.Min, progress_bb.Max, ImGui::GetColorU32(UIStyle.PrimaryDarkColor), + progress_rounding); + if (s_state.game_summary.num_unlocked_achievements > 0) { - const float progress_height = LayoutScale(20.0f); - const float progress_rounding = LayoutScale(5.0f); - const ImRect progress_bb(ImVec2(left, top), ImVec2(right, top + progress_height)); - const float fraction = static_cast(s_state.game_summary.num_unlocked_achievements) / - static_cast(s_state.game_summary.num_core_achievements); - dl->AddRectFilled(progress_bb.Min, progress_bb.Max, ImGui::GetColorU32(UIStyle.PrimaryDarkColor), - progress_rounding); - if (s_state.game_summary.num_unlocked_achievements > 0) - { - dl->AddRectFilled(progress_bb.Min, - ImVec2(progress_bb.Min.x + fraction * progress_bb.GetWidth(), progress_bb.Max.y), - ImGui::GetColorU32(UIStyle.SecondaryColor), progress_rounding); - } - - text.format("{}%", static_cast(std::round(fraction * 100.0f))); - text_size = UIStyle.Font->CalcTextSizeA(UIStyle.MediumFontSize, UIStyle.BoldFontWeight, FLT_MAX, 0.0f, - IMSTR_START_END(text)); - const ImVec2 text_pos( - progress_bb.Min.x + ((progress_bb.Max.x - progress_bb.Min.x) / 2.0f) - (text_size.x / 2.0f), - progress_bb.Min.y + ((progress_bb.Max.y - progress_bb.Min.y) / 2.0f) - (text_size.y / 2.0f)); - dl->AddText(UIStyle.Font, UIStyle.MediumFontSize, UIStyle.BoldFontWeight, text_pos, - ImGui::GetColorU32(UIStyle.PrimaryTextColor), IMSTR_START_END(text)); - // top += progress_height + spacing; + dl->AddRectFilled(progress_bb.Min, + ImVec2(progress_bb.Min.x + fraction * progress_bb.GetWidth(), progress_bb.Max.y), + ImGui::GetColorU32(UIStyle.SecondaryColor), progress_rounding); } + + text.format("{}%", static_cast(std::round(fraction * 100.0f))); + text_size = UIStyle.Font->CalcTextSizeA(UIStyle.MediumFontSize, UIStyle.BoldFontWeight, FLT_MAX, 0.0f, + IMSTR_START_END(text)); + const ImVec2 text_pos(progress_bb.Min.x + ((progress_bb.Max.x - progress_bb.Min.x) / 2.0f) - (text_size.x / 2.0f), + progress_bb.Min.y + ((progress_bb.Max.y - progress_bb.Min.y) / 2.0f) - + (text_size.y / 2.0f)); + dl->AddText(UIStyle.Font, UIStyle.MediumFontSize, UIStyle.BoldFontWeight, text_pos, + ImGui::GetColorU32(UIStyle.PrimaryTextColor), IMSTR_START_END(text)); + // top += progress_height + spacing; } } ImGuiFullscreen::EndFullscreenWindow(); - ImGui::SetNextWindowBgAlpha(alpha); - // See note in FullscreenUI::DrawSettingsWindow(). if (ImGuiFullscreen::IsFocusResetFromWindowChange()) ImGui::SetNextWindowScroll(ImVec2(0.0f, 0.0f)); @@ -2883,56 +2871,47 @@ void Achievements::DrawAchievementsWindow() void Achievements::DrawAchievement(const rc_client_achievement_t* cheevo) { using ImGuiFullscreen::DarkerColor; - using ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT; using ImGuiFullscreen::LayoutScale; using ImGuiFullscreen::LayoutUnscale; using ImGuiFullscreen::RenderShadowedTextClipped; using ImGuiFullscreen::UIStyle; - static constexpr float alpha = 0.8f; static constexpr float progress_height_unscaled = 20.0f; static constexpr float progress_spacing_unscaled = 5.0f; static constexpr float progress_rounding_unscaled = 5.0f; - static constexpr float spacing_unscaled = 4.0f; - const float spacing = ImGuiFullscreen::LayoutScale(spacing_unscaled); + const float spacing = ImGuiFullscreen::LayoutScale(ImGuiFullscreen::LAYOUT_MENU_ITEM_TITLE_SUMMARY_SPACING); const u32 text_color = ImGui::GetColorU32(UIStyle.SecondaryTextColor); const u32 summary_color = ImGui::GetColorU32(DarkerColor(UIStyle.SecondaryTextColor)); const u32 rarity_color = ImGui::GetColorU32(DarkerColor(DarkerColor(UIStyle.SecondaryTextColor))); + const ImVec2 image_size = LayoutScale(50.0f, 50.0f); const bool is_unlocked = (cheevo->state == RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED); const std::string_view measured_progress(cheevo->measured_progress); const bool is_measured = !is_unlocked && !measured_progress.empty(); - const float unlock_rarity_height = spacing_unscaled + ImGuiFullscreen::LAYOUT_MEDIUM_FONT_SIZE; + const float unlock_rarity_height = spacing + UIStyle.MediumFontSize; const ImVec2 points_template_size = UIStyle.Font->CalcTextSizeA( UIStyle.MediumFontSize, UIStyle.NormalFontWeight, FLT_MAX, 0.0f, TRANSLATE("Achievements", "XXX points")); + const float avail_width = ImGuiFullscreen::GetMenuButtonAvailableWidth(); const size_t summary_length = std::strlen(cheevo->description); - const float summary_wrap_width = - (ImGui::GetCurrentWindow()->WorkRect.GetWidth() - (ImGui::GetStyle().FramePadding.x * 2.0f) - - LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT + 30.0f) - points_template_size.x); + const float summary_wrap_width = (avail_width - (image_size.x + spacing + spacing) - points_template_size.x); const ImVec2 summary_text_size = UIStyle.Font->CalcTextSizeA(UIStyle.MediumFontSize, UIStyle.NormalFontWeight, FLT_MAX, summary_wrap_width, cheevo->description, cheevo->description + summary_length); - // Messy, but need to undo LayoutScale in MenuButtonFrame()... - const float extra_summary_height = std::max(LayoutUnscale(summary_text_size.y) - LAYOUT_MENU_BUTTON_HEIGHT, 0.0f); - + const float content_height = UIStyle.LargeFontSize + spacing + summary_text_size.y + unlock_rarity_height + + LayoutScale(is_measured ? progress_height_unscaled : 0.0f) + + LayoutScale(ImGuiFullscreen::LAYOUT_MENU_ITEM_EXTRA_HEIGHT); ImRect bb; bool visible, hovered; - const bool clicked = ImGuiFullscreen::MenuButtonFrame( - TinyString::from_format("chv_{}", cheevo->id), true, - !is_measured ? (LAYOUT_MENU_BUTTON_HEIGHT + extra_summary_height + unlock_rarity_height) : - (LAYOUT_MENU_BUTTON_HEIGHT + extra_summary_height + unlock_rarity_height + progress_height_unscaled + - progress_spacing_unscaled), - &visible, &hovered, &bb.Min, &bb.Max, 0, alpha); + const bool clicked = ImGuiFullscreen::MenuButtonFrame(TinyString::from_format("chv_{}", cheevo->id), content_height, + true, &bb, &visible, &hovered); if (!visible) return; const std::string& badge_path = GetCachedAchievementBadgePath(cheevo, cheevo->state != RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED); - const ImVec2 image_size( - LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT)); if (!badge_path.empty()) { GPUTexture* badge = ImGuiFullscreen::GetCachedTextureAsync(badge_path); @@ -2982,8 +2961,7 @@ void Achievements::DrawAchievement(const rc_client_achievement_t* cheevo) const ImRect title_bb(ImVec2(text_start_x, bb.Min.y), ImVec2(points_start, midpoint)); const ImRect summary_bb(ImVec2(text_start_x, midpoint), ImVec2(points_start, midpoint + summary_text_size.y)); const ImRect unlock_rarity_bb(summary_bb.Min.x, summary_bb.Max.y + spacing, summary_bb.Max.x, - summary_bb.Max.y + - LayoutScale(spacing_unscaled + ImGuiFullscreen::LAYOUT_MEDIUM_FONT_SIZE)); + summary_bb.Max.y + unlock_rarity_height); const ImRect points_bb(ImVec2(points_start, midpoint), bb.Max); const ImRect lock_bb(ImVec2(points_template_start + ((points_template_size.x - right_icon_size.x) * 0.5f), bb.Min.y), ImVec2(bb.Max.x, midpoint)); @@ -3096,24 +3074,22 @@ void Achievements::DrawLeaderboardsWindow() const bool is_leaderboard_open = (s_state.open_leaderboard != nullptr); bool close_leaderboard_on_exit = false; - ImRect bb; SmallString text; const ImVec4 background = ImGuiFullscreen::ModAlpha(ImGuiFullscreen::UIStyle.BackgroundColor, alpha); const ImVec4 heading_background = ImGuiFullscreen::ModAlpha(ImGuiFullscreen::UIStyle.BackgroundColor, heading_alpha); const ImVec2 display_size = ImGui::GetIO().DisplaySize; const u32 text_color = ImGui::GetColorU32(ImGuiCol_Text); - const float padding = LayoutScale(10.0f); const float spacing = LayoutScale(10.0f); - const float spacing_small = spacing / 2.0f; + const float spacing_small = ImFloor(spacing * 0.5f); float heading_height = LayoutScale(heading_height_unscaled); if (is_leaderboard_open) { // tabs - heading_height += spacing_small + LayoutScale(tab_height_unscaled) + spacing; + heading_height += spacing * 2.0f + LayoutScale(tab_height_unscaled) + spacing * 2.0f; // Add space for a legend - spacing + 1 line of text + spacing + line - heading_height += LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY) + spacing; + heading_height += UIStyle.LargeFontSize; } const float rank_column_width = @@ -3130,196 +3106,191 @@ void Achievements::DrawLeaderboardsWindow() .x; const float column_spacing = spacing * 2.0f; - if (ImGuiFullscreen::BeginFullscreenWindow( - ImVec2(), ImVec2(display_size.x, heading_height), "leaderboards_heading", heading_background, 0.0f, ImVec2(), - ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoScrollWithMouse)) + if (ImGuiFullscreen::BeginFullscreenWindow(ImVec2(), ImVec2(display_size.x, heading_height), "leaderboards_heading", + heading_background, 0.0f, ImVec2(10.0f, 10.0f), + ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_NoScrollWithMouse)) { - bool visible, hovered; - bool pressed = ImGuiFullscreen::MenuButtonFrame("leaderboards_heading", false, heading_height_unscaled, &visible, - &hovered, &bb.Min, &bb.Max, 0, alpha); - UNREFERENCED_VARIABLE(pressed); + const ImVec2 heading_pos = ImGui::GetCursorScreenPos() + ImGui::GetStyle().FramePadding; + const float image_size = LayoutScale(85.0f); - if (visible) + if (!s_state.game_icon.empty()) { - const float image_height = LayoutScale(85.0f); - - const ImVec2 icon_min(bb.Min + ImVec2(padding, padding)); - const ImVec2 icon_max(icon_min + ImVec2(image_height, image_height)); - - if (!s_state.game_icon.empty()) + GPUTexture* badge = ImGuiFullscreen::GetCachedTextureAsync(s_state.game_icon); + if (badge) { - GPUTexture* badge = ImGuiFullscreen::GetCachedTextureAsync(s_state.game_icon); - if (badge) - { - ImGui::GetWindowDrawList()->AddImage(badge, icon_min, icon_max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), - IM_COL32(255, 255, 255, 255)); - } + ImGui::GetWindowDrawList()->AddImage(badge, heading_pos, heading_pos + ImVec2(image_size, image_size), + ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255)); } + } - float left = bb.Min.x + padding + image_height + spacing; - float right = bb.Max.x - padding; - float top = bb.Min.y + padding; + float left = heading_pos.x + image_size + spacing; + float right = heading_pos.x + ImGuiFullscreen::GetMenuButtonAvailableWidth(); + float top = heading_pos.y; - if (!is_leaderboard_open) + if (!is_leaderboard_open) + { + if (ImGuiFullscreen::FloatingButton(ICON_FA_SQUARE_XMARK, 10.0f, 10.0f, 1.0f, 0.0f, true) || + ImGuiFullscreen::WantsToCloseMenu()) { - if (ImGuiFullscreen::FloatingButton(ICON_FA_SQUARE_XMARK, 10.0f, 10.0f, 1.0f, 0.0f, true) || - ImGuiFullscreen::WantsToCloseMenu()) - { - FullscreenUI::ReturnToPreviousWindow(); - } + FullscreenUI::ReturnToPreviousWindow(); } - else + } + else + { + if (ImGuiFullscreen::FloatingButton(ICON_FA_SQUARE_CARET_LEFT, 10.0f, 10.0f, 1.0f, 0.0f, true) || + ImGuiFullscreen::WantsToCloseMenu()) { - if (ImGuiFullscreen::FloatingButton(ICON_FA_SQUARE_CARET_LEFT, 10.0f, 10.0f, 1.0f, 0.0f, true) || - ImGuiFullscreen::WantsToCloseMenu()) - { - close_leaderboard_on_exit = true; - } + close_leaderboard_on_exit = true; } + } - const ImRect title_bb(ImVec2(left, top), ImVec2(right, top + UIStyle.LargeFontSize)); - text.assign(Achievements::GetGameTitle()); + const ImRect title_bb(ImVec2(left, top), ImVec2(right, top + UIStyle.LargeFontSize)); + text.assign(Achievements::GetGameTitle()); + + top += UIStyle.LargeFontSize + spacing_small; + + RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, title_bb.Min, title_bb.Max, + text_color, text, nullptr, ImVec2(0.0f, 0.0f), 0.0f, &title_bb); + + u32 summary_color; + if (is_leaderboard_open) + { + const ImRect subtitle_bb(ImVec2(left, top), ImVec2(right, top + UIStyle.LargeFontSize)); + text.assign(s_state.open_leaderboard->title); top += UIStyle.LargeFontSize + spacing_small; - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, title_bb.Min, title_bb.Max, - text_color, text, nullptr, ImVec2(0.0f, 0.0f), 0.0f, &title_bb); + RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, subtitle_bb.Min, + subtitle_bb.Max, + ImGui::GetColorU32(DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text])), text, nullptr, + ImVec2(0.0f, 0.0f), 0.0f, &subtitle_bb); - u32 summary_color; - if (is_leaderboard_open) - { - const ImRect subtitle_bb(ImVec2(left, top), ImVec2(right, top + UIStyle.LargeFontSize)); - text.assign(s_state.open_leaderboard->title); + text.assign(s_state.open_leaderboard->description); + summary_color = ImGui::GetColorU32(DarkerColor(DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text]))); + } + else + { + u32 count = 0; + for (u32 i = 0; i < s_state.leaderboard_list->num_buckets; i++) + count += s_state.leaderboard_list->buckets[i].num_leaderboards; + text = TRANSLATE_PLURAL_SSTR("Achievements", "This game has %n leaderboards.", "Leaderboard count", count); + summary_color = ImGui::GetColorU32(DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text])); + } - top += UIStyle.LargeFontSize + spacing_small; + const ImRect summary_bb(ImVec2(left, top), ImVec2(right, top + UIStyle.MediumFontSize)); + top += UIStyle.MediumFontSize + spacing_small; - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, subtitle_bb.Min, - subtitle_bb.Max, - ImGui::GetColorU32(DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text])), text, - nullptr, ImVec2(0.0f, 0.0f), 0.0f, &subtitle_bb); + RenderShadowedTextClipped(UIStyle.Font, UIStyle.MediumFontSize, UIStyle.BoldFontWeight, summary_bb.Min, + summary_bb.Max, summary_color, text, nullptr, ImVec2(0.0f, 0.0f), 0.0f, &summary_bb); - text.assign(s_state.open_leaderboard->description); - summary_color = ImGui::GetColorU32(DarkerColor(DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text]))); - } - else - { - u32 count = 0; - for (u32 i = 0; i < s_state.leaderboard_list->num_buckets; i++) - count += s_state.leaderboard_list->buckets[i].num_leaderboards; - text = TRANSLATE_PLURAL_SSTR("Achievements", "This game has %n leaderboards.", "Leaderboard count", count); - summary_color = ImGui::GetColorU32(DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text])); - } - - const ImRect summary_bb(ImVec2(left, top), ImVec2(right, top + UIStyle.MediumFontSize)); + if (!is_leaderboard_open && !Achievements::IsHardcoreModeActive()) + { + const ImRect hardcore_warning_bb(ImVec2(left, top), ImVec2(right, top + UIStyle.MediumFontSize)); top += UIStyle.MediumFontSize + spacing_small; - RenderShadowedTextClipped(UIStyle.Font, UIStyle.MediumFontSize, UIStyle.BoldFontWeight, summary_bb.Min, - summary_bb.Max, summary_color, text, nullptr, ImVec2(0.0f, 0.0f), 0.0f, &summary_bb); + text.format( + ICON_EMOJI_WARNING " {}", + TRANSLATE_SV("Achievements", + "Submitting scores is disabled because hardcore mode is off. Leaderboards are read-only.")); - if (!is_leaderboard_open && !Achievements::IsHardcoreModeActive()) + RenderShadowedTextClipped(UIStyle.Font, UIStyle.MediumFontSize, UIStyle.BoldFontWeight, hardcore_warning_bb.Min, + hardcore_warning_bb.Max, + ImGui::GetColorU32(DarkerColor(DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text]))), + text, nullptr, ImVec2(0.0f, 0.0f), 0.0f, &hardcore_warning_bb); + } + + if (is_leaderboard_open) + { + const float avail_width = ImGuiFullscreen::GetMenuButtonAvailableWidth(); + const float tab_width = avail_width * 0.2f; + const float tab_spacing = LayoutScale(20.0f); + const float tab_left_padding = (avail_width - ((tab_width * 2.0f) + tab_spacing)) * 0.5f; + ImGui::SetCursorScreenPos(ImVec2(heading_pos.x + tab_left_padding, top + spacing * 2.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(ImGuiFullscreen::LAYOUT_MENU_WINDOW_X_PADDING, + ImGuiFullscreen::LAYOUT_MENU_WINDOW_Y_PADDING)); + + if (ImGui::IsKeyPressed(ImGuiKey_GamepadDpadLeft, false) || + ImGui::IsKeyPressed(ImGuiKey_NavGamepadTweakSlow, false) || ImGui::IsKeyPressed(ImGuiKey_LeftArrow, false) || + ImGui::IsKeyPressed(ImGuiKey_GamepadDpadRight, false) || + ImGui::IsKeyPressed(ImGuiKey_NavGamepadTweakFast, false) || ImGui::IsKeyPressed(ImGuiKey_RightArrow, false)) { - const ImRect hardcore_warning_bb(ImVec2(left, top), ImVec2(right, top + UIStyle.MediumFontSize)); - top += UIStyle.MediumFontSize + spacing_small; - - text.format( - ICON_EMOJI_WARNING " {}", - TRANSLATE_SV("Achievements", - "Submitting scores is disabled because hardcore mode is off. Leaderboards are read-only.")); - - RenderShadowedTextClipped(UIStyle.Font, UIStyle.MediumFontSize, UIStyle.BoldFontWeight, hardcore_warning_bb.Min, - hardcore_warning_bb.Max, - ImGui::GetColorU32(DarkerColor(DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text]))), - text, nullptr, ImVec2(0.0f, 0.0f), 0.0f, &hardcore_warning_bb); + s_state.is_showing_all_leaderboard_entries = !s_state.is_showing_all_leaderboard_entries; + ImGuiFullscreen::QueueResetFocus(ImGuiFullscreen::FocusResetType::ViewChanged); } - if (is_leaderboard_open) + for (const bool show_all : {false, true}) { - const float tab_width = (ImGui::GetWindowWidth() / ImGuiFullscreen::UIStyle.LayoutScale) * 0.5f; - ImGui::SetCursorPos(ImVec2(0.0f, top + spacing_small)); - - if (ImGui::IsKeyPressed(ImGuiKey_GamepadDpadLeft, false) || - ImGui::IsKeyPressed(ImGuiKey_NavGamepadTweakSlow, false) || - ImGui::IsKeyPressed(ImGuiKey_LeftArrow, false) || ImGui::IsKeyPressed(ImGuiKey_GamepadDpadRight, false) || - ImGui::IsKeyPressed(ImGuiKey_NavGamepadTweakFast, false) || ImGui::IsKeyPressed(ImGuiKey_RightArrow, false)) + const std::string_view title = + show_all ? TRANSLATE_SV("Achievements", "Show Best") : TRANSLATE_SV("Achievements", "Show Nearby"); + if (ImGuiFullscreen::NavTab(title, s_state.is_showing_all_leaderboard_entries == show_all, true, tab_width)) { - s_state.is_showing_all_leaderboard_entries = !s_state.is_showing_all_leaderboard_entries; + s_state.is_showing_all_leaderboard_entries = show_all; ImGuiFullscreen::QueueResetFocus(ImGuiFullscreen::FocusResetType::ViewChanged); } - for (const bool show_all : {false, true}) - { - const char* title = - show_all ? TRANSLATE("Achievements", "Show Best") : TRANSLATE("Achievements", "Show Nearby"); - if (ImGuiFullscreen::NavTab(title, s_state.is_showing_all_leaderboard_entries == show_all, true, tab_width, - tab_height_unscaled, heading_background)) - { - s_state.is_showing_all_leaderboard_entries = show_all; - ImGuiFullscreen::QueueResetFocus(ImGuiFullscreen::FocusResetType::ViewChanged); - } - } - - const ImVec2 bg_pos = - ImVec2(0.0f, ImGui::GetCurrentWindow()->DC.CursorPos.y + LayoutScale(tab_height_unscaled)); - const ImVec2 bg_size = - ImVec2(ImGui::GetWindowWidth(), - spacing + LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY) + spacing); - ImGui::GetWindowDrawList()->AddRectFilled(bg_pos, bg_pos + bg_size, ImGui::GetColorU32(heading_background)); - - ImGui::SetCursorPos(ImVec2(0.0f, ImGui::GetCursorPosY() + LayoutScale(tab_height_unscaled) + spacing)); - - pressed = - ImGuiFullscreen::MenuButtonFrame("legend", false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, - &visible, &hovered, &bb.Min, &bb.Max, 0, alpha); - UNREFERENCED_VARIABLE(pressed); - - // add padding from the window below, don't want the menu items butted up against the edge - bb.Min.x += LayoutScale(ImGuiFullscreen::LAYOUT_MENU_WINDOW_X_PADDING); - bb.Max.x -= LayoutScale(ImGuiFullscreen::LAYOUT_MENU_WINDOW_X_PADDING); - - const u32 heading_color = ImGui::GetColorU32(DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text])); - - const float midpoint = bb.Min.y + UIStyle.LargeFontSize + LayoutScale(4.0f); - float text_start_x = bb.Min.x + LayoutScale(15.0f) + padding; - - const ImRect rank_bb(ImVec2(text_start_x, bb.Min.y), ImVec2(bb.Max.x, midpoint)); - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, rank_bb.Min, rank_bb.Max, - heading_color, TRANSLATE_SV("Achievements", "Rank"), nullptr, ImVec2(0.0f, 0.0f), - 0.0f, &rank_bb); - text_start_x += rank_column_width + column_spacing; - - const ImRect user_bb(ImVec2(text_start_x, bb.Min.y), ImVec2(bb.Max.x, midpoint)); - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, user_bb.Min, user_bb.Max, - heading_color, TRANSLATE_SV("Achievements", "Name"), nullptr, ImVec2(0.0f, 0.0f), - 0.0f, &user_bb); - text_start_x += name_column_width + column_spacing; - - static const char* value_headings[NUM_RC_CLIENT_LEADERBOARD_FORMATS] = { - TRANSLATE_NOOP("Achievements", "Time"), - TRANSLATE_NOOP("Achievements", "Score"), - TRANSLATE_NOOP("Achievements", "Value"), - }; - - const ImRect score_bb(ImVec2(text_start_x, bb.Min.y), ImVec2(bb.Max.x, midpoint)); - RenderShadowedTextClipped( - UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, score_bb.Min, score_bb.Max, heading_color, - Host::TranslateToStringView( - "Achievements", - value_headings[std::min(s_state.open_leaderboard->format, NUM_RC_CLIENT_LEADERBOARD_FORMATS - 1)]), - nullptr, ImVec2(0.0f, 0.0f), 0.0f, &score_bb); - text_start_x += time_column_width + column_spacing; - - const ImRect date_bb(ImVec2(text_start_x, bb.Min.y), ImVec2(bb.Max.x, midpoint)); - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, date_bb.Min, date_bb.Max, - heading_color, TRANSLATE_SV("Achievements", "Date Submitted"), nullptr, - ImVec2(0.0f, 0.0f), 0.0f, &date_bb); - - const float line_thickness = LayoutScale(1.0f); - const float line_padding = LayoutScale(5.0f); - const ImVec2 line_start(bb.Min.x, bb.Min.y + UIStyle.LargeFontSize + line_padding); - const ImVec2 line_end(bb.Max.x, line_start.y); - ImGui::GetWindowDrawList()->AddLine(line_start, line_end, ImGui::GetColorU32(ImGuiCol_TextDisabled), - line_thickness); + if (!show_all) + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + tab_spacing); } + + ImGui::PopStyleVar(); + + ImGui::SetCursorPos(ImVec2(0.0f, ImGui::GetCursorPosY() + LayoutScale(tab_height_unscaled) + spacing * 2.0f)); + + ImVec2 column_heading_pos = ImGui::GetCursorScreenPos(); + float end_x = column_heading_pos.x + ImGui::GetContentRegionAvail().x; + + // add padding from the window below, don't want the menu items butted up against the edge + column_heading_pos.x += LayoutScale(ImGuiFullscreen::LAYOUT_MENU_WINDOW_X_PADDING); + end_x -= LayoutScale(ImGuiFullscreen::LAYOUT_MENU_WINDOW_X_PADDING); + + // and the padding for the frame itself + column_heading_pos.x += LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_X_PADDING); + end_x -= LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_X_PADDING); + + const u32 heading_color = ImGui::GetColorU32(DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text])); + + const float midpoint = column_heading_pos.y + UIStyle.LargeFontSize + LayoutScale(4.0f); + float text_start_x = column_heading_pos.x; + + const ImRect rank_bb(ImVec2(text_start_x, column_heading_pos.y), ImVec2(end_x, midpoint)); + RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, rank_bb.Min, rank_bb.Max, + heading_color, TRANSLATE_SV("Achievements", "Rank"), nullptr, ImVec2(0.0f, 0.0f), 0.0f, + &rank_bb); + text_start_x += rank_column_width + column_spacing; + + const ImRect user_bb(ImVec2(text_start_x, column_heading_pos.y), ImVec2(end_x, midpoint)); + RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, user_bb.Min, user_bb.Max, + heading_color, TRANSLATE_SV("Achievements", "Name"), nullptr, ImVec2(0.0f, 0.0f), 0.0f, + &user_bb); + text_start_x += name_column_width + column_spacing; + + static const char* value_headings[NUM_RC_CLIENT_LEADERBOARD_FORMATS] = { + TRANSLATE_NOOP("Achievements", "Time"), + TRANSLATE_NOOP("Achievements", "Score"), + TRANSLATE_NOOP("Achievements", "Value"), + }; + + const ImRect score_bb(ImVec2(text_start_x, column_heading_pos.y), ImVec2(end_x, midpoint)); + RenderShadowedTextClipped( + UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, score_bb.Min, score_bb.Max, heading_color, + Host::TranslateToStringView( + "Achievements", + value_headings[std::min(s_state.open_leaderboard->format, NUM_RC_CLIENT_LEADERBOARD_FORMATS - 1)]), + nullptr, ImVec2(0.0f, 0.0f), 0.0f, &score_bb); + text_start_x += time_column_width + column_spacing; + + const ImRect date_bb(ImVec2(text_start_x, column_heading_pos.y), ImVec2(end_x, midpoint)); + RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, date_bb.Min, date_bb.Max, + heading_color, TRANSLATE_SV("Achievements", "Date Submitted"), nullptr, + ImVec2(0.0f, 0.0f), 0.0f, &date_bb); + + const float line_thickness = LayoutScale(1.0f); + const float line_padding = LayoutScale(5.0f); + const ImVec2 line_start(column_heading_pos.x, column_heading_pos.y + UIStyle.LargeFontSize + line_padding); + const ImVec2 line_end(end_x, line_start.y); + ImGui::GetWindowDrawList()->AddLine(line_start, line_end, ImGui::GetColorU32(ImGuiCol_TextDisabled), + line_thickness); } } ImGuiFullscreen::EndFullscreenWindow(); @@ -3403,22 +3374,11 @@ void Achievements::DrawLeaderboardsWindow() } } - // Fetch next chunk if the loading indicator becomes visible (i.e. we scrolled enough). - bool visible, hovered; + bool visible; text.format(ICON_FA_HOURGLASS_HALF " {}", TRANSLATE_SV("Achievements", "Loading...")); - ImGuiFullscreen::MenuButtonFrame(text, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, &visible, - &hovered, &bb.Min, &bb.Max); - if (visible) - { - const float midpoint = bb.Min.y + UIStyle.LargeFontSize + LayoutScale(4.0f); - const ImRect title_bb(bb.Min, ImVec2(bb.Max.x, midpoint)); - - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, title_bb.Min, - title_bb.Max, text_color, text, nullptr, ImVec2(0, 0), 0.0f, &title_bb); - - if (!s_state.leaderboard_fetch_handle) - FetchNextLeaderboardEntries(); - } + ImGuiFullscreen::MenuButtonWithVisibilityQuery(text, {}, {}, &visible, false); + if (visible && !s_state.leaderboard_fetch_handle) + FetchNextLeaderboardEntries(); } ImGuiFullscreen::EndMenuButtons(); @@ -3451,18 +3411,15 @@ void Achievements::DrawLeaderboardEntry(const rc_client_leaderboard_entry_t& ent using ImGuiFullscreen::RenderShadowedTextClipped; using ImGuiFullscreen::UIStyle; - static constexpr float alpha = 0.8f; - ImRect bb; bool visible, hovered; bool pressed = - ImGuiFullscreen::MenuButtonFrame(entry.user, true, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, &visible, - &hovered, &bb.Min, &bb.Max, 0, alpha); + ImGuiFullscreen::MenuButtonFrame(entry.user, UIStyle.LargeFontSize, true, &bb, &visible, &hovered); if (!visible) return; const float midpoint = bb.Min.y + UIStyle.LargeFontSize + LayoutScale(4.0f); - float text_start_x = bb.Min.x + LayoutScale(15.0f); + float text_start_x = bb.Min.x; SmallString text; text.format("{}", entry.rank); @@ -3530,39 +3487,17 @@ void Achievements::DrawLeaderboardEntry(const rc_client_leaderboard_entry_t& ent void Achievements::DrawLeaderboardListEntry(const rc_client_leaderboard_t* lboard) { using ImGuiFullscreen::LayoutScale; - using ImGuiFullscreen::RenderShadowedTextClipped; + using ImGuiFullscreen::MenuButton; using ImGuiFullscreen::UIStyle; - static constexpr float alpha = 0.8f; - - TinyString id_str; - id_str.format("{}", lboard->id); - - ImRect bb; - bool visible, hovered; - bool pressed = ImGuiFullscreen::MenuButtonFrame(id_str, true, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT, &visible, - &hovered, &bb.Min, &bb.Max, 0, alpha); - if (!visible) - return; - - const float midpoint = bb.Min.y + UIStyle.LargeFontSize + LayoutScale(4.0f); - const float text_start_x = bb.Min.x + LayoutScale(15.0f); - const ImRect title_bb(ImVec2(text_start_x, bb.Min.y), ImVec2(bb.Max.x, midpoint)); - const ImRect summary_bb(ImVec2(text_start_x, midpoint), bb.Max); - - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, title_bb.Min, title_bb.Max, - ImGui::GetColorU32(ImGuiCol_Text), lboard->title, nullptr, ImVec2(0.0f, 0.0f), 0.0f, - &title_bb); + SmallString title; + title.format("{}##{}", lboard->title, lboard->id); + std::string_view summary; if (lboard->description && lboard->description[0] != '\0') - { - RenderShadowedTextClipped(UIStyle.Font, UIStyle.MediumFontSize, UIStyle.NormalFontWeight, summary_bb.Min, - summary_bb.Max, - ImGui::GetColorU32(ImGuiFullscreen::DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text])), - lboard->description, nullptr, ImVec2(0.0f, 0.0f), 0.0f, &summary_bb); - } + summary = lboard->description; - if (pressed) + if (MenuButton(title, summary)) FullscreenUI::BeginTransition([id = lboard->id]() { OpenLeaderboardById(id); }); } diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index 534010963..46e84f7ab 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -2474,21 +2474,9 @@ void FullscreenUI::DrawInputBindingButton(SettingsInterface* bsi, InputBindingIn if (type == InputBindingInfo::Type::Pointer || type == InputBindingInfo::Type::RelativePointer) return; - TinyString title; - title.format("{}/{}", section, name); - + SmallString title; SmallString value = bsi->GetSmallStringValue(section, name); const bool oneline = value.count('&') <= 1; - - ImRect bb; - bool visible, hovered, clicked; - clicked = MenuButtonFrame(title, true, - oneline ? ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY : - ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT, - &visible, &hovered, &bb.Min, &bb.Max); - if (!visible) - return; - if (oneline && type != InputBindingInfo::Type::Pointer && type != InputBindingInfo::Type::Device) InputManager::PrettifyInputBinding(value, &ImGuiFullscreen::GetControllerIconMapping); @@ -2524,38 +2512,24 @@ void FullscreenUI::DrawInputBindingButton(SettingsInterface* bsi, InputBindingIn } } } + else + { + title = display_name; + } - const float midpoint = bb.Min.y + UIStyle.LargeFontSize + LayoutScale(4.0f); + title.append_format("##{}/{}", section, name); + bool clicked; if (oneline) { if (value.empty()) value.assign(FSUI_VSTR("-")); - const ImVec2 value_size = UIStyle.Font->CalcTextSizeA(UIStyle.LargeFontSize, UIStyle.BoldFontWeight, - bb.Max.x - bb.Min.x, 0.0f, IMSTR_START_END(value)); - const float text_end = bb.Max.x - value_size.x; - const ImRect title_bb(bb.Min, ImVec2(text_end, midpoint)); - - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, title_bb.Min, title_bb.Max, - ImGui::GetColorU32(ImGuiCol_Text), show_type ? title.view() : display_name, nullptr, - ImVec2(0.0f, 0.0f), 0.0f, &title_bb); - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, bb.Min, bb.Max, - ImGui::GetColorU32(ImGuiCol_Text), value.empty() ? FSUI_VSTR("-") : value.view(), - &value_size, ImVec2(1.0f, 0.5f), 0.0f, &bb); + clicked = MenuButtonWithValue(title, {}, value); } else { - const ImRect title_bb(bb.Min, ImVec2(bb.Max.x, midpoint)); - const ImRect summary_bb(ImVec2(bb.Min.x, midpoint), bb.Max); - - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, title_bb.Min, title_bb.Max, - ImGui::GetColorU32(ImGuiCol_Text), show_type ? title.view() : display_name, nullptr, - ImVec2(0.0f, 0.0f), 0.0f, &title_bb); - RenderShadowedTextClipped(UIStyle.Font, UIStyle.MediumFontSize, UIStyle.NormalFontWeight, summary_bb.Min, - summary_bb.Max, ImGui::GetColorU32(DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text])), - value.empty() ? FSUI_VSTR("No Binding") : value.view(), nullptr, ImVec2(0.0f, 0.0f), 0.0f, - &summary_bb); + clicked = MenuButton(title, value); } if (clicked) @@ -3083,9 +3057,7 @@ void FullscreenUI::DrawFloatSpinBoxSetting(SettingsInterface* bsi, std::string_v ImVec2 button_pos(ImGui::GetCursorPos()); // Align value text in middle. - ImGui::SetCursorPosY( - button_pos.y + - ((LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY) + padding.y * 2.0f) - UIStyle.LargeFontSize) * 0.5f); + ImGui::SetCursorPosY(button_pos.y + padding.y); ImGui::TextUnformatted(str_value); float step = 0; @@ -3114,7 +3086,7 @@ void FullscreenUI::DrawFloatSpinBoxSetting(SettingsInterface* bsi, std::string_v dlg_value_changed = true; } - ImGui::SetCursorPosY(button_pos.y + (padding.y * 2.0f) + LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + 10.0f)); + ImGui::SetCursorPosY(button_pos.y + (padding.y * 2.0f) + UIStyle.LargeFontSize + LayoutScale(10.0f)); } if (dlg_value_changed) @@ -3836,8 +3808,6 @@ void FullscreenUI::DrawSettingsWindow() ImVec2(0.0f, 0.0f), heading_size, "settings_category", ImVec4(UIStyle.PrimaryColor.x, UIStyle.PrimaryColor.y, UIStyle.PrimaryColor.z, s_state.settings_last_bg_alpha))) { - static constexpr float ITEM_WIDTH = 25.0f; - static constexpr const SettingsPage global_pages[] = { SettingsPage::Interface, SettingsPage::GameList, SettingsPage::Console, SettingsPage::Emulation, SettingsPage::BIOS, SettingsPage::Graphics, SettingsPage::PostProcessing, SettingsPage::Audio, @@ -3910,12 +3880,11 @@ void FullscreenUI::DrawSettingsWindow() std::string_view(s_state.game_settings_entry->title) : Host::TranslateToStringView(TR_CONTEXT, titles[static_cast(pages[index])].first)); - RightAlignNavButtons(count, ITEM_WIDTH, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); + RightAlignNavButtons(count); for (u32 i = 0; i < count; i++) { - if (NavButton(titles[static_cast(pages[i])].second, i == index, true, ITEM_WIDTH, - LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY)) + if (NavButton(titles[static_cast(pages[i])].second, i == index, true)) { BeginTransition([page = pages[i]]() { s_state.settings_page = page; @@ -7750,7 +7719,6 @@ void FullscreenUI::DrawGameListWindow() if (BeginFullscreenWindow(ImVec2(0.0f, 0.0f), heading_size, "gamelist_view", MulAlpha(UIStyle.PrimaryColor, GetBackgroundAlpha()))) { - static constexpr float ITEM_WIDTH = 25.0f; static constexpr const char* icons[] = {ICON_FA_BORDER_ALL, ICON_FA_LIST}; static constexpr const char* titles[] = {FSUI_NSTR("Game Grid"), FSUI_NSTR("Game List")}; static constexpr u32 count = static_cast(std::size(titles)); @@ -7761,12 +7729,11 @@ void FullscreenUI::DrawGameListWindow() BeginTransition([]() { SwitchToMainWindow(MainWindowType::Landing); }); NavTitle(Host::TranslateToStringView(TR_CONTEXT, titles[static_cast(s_state.game_list_view)])); - RightAlignNavButtons(count, ITEM_WIDTH, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); + RightAlignNavButtons(count); for (u32 i = 0; i < count; i++) { - if (NavButton(icons[i], static_cast(i) == s_state.game_list_view, true, ITEM_WIDTH, - LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY)) + if (NavButton(icons[i], static_cast(i) == s_state.game_list_view, true)) { BeginTransition([]() { s_state.game_list_view = @@ -7863,7 +7830,8 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size) if (BeginFullscreenColumnWindow(0.0f, -530.0f, "game_list_entries", GetTransparentBackgroundColor(), ImVec2(LAYOUT_MENU_WINDOW_X_PADDING, LAYOUT_MENU_WINDOW_Y_PADDING))) { - const ImVec2 image_size(LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT, LAYOUT_MENU_BUTTON_HEIGHT)); + const float row_height = 50.0f; + const ImVec2 image_size(LayoutScale(row_height, row_height)); ResetFocusHere(); @@ -7877,8 +7845,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size) { ImRect bb; bool visible, hovered; - bool pressed = - MenuButtonFrame(entry->path.c_str(), true, LAYOUT_MENU_BUTTON_HEIGHT, &visible, &hovered, &bb.Min, &bb.Max); + bool pressed = MenuButtonFrame(entry->path.c_str(), LayoutScale(row_height), true, &bb, &visible, &hovered); if (!visible) continue; diff --git a/src/util/imgui_fullscreen.cpp b/src/util/imgui_fullscreen.cpp index 3e8f73001..79589a601 100644 --- a/src/util/imgui_fullscreen.cpp +++ b/src/util/imgui_fullscreen.cpp @@ -42,8 +42,6 @@ namespace ImGuiFullscreen { static constexpr float MENU_BACKGROUND_ANIMATION_TIME = 0.5f; static constexpr float MENU_ITEM_BORDER_ROUNDING = 10.0f; -static constexpr float MENU_ITEM_TITLE_SUMMARY_SPACING = 6.0f; -static constexpr float MENU_ITEM_EXTRA_HEIGHT = 2.0f; static constexpr float SMOOTH_SCROLLING_SPEED = 3.5f; static std::optional LoadTextureImage(std::string_view path, u32 svg_width, u32 svg_height); @@ -54,8 +52,6 @@ static void DrawLoadingScreen(std::string_view image, std::string_view message, s32 progress_value, bool is_persistent); static void DrawNotifications(ImVec2& position, float spacing); static void DrawToast(); -static bool MenuButtonFrame(std::string_view str_id, bool enabled, float height, bool* visible, bool* hovered, - ImRect* bb, ImGuiButtonFlags flags = 0, float hover_alpha = 1.0f); static bool MenuButtonFrame(std::string_view str_id, bool enabled, const ImRect& bb, bool* visible, bool* hovered, ImGuiButtonFlags flags = 0, float hover_alpha = 1.0f); static ImGuiID GetBackgroundProgressID(std::string_view str_id); @@ -115,6 +111,7 @@ struct MenuButtonBounds static float CalcAvailWidth(); static float GetSingleLineHeight(float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING); + static float GetSummaryLineHeight(float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING); void CalcBB(); void CalcTitleSize(const std::string_view& title); @@ -845,7 +842,9 @@ void ImGuiFullscreen::PushResetLayout() ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, LayoutScale(10.0f)); ImGui::PushStyleVar(ImGuiStyleVar_TabRounding, LayoutScale(4.0f)); ImGui::PushStyleVar(ImGuiStyleVar_ScrollSmooth, UIStyle.SmoothScrolling ? SMOOTH_SCROLLING_SPEED : 1.0f); - ImGui::PushStyleVar(ImGuiStyleVar_ScrollStepSize, LayoutScale(LAYOUT_LARGE_FONT_SIZE, LAYOUT_MENU_BUTTON_HEIGHT)); + ImGui::PushStyleVar( + ImGuiStyleVar_ScrollStepSize, + ImVec2(LayoutScale(LAYOUT_LARGE_FONT_SIZE), MenuButtonBounds::GetSingleLineHeight(LAYOUT_MENU_BUTTON_Y_PADDING))); ImGui::PushStyleColor(ImGuiCol_Text, UIStyle.SecondaryTextColor); ImGui::PushStyleColor(ImGuiCol_TextDisabled, UIStyle.DisabledColor); ImGui::PushStyleColor(ImGuiCol_Button, UIStyle.SecondaryColor); @@ -1359,6 +1358,44 @@ void ImGuiFullscreen::EndMenuButtons() ImGui::PopStyleVar(4); } +float ImGuiFullscreen::GetMenuButtonAvailableWidth() +{ + return MenuButtonBounds::CalcAvailWidth(); +} + +bool ImGuiFullscreen::IsNextMenuButtonClipped(std::string_view str_id, bool has_summary, + float y_padding /*= LAYOUT_MENU_BUTTON_Y_PADDING*/) +{ + ImGuiWindow* window = ImGui::GetCurrentWindow(); + const ImGuiID id = window->GetID(IMSTR_START_END(str_id)); + const ImGuiStyle& style = ImGui::GetStyle(); + const ImVec2 guessed_pos = window->DC.CursorPos; + const ImRect gussed_bb = + ImRect(guessed_pos, guessed_pos + ImVec2(style.FramePadding.x * 2.0f, + style.FramePadding.y * 2.0f + + (has_summary ? MenuButtonBounds::GetSummaryLineHeight(y_padding) : + MenuButtonBounds::GetSingleLineHeight(y_padding)))); + if (!ImGui::IsClippedEx(gussed_bb, id)) + return false; + + // still record it + ImGui::ItemSize(gussed_bb.GetSize()); + return ImGui::ItemAdd(gussed_bb, id); +} + +bool ImGuiFullscreen::MenuButtonFrame(std::string_view str_id, float height, bool enabled, ImRect* item_bb, + bool* visible, bool* hovered, ImGuiButtonFlags flags /*= 0*/, + float alpha /*= 1.0f*/) +{ + const ImVec2 pos = ImGui::GetCursorScreenPos(); + const float avail_width = MenuButtonBounds::CalcAvailWidth(); + const ImGuiStyle& style = ImGui::GetStyle(); + + *item_bb = ImRect(pos + style.FramePadding, pos + style.FramePadding + ImVec2(avail_width, height)); + const ImRect frame_bb = ImRect(pos, pos + style.FramePadding * 2.0f + ImVec2(avail_width, height)); + return MenuButtonFrame(str_id, enabled, frame_bb, visible, hovered, 0, alpha); +} + void ImGuiFullscreen::DrawWindowTitle(std::string_view title) { ImGuiWindow* window = ImGui::GetCurrentWindow(); @@ -1449,22 +1486,6 @@ bool ImGuiFullscreen::MenuButtonFrame(std::string_view str_id, bool enabled, con return pressed; } -bool ImGuiFullscreen::MenuButtonFrame(std::string_view str_id, bool enabled, float height, bool* visible, bool* hovered, - ImRect* bb, ImGuiButtonFlags flags, float hover_alpha) -{ - ImVec2 pos, size; - GetMenuButtonFrameBounds(height, &pos, &size); - *bb = ImRect(pos, pos + size); - - const bool pressed = MenuButtonFrame(str_id, enabled, *bb, visible, hovered, flags, hover_alpha); - - const ImGuiStyle& style = ImGui::GetStyle(); - bb->Min += style.FramePadding; - bb->Max -= style.FramePadding; - - return pressed; -} - void ImGuiFullscreen::DrawMenuButtonFrame(const ImVec2& p_min, const ImVec2& p_max, ImU32 fill_col, bool border /* = true */) { @@ -1507,17 +1528,6 @@ void ImGuiFullscreen::DrawMenuButtonFrame(const ImVec2& p_min, const ImVec2& p_m } } -bool ImGuiFullscreen::MenuButtonFrame(std::string_view str_id, bool enabled, float height, bool* visible, bool* hovered, - ImVec2* min, ImVec2* max, ImGuiButtonFlags flags /*= 0*/, - float hover_alpha /*= 0*/) -{ - ImRect bb; - const bool result = MenuButtonFrame(str_id, enabled, height, visible, hovered, &bb, flags, hover_alpha); - *min = bb.Min; - *max = bb.Max; - return result; -} - float ImGuiFullscreen::MenuButtonBounds::CalcAvailWidth() { return ImGui::GetCurrentWindowRead()->WorkRect.GetWidth() - ImGui::GetStyle().FramePadding.x * 2.0f; @@ -1581,10 +1591,10 @@ void ImGuiFullscreen::MenuButtonBounds::CalcBB() // give the frame a bit of a chin, because otherwise it's too cramped const ImVec2& padding = ImGui::GetStyle().FramePadding; const ImVec2 pos = ImGui::GetCurrentWindowRead()->DC.CursorPos + padding; - const float summary_spacing = LayoutScale(MENU_ITEM_TITLE_SUMMARY_SPACING); + const float summary_spacing = LayoutScale(LAYOUT_MENU_ITEM_TITLE_SUMMARY_SPACING); const float content_height = std::max(title_size.y, value_size.y) + - ((summary_size.x > 0.0f) ? (summary_size.y + LayoutScale(MENU_ITEM_EXTRA_HEIGHT) + summary_spacing) : 0.0f); + ((summary_size.x > 0.0f) ? (summary_size.y + LayoutScale(LAYOUT_MENU_ITEM_EXTRA_HEIGHT) + summary_spacing) : 0.0f); const ImVec2 br_pos = pos + ImVec2(available_width, content_height); frame_bb = ImRect(pos - padding, br_pos + padding); @@ -1605,6 +1615,12 @@ float ImGuiFullscreen::MenuButtonBounds::GetSingleLineHeight(float padding) return (LayoutScale(padding) * 2.0f) + UIStyle.LargeFontSize; } +float ImGuiFullscreen::MenuButtonBounds::GetSummaryLineHeight(float y_padding) +{ + return GetSingleLineHeight(y_padding) + LayoutScale(LAYOUT_MENU_ITEM_TITLE_SUMMARY_SPACING) + UIStyle.MediumFontSize + + LayoutScale(LAYOUT_MENU_ITEM_EXTRA_HEIGHT); +} + void ImGuiFullscreen::ResetMenuButtonFrame() { s_state.had_hovered_menu_item = false; @@ -1785,19 +1801,20 @@ void ImGuiFullscreen::MenuHeading(std::string_view title, bool draw_line /*= tru const float line_thickness = draw_line ? LayoutScale(1.0f) : 0.0f; const float line_padding = draw_line ? LayoutScale(5.0f) : 0.0f; + const MenuButtonBounds bb(title, ImVec2(), {}); bool visible, hovered; - ImRect bb; - MenuButtonFrame(title, false, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, &visible, &hovered, &bb); + MenuButtonFrame(title, false, bb.frame_bb, &visible, &hovered); if (!visible) return; - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, bb.Min, bb.Max, - ImGui::GetColorU32(ImGuiCol_TextDisabled), title, nullptr, ImVec2(0.0f, 0.0f), 0.0f, &bb); + RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, bb.title_bb.Min, + bb.title_bb.Max, ImGui::GetColorU32(ImGuiCol_TextDisabled), title, &bb.title_size, + ImVec2(0.0f, 0.0f), bb.title_size.x, &bb.title_bb); if (draw_line) { - const ImVec2 line_start(bb.Min.x, bb.Min.y + UIStyle.LargeFontSize + line_padding); - const ImVec2 line_end(bb.Max.x, line_start.y); + const ImVec2 line_start(bb.title_bb.Min.x, bb.title_bb.Max.y + line_padding); + const ImVec2 line_end(bb.title_bb.Min.x + bb.available_width, line_start.y); const ImVec2 shadow_offset = LayoutScale(LAYOUT_SHADOW_OFFSET, LAYOUT_SHADOW_OFFSET); ImGui::GetWindowDrawList()->AddLine(line_start + shadow_offset, line_end + shadow_offset, UIStyle.ShadowColor, line_thickness); @@ -1812,29 +1829,28 @@ bool ImGuiFullscreen::MenuHeadingButton(std::string_view title, std::string_view const float line_thickness = draw_line ? LayoutScale(1.0f) : 0.0f; const float line_padding = draw_line ? LayoutScale(5.0f) : 0.0f; - ImRect bb; + const MenuButtonBounds bb(title, value, {}); bool visible, hovered; - bool pressed = MenuButtonFrame(title, enabled, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, &visible, &hovered, &bb); + const bool pressed = MenuButtonFrame(title, false, bb.frame_bb, &visible, &hovered); if (!visible) return false; const u32 color = enabled ? ImGui::GetColorU32(ImGuiCol_Text) : ImGui::GetColorU32(ImGuiCol_TextDisabled); - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, bb.Min, bb.Max, color, title, - nullptr, ImVec2(0.0f, 0.0f), 0.0f, &bb); + RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, bb.title_bb.Min, + bb.title_bb.Max, color, title, &bb.title_size, ImVec2(0.0f, 0.0f), bb.title_size.x, + &bb.title_bb); if (!value.empty()) { - const ImVec2 value_size(UIStyle.Font->CalcTextSizeA( - UIStyle.LargeFontSize, UIStyle.BoldFontWeight, std::numeric_limits::max(), 0.0f, IMSTR_START_END(value))); - const ImRect value_bb(ImVec2(bb.Max.x - value_size.x, bb.Min.y), ImVec2(bb.Max.x, bb.Max.y)); - RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, value_bb.Min, value_bb.Max, - color, value, &value_size, ImVec2(0.0f, 0.0f), 0.0f, &value_bb); + RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, bb.value_bb.Min, + bb.value_bb.Max, color, value, &bb.value_size, ImVec2(0.0f, 0.0f), bb.value_size.x, + &bb.value_bb); } if (draw_line) { - const ImVec2 line_start(bb.Min.x, bb.Min.y + UIStyle.LargeFontSize + line_padding); - const ImVec2 line_end(bb.Max.x, line_start.y); + const ImVec2 line_start(bb.title_bb.Min.x, bb.title_bb.Max.y + line_padding); + const ImVec2 line_end(bb.title_bb.Min.x + bb.available_width, line_start.y); const ImVec2 shadow_offset = LayoutScale(LAYOUT_SHADOW_OFFSET, LAYOUT_SHADOW_OFFSET); ImGui::GetWindowDrawList()->AddLine(line_start + shadow_offset, line_end + shadow_offset, UIStyle.ShadowColor, line_thickness); @@ -1848,23 +1864,33 @@ bool ImGuiFullscreen::MenuHeadingButton(std::string_view title, std::string_view bool ImGuiFullscreen::MenuButton(std::string_view title, std::string_view summary, bool enabled /* = true */, const ImVec2& text_align /* = ImVec2(0.0f, 0.0f) */) { - return MenuButtonWithValue(title, summary, {}, enabled, text_align); + bool visible; + return MenuButtonWithVisibilityQuery(title, summary, {}, &visible, enabled, text_align); } bool ImGuiFullscreen::MenuButtonWithoutSummary(std::string_view title, bool enabled /* = true */, const ImVec2& text_align /* = ImVec2(0.0f, 0.0f) */) { - return MenuButtonWithValue(title, {}, {}, enabled, text_align); + bool visible; + return MenuButtonWithVisibilityQuery(title, {}, {}, &visible, enabled, text_align); } bool ImGuiFullscreen::MenuButtonWithValue(std::string_view title, std::string_view summary, std::string_view value, bool enabled /* = true*/, const ImVec2& text_align /* = ImVec2(0.0f, 0.0f)*/) +{ + bool visible; + return MenuButtonWithVisibilityQuery(title, summary, value, &visible, enabled, text_align); +} + +bool ImGuiFullscreen::MenuButtonWithVisibilityQuery(std::string_view title, std::string_view summary, + std::string_view value, bool* visible, bool enabled /* = true */, + const ImVec2& text_align /* = ImVec2(0.0f, 0.0f) */) { const MenuButtonBounds bb(title, value, summary); - bool visible, hovered; - bool pressed = MenuButtonFrame(title, enabled, bb.frame_bb, &visible, &hovered); - if (!visible) + bool hovered; + bool pressed = MenuButtonFrame(title, enabled, bb.frame_bb, visible, &hovered); + if (!*visible) return false; const ImVec4& color = ImGui::GetStyle().Colors[enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled]; @@ -2257,7 +2283,6 @@ bool ImGuiFullscreen::EnumChoiceButtonImpl(std::string_view title, std::string_v void ImGuiFullscreen::BeginHorizontalMenuButtons(u32 num_items, float max_item_width /* = 0.0f */, float x_padding /* = LAYOUT_MENU_BUTTON_Y_PADDING */, float y_padding /* = LAYOUT_MENU_BUTTON_Y_PADDING */, - float item_height /* = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY */, float x_spacing /* = LAYOUT_MENU_BUTTON_X_PADDING */, float x_margin /* = LAYOUT_MENU_WINDOW_X_PADDING */) { @@ -2277,8 +2302,7 @@ void ImGuiFullscreen::BeginHorizontalMenuButtons(u32 num_items, float max_item_w std::max((available_width - LayoutScale(x_margin) - (style.ItemSpacing.x * static_cast(num_items - 1))) / static_cast(num_items), 0.0f)); - s_state.horizontal_menu_button_size = - ImVec2(space_per_item, LayoutScale(item_height) + (style.FramePadding.y * 2.0f)); + s_state.horizontal_menu_button_size = ImVec2(space_per_item, MenuButtonBounds::GetSingleLineHeight(y_padding)); s_state.horizontal_menu_button_size.x = (max_item_width > 0.0f) ? std::min(s_state.horizontal_menu_button_size.x, LayoutScale(max_item_width) + (style.FramePadding.x * 2.0f)) : @@ -2391,7 +2415,7 @@ void ImGuiFullscreen::EndNavBar() ImGui::PopStyleVar(4); } -void ImGuiFullscreen::NavTitle(std::string_view title, float height /* = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY */) +void ImGuiFullscreen::NavTitle(std::string_view title) { ImGuiWindow* window = ImGui::GetCurrentWindow(); if (window->SkipItems) @@ -2403,7 +2427,7 @@ void ImGuiFullscreen::NavTitle(std::string_view title, float height /* = LAYOUT_ std::numeric_limits::max(), 0.0f, IMSTR_START_END(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); + const ImVec2 size = ImVec2(text_size.x, 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)); @@ -2420,21 +2444,18 @@ void ImGuiFullscreen::NavTitle(std::string_view title, float height /* = LAYOUT_ ImGui::GetColorU32(ImGuiCol_Text), title, &text_size, ImVec2(0.0f, 0.0f), 0.0f, &bb); } -void ImGuiFullscreen::RightAlignNavButtons(u32 num_items /*= 0*/, - float item_width /*= LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY*/, - float item_height /*= LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY*/) +void ImGuiFullscreen::RightAlignNavButtons(u32 num_items /*= 0*/) { ImGuiWindow* window = ImGui::GetCurrentWindow(); 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 total_item_width = style.FramePadding.x * 2.0f + style.FrameBorderSize + style.ItemSpacing.x + + LayoutScale(LAYOUT_LARGE_FONT_SIZE - 1.0f); const float margin = total_item_width * static_cast(num_items); ImGui::SetCursorPosX(window->InnerClipRect.Max.x - margin - style.FramePadding.x); } -bool ImGuiFullscreen::NavButton(std::string_view title, bool is_active, bool enabled /* = true */, - float width /* = -1.0f */, float height /* = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY */) +bool ImGuiFullscreen::NavButton(std::string_view title, bool is_active, bool enabled /* = true */) { ImGuiWindow* window = ImGui::GetCurrentWindow(); if (window->SkipItems) @@ -2446,8 +2467,8 @@ bool ImGuiFullscreen::NavButton(std::string_view title, bool is_active, bool ena std::numeric_limits::max(), 0.0f, IMSTR_START_END(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); + const ImVec2 size = ImVec2(LayoutScale(LAYOUT_LARGE_FONT_SIZE - 1.0f) + 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)); @@ -2498,22 +2519,23 @@ bool ImGuiFullscreen::NavButton(std::string_view title, bool is_active, bool ena return pressed; } -bool ImGuiFullscreen::NavTab(std::string_view title, bool is_active, bool enabled, float width, float height, - const ImVec4& background) +bool ImGuiFullscreen::NavTab(std::string_view title, bool is_active, bool enabled, float width) { - ImGuiWindow* window = ImGui::GetCurrentWindow(); + ImGuiWindow* const window = ImGui::GetCurrentWindow(); if (window->SkipItems) return false; s_state.menu_button_index++; - const ImVec2 text_size(UIStyle.Font->CalcTextSizeA(UIStyle.LargeFontSize, UIStyle.BoldFontWeight, - std::numeric_limits::max(), 0.0f, IMSTR_START_END(title))); - const ImVec2 pos(window->DC.CursorPos); - const ImVec2 size = ImVec2(((width < 0.0f) ? text_size.x : LayoutScale(width)), LayoutScale(height)); + const ImVec2 text_size = UIStyle.Font->CalcTextSizeA(UIStyle.LargeFontSize, UIStyle.BoldFontWeight, + std::numeric_limits::max(), 0.0f, IMSTR_START_END(title)); + + const ImGuiStyle& style = ImGui::GetStyle(); + const ImVec2 pos = window->DC.CursorPos; + const ImVec2 size = ImVec2(((width < 0.0f) ? text_size.x : width), text_size.y) + (style.FramePadding * 2.0f); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); - ImGui::ItemSize(ImVec2(size.x, size.y)); + ImGui::ItemSize(size); ImGui::SameLine(); ImGui::PopStyleVar(); @@ -2546,19 +2568,11 @@ bool ImGuiFullscreen::NavTab(std::string_view title, bool is_active, bool enable hovered = false; } - const ImU32 col = - hovered ? ImGui::GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered, 1.0f) : - ImGui::GetColorU32(is_active ? background : ImVec4(background.x, background.y, background.z, 0.5f)); - - if (hovered) - DrawMenuButtonFrame(bb.Min, bb.Max, col, true); - - if (is_active) + if (is_active || hovered) { - const float line_thickness = LayoutScale(2.0f); - ImGui::GetWindowDrawList()->AddLine(ImVec2(bb.Min.x, bb.Max.y - line_thickness), - ImVec2(bb.Max.x, bb.Max.y - line_thickness), - ImGui::GetColorU32(ImGuiCol_TextDisabled), line_thickness); + const ImU32 col = hovered ? ImGui::GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered, 1.0f) : + ImGui::GetColorU32(DarkerColor(style.Colors[ImGuiCol_ButtonHovered])); + ImGui::RenderFrame(bb.Min, bb.Max, col, true, LayoutScale(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)); diff --git a/src/util/imgui_fullscreen.h b/src/util/imgui_fullscreen.h index 30f40806a..6d6b7d7dd 100644 --- a/src/util/imgui_fullscreen.h +++ b/src/util/imgui_fullscreen.h @@ -43,6 +43,8 @@ static constexpr float LAYOUT_MENU_BUTTON_Y_PADDING = 10.0f; static constexpr float LAYOUT_MENU_BUTTON_SPACING = 6.0f; static constexpr float LAYOUT_MENU_WINDOW_X_PADDING = 12.0f; static constexpr float LAYOUT_MENU_WINDOW_Y_PADDING = 12.0f; +static constexpr float LAYOUT_MENU_ITEM_TITLE_SUMMARY_SPACING = 6.0f; +static constexpr float LAYOUT_MENU_ITEM_EXTRA_HEIGHT = 2.0f; static constexpr float LAYOUT_FOOTER_PADDING = 10.0f; static constexpr float LAYOUT_FOOTER_HEIGHT = LAYOUT_MEDIUM_FONT_SIZE + LAYOUT_FOOTER_PADDING * 2.0f; static constexpr float LAYOUT_HORIZONTAL_MENU_HEIGHT = 320.0f; @@ -278,9 +280,11 @@ void BeginMenuButtons(u32 num_items = 0, float y_align = 0.0f, float x_padding = float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING, float x_spacing = 0.0f, float y_spacing = LAYOUT_MENU_BUTTON_SPACING, bool prerender_frame = true); void EndMenuButtons(); +float GetMenuButtonAvailableWidth(); +bool IsNextMenuButtonClipped(std::string_view str_id, bool has_summary, float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING); void GetMenuButtonFrameBounds(float height, ImVec2* pos, ImVec2* size); -bool MenuButtonFrame(std::string_view str_id, bool enabled, float height, bool* visible, bool* hovered, ImVec2* min, - ImVec2* max, ImGuiButtonFlags flags = 0, float hover_alpha = 1.0f); +bool MenuButtonFrame(std::string_view str_id, float height, bool enabled, ImRect* item_bb, bool* visible, bool* hovered, + ImGuiButtonFlags flags = 0, float alpha = 1.0f); void DrawMenuButtonFrame(const ImVec2& p_min, const ImVec2& p_max, ImU32 fill_col, bool border = true); void ResetMenuButtonFrame(); void RenderShadowedTextClipped(ImFont* font, float font_size, float font_weight, const ImVec2& pos_min, @@ -304,6 +308,8 @@ bool MenuButtonWithoutSummary(std::string_view title, bool enabled = true, const ImVec2& text_align = ImVec2(0.0f, 0.0f)); bool MenuButtonWithValue(std::string_view title, std::string_view summary, std::string_view value, bool enabled = true, const ImVec2& text_align = ImVec2(0.0f, 0.0f)); +bool MenuButtonWithVisibilityQuery(std::string_view title, std::string_view summary, std::string_view value, + bool* visible, bool enabled = true, const ImVec2& text_align = ImVec2(0.0f, 0.0f)); bool MenuImageButton(std::string_view title, std::string_view summary, ImTextureID user_texture_id, const ImVec2& image_size, bool enabled = true, const ImVec2& uv0 = ImVec2(0.0f, 0.0f), const ImVec2& uv1 = ImVec2(1.0f, 1.0f)); @@ -345,7 +351,6 @@ ALWAYS_INLINE static bool EnumChoiceButton(std::string_view title, std::string_v void BeginHorizontalMenuButtons(u32 num_items, float max_item_width = 0.0f, float x_padding = LAYOUT_MENU_BUTTON_Y_PADDING, float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING, - float item_height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, float x_spacing = LAYOUT_MENU_BUTTON_X_PADDING, float x_margin = LAYOUT_MENU_WINDOW_X_PADDING); void EndHorizontalMenuButtons(); @@ -354,12 +359,10 @@ 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 EndNavBar(); -void NavTitle(std::string_view title, float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); -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(std::string_view title, bool is_active, bool enabled = true, float width = -1.0f, - float height = LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); -bool NavTab(std::string_view title, bool is_active, bool enabled, float width, float height, const ImVec4& background); +void NavTitle(std::string_view title); +void RightAlignNavButtons(u32 num_items = 0); +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 BeginHorizontalMenu(const char* name, const ImVec2& position, const ImVec2& size, const ImVec4& bg_color, u32 num_items);