deselect build tool when it becomes unaffordable and fix stale enabled button
BuildButtonGrid now holds the Simulation and reads the building block stock on demand, subscribing to BuildingBlocksChangedEvent itself instead of being driven through MainWindow. When the currently selected build tool can no longer be afforded, builder mode is exited so the button does not stay selected or linger enabled after exit. m_activeIndex is now a std::optional. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y7N59FsLA5e2kuVdqe4Uhc
This commit is contained in:
@@ -12,12 +12,13 @@
|
|||||||
#include "DisplayName.h"
|
#include "DisplayName.h"
|
||||||
#include "EventManager.h"
|
#include "EventManager.h"
|
||||||
#include "ExitBuilderModeRequestedEvent.h"
|
#include "ExitBuilderModeRequestedEvent.h"
|
||||||
|
#include "Simulation.h"
|
||||||
|
|
||||||
|
|
||||||
BuildButtonGrid::BuildButtonGrid(const GameConfig* config, QWidget* parent)
|
BuildButtonGrid::BuildButtonGrid(Simulation* sim, const GameConfig* config, QWidget* parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
|
, m_sim(sim)
|
||||||
, m_config(config)
|
, m_config(config)
|
||||||
, m_activeIndex(-1)
|
|
||||||
{
|
{
|
||||||
QGridLayout* layout = new QGridLayout(this);
|
QGridLayout* layout = new QGridLayout(this);
|
||||||
layout->setSpacing(4);
|
layout->setSpacing(4);
|
||||||
@@ -79,24 +80,42 @@ BuildButtonGrid::~BuildButtonGrid()
|
|||||||
unregisterForEvents();
|
unregisterForEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildButtonGrid::updateAffordability(int buildingBlocks)
|
void BuildButtonGrid::updateAffordability()
|
||||||
{
|
{
|
||||||
|
const int buildingBlocks = m_sim->getBuildingBlocksStock();
|
||||||
|
|
||||||
|
// If the currently selected tool can no longer be afforded, exit builder mode
|
||||||
|
// before recomputing button states so it does not stay selected. Clearing the
|
||||||
|
// active index first lets the loop below disable the now-unaffordable button.
|
||||||
|
if (m_activeIndex)
|
||||||
|
{
|
||||||
|
const BuildingType activeType = m_types[*m_activeIndex];
|
||||||
|
const std::map<BuildingType, int>::const_iterator it = m_costs.find(activeType);
|
||||||
|
const int cost = (it != m_costs.end()) ? it->second : 0;
|
||||||
|
if (buildingBlocks < cost)
|
||||||
|
{
|
||||||
|
clearActiveButton();
|
||||||
|
EventManager::getInstance()->sendEventImmediately(
|
||||||
|
std::make_shared<ExitBuilderModeRequestedEvent>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (std::size_t i = 0; i < m_buttons.size(); ++i)
|
for (std::size_t i = 0; i < m_buttons.size(); ++i)
|
||||||
{
|
{
|
||||||
const BuildingType type = m_types[i];
|
const BuildingType type = m_types[i];
|
||||||
const std::map<BuildingType, int>::const_iterator it = m_costs.find(type);
|
const std::map<BuildingType, int>::const_iterator it = m_costs.find(type);
|
||||||
const int cost = (it != m_costs.end()) ? it->second : 0;
|
const int cost = (it != m_costs.end()) ? it->second : 0;
|
||||||
m_buttons[i]->setEnabled(buildingBlocks >= cost || m_activeIndex == static_cast<int>(i));
|
m_buttons[i]->setEnabled(buildingBlocks >= cost || m_activeIndex == i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildButtonGrid::clearActiveButton()
|
void BuildButtonGrid::clearActiveButton()
|
||||||
{
|
{
|
||||||
if (m_activeIndex >= 0 && m_activeIndex < static_cast<int>(m_buttons.size()))
|
if (m_activeIndex)
|
||||||
{
|
{
|
||||||
m_buttons[static_cast<std::size_t>(m_activeIndex)]->setChecked(false);
|
m_buttons[*m_activeIndex]->setChecked(false);
|
||||||
}
|
}
|
||||||
m_activeIndex = -1;
|
m_activeIndex.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildButtonGrid::onBuildButton(int index)
|
void BuildButtonGrid::onBuildButton(int index)
|
||||||
@@ -105,8 +124,9 @@ void BuildButtonGrid::onBuildButton(int index)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const std::size_t idx = static_cast<std::size_t>(index);
|
||||||
|
|
||||||
if (m_activeIndex == index)
|
if (m_activeIndex == idx)
|
||||||
{
|
{
|
||||||
clearActiveButton();
|
clearActiveButton();
|
||||||
EventManager::getInstance()->sendEventImmediately(
|
EventManager::getInstance()->sendEventImmediately(
|
||||||
@@ -114,15 +134,15 @@ void BuildButtonGrid::onBuildButton(int index)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_activeIndex >= 0 && m_activeIndex < static_cast<int>(m_buttons.size()))
|
if (m_activeIndex)
|
||||||
{
|
{
|
||||||
m_buttons[static_cast<std::size_t>(m_activeIndex)]->setChecked(false);
|
m_buttons[*m_activeIndex]->setChecked(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_activeIndex = index;
|
m_activeIndex = idx;
|
||||||
m_buttons[static_cast<std::size_t>(index)]->setChecked(true);
|
m_buttons[idx]->setChecked(true);
|
||||||
EventManager::getInstance()->sendEventImmediately(
|
EventManager::getInstance()->sendEventImmediately(
|
||||||
std::make_shared<BuildingTypeSelectedEvent>(m_types[static_cast<std::size_t>(index)]));
|
std::make_shared<BuildingTypeSelectedEvent>(m_types[idx]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildButtonGrid::handleEvent(std::shared_ptr<const BuilderModeExitedEvent> /*event*/)
|
void BuildButtonGrid::handleEvent(std::shared_ptr<const BuilderModeExitedEvent> /*event*/)
|
||||||
@@ -130,6 +150,11 @@ void BuildButtonGrid::handleEvent(std::shared_ptr<const BuilderModeExitedEvent>
|
|||||||
clearActiveButton();
|
clearActiveButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BuildButtonGrid::handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> /*event*/)
|
||||||
|
{
|
||||||
|
updateAffordability();
|
||||||
|
}
|
||||||
|
|
||||||
void BuildButtonGrid::handleEvent(std::shared_ptr<const DemolishModeChangedEvent> event)
|
void BuildButtonGrid::handleEvent(std::shared_ptr<const DemolishModeChangedEvent> event)
|
||||||
{
|
{
|
||||||
m_demolishButton->setChecked(event->active);
|
m_demolishButton->setChecked(event->active);
|
||||||
|
|||||||
@@ -1,46 +1,56 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "BuilderModeExitedEvent.h"
|
#include "BuilderModeExitedEvent.h"
|
||||||
#include "BuildHotkeyPressedEvent.h"
|
#include "BuildHotkeyPressedEvent.h"
|
||||||
|
#include "BuildingBlocksChangedEvent.h"
|
||||||
#include "BuildingType.h"
|
#include "BuildingType.h"
|
||||||
#include "DemolishModeChangedEvent.h"
|
#include "DemolishModeChangedEvent.h"
|
||||||
#include "EventHandler.h"
|
#include "EventHandler.h"
|
||||||
#include "GameConfig.h"
|
#include "GameConfig.h"
|
||||||
|
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
|
class Simulation;
|
||||||
|
|
||||||
class BuildButtonGrid : public QWidget,
|
class BuildButtonGrid : public QWidget,
|
||||||
public CombinedEventHandler<BuilderModeExitedEvent,
|
public CombinedEventHandler<BuilderModeExitedEvent,
|
||||||
DemolishModeChangedEvent,
|
DemolishModeChangedEvent,
|
||||||
BuildHotkeyPressedEvent>
|
BuildHotkeyPressedEvent,
|
||||||
|
BuildingBlocksChangedEvent>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BuildButtonGrid(const GameConfig* config, QWidget* parent = nullptr);
|
BuildButtonGrid(Simulation* sim, const GameConfig* config, QWidget* parent = nullptr);
|
||||||
~BuildButtonGrid() override;
|
~BuildButtonGrid() override;
|
||||||
|
|
||||||
void updateAffordability(int buildingBlocks);
|
|
||||||
void clearActiveButton();
|
void clearActiveButton();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Re-evaluates which build buttons are enabled from the current building block
|
||||||
|
// stock (read from the simulation). If the currently selected tool can no longer
|
||||||
|
// be afforded, it exits builder mode so the button does not stay selected.
|
||||||
|
void updateAffordability();
|
||||||
|
|
||||||
void handleEvent(std::shared_ptr<const BuilderModeExitedEvent> event) override;
|
void handleEvent(std::shared_ptr<const BuilderModeExitedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const DemolishModeChangedEvent> event) override;
|
void handleEvent(std::shared_ptr<const DemolishModeChangedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const BuildHotkeyPressedEvent> event) override;
|
void handleEvent(std::shared_ptr<const BuildHotkeyPressedEvent> event) override;
|
||||||
|
void handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onBuildButton(int index);
|
void onBuildButton(int index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Simulation* m_sim;
|
||||||
const GameConfig* m_config;
|
const GameConfig* m_config;
|
||||||
std::vector<BuildingType> m_types;
|
std::vector<BuildingType> m_types;
|
||||||
std::vector<QPushButton*> m_buttons;
|
std::vector<QPushButton*> m_buttons;
|
||||||
std::map<BuildingType, int> m_costs;
|
std::map<BuildingType, int> m_costs;
|
||||||
int m_activeIndex;
|
std::optional<std::size_t> m_activeIndex;
|
||||||
QPushButton* m_demolishButton;
|
QPushButton* m_demolishButton;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
#include "BlueprintPanel.h"
|
#include "BlueprintPanel.h"
|
||||||
#include "BuildButtonGrid.h"
|
#include "BuildButtonGrid.h"
|
||||||
#include "BuildingBlocksChangedEvent.h"
|
|
||||||
#include "BuildingSystem.h"
|
#include "BuildingSystem.h"
|
||||||
#include "Command.h"
|
#include "Command.h"
|
||||||
#include "CommandRequestedEvent.h"
|
#include "CommandRequestedEvent.h"
|
||||||
@@ -53,7 +52,7 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir,
|
|||||||
sideLayout->setSpacing(1);
|
sideLayout->setSpacing(1);
|
||||||
|
|
||||||
m_selectedBuildingPanel = new SelectedBuildingPanel(sim, &sim->getConfig(), m_sidePanel);
|
m_selectedBuildingPanel = new SelectedBuildingPanel(sim, &sim->getConfig(), m_sidePanel);
|
||||||
m_buildButtonGrid = new BuildButtonGrid(&sim->getConfig(), m_sidePanel);
|
m_buildButtonGrid = new BuildButtonGrid(sim, &sim->getConfig(), m_sidePanel);
|
||||||
m_blueprintPanel = new BlueprintPanel(sim, &sim->getConfig(), m_sidePanel);
|
m_blueprintPanel = new BlueprintPanel(sim, &sim->getConfig(), m_sidePanel);
|
||||||
|
|
||||||
sideLayout->addWidget(m_selectedBuildingPanel, 1);
|
sideLayout->addWidget(m_selectedBuildingPanel, 1);
|
||||||
@@ -151,11 +150,6 @@ void MainWindow::layoutPanels()
|
|||||||
m_dimOverlay->setGeometry(0, 0, totalW, totalH);
|
m_dimOverlay->setGeometry(0, 0, totalW, totalH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event)
|
|
||||||
{
|
|
||||||
m_buildButtonGrid->updateAffordability(event->blocks);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::handleEvent(std::shared_ptr<const SchematicChoicesAvailableEvent> event)
|
void MainWindow::handleEvent(std::shared_ptr<const SchematicChoicesAvailableEvent> event)
|
||||||
{
|
{
|
||||||
const double prevSpeed = m_gameWorldView->getGameSpeed();
|
const double prevSpeed = m_gameWorldView->getGameSpeed();
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "BuildingBlocksChangedEvent.h"
|
|
||||||
#include "BuildingId.h"
|
#include "BuildingId.h"
|
||||||
#include "EscapeMenuRequestedEvent.h"
|
#include "EscapeMenuRequestedEvent.h"
|
||||||
#include "EventHandler.h"
|
#include "EventHandler.h"
|
||||||
@@ -32,8 +31,7 @@ class QCloseEvent;
|
|||||||
class QResizeEvent;
|
class QResizeEvent;
|
||||||
|
|
||||||
class MainWindow : public QWidget,
|
class MainWindow : public QWidget,
|
||||||
public CombinedEventHandler<BuildingBlocksChangedEvent,
|
public CombinedEventHandler<SchematicChoicesAvailableEvent,
|
||||||
SchematicChoicesAvailableEvent,
|
|
||||||
GameOverEvent,
|
GameOverEvent,
|
||||||
WinEvent,
|
WinEvent,
|
||||||
EscapeMenuRequestedEvent,
|
EscapeMenuRequestedEvent,
|
||||||
@@ -52,7 +50,6 @@ protected:
|
|||||||
void closeEvent(QCloseEvent* event) override;
|
void closeEvent(QCloseEvent* event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event) override;
|
|
||||||
void handleEvent(std::shared_ptr<const SchematicChoicesAvailableEvent> event) override;
|
void handleEvent(std::shared_ptr<const SchematicChoicesAvailableEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const GameOverEvent> 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 WinEvent> event) override;
|
||||||
|
|||||||
Reference in New Issue
Block a user