From 875a0f0765d7eb4b3d4cc4dd8cbef25a20d30b5f Mon Sep 17 00:00:00 2001 From: bicarus <202771338+bicarus-dev@users.noreply.github.com> Date: Fri, 30 Jan 2026 19:17:44 -0800 Subject: [PATCH] overlay: address small polish issues (#543) * Make a custom widget for truncated text that shows a tooltip only when truncated * Use the above widget more consistently in various places * Ensure tooltips still show even when the preceding widget is disabled --- src/spice2x/overlay/imgui/extensions.cpp | 16 +++- src/spice2x/overlay/imgui/extensions.h | 2 +- src/spice2x/overlay/windows/config.cpp | 77 ++++++------------- src/spice2x/overlay/windows/patch_manager.cpp | 10 +-- 4 files changed, 45 insertions(+), 60 deletions(-) diff --git a/src/spice2x/overlay/imgui/extensions.cpp b/src/spice2x/overlay/imgui/extensions.cpp index 14bf04c..42eb2b0 100644 --- a/src/spice2x/overlay/imgui/extensions.cpp +++ b/src/spice2x/overlay/imgui/extensions.cpp @@ -93,14 +93,14 @@ namespace ImGui { thickness); } - - std::string TruncateText(const std::string& p_text, float p_truncated_width) { + std::string TruncateText(const std::string& p_text, float p_truncated_width, bool &truncated) { std::string truncated_text = p_text; const float text_width = ImGui::CalcTextSize(p_text.c_str(), nullptr, true).x; if (text_width > p_truncated_width) { + truncated = true; constexpr const char* ELLIPSIS = " ..."; const float ellipsis_size = ImGui::CalcTextSize(ELLIPSIS).x; @@ -122,6 +122,18 @@ namespace ImGui { return truncated_text; } + void TextTruncated(const std::string& p_text, float p_truncated_width) { + if (p_text.empty()) { + ImGui::TextDisabled("-"); + return; + } + bool truncated = false; + ImGui::TextUnformatted(TruncateText(p_text, p_truncated_width, truncated).c_str()); + if (truncated && ImGui::IsItemHovered()) { + ImGui::HelpTooltip(p_text.c_str()); + } + } + bool AddButton(const std::string& tooltip) { ImGui::PushID(tooltip.c_str()); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.1f, 0.6f, 0.1f, 0.3f)); diff --git a/src/spice2x/overlay/imgui/extensions.h b/src/spice2x/overlay/imgui/extensions.h index c879269..265d4d2 100644 --- a/src/spice2x/overlay/imgui/extensions.h +++ b/src/spice2x/overlay/imgui/extensions.h @@ -13,7 +13,7 @@ namespace ImGui { void Knob(float fraction, float size, float thickness = 2.f, float pos_x = -1.f, float pos_y = -1.f); - std::string TruncateText(const std::string& p_text, float p_truncated_width); + void TextTruncated(const std::string& p_text, float p_truncated_width); bool AddButton(const std::string& tooltip); bool DeleteButton(const std::string& tooltip); bool ClearButton(const std::string& tooltip); diff --git a/src/spice2x/overlay/windows/config.cpp b/src/spice2x/overlay/windows/config.cpp index 61008e6..f0cb2e7 100644 --- a/src/spice2x/overlay/windows/config.cpp +++ b/src/spice2x/overlay/windows/config.cpp @@ -294,8 +294,9 @@ namespace overlay::windows { buttons_many_index = -1; buttons_many_delay = 0; } - ImGui::SameLine(); - ImGui::HelpMarker("Immediately query for the next button after binding one."); + if (ImGui::IsItemHovered()) { + ImGui::HelpTooltip("Immediately query for the next button after binding one."); + } ImGui::EndTabItem(); } @@ -641,7 +642,7 @@ namespace overlay::windows { if (button_state) { ImGui::PushStyleColor(ImGuiCol_Text, TEXT_COLOR_GREEN); } - ImGui::TextUnformatted(button_name.c_str()); + ImGui::TextTruncated(button_name, ImGui::GetContentRegionAvail().x - overlay::apply_scaling(20)); if (button_state) { ImGui::PopStyleColor(); } @@ -650,23 +651,13 @@ namespace overlay::windows { // column for key binding display ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); - if (button_display.size() > 0) { - if (button_state) { - ImGui::PushStyleColor(ImGuiCol_Text, TEXT_COLOR_GREEN); - } - std::string button_text = ImGui::TruncateText( - button_display, ImGui::GetContentRegionAvail().x - overlay::apply_scaling(20)); - ImGui::TextUnformatted(button_text.c_str()); - if (button_state) { - ImGui::PopStyleColor(); - } - if (ImGui::IsItemHovered()) { - ImGui::SameLine(); - ImGui::HelpTooltip(button_display.c_str()); - } - } else { - // placeholder - ImGui::TextDisabled("-"); + if (button_state) { + ImGui::PushStyleColor(ImGuiCol_Text, TEXT_COLOR_GREEN); + } + ImGui::TextTruncated( + button_display, ImGui::GetContentRegionAvail().x - overlay::apply_scaling(20)); + if (button_state) { + ImGui::PopStyleColor(); } // clear button @@ -1759,21 +1750,13 @@ namespace overlay::windows { if (analog_display.empty()) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.7f, 0.7f, 0.7f, 1.f)); } - ImGui::TextUnformatted(analog_name.c_str()); + ImGui::TextTruncated( + analog_name, ImGui::GetContentRegionAvail().x - overlay::apply_scaling(20)); ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); - if (analog_display.size() > 0) { - std::string analog_text = ImGui::TruncateText( - analog_display, ImGui::GetContentRegionAvail().x - overlay::apply_scaling(20)); - ImGui::TextUnformatted(analog_text.c_str()); - if (ImGui::IsItemHovered()) { - ImGui::SameLine(); - ImGui::HelpTooltip(analog_display.c_str()); - } - } else { - ImGui::TextDisabled("-"); - } + ImGui::TextTruncated( + analog_display, ImGui::GetContentRegionAvail().x - overlay::apply_scaling(20)); // clear analog if (analog_display.size() > 0) { @@ -2230,22 +2213,13 @@ namespace overlay::windows { ImGui::TableNextColumn(); ImGui::ProgressBar(light_state, ImVec2(32.f, 0)); ImGui::SameLine(); - ImGui::TextUnformatted(light_name.c_str()); + ImGui::TextTruncated(light_name, ImGui::GetContentRegionAvail().x - overlay::apply_scaling(20)); // binding name ImGui::TableNextColumn(); ImGui::AlignTextToFramePadding(); - if (light_display.size() > 0) { - std::string light_text = ImGui::TruncateText( - light_display, ImGui::GetContentRegionAvail().x - overlay::apply_scaling(20)); - ImGui::TextUnformatted(light_text.c_str()); - if (ImGui::IsItemHovered()) { - ImGui::SameLine(); - ImGui::HelpTooltip(light_display.c_str()); - } - } else { - ImGui::TextDisabled("-"); - } + ImGui::TextTruncated( + light_display, ImGui::GetContentRegionAvail().x - overlay::apply_scaling(20)); // clear light if (light_display.size() > 0) { @@ -2828,7 +2802,7 @@ namespace overlay::windows { ImGui::TextUnformatted(definition.title.c_str()); } ImGui::Unindent(INDENT); - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { ImGui::HelpTooltip(definition.desc.c_str()); } @@ -2842,7 +2816,7 @@ namespace overlay::windows { param += definition.display_name; } ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.f), "%s", param.c_str()); - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { const auto help = param + "\n\nClick to copy the parameter to the clipboard.\n\n" @@ -2850,7 +2824,6 @@ namespace overlay::windows { "Example: spice.exe -w -ea\n" " spice64.exe -api 1337 -apipass changeme"; ImGui::HelpTooltip(help.c_str()); - } if (ImGui::IsItemClicked()) { clipboard::copy_text(param.c_str()); @@ -2871,7 +2844,7 @@ namespace overlay::windows { option.value = state ? "/ENABLED" : ""; ::Config::getInstance().updateBinding(games_list[games_selected], option); } - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { ImGui::HelpTooltip(definition.desc.c_str()); } break; @@ -2900,7 +2873,7 @@ namespace overlay::windows { option.value = buffer; ::Config::getInstance().updateBinding(games_list[games_selected], option); } - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { ImGui::HelpTooltip(definition.desc.c_str()); } break; @@ -2936,7 +2909,7 @@ namespace overlay::windows { option.value = buffer; ::Config::getInstance().updateBinding(games_list[games_selected], option); } - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { ImGui::HelpTooltip(definition.desc.c_str()); } break; @@ -2956,7 +2929,7 @@ namespace overlay::windows { option.value = buffer; ::Config::getInstance().updateBinding(games_list[games_selected], option); } - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { ImGui::HelpTooltip(definition.desc.c_str()); } break; @@ -2993,7 +2966,7 @@ namespace overlay::windows { } ImGui::EndCombo(); } - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { ImGui::HelpTooltip(definition.desc.c_str()); } break; diff --git a/src/spice2x/overlay/windows/patch_manager.cpp b/src/spice2x/overlay/windows/patch_manager.cpp index e22247f..9151163 100644 --- a/src/spice2x/overlay/windows/patch_manager.cpp +++ b/src/spice2x/overlay/windows/patch_manager.cpp @@ -721,7 +721,7 @@ namespace overlay::windows { if (style_color_pushed) { ImGui::PopStyleColor(style_color_pushed); } - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { show_patch_tooltip(patch); } @@ -762,7 +762,7 @@ namespace overlay::windows { patch.last_status = is_patch_active(patch); } ImGui::EndDisabled(); - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { show_patch_tooltip(patch); } @@ -791,7 +791,7 @@ namespace overlay::windows { } ImGui::EndCombo(); } - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { show_patch_tooltip(patch); } } else if (patch.type == PatchType::Integer) { @@ -807,7 +807,7 @@ namespace overlay::windows { apply_patch(patch, true); config_dirty = true; } - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { show_patch_tooltip(patch); } } @@ -824,7 +824,7 @@ namespace overlay::windows { ImGui::InputInt("##dummy_int_input", &patch.patch_number.value); } ImGui::EndDisabled(); - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { show_patch_tooltip(patch); } }