84 lines
3.2 KiB
C++
84 lines
3.2 KiB
C++
#pragma once
|
|
|
|
#include <vector>
|
|
|
|
#include <QRect>
|
|
#include <QString>
|
|
#include <QWidget>
|
|
|
|
#include "ControlAction.h"
|
|
|
|
class GameWorldView;
|
|
class QLabel;
|
|
class QTimer;
|
|
class QVBoxLayout;
|
|
|
|
// Shows the controls available in the player's current situation
|
|
// (REQ-UI-CONTROLS-PANEL). The panel decides nothing: which rows apply is
|
|
// ControlAction.h's answer, the same one the key handling and the world view's mouse
|
|
// dispatch act on, so what is shown and what happens cannot part company
|
|
// (REQ-UI-CONTROLS-ACCURACY).
|
|
//
|
|
// It floats over the game world at the left edge, bottom-aligned within the band its
|
|
// owner hands it, and collapses to its heading when the heading is clicked.
|
|
//
|
|
// Refreshed on a timer rather than by subscribing to events: two of the things that
|
|
// change a row -- a belt drag starting, the ghost moving over a transfer target --
|
|
// happen on mouse movement and publish nothing, and they still have to be reflected
|
|
// while the game is paused, so there is no tick to hang it on either. The rebuild is
|
|
// skipped unless the resolved content actually differs, which is a vector of enums to
|
|
// compare.
|
|
class ControlsPanel : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
// Neither pointer is owned; both must outlive this widget. The view is the source
|
|
// of the control context, being the widget that owns the build mode and the
|
|
// selection.
|
|
ControlsPanel(const GameWorldView* view, QWidget* parent = nullptr);
|
|
|
|
// Confines the panel to the given band of the game world view: it left-aligns
|
|
// within it and sits on its bottom edge. 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-CONTROLS-PANEL, REQ-UI-BUILD-BAR).
|
|
void anchorTo(const QRect& bandRect);
|
|
|
|
protected:
|
|
// Clicking the heading collapses and expands the panel (REQ-UI-CONTROLS-PANEL).
|
|
void mousePressEvent(QMouseEvent* event) override;
|
|
|
|
private:
|
|
// Re-resolves the context and rebuilds only if the rows or the heading changed.
|
|
void refresh();
|
|
// Replaces the rows with those of the current context.
|
|
void rebuild(const ControlContext& context);
|
|
// The heading's "<name> * <detail>" text for the context, detail omitted when the
|
|
// context has none.
|
|
QString getHeadingText(const ControlContext& context) const;
|
|
// Re-fits the panel to its content within the anchored band.
|
|
void refit();
|
|
|
|
const GameWorldView* m_view;
|
|
|
|
QLabel* m_heading;
|
|
QWidget* m_rows;
|
|
QVBoxLayout* m_rowsLayout;
|
|
QTimer* m_refreshTimer;
|
|
|
|
// What is currently drawn, so a refresh that resolves to the same thing does
|
|
// nothing. The always-available block is kept separately because the divider
|
|
// between the two is part of what is drawn.
|
|
QString m_shownHeading;
|
|
std::vector<ControlAction> m_shownContextActions;
|
|
std::vector<ControlAction> m_shownAlwaysActions;
|
|
|
|
// Survives context changes and simulation restarts; presentation only, never a
|
|
// command (REQ-UI-CONTROLS-PANEL).
|
|
bool m_collapsed = false;
|
|
|
|
// 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;
|
|
};
|