From c479291c1b6ecf1da350a7379b26b2c66be45ec0 Mon Sep 17 00:00:00 2001 From: Malte Langkabel Date: Wed, 22 Jul 2026 19:48:15 +0200 Subject: [PATCH] Reapply build button grid icons Revert of "Undo build button grid icons" (614dda8): restore the per-building SVG icons, the QtSvg-based icon loading in BuildButtonGrid, the icon dir plumbing in MainWindow, and the Qt5::Svg dependency. This returns the unlock-groups branch to having the icons. The preceding undo commit exists only so the Demolish -> Deconstruct rename can be cherry-picked on its own (rename+icons commit together with the undo). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Y7N59FsLA5e2kuVdqe4Uhc --- CMakeLists.txt | 3 +- bin/app/data/icons/buildings/assembler.svg | 6 ++ bin/app/data/icons/buildings/belt.svg | 6 ++ bin/app/data/icons/buildings/deconstruct.svg | 6 ++ bin/app/data/icons/buildings/miner.svg | 6 ++ .../icons/buildings/reprocessing_plant.svg | 6 ++ bin/app/data/icons/buildings/salvage_bay.svg | 6 ++ bin/app/data/icons/buildings/shipyard.svg | 6 ++ bin/app/data/icons/buildings/smelter.svg | 6 ++ bin/app/data/icons/buildings/splitter.svg | 6 ++ bin/app/data/icons/buildings/tunnel_entry.svg | 6 ++ src/CMakeLists.txt | 1 + src/ui/BuildButtonGrid.cpp | 69 ++++++++++++++++++- src/ui/BuildButtonGrid.h | 7 +- src/ui/MainWindow.cpp | 8 ++- 15 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 bin/app/data/icons/buildings/assembler.svg create mode 100644 bin/app/data/icons/buildings/belt.svg create mode 100644 bin/app/data/icons/buildings/deconstruct.svg create mode 100644 bin/app/data/icons/buildings/miner.svg create mode 100644 bin/app/data/icons/buildings/reprocessing_plant.svg create mode 100644 bin/app/data/icons/buildings/salvage_bay.svg create mode 100644 bin/app/data/icons/buildings/shipyard.svg create mode 100644 bin/app/data/icons/buildings/smelter.svg create mode 100644 bin/app/data/icons/buildings/splitter.svg create mode 100644 bin/app/data/icons/buildings/tunnel_entry.svg diff --git a/CMakeLists.txt b/CMakeLists.txt index e51d757..d5e3cb9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ set(CMAKE_BUILD_TYPE_INIT "Release") # Qt --------------------------------------------------------------------------- -find_package(Qt5 COMPONENTS Widgets Network Multimedia Charts REQUIRED) +find_package(Qt5 COMPONENTS Widgets Network Multimedia Charts Svg REQUIRED) if(Qt5Widgets_FOUND) message(STATUS "Found Qt ${Qt5Widgets_VERSION_STRING}") @@ -64,6 +64,7 @@ function(COPY_QT_BINARIES TARGET_DIR IS_DEBUG) configure_file("${QT_BINARY_DIR}/Qt5Network${SUFFIX}.dll" "${TARGET_DIR}/Qt5Network${SUFFIX}.dll" COPYONLY) configure_file("${QT_BINARY_DIR}/Qt5Widgets${SUFFIX}.dll" "${TARGET_DIR}/Qt5Widgets${SUFFIX}.dll" COPYONLY) configure_file("${QT_BINARY_DIR}/Qt5Multimedia${SUFFIX}.dll" "${TARGET_DIR}/Qt5Multimedia${SUFFIX}.dll" COPYONLY) + configure_file("${QT_BINARY_DIR}/Qt5Svg${SUFFIX}.dll" "${TARGET_DIR}/Qt5Svg${SUFFIX}.dll" COPYONLY) endfunction(COPY_QT_BINARIES) diff --git a/bin/app/data/icons/buildings/assembler.svg b/bin/app/data/icons/buildings/assembler.svg new file mode 100644 index 0000000..8fcf9f2 --- /dev/null +++ b/bin/app/data/icons/buildings/assembler.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/bin/app/data/icons/buildings/belt.svg b/bin/app/data/icons/buildings/belt.svg new file mode 100644 index 0000000..9739134 --- /dev/null +++ b/bin/app/data/icons/buildings/belt.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/bin/app/data/icons/buildings/deconstruct.svg b/bin/app/data/icons/buildings/deconstruct.svg new file mode 100644 index 0000000..a07a642 --- /dev/null +++ b/bin/app/data/icons/buildings/deconstruct.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/bin/app/data/icons/buildings/miner.svg b/bin/app/data/icons/buildings/miner.svg new file mode 100644 index 0000000..30123a2 --- /dev/null +++ b/bin/app/data/icons/buildings/miner.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/bin/app/data/icons/buildings/reprocessing_plant.svg b/bin/app/data/icons/buildings/reprocessing_plant.svg new file mode 100644 index 0000000..f5024ba --- /dev/null +++ b/bin/app/data/icons/buildings/reprocessing_plant.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/bin/app/data/icons/buildings/salvage_bay.svg b/bin/app/data/icons/buildings/salvage_bay.svg new file mode 100644 index 0000000..844cbcd --- /dev/null +++ b/bin/app/data/icons/buildings/salvage_bay.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/bin/app/data/icons/buildings/shipyard.svg b/bin/app/data/icons/buildings/shipyard.svg new file mode 100644 index 0000000..cf8043a --- /dev/null +++ b/bin/app/data/icons/buildings/shipyard.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/bin/app/data/icons/buildings/smelter.svg b/bin/app/data/icons/buildings/smelter.svg new file mode 100644 index 0000000..3697779 --- /dev/null +++ b/bin/app/data/icons/buildings/smelter.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/bin/app/data/icons/buildings/splitter.svg b/bin/app/data/icons/buildings/splitter.svg new file mode 100644 index 0000000..9ab41fa --- /dev/null +++ b/bin/app/data/icons/buildings/splitter.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/bin/app/data/icons/buildings/tunnel_entry.svg b/bin/app/data/icons/buildings/tunnel_entry.svg new file mode 100644 index 0000000..b31390d --- /dev/null +++ b/bin/app/data/icons/buildings/tunnel_entry.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2f71a4e..929bc42 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -117,6 +117,7 @@ target_link_libraries(${TARGET_UI_NAME} Qt5::Network Qt5::Multimedia Qt5::Charts + Qt5::Svg ) target_compile_definitions(${TARGET_UI_NAME} PRIVATE TOML_FLOAT_CHARCONV=0) diff --git a/src/ui/BuildButtonGrid.cpp b/src/ui/BuildButtonGrid.cpp index 92aeef8..465866a 100644 --- a/src/ui/BuildButtonGrid.cpp +++ b/src/ui/BuildButtonGrid.cpp @@ -2,9 +2,18 @@ #include +#include +#include #include +#include +#include +#include #include +#include #include +#include +#include +#include #include "BuildingType.h" #include "BuildingTypeSelectedEvent.h" @@ -14,11 +23,60 @@ #include "ExitBuilderModeRequestedEvent.h" #include "Simulation.h" +namespace +{ + // Pixel size the SVG chips are rasterized at; downscaled to the button icon size. + const int kIconRenderSize = 64; + const QSize kIconSize(28, 28); -BuildButtonGrid::BuildButtonGrid(Simulation* sim, const GameConfig* config, QWidget* parent) + QPixmap renderChip(const QByteArray& svg) + { + QSvgRenderer renderer(svg); + QPixmap pixmap(kIconRenderSize, kIconRenderSize); + pixmap.fill(Qt::transparent); + QPainter painter(&pixmap); + renderer.render(&painter); + return pixmap; + } + + // Builds a build-button icon from a ".svg" chip file. The returned QIcon also + // carries a Disabled-mode pixmap whose chip background is recolored grey, so an + // unaffordable (disabled) button shows the grey variant automatically + // (REQ-UI-BUILD-DISABLED) without any extra work in updateAffordability(). + QIcon loadBuildingIcon(const QString& path) + { + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) + { + return QIcon(); + } + const QByteArray svg = file.readAll(); + + QIcon icon; + icon.addPixmap(renderChip(svg), QIcon::Normal); + + // 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\"")); + } + icon.addPixmap(renderChip(greyed.toUtf8()), QIcon::Disabled); + return icon; + } +} + + +BuildButtonGrid::BuildButtonGrid(Simulation* sim, const GameConfig* config, + const std::string& iconDir, QWidget* parent) : QWidget(parent) , m_sim(sim) , m_config(config) + , m_iconDir(iconDir) { QGridLayout* layout = new QGridLayout(this); layout->setSpacing(4); @@ -53,6 +111,12 @@ BuildButtonGrid::BuildButtonGrid(Simulation* sim, const GameConfig* config, QWid QPushButton* btn = new QPushButton(label, this); btn->setCheckable(true); btn->setFixedHeight(48); + // Icon file name matches the building id (REQ-UI-BUILD-GRID); Tunnel Entry's + // "tunnel_entry.svg" serves the shared Tunnel button. + const QString iconPath = QString::fromStdString(m_iconDir) + "/" + + QString::fromStdString(def.id) + ".svg"; + btn->setIcon(loadBuildingIcon(iconPath)); + btn->setIconSize(kIconSize); if (def.tooltip) { btn->setToolTip(QString::fromStdString(*def.tooltip)); @@ -76,6 +140,9 @@ BuildButtonGrid::BuildButtonGrid(Simulation* sim, const GameConfig* config, QWid m_deconstructButton = new QPushButton(tr("Deconstruct"), this); m_deconstructButton->setCheckable(true); m_deconstructButton->setFixedHeight(48); + m_deconstructButton->setIcon(loadBuildingIcon( + QString::fromStdString(m_iconDir) + "/deconstruct.svg")); + m_deconstructButton->setIconSize(kIconSize); layout->addWidget(m_deconstructButton, row, col); connect(m_deconstructButton, &QPushButton::clicked, this, [this]() { EventManager::getInstance()->sendEventImmediately( diff --git a/src/ui/BuildButtonGrid.h b/src/ui/BuildButtonGrid.h index b9578dc..3cc4c62 100644 --- a/src/ui/BuildButtonGrid.h +++ b/src/ui/BuildButtonGrid.h @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -28,7 +29,10 @@ class BuildButtonGrid : public QWidget, Q_OBJECT public: - BuildButtonGrid(Simulation* sim, const GameConfig* config, QWidget* parent = nullptr); + // iconDir is the directory holding the per-building ".svg" chip icons + // (REQ-UI-BUILD-GRID); read from disk at runtime, like the config files. + BuildButtonGrid(Simulation* sim, const GameConfig* config, + const std::string& iconDir, QWidget* parent = nullptr); ~BuildButtonGrid() override; void clearActiveButton(); @@ -55,6 +59,7 @@ private slots: private: Simulation* m_sim; const GameConfig* m_config; + std::string m_iconDir; std::vector m_types; std::vector m_buttons; std::map m_costs; diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp index c6c53ff..14fe5f5 100644 --- a/src/ui/MainWindow.cpp +++ b/src/ui/MainWindow.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -51,8 +52,13 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir, sideLayout->setContentsMargins(1, 1, 1, 1); sideLayout->setSpacing(1); + // Building icons live alongside the config (a sibling of the config dir), read + // from disk at runtime the same way visuals.toml is. + const std::string iconDir = QDir::cleanPath( + QString::fromStdString(m_configDir) + "/../icons/buildings").toStdString(); + m_selectedBuildingPanel = new SelectedBuildingPanel(sim, &sim->getConfig(), m_sidePanel); - m_buildButtonGrid = new BuildButtonGrid(sim, &sim->getConfig(), m_sidePanel); + m_buildButtonGrid = new BuildButtonGrid(sim, &sim->getConfig(), iconDir, m_sidePanel); m_blueprintPanel = new BlueprintPanel(sim, &sim->getConfig(), m_sidePanel); sideLayout->addWidget(m_selectedBuildingPanel, 1);