split the selection panel into one card per kind of selection

This commit is contained in:
2026-08-07 18:38:55 +02:00
parent cc0ef856e3
commit 2289277e12
60 changed files with 3014 additions and 1559 deletions

View File

@@ -2,9 +2,7 @@
#include <string>
#include <QByteArray>
#include <QColor>
#include <QFile>
#include <QFont>
#include <QFontMetrics>
#include <QGuiApplication>
@@ -15,12 +13,11 @@
#include <QPixmap>
#include <QPushButton>
#include <QRect>
#include <QRegularExpression>
#include <QSignalMapper>
#include <QSize>
#include <QString>
#include <QSvgRenderer>
#include "BuildingIconCache.h"
#include "BuildingType.h"
#include "BuildingTypeSelectedEvent.h"
#include "DeconstructModeToggleRequestedEvent.h"
@@ -54,45 +51,15 @@ namespace
// Gap between the chip icon and the cost line on a button face.
const int kFaceGapPx = 2;
// Rasterizes a chip SVG straight at its on-screen size times the device pixel
// ratio, so it stays crisp without a downscale step.
QPixmap renderChip(const QByteArray& svg)
{
const qreal dpr = qApp ? qApp->devicePixelRatio() : 1.0;
QSvgRenderer renderer(svg);
QPixmap pixmap(static_cast<int>(kIconSize.width() * dpr),
static_cast<int>(kIconSize.height() * dpr));
pixmap.setDevicePixelRatio(dpr);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
renderer.render(&painter);
return pixmap;
}
// Normal and grey-background chip pixmaps for a "<id>.svg" file. Empty pixmaps if
// the file cannot be read; the caller then falls back to a name caption
// Normal and grey-background chip pixmaps for one icon name. Empty pixmaps if the
// file cannot be read; the caller then falls back to a name caption
// (REQ-UI-BUILD-ICON).
struct ChipPixmaps { QPixmap normal; QPixmap grey; };
ChipPixmaps loadChipPixmaps(const QString& path)
ChipPixmaps loadChipPixmaps(BuildingIconCache& icons, const std::string& iconName)
{
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) { return {}; }
const QByteArray svg = file.readAll();
ChipPixmaps result;
result.normal = renderChip(svg);
// Recolor only the chip background: the first "#rrggbb" fill in the file is the
// rounded background rect; the white glyph uses fill="none" and is left alone.
QString greyed = QString::fromUtf8(svg);
static const QRegularExpression fillPattern(QStringLiteral("fill=\"#[0-9a-fA-F]{6}\""));
const QRegularExpressionMatch match = fillPattern.match(greyed);
if (match.hasMatch())
{
greyed.replace(match.capturedStart(), match.capturedLength(),
QStringLiteral("fill=\"#5f636e\""));
}
result.grey = renderChip(greyed.toUtf8());
result.normal = icons.getChip(iconName, kIconSize.width());
result.grey = icons.getGreyChip(iconName, kIconSize.width());
return result;
}
@@ -181,12 +148,12 @@ namespace
BuildButtonBar::BuildButtonBar(Simulation* sim, const GameConfig* config,
const std::string& iconDir,
BuildingIconCache* buildingIcons,
ItemIconCache* itemIcons, QWidget* parent)
: QWidget(parent)
, m_sim(sim)
, m_config(config)
, m_iconDir(iconDir)
, m_buildingIcons(buildingIcons)
, m_itemIcons(itemIcons)
{
// The bar floats over the rendered world rather than sitting in a panel, so it
@@ -231,13 +198,12 @@ BuildButtonBar::BuildButtonBar(Simulation* sim, const GameConfig* config,
const QString name = (def.type == BuildingType::TunnelEntry)
? tr("Tunnel")
: QString::fromStdString(toDisplayName(def.id));
// Icon file name matches the building id (REQ-UI-BUILD-ICON); Tunnel Entry's
// "tunnel_entry.svg" serves the shared Tunnel button.
const QString iconPath = QString::fromStdString(m_iconDir) + "/"
+ QString::fromStdString(def.id) + ".svg";
const ButtonFace face = buildButtonFace(
loadChipPixmaps(iconPath), InputMapper::getBuildHotkeyLabel(def.type), name,
loadChipPixmaps(*m_buildingIcons, def.id),
InputMapper::getBuildHotkeyLabel(def.type), name,
QString::number(def.cost), blockIcon, font(), palette());
QPushButton* btn = new QPushButton(this);
@@ -268,7 +234,7 @@ BuildButtonBar::BuildButtonBar(Simulation* sim, const GameConfig* config,
// Having no cost, it shows its name where the building buttons show theirs
// (REQ-UI-DECONSTRUCT-BUTTON), and its Q toggle as the badge (REQ-UI-HOTKEYS).
const ButtonFace deconstructFace = buildButtonFace(
loadChipPixmaps(QString::fromStdString(m_iconDir) + "/deconstruct.svg"),
loadChipPixmaps(*m_buildingIcons, "deconstruct"),
QStringLiteral("Q"), tr("Deconstruct"), tr("Deconstruct"), QPixmap(),
font(), palette());