#pragma once #include #include #include #include #include #include #include "GameConfig.h" #include "ModalDialog.h" #include "Rotation.h" #include "ShipLayout.h" #include "ShipLayoutBlueprint.h" class ItemIconCache; class QPushButton; class RecipeLineRow; class SectionBox; class ShipStatsPanel; class ShipLayoutDialog : public ModalDialog { Q_OBJECT public: // itemIcons draws what each module costs and what the layout costs in total // (REQ-MOD-UI-DIALOG, REQ-MOD-UI-STATS-PANEL). Not owned. ShipLayoutDialog(const GameConfig* config, const std::string& shipId, const ShipLayoutConfig& currentLayout, std::vector& allBlueprints, std::set unlockedModuleIds, bool debugDraw, ItemIconCache* itemIcons, QWidget* parent = nullptr); std::optional getResult() const; bool isDismissible() const override; public slots: // Backs out one level per dismissal, as Q does in the game world: the module being // placed, then remove mode, then the dialog itself, which discards the session // (REQ-UI-DIALOG-DISMISS). So a single press or click never both leaves a mode and // throws the session away. void requestDismiss() override; protected: void keyPressEvent(QKeyEvent* event) override; signals: void gridCellClicked(QPoint cell); private slots: void onModuleButtonClicked(int index); // Enters remove mode, or leaves it when it is already active (REQ-MOD-REMOVE). // Reached by the Remove button and by a dismissal, which leaves the mode on its way // out of the dialog (REQ-UI-DIALOG-DISMISS). void onRemoveButtonClicked(); void onConfirm(); void onCancel(); public: struct CellInfo { bool buildable; std::optional moduleIndex; // nullopt if empty }; private: void rebuildOccupancy(); void updateGridWidget(); void updateStats(); bool canPlaceModule(const ModuleDef& def, QPoint position, Rotation rotation) const; std::vector rotatedMask(const ModuleDef& def, Rotation rotation) const; void loadLayoutBlueprint(const std::vector& modules); const GameConfig* m_config; ItemIconCache* m_itemIcons; std::string m_shipId; std::set m_unlockedModuleIds; std::vector m_shipLayout; int m_rows; int m_cols; std::vector m_placedModules; std::vector> m_grid; // The module to place, as an index into config modules; nullopt when no // module is selected for placement. m_removeMode is a separate mode in which // clicking a cell removes the module there (mutually exclusive with a // selected module). std::optional m_activeModuleIndex; bool m_removeMode = false; Rotation m_currentRotation; std::vector m_moduleButtons; QPushButton* m_removeButton; QWidget* m_gridWidget; ShipStatsPanel* m_statsPanel; SectionBox* m_buildCostSection; RecipeLineRow* m_buildCostLine; bool m_debugDraw; std::optional m_result; };