place the selection panel beside what it describes

This commit is contained in:
2026-08-09 13:45:04 +02:00
parent 7ae5f8c4dc
commit c0b009c548
25 changed files with 789 additions and 182 deletions

View File

@@ -3,11 +3,17 @@
#include <QRect>
#include <QWidget>
#include <optional>
#include <vector>
#include "DebrisSelectionChangedEvent.h"
#include "DebugDrawToggledEvent.h"
#include "EntitySelectionChangedEvent.h"
#include "EventHandler.h"
#include "FloatingPanel.h"
#include "FloatingPanelPlacement.h"
#include "PlayerCommandsAppliedEvent.h"
#include "SelectionAnchorChangedEvent.h"
#include "SelectionChangedEvent.h"
#include "TickAdvancedEvent.h"
#include "selection/SelectionContentFactory.h"
@@ -28,14 +34,16 @@ class QVBoxLayout;
// What each card looks like lives in src/ui/selection/.
//
// The panel floats over the game world view rather than occupying a column of its own
// (REQ-UI-SELECTION-PANEL): it sizes itself to its card, anchors to the right edge of
// the band its owner hands it, and hides itself entirely while nothing is selected
// (REQ-UI-EMPTY-SELECTION).
// (REQ-UI-SELECTION-PANEL): it sizes itself to its card, places itself in what the build
// button bar and the controls panel have left free, and hides itself entirely while
// nothing is selected (REQ-UI-EMPTY-SELECTION).
class SelectionPanel : public QWidget,
public FloatingPanel,
public CombinedEventHandler<TickAdvancedEvent,
PlayerCommandsAppliedEvent,
EntitySelectionChangedEvent,
SelectionChangedEvent,
SelectionAnchorChangedEvent,
DebrisSelectionChangedEvent,
DebugDrawToggledEvent>
{
@@ -49,14 +57,16 @@ public:
BuildingIconCache* buildingIcons, QWidget* parent = nullptr);
~SelectionPanel() override;
// Confines the panel to the given band of the game world view: it right-aligns
// within it and centers vertically in it. The band is the world view less the strip
// the build button bar occupies, so the two never overlap and the bar never has to
// move (REQ-UI-SELECTION-PANEL, REQ-UI-BUILD-BAR).
void anchorTo(const QRect& bandRect);
// Sizes the panel to its card and places it beside the selection it describes, in
// what the widgets placed before it have left free. Keeping clear of them is entirely
// this panel's job; neither of them ever moves for it (REQ-UI-SELECTION-PANEL,
// REQ-UI-BUILD-BAR, REQ-UI-CONTROLS-PANEL).
void placeIn(const QRect& viewRect,
const std::vector<QRect>& occupiedRects) override;
private:
void handleEvent(std::shared_ptr<const SelectionChangedEvent> event) override;
void handleEvent(std::shared_ptr<const SelectionAnchorChangedEvent> event) override;
void handleEvent(std::shared_ptr<const EntitySelectionChangedEvent> event) override;
void handleEvent(std::shared_ptr<const DebrisSelectionChangedEvent> event) override;
void handleEvent(std::shared_ptr<const TickAdvancedEvent> event) override;
@@ -69,11 +79,9 @@ private:
void refreshContent();
// Replaces the card with the one the current selection calls for.
void rebuildContent();
// Shows the panel while a card exists and hides it otherwise
// (REQ-UI-EMPTY-SELECTION), re-fitting it to the card while it is shown.
void updateVisibility();
// Re-fits the panel to its card within the anchored band.
void refit();
// Asks for the placement pass to be re-run, the card having changed size or the
// panel having gained or lost its reason to be shown at all.
void invalidateLayout();
SelectionContext m_context;
// Read through m_context by the cards that need it, so a toggle reaches the card on
@@ -84,12 +92,18 @@ private:
ContentKey m_contentKey;
SelectionContent* m_content = nullptr;
// The band the panel confines itself to, in the coordinates of its parent; null
// until the owner has anchored it for the first time.
QRect m_bandRect;
// Where the current selection was on the screen when it started, in the game world
// view's coordinates, and which side of it the panel took. Both are frozen for as
// long as the selection lasts: the anchor because the panel does not chase a
// scrolling view or a moving ship, the side because a card that grows must not flip
// the panel across the object (REQ-UI-SELECTION-PANEL). The side is resolved on the
// first placement after a new anchor, being the first point at which the panel's
// width is known.
QRect m_anchorRect;
std::optional<PanelSide> m_side;
// Scrolls the card once it outgrows the band (REQ-UI-SELECTION-PANEL). The card is a
// child of m_body, not of the panel itself.
// Scrolls the card once it outgrows the space the panel has (REQ-UI-SELECTION-PANEL).
// The card is a child of m_body, not of the panel itself.
QScrollArea* m_scrollArea;
QWidget* m_body;
QVBoxLayout* m_bodyLayout;