From 5998f9f190ef422da0877b350f67e20ba15f8b0f Mon Sep 17 00:00:00 2001 From: Malte Langkabel Date: Tue, 11 Aug 2026 21:30:52 +0200 Subject: [PATCH] size option buttons to the face they carry QPushButton derives its size hint from its text and icon and ignores a layout set on it, so the recipe options, the shipyard schematic options and the layout dialog's module buttons all measured themselves as empty and clipped the name and recipe line drawn on them. OptionButton takes the hint from its layout instead and lets the style add what the button frame needs, so the padding stays the platform's rather than a number picked here. It falls back to QPushButton's own hint when there is no layout, which is what the "(None)" option uses. The module buttons drop their fixed height with it and take what their cost line needs. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x --- src/ui/CMakeLists.txt | 2 ++ src/ui/OptionButton.cpp | 35 ++++++++++++++++++++++++++++++++ src/ui/OptionButton.h | 28 +++++++++++++++++++++++++ src/ui/RecipeSelectionDialog.cpp | 5 ++++- src/ui/ShipLayoutDialog.cpp | 3 ++- 5 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 src/ui/OptionButton.cpp create mode 100644 src/ui/OptionButton.h diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index ab69eea..7ea9040 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -26,6 +26,7 @@ SET(HDRS ${CMAKE_CURRENT_SOURCE_DIR}/SchematicChoiceDialog.h ${CMAKE_CURRENT_SOURCE_DIR}/RecipeSelectionDialog.h ${CMAKE_CURRENT_SOURCE_DIR}/RecipeLineRow.h + ${CMAKE_CURRENT_SOURCE_DIR}/OptionButton.h ${CMAKE_CURRENT_SOURCE_DIR}/ItemProducers.h ${CMAKE_CURRENT_SOURCE_DIR}/ItemIconCache.h ${CMAKE_CURRENT_SOURCE_DIR}/BuildingIconCache.h @@ -61,6 +62,7 @@ SET(SRCS ${CMAKE_CURRENT_SOURCE_DIR}/SchematicChoiceDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RecipeSelectionDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RecipeLineRow.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/OptionButton.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ItemProducers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ItemIconCache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BuildingIconCache.cpp diff --git a/src/ui/OptionButton.cpp b/src/ui/OptionButton.cpp new file mode 100644 index 0000000..aba0991 --- /dev/null +++ b/src/ui/OptionButton.cpp @@ -0,0 +1,35 @@ +#include "OptionButton.h" + +#include +#include +#include + +OptionButton::OptionButton(QWidget* parent) + : QPushButton(parent) +{ +} + +QSize OptionButton::sizeHint() const +{ + if (layout() == nullptr) + { + return QPushButton::sizeHint(); + } + return sizeForFace(layout()->sizeHint()); +} + +QSize OptionButton::minimumSizeHint() const +{ + if (layout() == nullptr) + { + return QPushButton::minimumSizeHint(); + } + return sizeForFace(layout()->minimumSize()); +} + +QSize OptionButton::sizeForFace(const QSize& faceSize) const +{ + QStyleOptionButton option; + initStyleOption(&option); + return style()->sizeFromContents(QStyle::CT_PushButton, &option, faceSize, this); +} diff --git a/src/ui/OptionButton.h b/src/ui/OptionButton.h new file mode 100644 index 0000000..2127a67 --- /dev/null +++ b/src/ui/OptionButton.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +// A push button whose face is built of widgets rather than of a caption: an option's +// name over the recipe line stating what it makes (REQ-UI-SELECT-OPTIONS), or a module's +// name over what it costs (REQ-MOD-UI-DIALOG). +// +// It exists only to be measured correctly. QPushButton computes its size hint from its +// text and icon and ignores a layout set on it, so a button carrying a face of widgets +// would be sized as if it were empty and clip everything in it. This asks the layout +// instead, and then lets the style add what the button's own frame needs. +class OptionButton : public QPushButton +{ + Q_OBJECT + +public: + explicit OptionButton(QWidget* parent = nullptr); + + QSize sizeHint() const override; + QSize minimumSizeHint() const override; + +private: + // The style's button size for the given face size, or the plain QPushButton hint + // when there is no face to measure. + QSize sizeForFace(const QSize& faceSize) const; +}; diff --git a/src/ui/RecipeSelectionDialog.cpp b/src/ui/RecipeSelectionDialog.cpp index c7189b4..9c996fa 100644 --- a/src/ui/RecipeSelectionDialog.cpp +++ b/src/ui/RecipeSelectionDialog.cpp @@ -13,6 +13,7 @@ #include "BuildingType.h" #include "DisplayName.h" #include "GameConfig.h" +#include "OptionButton.h" #include "RecipesConfig.h" #include "ShipsConfig.h" #include "Simulation.h" @@ -138,7 +139,9 @@ RecipeSelectionDialog::RecipeSelectionDialog( { const RecipeSelectionOption& option = options[static_cast(i)]; - QPushButton* button = new QPushButton(list); + // An OptionButton so the face of widgets below is what sizes the button + // (REQ-UI-SELECT-OPTIONS). + OptionButton* button = new OptionButton(list); if (option.line.isEmpty()) { // The "(None)" option makes nothing and is a caption alone diff --git a/src/ui/ShipLayoutDialog.cpp b/src/ui/ShipLayoutDialog.cpp index 9dc1ac8..7653ee1 100644 --- a/src/ui/ShipLayoutDialog.cpp +++ b/src/ui/ShipLayoutDialog.cpp @@ -5,6 +5,7 @@ #include #include "DisplayName.h" +#include "OptionButton.h" #include "ProductionRules.h" #include "RecipeLineRow.h" #include "SectionBox.h" @@ -520,7 +521,7 @@ ShipLayoutDialog::ShipLayoutDialog(const GameConfig* config, // The module's name and glyph over what it costs -- its materials and the // production time it adds (REQ-MOD-UI-DIALOG). Both children are transparent to // the mouse so a click anywhere on the face still reaches the button. - QPushButton* btn = new QPushButton(this); + OptionButton* btn = new OptionButton(this); btn->setCheckable(true); QVBoxLayout* face = new QVBoxLayout(btn);