show recipes visually instead of describing them in text
This commit is contained in:
140
src/ui/RecipeLineRow.cpp
Normal file
140
src/ui/RecipeLineRow.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
#include "RecipeLineRow.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLayoutItem>
|
||||
#include <QPixmap>
|
||||
|
||||
#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<Amount>& 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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user