move blueprints out of the sidebar into Ctrl+C / Ctrl+V dialogs
This commit is contained in:
175
src/ui/BlueprintLibrary.cpp
Normal file
175
src/ui/BlueprintLibrary.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
#include "BlueprintLibrary.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
#include <QMessageBox>
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
#include "BlueprintPlacementRequestedEvent.h"
|
||||
#include "BlueprintSerializer.h"
|
||||
#include "EventManager.h"
|
||||
#include "ExitBlueprintModeRequestedEvent.h"
|
||||
|
||||
#include "BuildingConfig.h"
|
||||
#include "Simulation.h"
|
||||
|
||||
BlueprintLibrary::BlueprintLibrary(Simulation* sim, const GameConfig* config,
|
||||
QWidget* dialogParent)
|
||||
: m_sim(sim)
|
||||
, m_config(config)
|
||||
, m_dialogParent(dialogParent)
|
||||
{
|
||||
loadFromDisk();
|
||||
registerForEvents();
|
||||
}
|
||||
|
||||
BlueprintLibrary::~BlueprintLibrary()
|
||||
{
|
||||
saveToDisk();
|
||||
unregisterForEvents();
|
||||
}
|
||||
|
||||
bool BlueprintLibrary::getCanCaptureSelection() const
|
||||
{
|
||||
// A construction site counts the same as an operational building (REQ-UI-BLUEPRINT-CREATE).
|
||||
return selectionHasPlaceableBuilding(*m_sim, m_selectedBuildingIds);
|
||||
}
|
||||
|
||||
void BlueprintLibrary::saveSelectionAs(const QString& name)
|
||||
{
|
||||
Blueprint blueprint = createBlueprintFromSelection();
|
||||
if (blueprint.buildings.empty()) { return; }
|
||||
|
||||
blueprint.name = name;
|
||||
m_blueprints.push_back(std::move(blueprint));
|
||||
}
|
||||
|
||||
const std::vector<Blueprint>& BlueprintLibrary::getBlueprints() const
|
||||
{
|
||||
return m_blueprints;
|
||||
}
|
||||
|
||||
QString BlueprintLibrary::getContentsSummary(int index) const
|
||||
{
|
||||
if (index < 0 || index >= static_cast<int>(m_blueprints.size())) { return QString(); }
|
||||
|
||||
QStringList entries;
|
||||
for (const BlueprintContentEntry& entry : summarizeBlueprintContents(
|
||||
m_blueprints[static_cast<std::size_t>(index)], m_config->buildings))
|
||||
{
|
||||
// The same "<type> x <count>" notation the building multi-selection summary
|
||||
// uses (REQ-UI-MULTI-SELECTION), which also sidesteps plural forms.
|
||||
entries << QObject::tr("%1 x %2")
|
||||
.arg(QString::fromStdString(entry.buildingName))
|
||||
.arg(entry.count);
|
||||
}
|
||||
return entries.join(QStringLiteral(", "));
|
||||
}
|
||||
|
||||
int BlueprintLibrary::getCost(int index) const
|
||||
{
|
||||
if (index < 0 || index >= static_cast<int>(m_blueprints.size())) { return 0; }
|
||||
return computeBlueprintCost(m_blueprints[static_cast<std::size_t>(index)],
|
||||
m_config->buildings);
|
||||
}
|
||||
|
||||
bool BlueprintLibrary::getCanAfford(int index) const
|
||||
{
|
||||
return m_sim->getBuildingBlocksStock() >= getCost(index);
|
||||
}
|
||||
|
||||
void BlueprintLibrary::remove(int index)
|
||||
{
|
||||
if (index < 0 || index >= static_cast<int>(m_blueprints.size())) { return; }
|
||||
|
||||
if (m_activeIndex == index)
|
||||
{
|
||||
m_activeIndex = std::nullopt;
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<ExitBlueprintModeRequestedEvent>());
|
||||
}
|
||||
else if (m_activeIndex.has_value() && *m_activeIndex > index)
|
||||
{
|
||||
--*m_activeIndex;
|
||||
}
|
||||
m_blueprints.erase(m_blueprints.begin() + index);
|
||||
}
|
||||
|
||||
void BlueprintLibrary::beginPlacement(int index)
|
||||
{
|
||||
if (index < 0 || index >= static_cast<int>(m_blueprints.size())) { return; }
|
||||
|
||||
m_activeIndex = index;
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<BlueprintPlacementRequestedEvent>(
|
||||
m_blueprints[static_cast<std::size_t>(index)]));
|
||||
}
|
||||
|
||||
void BlueprintLibrary::handleEvent(std::shared_ptr<const SelectionChangedEvent> event)
|
||||
{
|
||||
m_selectedBuildingIds = event->ids;
|
||||
}
|
||||
|
||||
void BlueprintLibrary::handleEvent(std::shared_ptr<const BlueprintModeExitedEvent> /*event*/)
|
||||
{
|
||||
m_activeIndex = std::nullopt;
|
||||
}
|
||||
|
||||
void BlueprintLibrary::handleEvent(
|
||||
std::shared_ptr<const TemporaryBlueprintRequestedEvent> /*event*/)
|
||||
{
|
||||
// Temporary blueprint (REQ-UI-BLUEPRINT-TEMP): build from the current selection and
|
||||
// enter placement mode without adding it to the list or persisting it. If nothing
|
||||
// player-placeable is selected, do nothing.
|
||||
Blueprint blueprint = createBlueprintFromSelection();
|
||||
if (blueprint.buildings.empty()) { return; }
|
||||
|
||||
// No saved blueprint is active while a temporary one is being placed.
|
||||
m_activeIndex = std::nullopt;
|
||||
EventManager::getInstance()->sendEventImmediately(
|
||||
std::make_shared<BlueprintPlacementRequestedEvent>(std::move(blueprint)));
|
||||
}
|
||||
|
||||
Blueprint BlueprintLibrary::createBlueprintFromSelection() const
|
||||
{
|
||||
// Capture is shared, testable logic in lib/sim: it resolves each selected id as an
|
||||
// operational building or a construction site alike (REQ-UI-BLUEPRINT-CREATE,
|
||||
// REQ-UI-BLUEPRINT-STORAGE).
|
||||
return captureBlueprintFromSelection(*m_sim, m_selectedBuildingIds);
|
||||
}
|
||||
|
||||
void BlueprintLibrary::loadFromDisk()
|
||||
{
|
||||
// Load at startup (REQ-UI-BLUEPRINT-LOAD). Missing file: start empty, no error.
|
||||
const QString path = QCoreApplication::applicationDirPath() + "/blueprints.toml";
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return; }
|
||||
try
|
||||
{
|
||||
m_blueprints = BlueprintSerializer::deserialize(file.readAll().toStdString());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
QMessageBox::critical(m_dialogParent, QObject::tr("Load Failed"),
|
||||
QObject::tr("Failed to load blueprints:\n%1").arg(e.what()));
|
||||
m_blueprints.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void BlueprintLibrary::saveToDisk() const
|
||||
{
|
||||
// Persist on shutdown; write errors are silently ignored (REQ-UI-BLUEPRINT-SAVE).
|
||||
const QString path = QCoreApplication::applicationDirPath() + "/blueprints.toml";
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; }
|
||||
try
|
||||
{
|
||||
const std::string content = BlueprintSerializer::serialize(m_blueprints);
|
||||
file.write(QByteArray::fromStdString(content));
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
Reference in New Issue
Block a user