move the field selection out of SelectedBuildingPanel

The two selection categories used to arbitrate ownership of the panel by
poking each other's widgets: buildFieldSelection() called clearContent()
and buildEmpty(), buildEmpty() hid the four entity widgets, and
hideAllWidgets() hid the scrap label. Splitting the halves apart without
naming an arbiter would only have spread that across a class boundary.

SelectedBuildingPanel is now the sole arbiter. It still receives all
three selection events, forwards the two field ones to the embedded
FieldSelectionPanel, and drops its own selection and content as soon as
the field panel reports a selection (yieldToFieldSelection), mirroring
what onSelectionChanged() already did in the other direction. The field
panel decides only what to render and whether it is visible at all.

Dropping the field branch of refreshSelectionDisplay() is behaviour
preserving: whenever the field category owns the panel, m_singleBuildingId
is null, so the building refresh returns immediately anyway.

clearContent() and buildEmpty() became identical once the cross-half
hiding was gone, so only buildEmpty() remains.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
This commit is contained in:
2026-08-04 15:47:22 +02:00
parent 0029236135
commit d713257fb5
2 changed files with 44 additions and 398 deletions

View File

@@ -7,12 +7,9 @@
#include <QPoint>
#include <QWidget>
#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"
@@ -26,20 +23,27 @@
#include "TickAdvancedEvent.h"
class Simulation;
class FieldSelectionPanel;
class ShipLayoutPreview;
class ShipStatsPanel;
class QLabel;
class QListWidget;
class QPushButton;
class QVBoxLayout;
// Shows the current selection. The building category (buildings and construction sites)
// is rendered by this panel itself; the field category (ships, defence stations, debris)
// is rendered by the embedded FieldSelectionPanel.
//
// The two categories are mutually exclusive (REQ-UI-SELECTION-CATEGORIES) and this panel
// is the sole arbiter of which one owns the content: it listens to all three selection
// events, forwards the field ones to the child panel, and drops the losing category's
// content. Neither panel touches the other's widgets.
class SelectedBuildingPanel : public QWidget,
public CombinedEventHandler<TickAdvancedEvent,
PlayerCommandsAppliedEvent,
EntitySelectionChangedEvent,
SelectionChangedEvent,
DebrisSelectionChangedEvent,
DebugDrawToggledEvent>
DebrisSelectionChangedEvent>
{
Q_OBJECT
@@ -54,7 +58,6 @@ private:
void handleEvent(std::shared_ptr<const EntitySelectionChangedEvent> event) override;
void handleEvent(std::shared_ptr<const SelectionChangedEvent> event) override;
void handleEvent(std::shared_ptr<const DebrisSelectionChangedEvent> event) override;
void handleEvent(std::shared_ptr<const DebugDrawToggledEvent> event) override;
private slots:
void onSelectRecipeClicked();
@@ -73,17 +76,14 @@ private:
};
void onSelectionChanged(const std::vector<BuildingId>& ids);
// Gives the panel to the field category once it has anything selected.
void yieldToFieldSelection();
void refreshSelectionDisplay(RefreshReason reason);
void rebuild();
void hideAllWidgets();
void clearContent();
void buildEmpty();
void buildSingle(BuildingId id);
void buildMulti(const std::vector<BuildingId>& ids);
// Summed remaining scrap across the selected debris (REQ-UI-DEBRIS-PANEL).
int selectedDebrisScrapTotal() const;
// "Scrap x N" line for the multi-object summary (REQ-UI-FIELD-MULTI-SELECTION).
QString scrapTotalText() const;
void refreshBuffers(const Building* b);
void refreshSiteProgress(const ConstructionSite* s);
void updateShipyardLayoutWidgets(BuildingType type,
@@ -116,28 +116,7 @@ private:
QPoint m_splitterTile;
std::string m_currentRecipeId;
bool m_debugDraw = false;
// The selected ships/defence stations. Shares the "field" selection category with
// debris (m_selectedDebris): both can be non-empty at once (REQ-UI-SELECTION-CATEGORIES).
std::vector<entt::entity> m_selectedEntities;
ShipStatsPanel* m_entityStatsPanel;
QLabel* m_entityTitleLabel;
QLabel* m_stationStatsLabel;
QLabel* m_entitySummaryLabel;
std::vector<entt::entity> m_selectedDebris;
// Shows the debris "Scrap" stat row (single selection) — the scrap total for the
// multi-object summary lives in m_entitySummaryLabel instead.
QLabel* m_scrapLabel;
// Renders the combined field selection (actors + debris): a single-object stats panel
// (ship, station, or debris) or a multi-object count summary that appends the debris
// count and scrap total when debris is also selected (REQ-UI-FIELD-MULTI-SELECTION).
void buildFieldSelection();
void buildEntityShip(entt::entity entity);
void buildEntityStation(entt::entity entity);
void buildEntitySummary();
void buildDebrisSingle();
void refreshEntityStats();
void clearEntityDisplay();
// Renders the field selection (actors + debris) below the building content
// (REQ-UI-FIELD-MULTI-SELECTION). Hides itself while nothing field-side is selected.
FieldSelectionPanel* m_fieldSelectionPanel;
};