replace combined stateUpdated signal with individual events

This commit is contained in:
2026-06-05 18:10:40 +02:00
parent 9677133c54
commit 4e3e3ac715
18 changed files with 216 additions and 66 deletions

View File

@@ -117,6 +117,12 @@ void EventManager::processEvents()
} }
} }
void EventManager::clearEvents()
{
std::scoped_lock<std::mutex> lock(m_eventsMutex);
m_events.clear();
}
bool EventManager::hasEvents() const bool EventManager::hasEvents() const
{ {
return !m_events.empty(); return !m_events.empty();

View File

@@ -28,6 +28,7 @@ public:
void sendEventImmediately(std::shared_ptr<Event> event); void sendEventImmediately(std::shared_ptr<Event> event);
void addEvent(std::shared_ptr<Event> event); void addEvent(std::shared_ptr<Event> event);
void processEvents(); void processEvents();
void clearEvents();
bool hasEvents() const; bool hasEvents() const;

View File

@@ -0,0 +1,17 @@
#ifndef BOSS_WAVE_UPDATED_EVENT_H
#define BOSS_WAVE_UPDATED_EVENT_H
#include "Event.h"
#include "Tick.h"
class BossWaveUpdatedEvent : public Event
{
public:
BossWaveUpdatedEvent(int counter, Tick countdownTicks)
: counter(counter), countdownTicks(countdownTicks) {}
const int counter;
const Tick countdownTicks;
};
#endif // BOSS_WAVE_UPDATED_EVENT_H

View File

@@ -0,0 +1,14 @@
#ifndef BUILDING_BLOCKS_CHANGED_EVENT_H
#define BUILDING_BLOCKS_CHANGED_EVENT_H
#include "Event.h"
class BuildingBlocksChangedEvent : public Event
{
public:
explicit BuildingBlocksChangedEvent(int blocks) : blocks(blocks) {}
const int blocks;
};
#endif // BUILDING_BLOCKS_CHANGED_EVENT_H

View File

@@ -1,6 +1,10 @@
SET(HDRS SET(HDRS
${HDRS} ${HDRS}
${CMAKE_CURRENT_SOURCE_DIR}/TracePrintRequestedEvent.h ${CMAKE_CURRENT_SOURCE_DIR}/TracePrintRequestedEvent.h
${CMAKE_CURRENT_SOURCE_DIR}/TickAdvancedEvent.h
${CMAKE_CURRENT_SOURCE_DIR}/BuildingBlocksChangedEvent.h
${CMAKE_CURRENT_SOURCE_DIR}/GameSpeedChangedEvent.h
${CMAKE_CURRENT_SOURCE_DIR}/BossWaveUpdatedEvent.h
PARENT_SCOPE PARENT_SCOPE
) )

View File

@@ -0,0 +1,14 @@
#ifndef GAME_SPEED_CHANGED_EVENT_H
#define GAME_SPEED_CHANGED_EVENT_H
#include "Event.h"
class GameSpeedChangedEvent : public Event
{
public:
explicit GameSpeedChangedEvent(double speed) : speed(speed) {}
const double speed;
};
#endif // GAME_SPEED_CHANGED_EVENT_H

View File

@@ -0,0 +1,15 @@
#ifndef TICK_ADVANCED_EVENT_H
#define TICK_ADVANCED_EVENT_H
#include "Event.h"
#include "Tick.h"
class TickAdvancedEvent : public Event
{
public:
explicit TickAdvancedEvent(Tick tick) : tick(tick) {}
const Tick tick;
};
#endif // TICK_ADVANCED_EVENT_H

View File

@@ -93,7 +93,7 @@ void Simulation::reset(GameConfig newConfig, unsigned int seed)
void Simulation::reset(unsigned int seed) void Simulation::reset(unsigned int seed)
{ {
EventManager::destroyInstance(); EventManager::getInstance()->clearEvents();
m_rng.seed(seed); m_rng.seed(seed);
m_currentTick = 0; m_currentTick = 0;
m_nextDepartureTick = secondsToTicks(m_config.world.departureIntervalSeconds); m_nextDepartureTick = secondsToTicks(m_config.world.departureIntervalSeconds);

View File

@@ -13,6 +13,7 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include "BlueprintSerializer.h" #include "BlueprintSerializer.h"
#include "BuildingBlocksChangedEvent.h"
#include "Building.h" #include "Building.h"
#include "BuildingSystem.h" #include "BuildingSystem.h"
@@ -60,6 +61,13 @@ BlueprintPanel::BlueprintPanel(Simulation* sim, const GameConfig* config, QWidge
connect(m_saveBtn, &QPushButton::clicked, this, &BlueprintPanel::onSaveClicked); connect(m_saveBtn, &QPushButton::clicked, this, &BlueprintPanel::onSaveClicked);
connect(m_loadBtn, &QPushButton::clicked, this, &BlueprintPanel::onLoadClicked); connect(m_loadBtn, &QPushButton::clicked, this, &BlueprintPanel::onLoadClicked);
registerForEvent();
}
BlueprintPanel::~BlueprintPanel()
{
unregisterForEvent();
} }
void BlueprintPanel::onSelectionChanged(const std::vector<BuildingId>& ids) void BlueprintPanel::onSelectionChanged(const std::vector<BuildingId>& ids)
@@ -68,9 +76,9 @@ void BlueprintPanel::onSelectionChanged(const std::vector<BuildingId>& ids)
refreshButtonStates(); refreshButtonStates();
} }
void BlueprintPanel::onStateUpdated(Tick /*tick*/, int blocks, double /*speed*/) void BlueprintPanel::handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event)
{ {
m_currentBlocks = blocks; m_currentBlocks = event->blocks;
refreshButtonStates(); refreshButtonStates();
} }

View File

@@ -5,7 +5,9 @@
#include <QWidget> #include <QWidget>
#include "Blueprint.h" #include "Blueprint.h"
#include "BuildingBlocksChangedEvent.h"
#include "BuildingId.h" #include "BuildingId.h"
#include "EventHandler.h"
#include "GameConfig.h" #include "GameConfig.h"
#include "Tick.h" #include "Tick.h"
@@ -14,22 +16,26 @@ class QPushButton;
class QScrollArea; class QScrollArea;
class QVBoxLayout; class QVBoxLayout;
class BlueprintPanel : public QWidget class BlueprintPanel : public QWidget,
public EventHandler<BuildingBlocksChangedEvent>
{ {
Q_OBJECT Q_OBJECT
public: public:
BlueprintPanel(Simulation* sim, const GameConfig* config, QWidget* parent = nullptr); BlueprintPanel(Simulation* sim, const GameConfig* config, QWidget* parent = nullptr);
~BlueprintPanel() override;
public slots: public slots:
void onSelectionChanged(const std::vector<BuildingId>& ids); void onSelectionChanged(const std::vector<BuildingId>& ids);
void onStateUpdated(Tick tick, int blocks, double speed);
void clearActiveBlueprintButton(); void clearActiveBlueprintButton();
signals: signals:
void blueprintPlacementRequested(Blueprint blueprint); void blueprintPlacementRequested(Blueprint blueprint);
void exitBlueprintModeRequested(); void exitBlueprintModeRequested();
private:
void handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event) override;
private slots: private slots:
void onCreateClicked(); void onCreateClicked();
void onDeleteBlueprintClicked(int index); void onDeleteBlueprintClicked(int index);

View File

@@ -34,6 +34,10 @@
#include "SurfaceMask.h" #include "SurfaceMask.h"
#include "Tick.h" #include "Tick.h"
#include "TracePrintRequestedEvent.h" #include "TracePrintRequestedEvent.h"
#include "BossWaveUpdatedEvent.h"
#include "BuildingBlocksChangedEvent.h"
#include "GameSpeedChangedEvent.h"
#include "TickAdvancedEvent.h"
namespace namespace
{ {
@@ -239,12 +243,33 @@ void GameWorldView::onFrame()
clampScroll(); clampScroll();
} }
// Emit state update for header bar / build grid // Fire events for any state that changed since the last frame
emit stateUpdated(m_sim->currentTick(), {
m_sim->buildingBlocksStock(), const Tick newTick = m_sim->currentTick();
m_gameSpeedMultiplier, const int newBlocks = m_sim->buildingBlocksStock();
m_sim->bossWaveCounter(), const int newBoss = m_sim->bossWaveCounter();
m_sim->bossCountdownTicks()); const Tick newCountdown = m_sim->bossCountdownTicks();
if (newTick != m_lastTick)
{
m_lastTick = newTick;
EventManager::getInstance()->sendEventImmediately(
std::make_shared<TickAdvancedEvent>(newTick));
}
if (newBlocks != m_lastBlocks)
{
m_lastBlocks = newBlocks;
EventManager::getInstance()->sendEventImmediately(
std::make_shared<BuildingBlocksChangedEvent>(newBlocks));
}
if (newBoss != m_lastBossCounter || newCountdown != m_lastBossCountdown)
{
m_lastBossCounter = newBoss;
m_lastBossCountdown = newCountdown;
EventManager::getInstance()->sendEventImmediately(
std::make_shared<BossWaveUpdatedEvent>(newBoss, newCountdown));
}
}
// Game over check // Game over check
if (m_sim->isGameOver() && !m_gameOverShown) if (m_sim->isGameOver() && !m_gameOverShown)
@@ -1403,11 +1428,8 @@ double GameWorldView::gameSpeed() const
void GameWorldView::setGameSpeed(double multiplier) void GameWorldView::setGameSpeed(double multiplier)
{ {
m_gameSpeedMultiplier = multiplier; m_gameSpeedMultiplier = multiplier;
emit stateUpdated(m_sim->currentTick(), EventManager::getInstance()->sendEventImmediately(
m_sim->buildingBlocksStock(), std::make_shared<GameSpeedChangedEvent>(m_gameSpeedMultiplier));
m_gameSpeedMultiplier,
m_sim->bossWaveCounter(),
m_sim->bossCountdownTicks());
} }
void GameWorldView::resetForNewGame() void GameWorldView::resetForNewGame()
@@ -1427,8 +1449,12 @@ void GameWorldView::resetForNewGame()
m_scrollLeft = false; m_scrollLeft = false;
m_scrollRight = false; m_scrollRight = false;
m_gameOverShown = false; m_gameOverShown = false;
m_gameSpeedMultiplier = 1.0;
m_prevNonZeroSpeed = 1.0; m_prevNonZeroSpeed = 1.0;
m_lastTick = Tick(-1);
m_lastBlocks = -1;
m_lastBossCounter = -1;
m_lastBossCountdown = Tick(-1);
emit selectionChanged({}); emit selectionChanged({});
setGameSpeed(1.0);
update(); update();
} }

View File

@@ -47,7 +47,6 @@ public:
signals: signals:
void selectionChanged(const std::vector<BuildingId>& ids); void selectionChanged(const std::vector<BuildingId>& ids);
void stateUpdated(Tick tick, int blocks, double speed, int bossCounter, Tick bossCountdownTicks);
void gameOver(); void gameOver();
void builderModeExited(); void builderModeExited();
void blueprintModeExited(); void blueprintModeExited();
@@ -173,4 +172,9 @@ private:
bool m_scrollLeft; bool m_scrollLeft;
bool m_scrollRight; bool m_scrollRight;
bool m_gameOverShown; bool m_gameOverShown;
Tick m_lastTick = Tick(-1);
int m_lastBlocks = -1;
int m_lastBossCounter = -1;
Tick m_lastBossCountdown = Tick(-1);
}; };

View File

@@ -41,41 +41,51 @@ HeaderBar::HeaderBar(QWidget* parent)
connect(btn, &QPushButton::clicked, mapper, qOverload<>(&QSignalMapper::map)); connect(btn, &QPushButton::clicked, mapper, qOverload<>(&QSignalMapper::map));
} }
connect(mapper, qOverload<int>(&QSignalMapper::mapped), this, &HeaderBar::onSpeedButton); connect(mapper, qOverload<int>(&QSignalMapper::mapped), this, &HeaderBar::onSpeedButton);
setFixedHeight(sizeHint().height()); setFixedHeight(sizeHint().height());
registerForEvents();
} }
void HeaderBar::onStateUpdated(Tick tick, int buildingBlocks, double gameSpeed, HeaderBar::~HeaderBar()
int bossCounter, Tick bossCountdownTicks)
{ {
const int totalSeconds = static_cast<int>(ticksToSeconds(tick)); unregisterForEvents();
const int minutes = totalSeconds / 60; }
const int seconds = totalSeconds % 60;
void HeaderBar::handleEvent(std::shared_ptr<const TickAdvancedEvent> event)
{
const int totalSeconds = static_cast<int>(ticksToSeconds(event->tick));
m_timeLabel->setText( m_timeLabel->setText(
QString("%1:%2") QString("%1:%2")
.arg(minutes, 2, 10, QChar('0')) .arg(totalSeconds / 60, 2, 10, QChar('0'))
.arg(seconds, 2, 10, QChar('0'))); .arg(totalSeconds % 60, 2, 10, QChar('0')));
}
m_blocksLabel->setText(tr("Blocks: %1").arg(buildingBlocks)); void HeaderBar::handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event)
{
const int bossSeconds = static_cast<int>(ticksToSeconds( m_blocksLabel->setText(tr("Blocks: %1").arg(event->blocks));
bossCountdownTicks > 0 ? bossCountdownTicks : 0)); }
const int bossMin = bossSeconds / 60;
const int bossSec = bossSeconds % 60;
m_bossLabel->setText(
tr("Boss Wave #%1 Next boss: %2:%3")
.arg(bossCounter)
.arg(bossMin)
.arg(bossSec, 2, 10, QChar('0')));
void HeaderBar::handleEvent(std::shared_ptr<const GameSpeedChangedEvent> event)
{
for (int i = 0; i < kSpeedCount; ++i) for (int i = 0; i < kSpeedCount; ++i)
{ {
const bool active = (std::abs(kSpeeds[i] - gameSpeed) < 0.001); m_speedButtons[static_cast<std::size_t>(i)]->setChecked(
m_speedButtons[static_cast<std::size_t>(i)]->setChecked(active); std::abs(kSpeeds[i] - event->speed) < 0.001);
} }
} }
void HeaderBar::handleEvent(std::shared_ptr<const BossWaveUpdatedEvent> event)
{
const int bossSeconds = static_cast<int>(
ticksToSeconds(event->countdownTicks > 0 ? event->countdownTicks : 0));
m_bossLabel->setText(
tr("Boss Wave #%1 Next boss: %2:%3")
.arg(event->counter)
.arg(bossSeconds / 60)
.arg(bossSeconds % 60, 2, 10, QChar('0')));
}
void HeaderBar::onSpeedButton(int index) void HeaderBar::onSpeedButton(int index)
{ {
if (index >= 0 && index < kSpeedCount) if (index >= 0 && index < kSpeedCount)
@@ -83,4 +93,3 @@ void HeaderBar::onSpeedButton(int index)
emit speedChanged(kSpeeds[index]); emit speedChanged(kSpeeds[index]);
} }
} }

View File

@@ -4,21 +4,27 @@
#include <QWidget> #include <QWidget>
#include "BossWaveUpdatedEvent.h"
#include "BuildingBlocksChangedEvent.h"
#include "EventHandler.h"
#include "GameSpeedChangedEvent.h"
#include "Tick.h" #include "Tick.h"
#include "TickAdvancedEvent.h"
class QLabel; class QLabel;
class QPushButton; class QPushButton;
class HeaderBar : public QWidget class HeaderBar : public QWidget,
public CombinedEventHandler<TickAdvancedEvent,
BuildingBlocksChangedEvent,
GameSpeedChangedEvent,
BossWaveUpdatedEvent>
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit HeaderBar(QWidget* parent = nullptr); explicit HeaderBar(QWidget* parent = nullptr);
~HeaderBar() override;
public slots:
void onStateUpdated(Tick tick, int buildingBlocks, double gameSpeed,
int bossCounter, Tick bossCountdownTicks);
signals: signals:
void speedChanged(double multiplier); void speedChanged(double multiplier);
@@ -27,6 +33,11 @@ private slots:
void onSpeedButton(int index); void onSpeedButton(int index);
private: private:
void handleEvent(std::shared_ptr<const TickAdvancedEvent> event) override;
void handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event) override;
void handleEvent(std::shared_ptr<const GameSpeedChangedEvent> event) override;
void handleEvent(std::shared_ptr<const BossWaveUpdatedEvent> event) override;
QLabel* m_timeLabel; QLabel* m_timeLabel;
QLabel* m_blocksLabel; QLabel* m_blocksLabel;
QLabel* m_bossLabel; QLabel* m_bossLabel;

View File

@@ -11,6 +11,7 @@
#include "BlueprintPanel.h" #include "BlueprintPanel.h"
#include "BuildButtonGrid.h" #include "BuildButtonGrid.h"
#include "BuildingBlocksChangedEvent.h"
#include "BuildingSystem.h" #include "BuildingSystem.h"
#include "ConfigLoader.h" #include "ConfigLoader.h"
#include "GameWorldView.h" #include "GameWorldView.h"
@@ -52,15 +53,6 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir, QWidget* p
connect(m_gameWorldView, &GameWorldView::selectionChanged, connect(m_gameWorldView, &GameWorldView::selectionChanged,
m_selectedBuildingPanel, &SelectedBuildingPanel::onSelectionChanged); m_selectedBuildingPanel, &SelectedBuildingPanel::onSelectionChanged);
connect(m_gameWorldView, &GameWorldView::stateUpdated,
m_headerBar, &HeaderBar::onStateUpdated);
connect(m_gameWorldView, &GameWorldView::stateUpdated,
this, &MainWindow::onStateUpdated); // for affordability
connect(m_gameWorldView, &GameWorldView::stateUpdated,
m_selectedBuildingPanel, &SelectedBuildingPanel::onStateUpdated);
connect(m_gameWorldView, &GameWorldView::gameOver, connect(m_gameWorldView, &GameWorldView::gameOver,
this, &MainWindow::onGameOver); this, &MainWindow::onGameOver);
@@ -90,9 +82,6 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir, QWidget* p
connect(m_gameWorldView, &GameWorldView::selectionChanged, connect(m_gameWorldView, &GameWorldView::selectionChanged,
m_blueprintPanel, &BlueprintPanel::onSelectionChanged); m_blueprintPanel, &BlueprintPanel::onSelectionChanged);
connect(m_gameWorldView, &GameWorldView::stateUpdated,
m_blueprintPanel, &BlueprintPanel::onStateUpdated);
connect(m_blueprintPanel, &BlueprintPanel::blueprintPlacementRequested, connect(m_blueprintPanel, &BlueprintPanel::blueprintPlacementRequested,
m_gameWorldView, &GameWorldView::enterBlueprintMode); m_gameWorldView, &GameWorldView::enterBlueprintMode);
@@ -132,6 +121,13 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir, QWidget* p
m_layoutBlueprints.clear(); m_layoutBlueprints.clear();
} }
} }
registerForEvent();
}
MainWindow::~MainWindow()
{
unregisterForEvent();
} }
void MainWindow::resizeEvent(QResizeEvent* event) void MainWindow::resizeEvent(QResizeEvent* event)
@@ -172,9 +168,9 @@ void MainWindow::layoutPanels()
m_bottomPanel->setGeometry(0, headerH + gameH, totalW, panelH); m_bottomPanel->setGeometry(0, headerH + gameH, totalW, panelH);
} }
void MainWindow::onStateUpdated(Tick /*tick*/, int blocks, double /*speed*/) void MainWindow::handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event)
{ {
m_buildButtonGrid->updateAffordability(blocks); m_buildButtonGrid->updateAffordability(event->blocks);
} }
void MainWindow::onEscapeMenuRequested() void MainWindow::onEscapeMenuRequested()

View File

@@ -5,7 +5,9 @@
#include <QWidget> #include <QWidget>
#include "BuildingBlocksChangedEvent.h"
#include "BuildingId.h" #include "BuildingId.h"
#include "EventHandler.h"
#include "ShipLayoutBlueprint.h" #include "ShipLayoutBlueprint.h"
#include "Tick.h" #include "Tick.h"
#include "VisualsConfig.h" #include "VisualsConfig.h"
@@ -19,26 +21,29 @@ class BlueprintPanel;
class QCloseEvent; class QCloseEvent;
class QResizeEvent; class QResizeEvent;
class MainWindow : public QWidget class MainWindow : public QWidget,
public EventHandler<BuildingBlocksChangedEvent>
{ {
Q_OBJECT Q_OBJECT
public: public:
MainWindow(Simulation* sim, const std::string& configDir, QWidget* parent = nullptr); MainWindow(Simulation* sim, const std::string& configDir, QWidget* parent = nullptr);
~MainWindow() override;
protected: protected:
void resizeEvent(QResizeEvent* event) override; void resizeEvent(QResizeEvent* event) override;
void closeEvent(QCloseEvent* event) override; void closeEvent(QCloseEvent* event) override;
private:
void handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event) override;
void layoutPanels();
private slots: private slots:
void onGameOver(); void onGameOver();
void onStateUpdated(Tick tick, int blocks, double speed);
void onEscapeMenuRequested(); void onEscapeMenuRequested();
void onLayoutDialogRequested(BuildingId shipyardId); void onLayoutDialogRequested(BuildingId shipyardId);
private: private:
void layoutPanels();
std::string m_configDir; std::string m_configDir;
VisualsConfig m_visuals; VisualsConfig m_visuals;
Simulation* m_sim; Simulation* m_sim;

View File

@@ -13,6 +13,7 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include "BeltSystem.h" #include "BeltSystem.h"
#include "TickAdvancedEvent.h"
#include "Building.h" #include "Building.h"
#include "BuildingSystem.h" #include "BuildingSystem.h"
#include "BuildingType.h" #include "BuildingType.h"
@@ -136,6 +137,13 @@ SelectedBuildingPanel::SelectedBuildingPanel(Simulation* sim,
this, &SelectedBuildingPanel::onSplitterFilterChanged); this, &SelectedBuildingPanel::onSplitterFilterChanged);
buildEmpty(); buildEmpty();
registerForEvent();
}
SelectedBuildingPanel::~SelectedBuildingPanel()
{
unregisterForEvent();
} }
void SelectedBuildingPanel::onSelectionChanged(const std::vector<BuildingId>& ids) void SelectedBuildingPanel::onSelectionChanged(const std::vector<BuildingId>& ids)
@@ -488,7 +496,7 @@ const ShipDef* SelectedBuildingPanel::findShipDef(const std::string& id) const
return nullptr; return nullptr;
} }
void SelectedBuildingPanel::onStateUpdated(Tick /*tick*/, int /*blocks*/, double /*speed*/) void SelectedBuildingPanel::handleEvent(std::shared_ptr<const TickAdvancedEvent> /*event*/)
{ {
if (m_singleBuildingId == kInvalidBuildingId) { return; } if (m_singleBuildingId == kInvalidBuildingId) { return; }
const Building* b = m_sim->buildings().findBuilding(m_singleBuildingId); const Building* b = m_sim->buildings().findBuilding(m_singleBuildingId);

View File

@@ -8,11 +8,13 @@
#include "Building.h" #include "Building.h"
#include "BuildingId.h" #include "BuildingId.h"
#include "EventHandler.h"
#include "GameConfig.h" #include "GameConfig.h"
#include "RecipesConfig.h" #include "RecipesConfig.h"
#include "ShipLayout.h" #include "ShipLayout.h"
#include "ShipsConfig.h" #include "ShipsConfig.h"
#include "Tick.h" #include "Tick.h"
#include "TickAdvancedEvent.h"
class Simulation; class Simulation;
class ShipLayoutPreview; class ShipLayoutPreview;
@@ -22,20 +24,24 @@ class QListWidget;
class QPushButton; class QPushButton;
class QVBoxLayout; class QVBoxLayout;
class SelectedBuildingPanel : public QWidget class SelectedBuildingPanel : public QWidget,
public EventHandler<TickAdvancedEvent>
{ {
Q_OBJECT Q_OBJECT
public: public:
SelectedBuildingPanel(Simulation* sim, const GameConfig* config, SelectedBuildingPanel(Simulation* sim, const GameConfig* config,
QWidget* parent = nullptr); QWidget* parent = nullptr);
~SelectedBuildingPanel() override;
signals: signals:
void layoutDialogRequested(BuildingId shipyardId); void layoutDialogRequested(BuildingId shipyardId);
public slots: public slots:
void onSelectionChanged(const std::vector<BuildingId>& ids); void onSelectionChanged(const std::vector<BuildingId>& ids);
void onStateUpdated(Tick tick, int blocks, double speed);
private:
void handleEvent(std::shared_ptr<const TickAdvancedEvent> event) override;
private slots: private slots:
void onRecipeChanged(int comboIndex); void onRecipeChanged(int comboIndex);