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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
This commit is contained in:
2026-08-11 21:30:52 +02:00
parent b7b5a92dbb
commit 5998f9f190
5 changed files with 71 additions and 2 deletions

View File

@@ -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

35
src/ui/OptionButton.cpp Normal file
View File

@@ -0,0 +1,35 @@
#include "OptionButton.h"
#include <QLayout>
#include <QStyle>
#include <QStyleOptionButton>
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);
}

28
src/ui/OptionButton.h Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include <QPushButton>
#include <QSize>
// 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;
};

View File

@@ -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<std::size_t>(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

View File

@@ -5,6 +5,7 @@
#include <functional>
#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);