move blueprints out of the sidebar into Ctrl+C / Ctrl+V dialogs

This commit is contained in:
2026-08-06 19:03:59 +02:00
parent 2cbcf1554f
commit 18cfe238f6
22 changed files with 1021 additions and 400 deletions

86
src/ui/BlueprintLibrary.h Normal file
View File

@@ -0,0 +1,86 @@
#pragma once
#include <optional>
#include <vector>
#include <QString>
#include "Blueprint.h"
#include "BlueprintModeExitedEvent.h"
#include "BuildingId.h"
#include "EventHandler.h"
#include "GameConfig.h"
#include "SelectionChangedEvent.h"
#include "TemporaryBlueprintRequestedEvent.h"
class Simulation;
class QWidget;
// The player's saved blueprints: the list itself, its persistence (REQ-UI-BLUEPRINT-SAVE,
// REQ-UI-BLUEPRINT-LOAD), capture from the current selection (REQ-UI-BLUEPRINT-CREATE,
// REQ-UI-BLUEPRINT-TEMP), and entry into blueprint placement mode.
//
// Deliberately not a widget: blueprints have no permanent place on screen any more
// (REQ-UI-BLUEPRINT-DIALOG), and the modal dialogs that present them must be driven from
// MainWindow, the only widget that can pause the game (ModalPauseScope) and raise the dim
// overlay. This class is the model those dialogs read and mutate.
class BlueprintLibrary : public CombinedEventHandler<SelectionChangedEvent,
BlueprintModeExitedEvent,
TemporaryBlueprintRequestedEvent>
{
public:
// dialogParent parents the load-failure message box (REQ-UI-BLUEPRINT-LOAD) and is
// not owned.
BlueprintLibrary(Simulation* sim, const GameConfig* config, QWidget* dialogParent);
~BlueprintLibrary();
// True when the current selection holds at least one player-placeable building or
// construction site -- the condition under which Ctrl+C has any effect
// (REQ-UI-BLUEPRINT-CREATE).
bool getCanCaptureSelection() const;
// Captures the current selection under the given name and appends it to the list.
// Silently does nothing when nothing player-placeable is selected.
void saveSelectionAs(const QString& name);
const std::vector<Blueprint>& getBlueprints() const;
// The blueprint's contents line, ready for its card: one "<name> x <count>" entry
// per building type, comma-separated, ordered by summarizeBlueprintContents
// (REQ-UI-BLUEPRINT-CARD).
QString getContentsSummary(int index) const;
// Sum of the constituent buildings' placement costs (REQ-UI-BLUEPRINT-CARD).
int getCost(int index) const;
// Whether the player can currently afford the blueprint's total cost, which is what
// enables or greys out its card (REQ-UI-BLUEPRINT-CARD).
bool getCanAfford(int index) const;
// Removes the blueprint, exiting blueprint placement mode if it was the active one
// (REQ-UI-BLUEPRINT-DELETE).
void remove(int index);
// Enters blueprint placement mode for the blueprint (REQ-UI-BLUEPRINT-MODE).
void beginPlacement(int index);
private:
void handleEvent(std::shared_ptr<const SelectionChangedEvent> event) override;
void handleEvent(std::shared_ptr<const BlueprintModeExitedEvent> event) override;
void handleEvent(std::shared_ptr<const TemporaryBlueprintRequestedEvent> event) override;
Blueprint createBlueprintFromSelection() const;
void loadFromDisk();
void saveToDisk() const;
// The simulation is the single source of truth for the block stock and the
// selection; the change events are only refresh signals.
Simulation* m_sim;
const GameConfig* m_config;
QWidget* m_dialogParent;
std::vector<BuildingId> m_selectedBuildingIds;
std::vector<Blueprint> m_blueprints;
// Index of the blueprint currently in placement mode, so deleting it can exit that
// mode (REQ-UI-BLUEPRINT-DELETE). nullopt = no saved blueprint is being placed.
std::optional<int> m_activeIndex;
};