overlay: help tooltip updates (#279)

## Link to GitHub Issue, if one exists
n/a

## Description of change

In Options (and in Advanced/API/Search tabs), remove the help marker
`(?)` and instead add a tooltip to the option name label and the control
widgets like the checkbox, text input, and combo. This is to help with
discoverability as many users failed to discover the `(?)` widget.

Similarly, update the Patches tab to remove `(?)` and add tooltips to
widgets. Patches with warnings `(!)` will continue to show it to
distinguish it from other patches.

Update styling for the tooltip (dark red background -> dark gray) so
that it stands out from other widgets.

Remove the purple option text used for game-specific options.

## Compiling
👍 

## Testing
Tested in spicecfg, and in-game overlay.
This commit is contained in:
bicarus-dev
2025-03-28 20:34:58 -07:00
committed by GitHub
parent 104a9cbffd
commit 4f1ada7a2f
5 changed files with 97 additions and 35 deletions
+33 -8
View File
@@ -6,22 +6,37 @@
namespace ImGui {
void HelpMarker(const char* desc) {
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
const auto fg = ImVec4(0.910f, 0.914f, 0.922f, 1.0f);
const auto bg = ImVec4(0.192f, 0.212f, 0.220f, 1.0f);
void HelpTooltip(const char* desc) {
ImGui::PushStyleColor(ImGuiCol_Border, bg);
ImGui::PushStyleColor(ImGuiCol_BorderShadow, bg);
ImGui::PushStyleColor(ImGuiCol_PopupBg, bg);
ImGui::PushStyleColor(ImGuiCol_Text, fg);
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
ImGui::PopStyleColor(4);
}
void HelpMarker(const char* desc) {
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
HelpTooltip(desc);
}
}
void WarnMarker(const char* desc, const char* warn) {
ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImVec4(1.f, 1.f, 0.f, 1.f));
ImGui::TextDisabled("(!)");
ImGui::PopStyleColor();
if (ImGui::IsItemHovered()) {
void WarnTooltip(const char* desc, const char* warn) {
ImGui::PushStyleColor(ImGuiCol_Border, bg);
ImGui::PushStyleColor(ImGuiCol_BorderShadow, bg);
ImGui::PushStyleColor(ImGuiCol_PopupBg, bg);
ImGui::PushStyleColor(ImGuiCol_Text, fg);
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
if (desc) {
@@ -36,6 +51,16 @@ namespace ImGui {
ImGui::PopStyleColor();
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
ImGui::PopStyleColor(4);
}
void WarnMarker(const char* desc, const char* warn) {
ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImVec4(1.f, 1.f, 0.f, 1.f));
ImGui::TextDisabled("(!)");
ImGui::PopStyleColor();
if (ImGui::IsItemHovered()) {
WarnTooltip(desc, warn);
}
}
+2
View File
@@ -2,7 +2,9 @@
namespace ImGui {
void HelpTooltip(const char* desc);
void HelpMarker(const char* desc);
void WarnTooltip(const char* desc, const char* warn);
void WarnMarker(const char* desc, const char* warn);
void DummyMarker();
void Knob(float fraction, float size, float thickness = 2.f,
+23 -6
View File
@@ -2629,9 +2629,8 @@ namespace overlay::windows {
// list entry
ImGui::PushID(&option);
ImGui::AlignTextToFramePadding();
ImGui::HelpMarker(definition.desc.c_str());
ImGui::SameLine();
if (option.is_active()) {
// active option
if (option.disabled || definition.disabled) {
ImGui::TextColored(ImVec4(1.f, 0.4f, 0.f, 1.f), "%s", definition.title.c_str());
} else {
@@ -2639,18 +2638,21 @@ namespace overlay::windows {
}
} else if (definition.hidden
|| (!definition.game_name.empty() && definition.game_name != this->games_selected_name)) {
// wrong game - grayed out
ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.f), "%s", definition.title.c_str());
} else if (definition.game_name == this->games_selected_name) {
ImGui::TextColored(ImVec4(0.8f, 0, 0.8f, 1.f), "%s", definition.title.c_str());
} else {
// normal text
ImGui::Text("%s", definition.title.c_str());
}
if (ImGui::IsItemHovered()) {
ImGui::HelpTooltip(definition.desc.c_str());
}
ImGui::NextColumn();
ImGui::AlignTextToFramePadding();
if (definition.display_name.empty()) {
ImGui::Text("-%s", definition.name.c_str());
ImGui::TextDisabled("-%s", definition.name.c_str());
} else {
ImGui::Text("-%s", definition.display_name.c_str());
ImGui::TextDisabled("-%s", definition.display_name.c_str());
}
ImGui::NextColumn();
if (option.disabled || definition.disabled) {
@@ -2665,6 +2667,9 @@ namespace overlay::windows {
option.value = state ? "/ENABLED" : "";
::Config::getInstance().updateBinding(games_list[games_selected], option);
}
if (ImGui::IsItemHovered()) {
ImGui::HelpTooltip(definition.desc.c_str());
}
break;
}
case OptionType::Integer: {
@@ -2691,6 +2696,9 @@ namespace overlay::windows {
option.value = buffer;
::Config::getInstance().updateBinding(games_list[games_selected], option);
}
if (ImGui::IsItemHovered()) {
ImGui::HelpTooltip(definition.desc.c_str());
}
break;
}
case OptionType::Hex: {
@@ -2724,6 +2732,9 @@ namespace overlay::windows {
option.value = buffer;
::Config::getInstance().updateBinding(games_list[games_selected], option);
}
if (ImGui::IsItemHovered()) {
ImGui::HelpTooltip(definition.desc.c_str());
}
break;
}
case OptionType::Text: {
@@ -2741,6 +2752,9 @@ namespace overlay::windows {
option.value = buffer;
::Config::getInstance().updateBinding(games_list[games_selected], option);
}
if (ImGui::IsItemHovered()) {
ImGui::HelpTooltip(definition.desc.c_str());
}
break;
}
case OptionType::Enum: {
@@ -2771,6 +2785,9 @@ namespace overlay::windows {
}
ImGui::EndCombo();
}
if (ImGui::IsItemHovered()) {
ImGui::HelpTooltip(definition.desc.c_str());
}
break;
}
default: {
+27 -10
View File
@@ -649,17 +649,9 @@ namespace overlay::windows {
// first column, part 1: help / caution marker
ImGui::TableNextColumn();
const std::string description = patch.description;
const std::string caution = patch.caution;
if (!description.empty() && !caution.empty()) {
if (!patch.caution.empty()) {
ImGui::AlignTextToFramePadding();
ImGui::WarnMarker(description.c_str(), caution.c_str());
} else if (!description.empty()) {
ImGui::AlignTextToFramePadding();
ImGui::HelpMarker(description.c_str());
} else if (!caution.empty()) {
ImGui::AlignTextToFramePadding();
ImGui::WarnMarker(nullptr, caution.c_str());
ImGui::WarnMarker(nullptr, patch.caution.c_str());
} else {
ImGui::DummyMarker();
}
@@ -705,6 +697,11 @@ namespace overlay::windows {
if (style_color_pushed) {
ImGui::PopStyleColor(style_color_pushed);
}
if (ImGui::IsItemHovered()) {
show_patch_tooltip(patch);
}
// show range after label for integer patches
if (patch.type == PatchType::Integer) {
ImGui::SameLine();
auto& numpatch = patch.patch_number;
@@ -741,6 +738,9 @@ namespace overlay::windows {
patch.last_status = is_patch_active(patch);
}
ImGui::EndDisabled();
if (ImGui::IsItemHovered()) {
show_patch_tooltip(patch);
}
// second column, part 2: additional options UI (dropdown, text input)
ImGui::SameLine();
@@ -767,6 +767,9 @@ namespace overlay::windows {
}
ImGui::EndCombo();
}
if (ImGui::IsItemHovered()) {
show_patch_tooltip(patch);
}
} else if (patch.type == PatchType::Integer) {
ImGui::SetNextItemWidth(200.0f);
auto& numpatch = patch.patch_number;
@@ -780,6 +783,9 @@ namespace overlay::windows {
apply_patch(patch, true);
config_dirty = true;
}
if (ImGui::IsItemHovered()) {
show_patch_tooltip(patch);
}
}
} else if (patch_status == PatchStatus::Disabled) {
ImGui::SetNextItemWidth(200.0f);
@@ -794,6 +800,9 @@ namespace overlay::windows {
ImGui::InputInt("##dummy_int_input", &patch.patch_number.value);
}
ImGui::EndDisabled();
if (ImGui::IsItemHovered()) {
show_patch_tooltip(patch);
}
}
} else {
ImGui::AlignTextToFramePadding();
@@ -822,6 +831,14 @@ namespace overlay::windows {
}
}
void PatchManager::show_patch_tooltip(const PatchData& patch) {
if (!patch.caution.empty()) {
ImGui::WarnTooltip(patch.description.c_str(), patch.caution.c_str());
} else if (!patch.description.empty()) {
ImGui::HelpTooltip(patch.description.c_str());
}
}
void PatchManager::hard_apply_patches() {
std::vector<std::string> written_list;
for (auto& patch : patches) {
@@ -142,6 +142,7 @@ namespace overlay::windows {
std::function<bool(const PatchData&)> filter = std::function<bool(const PatchData&)>(),
std::string pe_identifier_for_patch = "");
void show_patch_tooltip(const PatchData& patch);
};
PatchStatus is_patch_active(PatchData &patch);