show the selection card before measuring the panel against it

Clicking something sometimes left the panel collapsed to its scroll bar, most
often for field entities.

Same cause as the controls panel's collapse in d7c6734: a widget created under
an already-visible parent starts hidden, and a layout counts a hidden item as
empty. rebuildContent() built the card, added it to the body layout and
measured immediately, so the body reported nothing but its own margins. A width
of nearly zero makes heightForWidth() on the wrapped labels enormous, that
overflows the band, and refit() then caps the height and widens by the scroll
bar -- leaving the panel exactly one scroll bar wide.

It could not recover on the next tick either, because a word-wrapped label's
size hint follows its current width: once narrow, it keeps reporting narrow and
tall. So refit() now measures the body at the width cap rather than at whatever
width the panel currently has, and invalidates the body layout before reading
it -- cards are built and discarded whole, so its cached hint otherwise
describes the card before this one.

Field entities hit it more often because a field selection publishes twice,
actors then debris, so one click rebuilds the card twice.

The same defect existed one level down, where parts are rebuilt while the card
is already visible: ItemChipRow::rebuildChips() and RecipeSummaryRow::rebuild()
now show what they create. Those were measuring the buffer section and the
recipe line as empty on every recipe change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcReq7hVk4KUPhTDKWAG7K
This commit is contained in:
2026-08-07 20:56:18 +02:00
parent f06d79e60d
commit 6fa3ba7f0c
3 changed files with 46 additions and 11 deletions

View File

@@ -73,6 +73,11 @@ void ItemChipRow::rebuildChips(const std::vector<Entry>& entries)
ItemChip* chip = new ItemChip(icon, this);
m_layout->addWidget(chip, static_cast<int>(index) / kChipsPerRow,
static_cast<int>(index) % kChipsPerRow);
// Shown right away, because the panel measures itself as soon as this returns. A
// widget created under an already-visible parent starts hidden, and a layout
// treats a hidden item as empty, so an unshown chip would add nothing to the
// size hint and the panel would be fitted to a buffer section that looks empty.
chip->show();
m_chips.push_back(chip);
}
}

View File

@@ -13,6 +13,18 @@ namespace
// Size the item icons are drawn at on the summary line, in device-independent pixels.
const int kSummaryIconSizePx = 14;
// Adds a freshly built label to the summary and shows it.
//
// The show is what makes it count: a widget created under an already-visible parent
// starts hidden, and a layout treats a hidden item as empty, so an unshown label would
// add nothing to the size hint the panel measures itself against as soon as this
// returns.
void addAndShow(QHBoxLayout* layout, QLabel* label)
{
layout->addWidget(label);
label->show();
}
} // namespace
@@ -71,14 +83,14 @@ void RecipeSummaryRow::rebuild(const std::vector<Amount>& inputs,
if (!inputs.empty())
{
const QChar rightArrow(0x2192); // U+2192 RIGHTWARDS ARROW
m_layout->addWidget(new QLabel(QString(rightArrow), this));
addAndShow(m_layout, new QLabel(QString(rightArrow), this));
}
addAmounts(outputs);
if (durationSeconds > 0.0)
{
const QChar middleDot(0x00B7); // U+00B7 MIDDLE DOT
m_layout->addWidget(new QLabel(
addAndShow(m_layout, new QLabel(
QStringLiteral("%1 %2").arg(middleDot).arg(
tr("%1 s").arg(durationSeconds, 0, 'f', 1)), this));
}
@@ -96,13 +108,13 @@ void RecipeSummaryRow::addAmounts(const std::vector<Amount>& amounts)
QLabel* iconLabel = new QLabel(this);
iconLabel->setPixmap(
m_itemIcons->getPixmap(entry.itemId, kSummaryIconSizePx));
m_layout->addWidget(iconLabel);
addAndShow(m_layout, iconLabel);
}
else
{
m_layout->addWidget(
new QLabel(QString::fromStdString(entry.itemId), this));
addAndShow(m_layout,
new QLabel(QString::fromStdString(entry.itemId), this));
}
m_layout->addWidget(new QLabel(QString::number(entry.amount), this));
addAndShow(m_layout, new QLabel(QString::number(entry.amount), this));
}
}