134 lines
6.3 KiB
C++
134 lines
6.3 KiB
C++
#pragma once
|
|
|
|
#include <QPoint>
|
|
#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"
|
|
#include "selection/SelectionContext.h"
|
|
|
|
struct GameConfig;
|
|
struct VisualsConfig;
|
|
class BuildingIconCache;
|
|
class ItemIconCache;
|
|
class SelectionContent;
|
|
class Simulation;
|
|
class QMouseEvent;
|
|
class QScrollArea;
|
|
class QVBoxLayout;
|
|
|
|
// Shows the current selection. The panel itself renders nothing: it arbitrates between
|
|
// the two selection categories (REQ-UI-SELECTION-CATEGORIES), picks the card that fits
|
|
// what is selected (REQ-UI-SELECTION-CONTENT), and hosts exactly one of them at a time.
|
|
// 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, 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>
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
// visuals, itemIcons and buildingIcons are window-wide rendering resources the cards
|
|
// draw from; none is owned and all must outlive this widget.
|
|
SelectionPanel(Simulation* sim, const GameConfig* config,
|
|
const VisualsConfig* visuals, ItemIconCache* itemIcons,
|
|
BuildingIconCache* buildingIcons, QWidget* parent = nullptr);
|
|
~SelectionPanel() override;
|
|
|
|
// 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;
|
|
|
|
protected:
|
|
// The panel is moved by dragging its card header (REQ-UI-SELECTION-PANEL-DRAG). Every
|
|
// other mouse event over the panel is swallowed here so that none of them reaches the
|
|
// game world beneath (REQ-UI-SELECTION-PANEL).
|
|
void mousePressEvent(QMouseEvent* event) override;
|
|
void mouseMoveEvent(QMouseEvent* event) override;
|
|
void mouseReleaseEvent(QMouseEvent* event) 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;
|
|
void handleEvent(std::shared_ptr<const PlayerCommandsAppliedEvent> event) override;
|
|
void handleEvent(std::shared_ptr<const DebugDrawToggledEvent> event) override;
|
|
|
|
// Re-reads the live values of the card on screen. When the selection now calls for a
|
|
// different card -- a construction site finishing is the case that matters -- it
|
|
// rebuilds instead, because a card never changes its own shape.
|
|
void refreshContent();
|
|
// Replaces the card with the one the current selection calls for.
|
|
void rebuildContent();
|
|
// 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
|
|
// screen without it having to subscribe to the event itself.
|
|
bool m_debugDrawEnabled = false;
|
|
|
|
SelectionRequest m_request;
|
|
ContentKey m_contentKey;
|
|
SelectionContent* m_content = nullptr;
|
|
|
|
// 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. Dragging the panel supersedes the pair for the rest of the
|
|
// selection (REQ-UI-SELECTION-PANEL-DRAG).
|
|
QRect m_anchorRect;
|
|
std::optional<PanelSide> m_side;
|
|
|
|
// Where the player dragged the panel, in the game world view's coordinates, and the
|
|
// cursor's offset within the panel while a drag is running
|
|
// (REQ-UI-SELECTION-PANEL-DRAG). The desired position is kept exactly as dropped:
|
|
// resolving it against the view's edges and the widgets the panel steps around never
|
|
// writes back to it, so the panel returns to it once the room is there again. It
|
|
// lasts as long as the selection it was set in.
|
|
std::optional<QPoint> m_desiredTopLeftPx;
|
|
std::optional<QPoint> m_dragGrabOffsetPx;
|
|
// Origin of the view the panel was last placed in, which is what the two coordinate
|
|
// systems differ by -- the panel is a sibling of the view, not a child of it.
|
|
QPoint m_viewOriginPx;
|
|
|
|
// 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;
|
|
};
|