Files
dota_factory/src/ui/MainWindow.h
Malte Langkabel 89e984ec76 split the selection panel into one card per kind of selection
The panel rendered every selection out of a single pool of member widgets,
hidden and shown per branch, so each build path had to remember to hide the
other branches' widgets. That coupling produced the two defects fixed in
668ce0f, and the per-type detail the requirements now ask for would only add
more of it.

The pool is gone. SelectionPanel keeps the category arbitration, the float and
the hide-when-empty behaviour, and hosts exactly one SelectionContent at a
time; SelectionContentFactory picks which one from the selection alone. Each
card is one row of the catalog in REQ-UI-SELECTION-CONTENT and owns only its
own widgets.

The card structure (REQ-UI-SELECTION-CARD) lives in the base class: a header
with an identity symbol, a name and one right slot, then a configuration group
and a runtime group. A construction site keeps its configuration and has its
whole runtime group replaced by the construction progress, decided once there
rather than in every card (REQ-BLD-SITE-CONFIG).

Also implemented here:
- REQ-UI-SELECTION-STATUS: the header status dot, taken from the simulation's
  own getProductionStatus() so the panel and the world's status light cannot
  disagree.
- REQ-UI-SELECTION-AGGREGATE: belt-subsystem tiles and debris-only selections
  collapse into one card with a count instead of a count summary.
- REQ-UI-HQ-PANEL: the HQ shows the global block stock and its HP, neither of
  which is a buffer.
- BuildingIconCache, extracted from BuildButtonBar's file-local chip loading so
  the card headers and the build buttons rasterize the same SVGs once.

FieldSelectionPanel is deleted: ships, stations, debris and the field count
summary are four more cards in the same factory, so the two-panel arbitration
collapses into one decision.

The card parts are still today's labels and buttons; the item chips, bars,
recipe summary and stat rows follow.

Build clean, 541 tests pass, app runs with no Qt warnings. Visual check
pending.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcReq7hVk4KUPhTDKWAG7K
2026-08-07 12:18:33 +02:00

111 lines
4.6 KiB
C++

#pragma once
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include <QWidget>
#include "BlueprintSaveRequestedEvent.h"
#include "BlueprintSelectionRequestedEvent.h"
#include "BuildingId.h"
#include "EscapeMenuRequestedEvent.h"
#include "EventHandler.h"
#include "GameConfig.h"
#include "GameOverEvent.h"
#include "LayoutDialogRequestedEvent.h"
#include "ModalDimOverlay.h"
#include "WinEvent.h"
#include "RecipeSelectionRequestedEvent.h"
#include "SchematicChoicesAvailableEvent.h"
#include "ShipLayout.h"
#include "ShipLayoutBlueprint.h"
#include "Tick.h"
#include "VisualsConfig.h"
struct ParsedReplay;
class Simulation;
class GameWorldView;
class HeaderBar;
class SelectionPanel;
class BuildButtonBar;
class BlueprintLibrary;
class BuildingIconCache;
class ItemIconCache;
class QCloseEvent;
class QResizeEvent;
class MainWindow : public QWidget,
public CombinedEventHandler<SchematicChoicesAvailableEvent,
GameOverEvent,
WinEvent,
EscapeMenuRequestedEvent,
LayoutDialogRequestedEvent,
RecipeSelectionRequestedEvent,
BlueprintSaveRequestedEvent,
BlueprintSelectionRequestedEvent>
{
Q_OBJECT
public:
MainWindow(Simulation* sim, const std::string& configDir,
std::shared_ptr<ParsedReplay> replay = nullptr, QWidget* parent = nullptr);
~MainWindow() override;
protected:
void resizeEvent(QResizeEvent* event) override;
void closeEvent(QCloseEvent* event) override;
private:
void handleEvent(std::shared_ptr<const SchematicChoicesAvailableEvent> event) override;
void handleEvent(std::shared_ptr<const GameOverEvent> event) override;
void handleEvent(std::shared_ptr<const WinEvent> event) override;
void handleEvent(std::shared_ptr<const EscapeMenuRequestedEvent> event) override;
void handleEvent(std::shared_ptr<const LayoutDialogRequestedEvent> event) override;
void handleEvent(std::shared_ptr<const RecipeSelectionRequestedEvent> event) override;
void handleEvent(std::shared_ptr<const BlueprintSaveRequestedEvent> event) override;
void handleEvent(std::shared_ptr<const BlueprintSelectionRequestedEvent> event) override;
// Reloads the game config and visuals.toml from disk (REQ-CFG-RELOAD), shared
// by every restart path. On success the reloaded visuals are applied to this
// window and the fresh GameConfig is returned; on failure a modal error dialog
// is shown and std::nullopt is returned, leaving the window state untouched.
std::optional<GameConfig> reloadConfig();
// Opens the shipyard layout configuration dialog for the given schematic and
// current layout, applying the result via SetShipLayoutCommand (REQ-MOD-UI-DIALOG).
void openShipLayoutDialog(BuildingId shipyardId,
const std::string& schematicId,
const ShipLayoutConfig& currentLayout);
// Runs the blueprint selection dialog and enters placement mode for whatever the
// player picked (REQ-UI-BLUEPRINT-DIALOG). Holds no pause or dim scope of its own:
// both callers already hold theirs, which is what keeps the dim continuous when a
// confirmed save hands straight over to this dialog (REQ-UI-MODAL-DIM).
void showBlueprintSelectionDialog();
void layoutPanels();
private:
std::string m_configDir;
VisualsConfig m_visuals;
Simulation* m_sim;
// One per-item icon cache for the whole window (REQ-UI-ITEM-ICON): the header,
// build bar, world view, and recipe dialog all rasterize the same SVGs.
std::unique_ptr<ItemIconCache> m_itemIcons;
// Likewise one per-building chip cache (REQ-UI-BUILD-ICON), shared by the build bar
// and the selection panel's card headers (REQ-UI-SELECTION-CARD).
std::unique_ptr<BuildingIconCache> m_buildingIcons;
GameWorldView* m_gameWorldView;
HeaderBar* m_headerBar;
SelectionPanel* m_selectionPanel;
BuildButtonBar* m_buildButtonBar;
// The saved blueprints themselves; they have no widget of their own any more and
// are reached through the two modal dialogs (REQ-UI-BLUEPRINT-DIALOG).
std::unique_ptr<BlueprintLibrary> m_blueprintLibrary;
ModalDimOverlay* m_dimOverlay = nullptr;
std::vector<ShipLayoutBlueprint> m_layoutBlueprints;
std::shared_ptr<ParsedReplay> m_replay; // non-null => view-only playback
};