#include "RecipeLineRow.h" #include #include #include #include #include "BuildingIconCache.h" #include "ItemIconCache.h" namespace { // Size the items' colored squares and the building's chip are drawn at on a line, in // device-independent pixels. Larger than the artwork they carry, which the square // insets (REQ-UI-ITEM-ICON). const int kIconSizePx = 18; // Adds a freshly built label to the line 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 surrounding widget measures itself against as soon // as this returns. void addAndShow(QHBoxLayout* layout, QLabel* label) { layout->addWidget(label); label->show(); } } // namespace RecipeLineRow::RecipeLineRow(ItemIconCache* itemIcons, BuildingIconCache* buildingIcons, QWidget* parent) : QWidget(parent) , m_itemIcons(itemIcons) , m_buildingIcons(buildingIcons) { m_layout = new QHBoxLayout(this); m_layout->setContentsMargins(0, 0, 0, 0); m_layout->setSpacing(4); hide(); } void RecipeLineRow::setLine(const Spec& spec) { if (spec.isEmpty()) { // Forgotten as well as hidden, so re-selecting the same recipe later is seen as // a change and shows the row again. m_spec = Spec(); hide(); return; } if (spec == m_spec) { return; } m_spec = spec; rebuild(spec); show(); } void RecipeLineRow::rebuild(const Spec& spec) { while (QLayoutItem* item = m_layout->takeAt(0)) { if (item->widget()) { item->widget()->deleteLater(); } delete item; } // The building the recipe runs in, where the line has to distinguish one producer // from another (REQ-UI-ITEM-TOOLTIP). A building with no chip file leaves the icon // off, as everywhere else (REQ-UI-BUILD-ICON). if (spec.building.has_value() && m_buildingIcons != nullptr) { const QPixmap chip = m_buildingIcons->getChip(buildingTypeId(*spec.building), kIconSizePx); if (!chip.isNull()) { QLabel* chipLabel = new QLabel(this); chipLabel->setPixmap(chip); addAndShow(m_layout, chipLabel); } } if (!spec.name.isEmpty()) { addAndShow(m_layout, new QLabel(spec.name, this)); } addAmounts(spec.inputs); if (!spec.inputs.empty() && !spec.outputs.empty()) { const QChar rightArrow(0x2192); // U+2192 RIGHTWARDS ARROW addAndShow(m_layout, new QLabel(QString(rightArrow), this)); } addAmounts(spec.outputs); if (spec.durationSeconds.has_value() && *spec.durationSeconds > 0.0) { const QChar middleDot(0x00B7); // U+00B7 MIDDLE DOT const QString time = spec.durationIsAddition ? tr("+%1 s").arg(*spec.durationSeconds, 0, 'f', 1) : tr("%1 s").arg(*spec.durationSeconds, 0, 'f', 1); addAndShow(m_layout, new QLabel( QStringLiteral("%1 %2").arg(middleDot).arg(time), this)); } m_layout->addStretch(1); } void RecipeLineRow::addAmounts(const std::vector& amounts) { for (const Amount& entry : amounts) { // The item's icon on its colored square (REQ-UI-ITEM-ICON). A missing icon file // is not an error: the square stands alone then, and only an item with no square // either falls back to its id in text. const QPixmap icon = (m_itemIcons != nullptr) ? m_itemIcons->getSquarePixmap(entry.itemId, kIconSizePx) : QPixmap(); if (!icon.isNull()) { QLabel* iconLabel = new QLabel(this); iconLabel->setPixmap(icon); addAndShow(m_layout, iconLabel); } else { addAndShow(m_layout, new QLabel(QString::fromStdString(entry.itemId), this)); } addAndShow(m_layout, new QLabel(QString::number(entry.amount), this)); } }