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
//! **The layout**, and the notice that stands where content would have been.
//!
//! One function, and it is the whole window: a notice bar, the roster, the
//! conversation list, and the conversation with its composer under it. There is
//! no per-pane enablement to drift — a pane with nothing to show says so in its
//! own words, which is a sentence an operator can act on rather than a control
//! that only looks actionable.
use crate;
/// Paint one frame of the whole window.
///
/// It takes the context rather than an `eframe::Frame`, which is what makes the
/// window testable at all: every assertion in this crate runs this function on
/// an offscreen context and reads back the glyphs it painted
/// (`crate::paint_probe`). The native boot is `src/main.rs`, which decides
/// nothing.
/// **What the two list panes are worth when the window is wide enough**, in
/// points: the roster holds a handful of short words, the conversation list
/// holds a headline and a preview under it.
const ROSTER: f32 = 280.0;
const CONVS: f32 = 320.0;
/// **The floor the conversation and its composer keep.** Below this a chat pane
/// is a strip: a message elides inside its own width, the composer's box shows
/// the first few words of a draft, and `send` sits against the frame.
pub const CHAT_FLOOR: f32 = 420.0;
/// **The width a list pane never goes under**, however narrow the window. A
/// pane below it shows nothing at all, which is worse than a chat pane under
/// its floor — so this is the one thing the floor yields to.
pub const SIDE_FLOOR: f32 = 140.0;
/// **The two list panes' widths at a given window width** — the policy the
/// window had none of (bl-e5d2).
///
/// The side panels used to keep their widths as the window narrowed and the
/// central panel absorbed the whole loss, so at 900 points the pane the window
/// exists for was a ~140-point strip while the roster kept 280. The rule is the
/// other way round: **the conversation has a floor and the list panes yield to
/// it**, together and in proportion to what each is worth, until they reach
/// their own floor. Past that nothing yields, because two panes showing nothing
/// buys the chat pane a width it still cannot use.
///
/// It is a pure function of one number, so the policy is a value a test reads
/// back rather than a layout somebody has to look at.
/// The notice bar: the last thing the seat heard that was not content, in the
/// words of whoever said it, and dismissible.
///
/// It is a **bar rather than a modal** because a refusal about one pane must not
/// stop the operator reading the other three: the engine refusing a deposit says
/// nothing about the roster beside it.
/// The word that puts a notice down. An operator who has read it should not
/// have to wait for the next answer to clear it.
pub const DISMISS: &str = "×";