Skip to main content

max / makeover-layout

3.8 KB · 108 lines History Blame Raw
1 use crate::{State, Tone};
2
3 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4 pub struct Act<'a> {
5 /// What the control says.
6 pub label: &'a str,
7 /// The key that reaches it where a host has keys.
8 ///
9 /// The one member written for a terminal before there was one. A webview
10 /// hangs it off `accesskey` or ignores it; a terminal has nothing else to
11 /// offer, so this is the whole of how a control is reached there.
12 pub key: Option<&'a str>,
13 /// What pressing it means. [`Tone::Danger`] is the destructive one.
14 pub tone: Tone,
15 /// Disabled, or nothing said.
16 ///
17 /// [`State::Disabled`] is what changes what a renderer may do: see
18 /// [`State::suppresses_interaction`], which is what says a disabled control
19 /// is drawn and not reachable. A control's focus is not sayable here at
20 /// all: see the crate header, "Reach, focus and the focus ring".
21 pub state: Option<State>,
22 /// A sentence that is always true of this control, shown rather than hunted
23 /// for.
24 ///
25 /// Standing help, not a message and not a tooltip. Half the hosts that read
26 /// this have no pointer: a hover is one spelling of it, and the shipped
27 /// apps reached for that spelling only because egui and a browser both had
28 /// one. What is being said is that the sentence is true, never that it is
29 /// hidden until a pointer arrives.
30 ///
31 /// # Why it is here rather than a layer up
32 ///
33 /// A hint left to `quasi_router::Act` alone means each renderer draws it
34 /// for itself: `makeover_tui` had no hint to read, so quasi-tui built
35 /// the muted line, and quasi-immediate called `on_hover_text` outside
36 /// [`crate::Act`] rather than inside it. `Field::hint` was here the whole
37 /// time, so the same idea sat at two layers depending on which thing
38 /// carried it, and a host that was not quasi could say it of a field and
39 /// not of a control.
40 ///
41 /// What kept it out was price rather than doubt: this crate declares
42 /// `links`, so a member here moves 25 manifests across 12 repos. That is a
43 /// release's forward-fix pass, which is a cost and was being read as a
44 /// barrier.
45 ///
46 /// # What a renderer owes it
47 ///
48 /// Somewhere to put it, or nothing. Dropping it is legitimate; drawing it
49 /// *instead of* the label is not, and neither is drawing it in a way that
50 /// takes it out of the accessible tree, which is the failure `title` alone
51 /// has on a browser. Nothing may live only in a hint.
52 ///
53 /// `None` is a control whose label is the whole of it, which is nearly all
54 /// of them.
55 pub hint: Option<&'a str>,
56 }
57
58 impl<'a> Act<'a> {
59 /// An ordinary control, reachable, with no key.
60 #[must_use]
61 pub const fn new(label: &'a str) -> Self {
62 Self {
63 label,
64 key: None,
65 tone: Tone::Neutral,
66 state: None,
67 hint: None,
68 }
69 }
70
71 /// The sentence that is always true of it; see [`hint`](Self::hint).
72 ///
73 /// A renderer with nowhere to put it drops it, so this must never be the
74 /// only place a fact appears.
75 #[must_use]
76 pub const fn hinted(mut self, hint: &'a str) -> Self {
77 self.hint = Some(hint);
78 self
79 }
80
81 /// The key that reaches it.
82 #[must_use]
83 pub const fn key(mut self, key: &'a str) -> Self {
84 self.key = Some(key);
85 self
86 }
87
88 /// What pressing it means.
89 #[must_use]
90 pub const fn tone(mut self, tone: Tone) -> Self {
91 self.tone = tone;
92 self
93 }
94
95 /// Focus, or disabled.
96 #[must_use]
97 pub const fn state(mut self, state: State) -> Self {
98 self.state = Some(state);
99 self
100 }
101
102 /// Whether the control is drawn and does not answer.
103 #[must_use]
104 pub fn disabled(&self) -> bool {
105 self.state.is_some_and(State::suppresses_interaction)
106 }
107 }
108