Compare commits
2 Commits
0.1.2
...
ee1ee84f4f
| Author | SHA1 | Date | |
|---|---|---|---|
| ee1ee84f4f | |||
| 42a23ae42a |
@@ -259,7 +259,7 @@ Modules in `modules.toml` define a `surface_mask` — a list of strings that des
|
|||||||
|
|
||||||
### Module UI
|
### Module UI
|
||||||
|
|
||||||
- REQ-MOD-UI-PREVIEW: When a schematic is selected in a shipyard's selected building panel, a small non-interactive **ship layout preview** widget is shown below the schematic selection button (REQ-UI-SELECT-BUTTON). The preview renders the ship's layout grid at a reduced scale: buildable cells without a module are shown as white, non-buildable cells are shown as black, and cells occupied by a module are shown in that module's `fill_color` with the module's `glyph` character. Below the preview, a "Configure" button is shown.
|
- REQ-MOD-UI-PREVIEW: For a selected shipyard (operational building or construction site), the selected building panel always shows a small non-interactive **ship layout preview** widget below the schematic selection button (REQ-UI-SELECT-BUTTON) and a "Configure" button below the preview. Both are **disabled while no schematic is selected**, and enabled once one is; the preview then shows an empty placeholder in place of a layout grid. When a schematic is selected, the preview renders the ship's layout grid at a reduced scale: buildable cells without a module are shown as white, non-buildable cells are shown as black, and cells occupied by a module are shown in that module's `fill_color` with the module's `glyph` character. For non-shipyard buildings, neither the preview nor the "Configure" button is shown.
|
||||||
- REQ-MOD-UI-DIALOG: Clicking the "Configure" button opens the **layout configuration dialog** as a modal. While the dialog is open, the game is paused (speed set to 0×). On close, the game speed is restored to what it was before the dialog was opened.
|
- REQ-MOD-UI-DIALOG: Clicking the "Configure" button opens the **layout configuration dialog** as a modal. While the dialog is open, the game is paused (speed set to 0×). On close, the game speed is restored to what it was before the dialog was opened.
|
||||||
|
|
||||||
The dialog contains:
|
The dialog contains:
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir,
|
|||||||
|
|
||||||
m_sidePanel = new QWidget(this);
|
m_sidePanel = new QWidget(this);
|
||||||
QVBoxLayout* sideLayout = new QVBoxLayout(m_sidePanel);
|
QVBoxLayout* sideLayout = new QVBoxLayout(m_sidePanel);
|
||||||
sideLayout->setContentsMargins(0, 0, 0, 0);
|
sideLayout->setContentsMargins(1, 1, 1, 1);
|
||||||
sideLayout->setSpacing(0);
|
sideLayout->setSpacing(1);
|
||||||
|
|
||||||
m_selectedBuildingPanel = new SelectedBuildingPanel(sim, &sim->config(), m_sidePanel);
|
m_selectedBuildingPanel = new SelectedBuildingPanel(sim, &sim->config(), m_sidePanel);
|
||||||
m_buildButtonGrid = new BuildButtonGrid(&sim->config(), m_sidePanel);
|
m_buildButtonGrid = new BuildButtonGrid(&sim->config(), m_sidePanel);
|
||||||
@@ -60,6 +60,20 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir,
|
|||||||
sideLayout->addWidget(m_buildButtonGrid, 1);
|
sideLayout->addWidget(m_buildButtonGrid, 1);
|
||||||
sideLayout->addWidget(m_blueprintPanel, 1);
|
sideLayout->addWidget(m_blueprintPanel, 1);
|
||||||
|
|
||||||
|
// Draw a thin border around each of the three side-panel sections. The class
|
||||||
|
// scoped selectors keep the border on the panels themselves rather than
|
||||||
|
// cascading onto their child widgets; WA_StyledBackground lets the plain
|
||||||
|
// QWidget subclasses honor the stylesheet box (border/background).
|
||||||
|
for (QWidget* panel : { static_cast<QWidget*>(m_selectedBuildingPanel),
|
||||||
|
static_cast<QWidget*>(m_buildButtonGrid),
|
||||||
|
static_cast<QWidget*>(m_blueprintPanel) })
|
||||||
|
{
|
||||||
|
panel->setAttribute(Qt::WA_StyledBackground, true);
|
||||||
|
}
|
||||||
|
m_sidePanel->setStyleSheet(QStringLiteral(
|
||||||
|
"SelectedBuildingPanel, BuildButtonGrid, BlueprintPanel {"
|
||||||
|
" border: 1px solid palette(mid); }"));
|
||||||
|
|
||||||
m_gameWorldView->setFocus();
|
m_gameWorldView->setFocus();
|
||||||
|
|
||||||
connect(qApp, &QApplication::focusChanged, this, [this](QWidget*, QWidget* newWidget) {
|
connect(qApp, &QApplication::focusChanged, this, [this](QWidget*, QWidget* newWidget) {
|
||||||
|
|||||||
@@ -566,11 +566,21 @@ void SelectedBuildingPanel::updateShipyardLayoutWidgets(
|
|||||||
const std::string& recipeId,
|
const std::string& recipeId,
|
||||||
const std::optional<ShipLayoutConfig>& shipLayout)
|
const std::optional<ShipLayoutConfig>& shipLayout)
|
||||||
{
|
{
|
||||||
const ShipDef* shipDef = (type == BuildingType::Shipyard)
|
// The preview and Configure button are shipyard-only controls; hide them
|
||||||
? findShipDef(recipeId)
|
// entirely for other building types.
|
||||||
: nullptr;
|
if (type != BuildingType::Shipyard)
|
||||||
|
{
|
||||||
|
m_layoutPreview->hide();
|
||||||
|
m_configureLayoutBtn->hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (shipDef && !shipDef->layout.empty())
|
const ShipDef* shipDef = findShipDef(recipeId);
|
||||||
|
const bool hasSchematic = shipDef && !shipDef->layout.empty();
|
||||||
|
|
||||||
|
// Always show the preview and Configure button for a shipyard; they are only
|
||||||
|
// enabled once a schematic is selected (REQ-MOD-UI-PREVIEW).
|
||||||
|
if (hasSchematic)
|
||||||
{
|
{
|
||||||
ShipLayoutConfig layout;
|
ShipLayoutConfig layout;
|
||||||
if (shipLayout.has_value())
|
if (shipLayout.has_value())
|
||||||
@@ -579,14 +589,16 @@ void SelectedBuildingPanel::updateShipyardLayoutWidgets(
|
|||||||
}
|
}
|
||||||
m_layoutPreview->setShipAndLayout(
|
m_layoutPreview->setShipAndLayout(
|
||||||
shipDef->layout, layout, &m_config->modules.modules);
|
shipDef->layout, layout, &m_config->modules.modules);
|
||||||
m_layoutPreview->show();
|
|
||||||
m_configureLayoutBtn->show();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_layoutPreview->hide();
|
m_layoutPreview->showPlaceholder();
|
||||||
m_configureLayoutBtn->hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_layoutPreview->setEnabled(hasSchematic);
|
||||||
|
m_configureLayoutBtn->setEnabled(hasSchematic);
|
||||||
|
m_layoutPreview->show();
|
||||||
|
m_configureLayoutBtn->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
const RecipeDef* SelectedBuildingPanel::findRecipe(const Building* b) const
|
const RecipeDef* SelectedBuildingPanel::findRecipe(const Building* b) const
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ namespace
|
|||||||
|
|
||||||
const int kCellSize = 8;
|
const int kCellSize = 8;
|
||||||
|
|
||||||
|
// Size of the empty placeholder box shown when no schematic is selected.
|
||||||
|
const int kPlaceholderWidth = 64;
|
||||||
|
const int kPlaceholderHeight = 40;
|
||||||
|
|
||||||
const ModuleDef* findModuleDef(const std::vector<ModuleDef>& modules,
|
const ModuleDef* findModuleDef(const std::vector<ModuleDef>& modules,
|
||||||
const std::string& id)
|
const std::string& id)
|
||||||
{
|
{
|
||||||
@@ -90,14 +94,28 @@ void ShipLayoutPreview::clear()
|
|||||||
m_modules = nullptr;
|
m_modules = nullptr;
|
||||||
m_rows = 0;
|
m_rows = 0;
|
||||||
m_cols = 0;
|
m_cols = 0;
|
||||||
|
m_placeholder = false;
|
||||||
setFixedSize(0, 0);
|
setFixedSize(0, 0);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShipLayoutPreview::showPlaceholder()
|
||||||
|
{
|
||||||
|
m_grid.clear();
|
||||||
|
m_placedModules.clear();
|
||||||
|
m_modules = nullptr;
|
||||||
|
m_rows = 0;
|
||||||
|
m_cols = 0;
|
||||||
|
m_placeholder = true;
|
||||||
|
setFixedSize(kPlaceholderWidth, kPlaceholderHeight);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void ShipLayoutPreview::setShipAndLayout(const std::vector<std::string>& shipLayout,
|
void ShipLayoutPreview::setShipAndLayout(const std::vector<std::string>& shipLayout,
|
||||||
const ShipLayoutConfig& layout,
|
const ShipLayoutConfig& layout,
|
||||||
const std::vector<ModuleDef>* modules)
|
const std::vector<ModuleDef>* modules)
|
||||||
{
|
{
|
||||||
|
m_placeholder = false;
|
||||||
m_modules = modules;
|
m_modules = modules;
|
||||||
m_placedModules = layout.placedModules;
|
m_placedModules = layout.placedModules;
|
||||||
m_rows = static_cast<int>(shipLayout.size());
|
m_rows = static_cast<int>(shipLayout.size());
|
||||||
@@ -156,6 +174,18 @@ void ShipLayoutPreview::setShipAndLayout(const std::vector<std::string>& shipLay
|
|||||||
|
|
||||||
void ShipLayoutPreview::paintEvent(QPaintEvent* /*event*/)
|
void ShipLayoutPreview::paintEvent(QPaintEvent* /*event*/)
|
||||||
{
|
{
|
||||||
|
if (m_placeholder)
|
||||||
|
{
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing, false);
|
||||||
|
const QRect box = rect().adjusted(0, 0, -1, -1);
|
||||||
|
painter.fillRect(box, QColor(40, 40, 40));
|
||||||
|
painter.setPen(QColor(128, 128, 128));
|
||||||
|
painter.drawRect(box);
|
||||||
|
painter.drawText(box, Qt::AlignCenter, tr("No schematic"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_rows == 0 || m_cols == 0)
|
if (m_rows == 0 || m_cols == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ public:
|
|||||||
const std::vector<ModuleDef>* modules);
|
const std::vector<ModuleDef>* modules);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
// Shows an empty placeholder box (no ship layout) so the preview stays
|
||||||
|
// visible while no schematic is selected (REQ-MOD-UI-PREVIEW).
|
||||||
|
void showPlaceholder();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent* event) override;
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
|
||||||
@@ -35,4 +39,5 @@ private:
|
|||||||
const std::vector<ModuleDef>* m_modules;
|
const std::vector<ModuleDef>* m_modules;
|
||||||
int m_rows;
|
int m_rows;
|
||||||
int m_cols;
|
int m_cols;
|
||||||
|
bool m_placeholder = false;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user