The panel decides nothing about what the controls are: it asks the same resolver the key handling and the mouse dispatch ask, and renders each badge from the binding that resolver matches. A chip cannot claim a key that does nothing, and a label cannot describe a click that does something else, because neither is written here. Display text is the one part that is not shared -- lib/core says what is available and what triggers it, ControlActionText.cpp says what it is called. That split is why the table can stay free of UI strings and still be the single source of the pairing. It refreshes on a timer rather than by subscribing. Two things that change a row -- a belt drag starting, the ghost crossing a transfer target -- happen on mouse movement and publish nothing, and they must still show while the game is paused, so there is no event and no tick to hang it on. Resolving is comparing two vectors of enums, and the rebuild is skipped unless they differ. Left edge, bottom-aligned in the same band the selection panel is confined to, so it clears the build bar's strip and never meets the panel on the opposite edge. Clicking the heading collapses it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
113 lines
4.7 KiB
C++
113 lines
4.7 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 ControlsPanel;
|
|
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;
|
|
ControlsPanel* m_controlsPanel;
|
|
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
|
|
};
|