show the available controls in a panel over the world
This commit is contained in:
83
src/ui/ControlsPanel.h
Normal file
83
src/ui/ControlsPanel.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#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;
|
||||
};
|
||||
Reference in New Issue
Block a user