Skip to main content

shuyi_ui/screens/key_bindings/
view.rs

1//! What the Key bindings screen shows, as plain data: no cells, glyphs,
2//! colours or positions. The screen builds a [`KeyBindingsView`] each frame
3//! ([`KeyBindingsScreen::view`](super::KeyBindingsScreen::view)) and a skin
4//! paints it ([`super::glyph::paint`] today).
5
6use super::Side;
7use crate::prelude::*;
8use crate::widgets::AskView;
9
10/// The whole screen, as it is this frame.
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct KeyBindingsView<A> {
13    /// The screen's title.
14    pub title: String,
15    /// The keyboard / controller switch; `None` with no keyboard, when the
16    /// controller side is the only one.
17    pub switch: Option<SwitchView>,
18    /// The headings over the slot columns, left to right.
19    pub columns: Vec<String>,
20    /// The actions, grouped: the required ones, then the optional ones.
21    pub groups: Vec<GroupView<A>>,
22    /// The row under the actions that puts the shown side's defaults back.
23    pub restore: RestoreView,
24    /// The note on a row with nothing in any slot (`! not mapped`).
25    pub not_mapped: String,
26    /// A message for the player (a key can't be used, leaving is blocked).
27    pub message: Option<String>,
28    /// The yes/no question open over the rows, if any (no answers, but
29    /// the line naming its keys).
30    pub question: Option<AskView<bool>>,
31    /// The choices open under the focused slot, if any (the controller
32    /// side's change / clear).
33    pub choices: Option<ChoicesView>,
34    /// The help line: what the keys do here.
35    pub help: String,
36}
37
38impl<A: Copy + PartialEq> KeyBindingsView<A> {
39    /// Every action's row, top to bottom.
40    pub fn rows(&self) -> impl Iterator<Item = &RowView<A>> {
41        self.groups.iter().flat_map(|g| g.rows.iter())
42    }
43
44    /// The row of `action`, if it is shown.
45    pub fn row(&self, action: A) -> Option<&RowView<A>> {
46        self.rows().find(|r| r.action == action)
47    }
48
49    /// The focused row, if the focus is on an action.
50    pub fn focused(&self) -> Option<&RowView<A>> {
51        self.rows().find(|r| r.focus.is_some())
52    }
53}
54
55/// The switch between the keyboard and the controller.
56#[derive(Debug, Clone, PartialEq, Eq)]
57pub struct SwitchView {
58    /// The name of the keyboard side, with the layout it edits.
59    pub keyboard: String,
60    /// The name of the controller side.
61    pub controller: String,
62    /// The side shown.
63    pub shown: Side,
64    /// Whether the cursor is on the switch.
65    pub focused: bool,
66}
67
68/// A heading and the actions under it.
69#[derive(Debug, Clone, PartialEq, Eq)]
70pub struct GroupView<A> {
71    /// What the group is.
72    pub heading: String,
73    /// Whether these are the required actions (each must have a key or a
74    /// button before the screen can be left).
75    pub required: bool,
76    /// Its actions, top to bottom.
77    pub rows: Vec<RowView<A>>,
78}
79
80/// One action.
81#[derive(Debug, Clone, PartialEq, Eq)]
82pub struct RowView<A> {
83    /// Which action it is.
84    pub action: A,
85    /// Its name.
86    pub label: String,
87    /// The keys it also has that can't be changed (keyboard side only).
88    pub fixed: Vec<String>,
89    /// What each of its slots holds.
90    pub slots: Vec<SlotView>,
91    /// The slot the cursor is on, if the cursor is on this row.
92    pub focus: Option<usize>,
93    /// Whether nothing is in any of its slots.
94    pub unmapped: bool,
95    /// Whether it is unmapped and so blocks leaving the screen (a required
96    /// action with nothing on the shown side).
97    pub blocks_leaving: bool,
98    /// Whether it just lost its key to another slot (it stays highlighted
99    /// for a moment).
100    pub lost_key: bool,
101}
102
103impl<A> RowView<A> {
104    /// Whether the cursor is on this row.
105    pub fn focused(&self) -> bool {
106        self.focus.is_some()
107    }
108}
109
110/// What one slot holds.
111#[derive(Debug, Clone, PartialEq, Eq)]
112pub enum SlotView {
113    /// Nothing.
114    Empty,
115    /// A key or button, by name.
116    Bound(String),
117    /// Waiting for the key or button to put in it: what it shows meanwhile.
118    Capturing(String),
119}
120
121/// The restore defaults row.
122#[derive(Debug, Clone, PartialEq, Eq)]
123pub struct RestoreView {
124    /// Its name.
125    pub label: String,
126    /// Whether the cursor is on it.
127    pub focused: bool,
128}
129
130/// The choices a slot offers.
131#[derive(Debug, Clone, PartialEq, Eq)]
132pub struct ChoicesView {
133    /// The choices, top to bottom.
134    pub lines: Vec<String>,
135    /// The one the cursor is on.
136    pub focused: usize,
137    /// The slot they belong to (on the focused row).
138    pub slot: usize,
139}