197 lines
6.2 KiB
C++
197 lines
6.2 KiB
C++
#include "RecipeLineRow.h"
|
|
|
|
#include <QFont>
|
|
#include <QHBoxLayout>
|
|
#include <QLabel>
|
|
#include <QLayoutItem>
|
|
#include <QMargins>
|
|
#include <QPixmap>
|
|
#include <QVBoxLayout>
|
|
|
|
#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();
|
|
}
|
|
|
|
// Empties one of the two rows, leaving the row widget and its layout in place.
|
|
void clearRow(QHBoxLayout* layout)
|
|
{
|
|
while (QLayoutItem* item = layout->takeAt(0))
|
|
{
|
|
if (item->widget())
|
|
{
|
|
item->widget()->deleteLater();
|
|
}
|
|
delete item;
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
RecipeLineRow::RecipeLineRow(ItemIconCache* itemIcons, BuildingIconCache* buildingIcons,
|
|
QWidget* parent)
|
|
: QWidget(parent)
|
|
, m_itemIcons(itemIcons)
|
|
, m_buildingIcons(buildingIcons)
|
|
{
|
|
m_outerLayout = new QVBoxLayout(this);
|
|
m_outerLayout->setContentsMargins(0, 0, 0, 0);
|
|
m_outerLayout->setSpacing(1);
|
|
|
|
m_headerRow = new QWidget(this);
|
|
m_headerLayout = new QHBoxLayout(m_headerRow);
|
|
m_headerLayout->setContentsMargins(0, 0, 0, 0);
|
|
m_headerLayout->setSpacing(4);
|
|
m_headerRow->hide();
|
|
m_outerLayout->addWidget(m_headerRow);
|
|
|
|
m_amountsRow = new QWidget(this);
|
|
m_amountsLayout = new QHBoxLayout(m_amountsRow);
|
|
m_amountsLayout->setContentsMargins(0, 0, 0, 0);
|
|
m_amountsLayout->setSpacing(4);
|
|
m_outerLayout->addWidget(m_amountsRow);
|
|
|
|
hide();
|
|
}
|
|
|
|
void RecipeLineRow::setCardChrome(bool enabled)
|
|
{
|
|
// Palette colors like the item chip's chrome (REQ-UI-SELECTION-CARD), not
|
|
// visuals.toml, which is for world rendering. The selector names this class alone, so
|
|
// nothing inside the card inherits the border.
|
|
setAttribute(Qt::WA_StyledBackground, enabled);
|
|
setStyleSheet(enabled
|
|
? QStringLiteral("RecipeLineRow { border: 1px solid palette(mid); "
|
|
"border-radius: 4px; }")
|
|
: QString());
|
|
m_outerLayout->setContentsMargins(enabled ? QMargins(6, 4, 6, 4)
|
|
: QMargins(0, 0, 0, 0));
|
|
}
|
|
|
|
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)
|
|
{
|
|
clearRow(m_headerLayout);
|
|
clearRow(m_amountsLayout);
|
|
|
|
// First line: which building runs the recipe and which recipe it is, 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(m_headerRow);
|
|
chipLabel->setPixmap(chip);
|
|
addAndShow(m_headerLayout, chipLabel);
|
|
}
|
|
}
|
|
if (!spec.name.isEmpty())
|
|
{
|
|
QLabel* nameLabel = new QLabel(spec.name, m_headerRow);
|
|
QFont nameFont = nameLabel->font();
|
|
nameFont.setBold(true);
|
|
nameLabel->setFont(nameFont);
|
|
addAndShow(m_headerLayout, nameLabel);
|
|
}
|
|
const bool hasHeader = m_headerLayout->count() > 0;
|
|
if (hasHeader)
|
|
{
|
|
m_headerLayout->addStretch(1);
|
|
}
|
|
m_headerRow->setVisible(hasHeader);
|
|
|
|
// Second line: what the cycle costs, makes and takes.
|
|
addAmounts(spec.inputs);
|
|
if (!spec.inputs.empty() && !spec.outputs.empty())
|
|
{
|
|
const QChar rightArrow(0x2192); // U+2192 RIGHTWARDS ARROW
|
|
addAndShow(m_amountsLayout, new QLabel(QString(rightArrow), m_amountsRow));
|
|
}
|
|
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_amountsLayout, new QLabel(
|
|
QStringLiteral("%1 %2").arg(middleDot).arg(time), m_amountsRow));
|
|
}
|
|
m_amountsLayout->addStretch(1);
|
|
}
|
|
|
|
void RecipeLineRow::addAmounts(const std::vector<Amount>& amounts)
|
|
{
|
|
for (const Amount& entry : amounts)
|
|
{
|
|
// Between one item and the next, so a run of icons and numbers reads as a sum
|
|
// rather than as a list.
|
|
if (&entry != &amounts.front())
|
|
{
|
|
addAndShow(m_amountsLayout, new QLabel(QStringLiteral("+"), m_amountsRow));
|
|
}
|
|
|
|
// 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(m_amountsRow);
|
|
iconLabel->setPixmap(icon);
|
|
addAndShow(m_amountsLayout, iconLabel);
|
|
}
|
|
else
|
|
{
|
|
addAndShow(m_amountsLayout,
|
|
new QLabel(QString::fromStdString(entry.itemId), m_amountsRow));
|
|
}
|
|
addAndShow(m_amountsLayout,
|
|
new QLabel(QString::number(entry.amount), m_amountsRow));
|
|
}
|
|
}
|