1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
//! **The keyboard**: every act this window affords, reachable without a
//! pointer (yog's `docs/QUALITY.md` F1 — *everything keyboard-operable*).
//!
//! A face an operator has to leave the keyboard for, once per selection, is a
//! face they use through the command line instead. The obligation is inherited;
//! the implementation is not, because the shape that fits four panes is not the
//! shape that fits thirty.
//!
//! # Most of it is egui's, and that is the point
//!
//! Every control here is a button or a text box, and egui already moves focus
//! between them with Tab and fires a focused one with Space or Enter. So Send,
//! Nudge, Start and the notice's dismiss are keyboard-operable with nothing
//! written — `tests` proves it rather than assuming it. What Tab cannot make
//! *usable* is a list: tabbing through thirty walls to reach the composer is
//! reachability without operability, and that is the whole of what this module
//! adds.
//!
//! # The cursor IS the selection, so there is nothing to keep in step
//!
//! A list cursor beside a selection is two highlights, two things to paint and
//! two ways to disagree. There is no cursor: **moving in a list selects**, so
//! the highlight the pointer already paints is where the keyboard is, and the
//! reads that follow a selection follow a keypress for free (the standing set
//! is derived — `crate::state::Standing`). What is left to paint is only
//! *which list the arrows belong to*, which is [`Pane`], and it is marked on
//! that pane's own heading: a focus that cannot be seen is a focus nobody can
//! use.
//!
//! # It names controls; it never adds one
//!
//! Every binding below calls the same door a click calls
//! (`crate::ui::model::acts`), and the roster walk asks the same question the
//! roster's own paint asks — so a row no pointer can aim at is a row no key can
//! aim at either. A binding that could fire something a click cannot is a
//! second surface.
//!
//! **A box that is taking text takes every key**, which is the one gate: while
//! a text box holds the focus nothing here runs, so an arrow is a cursor move
//! inside the draft and Escape is egui's own *leave the box*. Press it again
//! with no box focused and it is [`Model::escape`] below — which closes the
//! enrollment where one covers the window, and puts the notice down otherwise.
//! One key, three contexts, and the contexts never overlap.
//!
//! The gate asks for **that box by name** rather than for egui's
//! `wants_keyboard_input`, which answers *is anything focused at all* — every
//! button included. Tabbing to Send would otherwise turn the arrows off, and a
//! click focuses a control too, so the honest question is the narrow one: the
//! composer's box wears [`BOX_ID`] and the gate compares against it.
use crate;
/// Which list the arrows belong to. Two, because two of the four panes hold a
/// list; the chat pane scrolls and the composer takes text, and both are
/// reached the way every control is, with Tab.
/// **The id the composer's box wears**, and the whole of what the keyboard has
/// to know about it. The deposit's box and the start's are one control with two
/// subjects and are never painted together, so they wear one id — and the gate
/// below is a comparison rather than a guess about what "focused" means.
pub const BOX_ID: &str = "the composer's box";
/// Whether the composer's box holds the keyboard right now.
/// The mark a focused pane's heading wears — and the heading is where it goes
/// because a pane's heading is the one thing on it that is always painted, even
/// when it holds nothing at all.
pub const HERE: &str = "›";
/// The heading a pane paints, with the mark when the arrows are its.
/// **Take this frame's keys.** Called at the top of the frame, so what a key
/// changed is what the frame paints.
/// Move the focused list's selection by one, and say the pane owes the new
/// selection a place on the glass.
///
/// **The walk is the surface that can leave the glass behind.** A list longer
/// than its pane scrolls ([`crate::ui::shell`]), and a key that moved the
/// selection past the fold without moving the fold would put the two surfaces
/// back into the disagreement `crate::ui::roster::aimable` exists to prevent —
/// the cursor IS the selection, so the selection has to be somewhere an
/// operator can see it.
/// Where the cursor lands.
///
/// **Nothing selected goes to the first row, whichever way it was pressed**: a
/// list an operator has not entered has no direction to move in yet, and the
/// alternative is teaching them that Up means "the last one" before they have
/// selected anything. The ends **saturate** rather than wrap, because a wrap
/// makes the same keypress mean *next* thirty times and *back to the top* once,
/// with nothing on the glass to say which it will be.