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:
@@ -193,6 +193,13 @@ void SelectionPanel::rebuildContent()
|
||||
if (m_content)
|
||||
{
|
||||
m_bodyLayout->addWidget(m_content);
|
||||
// The show is what makes the card count. A widget created under an
|
||||
// already-visible parent starts hidden, and a layout treats a hidden item as
|
||||
// empty -- it adds nothing to the size hint until something shows it, which
|
||||
// otherwise does not happen until the event loop next runs, long after refit()
|
||||
// has measured the panel. The panel then fits itself to an empty body and
|
||||
// collapses to its scroll bar.
|
||||
m_content->show();
|
||||
m_content->refresh();
|
||||
}
|
||||
updateVisibility();
|
||||
@@ -214,11 +221,6 @@ void SelectionPanel::updateVisibility()
|
||||
|
||||
void SelectionPanel::refit()
|
||||
{
|
||||
// The layout drops hidden widgets from its size hint, but only once it has been
|
||||
// re-run: a card hides and shows its parts as it refreshes, before Qt would get
|
||||
// around to it on its own.
|
||||
m_body->layout()->activate();
|
||||
|
||||
const QRect band =
|
||||
m_bandRect.adjusted(kMarginPx, kMarginPx, -kMarginPx, -kMarginPx);
|
||||
|
||||
@@ -234,6 +236,22 @@ void SelectionPanel::refit()
|
||||
return;
|
||||
}
|
||||
|
||||
// Measured at the cap rather than at whatever width the panel happens to have. A
|
||||
// word-wrapped label's size hint follows its current width, so a panel that once
|
||||
// came out too narrow would keep reporting a narrow, tall hint and stay that way.
|
||||
m_body->resize(maxWidthPx, m_body->height());
|
||||
|
||||
// Cards are built and thrown away whole, so the body layout's cached hint describes
|
||||
// the card before this one until it is discarded. Re-running the layout is what
|
||||
// makes the current card's parts measurable: a card hides and shows its parts as it
|
||||
// refreshes, and Qt would not get around to either on its own before the panel is
|
||||
// sized here. The polish belongs to the same step -- a freshly created chip reports
|
||||
// an unstyled hint until the stylesheet has reached it, and the chips carry border
|
||||
// and padding that change their width.
|
||||
m_body->ensurePolished();
|
||||
m_body->layout()->invalidate();
|
||||
m_body->layout()->activate();
|
||||
|
||||
int contentWidthPx = qMin(m_body->sizeHint().width(), maxWidthPx);
|
||||
// Word-wrapped labels only know their height once the width is fixed; the layout
|
||||
// reports -1 when nothing in it wraps, in which case the plain hint is exact.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user