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

@@ -0,0 +1,103 @@
#include "ShipyardContent.h"
#include <QPushButton>
#include <QVBoxLayout>
#include "Building.h"
#include "BuildingTarget.h"
#include "EventManager.h"
#include "GameConfig.h"
#include "LayoutDialogRequestedEvent.h"
#include "ProductionRules.h"
#include "RecipeSelectionControl.h"
#include "SelectionNames.h"
#include "ShipLayoutPreview.h"
ShipyardContent::ShipyardContent(const SelectionContext& context,
const SelectionRequest& request, QWidget* parent)
: BufferedBuildingContent(context, request.buildings.front(), parent)
{
m_schematicControl = new RecipeSelectionControl(context, getBuildingId(),
BuildingType::Shipyard, this);
m_layoutPreview = new ShipLayoutPreview(this);
m_configureButton = new QPushButton(tr("Configure Layout"), this);
getConfigurationLayout()->addWidget(m_schematicControl);
getConfigurationLayout()->addWidget(m_layoutPreview);
getConfigurationLayout()->addWidget(m_configureButton);
const BuildingId id = getBuildingId();
connect(m_configureButton, &QPushButton::clicked, this, [id]() {
EventManager::getInstance()->sendEventImmediately(
std::make_shared<LayoutDialogRequestedEvent>(id));
});
}
void ShipyardContent::refreshConfiguration()
{
const BuildingTarget target = resolveBuildingTarget(getContext(), getBuildingId());
if (!target.isValid())
{
return;
}
setBuildingIdentity(target.type, getBuildingTypeName(target.type));
m_schematicControl->setRecipeId(target.recipeId);
// The preview and Configure button are always shown for a shipyard and are only
// enabled once a schematic is selected (REQ-MOD-UI-PREVIEW). The schematic arrives
// by queued command, so this refresh is what picks it up rather than the click that
// chose it.
const ShipDef* shipDef = target.recipeId.empty()
? nullptr
: getContext().config->ships.findShipDef(target.recipeId);
const bool hasSchematic = shipDef && !shipDef->layout.empty();
if (hasSchematic)
{
m_layoutPreview->setShipAndLayout(
shipDef->layout,
target.shipLayout.has_value() ? *target.shipLayout : ShipLayoutConfig(),
&getContext().config->modules);
}
else
{
m_layoutPreview->showPlaceholder();
}
m_layoutPreview->setEnabled(hasSchematic);
m_configureButton->setEnabled(hasSchematic);
}
BufferedBuildingContent::CycleInfo ShipyardContent::getCycleInfo(
const Building& building) const
{
CycleInfo info;
const ShipDef* shipDef = building.recipeId.empty()
? nullptr
: getContext().config->ships.findShipDef(building.recipeId);
if (!shipDef)
{
return info;
}
// The schematic's materials plus every placed module's, which is also what sized the
// input buffers (REQ-BLD-SHIPYARD). The simulation owns that sum, so the panel asks
// it rather than adding the modules up a second time.
info.perCycleInputs =
computeShipyardRequiredMaterials(*getContext().config, building);
info.durationSeconds = shipDef->schematic.productionTimeSeconds;
if (building.shipLayout.has_value())
{
for (const PlacedModule& placed : building.shipLayout->placedModules)
{
const ModuleDef* moduleDef =
getContext().config->modules.findModuleDef(placed.moduleId);
if (moduleDef)
{
info.durationSeconds += moduleDef->productionTimeSeconds;
}
}
}
info.runsProduction = true;
return info;
}