From 301e15c44d74c2746358b5ed75f42a5434d3bcd4 Mon Sep 17 00:00:00 2001 From: bicarus <202771338+bicarus-dev@users.noreply.github.com> Date: Wed, 17 Jun 2026 01:14:50 -0700 Subject: [PATCH] overlay: make tabs bigger (#764) --- src/spice2x/launcher/launcher.cpp | 2 +- src/spice2x/overlay/imgui/extensions.cpp | 43 ++++++++++++++++++++++++ src/spice2x/overlay/imgui/extensions.h | 5 +++ src/spice2x/overlay/windows/config.cpp | 27 ++++++++++----- 4 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/spice2x/launcher/launcher.cpp b/src/spice2x/launcher/launcher.cpp index 834015c..1804ed2 100644 --- a/src/spice2x/launcher/launcher.cpp +++ b/src/spice2x/launcher/launcher.cpp @@ -1503,7 +1503,7 @@ int main_implementation(int argc, char *argv[]) { log_info("launcher", "{}", VERSION_STRING); // note: distribution of modified version of this software without providing source is GPLv3 license violation. - log_info("launcher", "spice2x is free & open source; if you paid money for it, you got scammed"); + log_info("launcher", "spice2x is free & open source software; if you paid for it, you were scammed"); log_info("launcher", "visit https://spice2x.github.io to download the latest version for free"); // log command line arguments diff --git a/src/spice2x/overlay/imgui/extensions.cpp b/src/spice2x/overlay/imgui/extensions.cpp index b237d1e..66fd23b 100644 --- a/src/spice2x/overlay/imgui/extensions.cpp +++ b/src/spice2x/overlay/imgui/extensions.cpp @@ -2,6 +2,7 @@ #include #include "external/imgui/imgui.h" +#include "overlay/overlay.h" namespace ImGui { @@ -9,6 +10,15 @@ namespace ImGui { const auto fg = ImVec4(0.910f, 0.914f, 0.922f, 1.0f); const auto bg = ImVec4(0.192f, 0.212f, 0.220f, 1.0f); + // FramePadding shared by the config tab bar and its items so the bar height + // matches the padded tabs; gives the labels a bit more breathing room. + static ImVec2 PaddedTabFramePadding() { + const ImVec2 base = ImGui::GetStyle().FramePadding; + return ImVec2( + base.x + overlay::apply_scaling(10.0f), + base.y + overlay::apply_scaling(1.0f)); + } + void HelpTooltip(const char* desc) { ImGui::PushStyleColor(ImGuiCol_Border, bg); ImGui::PushStyleColor(ImGuiCol_BorderShadow, bg); @@ -166,6 +176,39 @@ namespace ImGui { return clicked; } + bool BeginPaddedTabItem(const char* label) { + // fixed uniform label width (scaled for DPI) so all tabs are equally sized; + // wide enough to fit the longest label ("Controller") + const float uniform_width = overlay::apply_scaling(70.0f); + + // ImGui renders tab labels left-aligned, so a forced width would leave short + // labels hugging the left edge. Instead we pad the label with equal leading/ + // trailing spaces to reach a uniform width, which both keeps all tabs the same + // size and centers the text. A stable "##" id suffix keeps each tab's identity + // independent of the padding. + const float space_w = ImGui::CalcTextSize(" ").x; + const float label_w = ImGui::CalcTextSize(label).x; + const int pad = (space_w > 0.0f) + ? (int) ((uniform_width - label_w) * 0.5f / space_w) + : 0; + const std::string padded = (pad > 0) + ? std::string(pad, ' ') + label + std::string(pad, ' ') + "##" + label + : std::string(label); + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, PaddedTabFramePadding()); + const bool open = ImGui::BeginTabItem(padded.c_str()); + ImGui::PopStyleVar(); + return open; + } + + bool BeginPaddedTabBar(const char* str_id, ImGuiTabBarFlags flags) { + // push the same padding used by the tab items so the bar height matches + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, PaddedTabFramePadding()); + const bool open = ImGui::BeginTabBar(str_id, flags); + ImGui::PopStyleVar(); + return open; + } + void InvisibleTableRowSelectable() { ImGui::TableSetColumnIndex(0); ImGui::PushStyleColor(ImGuiCol_Header, 0); diff --git a/src/spice2x/overlay/imgui/extensions.h b/src/spice2x/overlay/imgui/extensions.h index 1620e20..261968f 100644 --- a/src/spice2x/overlay/imgui/extensions.h +++ b/src/spice2x/overlay/imgui/extensions.h @@ -21,4 +21,9 @@ namespace ImGui { bool DeleteButton(const std::string& tooltip); bool ClearButton(const std::string& tooltip); void InvisibleTableRowSelectable(); + + // Config tab bar with extra label padding and uniform, centered tab widths. + // Wrap items in BeginPaddedTabItem between BeginPaddedTabBar/EndTabBar. + bool BeginPaddedTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); + bool BeginPaddedTabItem(const char* label); } diff --git a/src/spice2x/overlay/windows/config.cpp b/src/spice2x/overlay/windows/config.cpp index 950d97f..8ec5d0f 100644 --- a/src/spice2x/overlay/windows/config.cpp +++ b/src/spice2x/overlay/windows/config.cpp @@ -513,7 +513,7 @@ namespace overlay::windows { void Config::build_controller_tab(float page_offset, ControllerPage *page_selected_new) { const float content_height = ImGui::GetWindowContentRegionMax().y - page_offset; - const float nav_width = overlay::apply_scaling(100); + const float nav_width = overlay::apply_scaling(99); // hide sub-pages that expose no controls for the selected game auto analogs = games::get_analogs(this->games_selected_name); @@ -697,20 +697,29 @@ namespace overlay::windows { // tab + controller sub-page selection auto tab_selected_new = ConfigTab::CONFIG_TAB_INVALID; auto controller_page_new = ControllerPage::CONTROLLER_PAGE_INVALID; - if (ImGui::BeginTabBar("Config Tabs", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) { - const int page_offset2 = overlay::apply_scaling(cfg::CONFIGURATOR_STANDALONE ? 65 : 87); - if (ImGui::BeginTabItem("Controller")) { + if (ImGui::BeginPaddedTabBar( + "Config Tabs", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) { + + // the padded tab bar is taller than a stock tab bar by twice the extra + // FramePadding.y added in PaddedTabFramePadding() (top + bottom); include + // it so the tab content child height accounts for the larger bar and + // doesn't overflow the bottom of the window + const int page_offset2 = + overlay::apply_scaling(cfg::CONFIGURATOR_STANDALONE ? 65 : 87) + + overlay::apply_scaling(2); + + if (ImGui::BeginPaddedTabItem("Controller")) { tab_selected_new = ConfigTab::CONFIG_TAB_CONTROLLER; this->build_controller_tab(page_offset2, &controller_page_new); ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("Cards")) { + if (ImGui::BeginPaddedTabItem("Cards")) { tab_selected_new = ConfigTab::CONFIG_TAB_CARDS; this->build_cards_tab(page_offset2); ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("Patches")) { + if (ImGui::BeginPaddedTabItem("Patches")) { tab_selected_new = ConfigTab::CONFIG_TAB_PATCHES; // initialization @@ -752,7 +761,7 @@ namespace overlay::windows { ImGui::EndChild(); ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("Options")) { + if (ImGui::BeginPaddedTabItem("Options")) { tab_selected_new = ConfigTab::CONFIG_TAB_OPTIONS; this->build_options_tab(page_offset2); ImGui::EndTabItem(); @@ -785,7 +794,7 @@ namespace overlay::windows { // note: distribution of modified version of this software without providing source is GPLv3 license violation. ImGui::TextColored( ImVec4(1, 0.5f, 0.5f, 1.f), - "spice2x is free & open source; if you paid money for it, you got scammed."); + "spice2x is free & open source software; if you paid for it, you were scammed."); if (cfg::CONFIGURATOR_STANDALONE) { ImGui::SameLine(); if (ImGui::TextLink(PROJECT_URL)) { @@ -4135,7 +4144,7 @@ namespace overlay::windows { void Config::build_cards_tab(float page_offset) { const float content_height = ImGui::GetWindowContentRegionMax().y - page_offset; - const float nav_width = overlay::apply_scaling(100); + const float nav_width = overlay::apply_scaling(99); // early quit if (this->games_selected < 0 || this->games_selected_name.empty()) {