#include "RecipeSelectionDialog.h" #include #include #include #include #include #include "Building.h" #include "BuildingType.h" #include "DisplayName.h" #include "GameConfig.h" #include "RecipesConfig.h" #include "ShipsConfig.h" #include "Simulation.h" namespace { QString itemLine(const std::string& itemId, int amount) { return QStringLiteral(" ") + QString::fromStdString(toDisplayName(itemId)) + QStringLiteral(" ×") + QString::number(amount); } QString recipeTooltip(const RecipeDef& recipe) { QStringList lines; lines << QObject::tr("Recipe: %1") .arg(QString::fromStdString(toDisplayName(recipe.id))); if (recipe.inputs.empty()) { lines << QObject::tr("Inputs: none"); } else { lines << QObject::tr("Inputs:"); for (const RecipeIngredient& ingredient : recipe.inputs) { lines << itemLine(ingredient.item, ingredient.amount); } } lines << QObject::tr("Completion time: %1 s").arg(recipe.durationSeconds); if (!recipe.outputs.empty()) { lines << QObject::tr("Produces:"); for (const RecipeOutput& output : recipe.outputs) { lines << itemLine(output.item, output.amount); } } return lines.join('\n'); } QString shipTooltip(const ShipDef& def) { const QString name = QString::fromStdString(toDisplayName(def.id)); QStringList lines; lines << QObject::tr("Ship: %1").arg(name); if (def.schematic.materials.empty()) { lines << QObject::tr("Materials: none"); } else { lines << QObject::tr("Materials:"); for (const RecipeIngredient& material : def.schematic.materials) { lines << itemLine(material.item, material.amount); } } lines << QObject::tr("Completion time: %1 s") .arg(def.schematic.productionTimeSeconds); lines << QObject::tr("Produces: 1 %1").arg(name); return lines.join('\n'); } } // namespace std::vector buildRecipeSelectionOptions( BuildingType type, Simulation& sim, const GameConfig& config) { std::vector options; options.push_back({std::string(), QObject::tr("(None)"), QString()}); if (type == BuildingType::Shipyard) { for (const ShipDef& def : config.ships.ships) { if (!sim.isSchematicUnlocked(def.id)) { continue; } options.push_back({def.id, QString::fromStdString(toDisplayName(def.id)), shipTooltip(def)}); } } else { for (const RecipeDef& recipe : config.recipes.recipes) { if (recipe.building != type) { continue; } if ((type == BuildingType::Miner || type == BuildingType::Assembler) && !sim.isRecipeUnlocked(recipe.id)) { continue; } options.push_back({recipe.id, QString::fromStdString(toDisplayName(recipe.id)), recipeTooltip(recipe)}); } } return options; } RecipeSelectionDialog::RecipeSelectionDialog( const std::vector& options, const QString& title, QWidget* parent) : QDialog(parent) { setWindowTitle(title); setModal(true); QVBoxLayout* mainLayout = new QVBoxLayout(this); QGridLayout* grid = new QGridLayout(); mainLayout->addLayout(grid); const int columnCount = 2; for (int i = 0; i < static_cast(options.size()); ++i) { const RecipeSelectionOption& option = options[static_cast(i)]; QPushButton* button = new QPushButton(option.caption, this); if (!option.tooltip.isEmpty()) { button->setToolTip(option.tooltip); } button->setMinimumHeight(40); grid->addWidget(button, i / columnCount, i % columnCount); m_optionIds.push_back(option.id); const int index = i; connect(button, &QPushButton::clicked, this, [this, index]() { onOptionClicked(index); }); } } std::optional RecipeSelectionDialog::getChosenId() const { return m_chosenId; } void RecipeSelectionDialog::onOptionClicked(int index) { if (index >= 0 && index < static_cast(m_optionIds.size())) { m_chosenId = m_optionIds[static_cast(index)]; } accept(); }