Replace recipe/schematic dropdowns with button and selection dialog

This commit is contained in:
2026-06-22 12:17:42 +02:00
parent c43225b6fa
commit c7218c7c1e
10 changed files with 318 additions and 50 deletions

View File

@@ -0,0 +1,172 @@
#include "RecipeSelectionDialog.h"
#include <cstddef>
#include <QGridLayout>
#include <QPushButton>
#include <QStringList>
#include <QVBoxLayout>
#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<RecipeSelectionOption> buildRecipeSelectionOptions(
const Building& building, Simulation& sim, const GameConfig& config)
{
std::vector<RecipeSelectionOption> options;
options.push_back({std::string(), QObject::tr("(None)"), QString()});
if (building.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 != building.type) { continue; }
if ((building.type == BuildingType::Miner
|| building.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<RecipeSelectionOption>& 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<int>(options.size()); ++i)
{
const RecipeSelectionOption& option = options[static_cast<std::size_t>(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<std::string> RecipeSelectionDialog::getChosenId() const
{
return m_chosenId;
}
void RecipeSelectionDialog::onOptionClicked(int index)
{
if (index >= 0 && index < static_cast<int>(m_optionIds.size()))
{
m_chosenId = m_optionIds[static_cast<std::size_t>(index)];
}
accept();
}