#pragma once #include #include #include #include #include #include "entt/entity/entity.hpp" #include "BeltSystem.h" #include "Building.h" #include "BuildingId.h" #include "DebugDrawToggledEvent.h" #include "EntitySelectionChangedEvent.h" #include "EventHandler.h" #include "GameConfig.h" #include "PlayerCommandsAppliedEvent.h" #include "RecipesConfig.h" #include "ScrapSelectionChangedEvent.h" #include "SelectionChangedEvent.h" #include "ShipLayout.h" #include "ShipsConfig.h" #include "Tick.h" #include "TickAdvancedEvent.h" class Simulation; class ShipLayoutPreview; class ShipStatsPanel; class QLabel; class QListWidget; class QPushButton; class QVBoxLayout; class SelectedBuildingPanel : public QWidget, public CombinedEventHandler { Q_OBJECT public: SelectedBuildingPanel(Simulation* sim, const GameConfig* config, QWidget* parent = nullptr); ~SelectedBuildingPanel() override; private: void handleEvent(std::shared_ptr event) override; void handleEvent(std::shared_ptr event) override; void handleEvent(std::shared_ptr event) override; void handleEvent(std::shared_ptr event) override; void handleEvent(std::shared_ptr event) override; void handleEvent(std::shared_ptr event) override; private slots: void onSelectRecipeClicked(); void onClearBelt(); void onSplitterFilterChanged(); private: // Why the selection display is being refreshed. A periodic tick only needs a // lightweight content update (e.g. a construction site's progress label), // whereas an applied player command may have changed the configuration and // needs a full structural rebuild. enum class RefreshReason { PeriodicTick, CommandApplied }; void onSelectionChanged(const std::vector& ids); void refreshSelectionDisplay(RefreshReason reason); void rebuild(); void hideAllWidgets(); void clearContent(); void buildEmpty(); void buildSingle(BuildingId id); void buildMulti(const std::vector& ids); void refreshScrapTotal(); // "Scrap: N" for the summed remaining amount of the selected piles (REQ-UI-SCRAP-PANEL). QString scrapTotalText() const; void refreshBuffers(const Building* b); void refreshSiteProgress(const ConstructionSite* s); void updateShipyardLayoutWidgets(BuildingType type, const std::string& recipeId, const std::optional& shipLayout); void buildSplitterFilters(const std::optional& info); const RecipeDef* findRecipe(const Building* b) const; const ShipDef* findShipDef(const std::string& id) const; std::vector getAllItemIds() const; Simulation* m_sim; const GameConfig* m_config; std::vector m_selectedBuildingIds; QVBoxLayout* m_layout; QLabel* m_titleLabel; QPushButton* m_recipeSelectButton; QPushButton* m_clearBeltBtn; QLabel* m_filterALabel; QListWidget* m_filterAList; QLabel* m_filterBLabel; QListWidget* m_filterBList; QLabel* m_buffersLabel; ShipLayoutPreview* m_layoutPreview; QPushButton* m_configureLayoutBtn; std::optional m_singleBuildingId; bool m_singleIsSite = false; // selected single entity is a construction site QPoint m_splitterTile; std::string m_currentRecipeId; bool m_debugDraw = false; // The selected ships/defence stations. Shares the "field" selection category with // scrap (m_selectedScrap): both can be non-empty at once (REQ-UI-SELECTION-CATEGORIES). std::vector m_selectedEntities; ShipStatsPanel* m_entityStatsPanel; QLabel* m_entityTitleLabel; QLabel* m_stationStatsLabel; QLabel* m_entitySummaryLabel; std::vector m_selectedScrap; QLabel* m_scrapLabel; // Renders the combined field selection (actors + scrap): a single-actor stats panel // or a multi-actor summary, plus the scrap total when scrap is also selected // (REQ-UI-FIELD-MULTI-SELECTION). void buildFieldSelection(); void buildEntityShip(entt::entity entity); void buildEntityStation(entt::entity entity); void buildEntitySummary(); void refreshEntityStats(); void clearEntityDisplay(); };