retroglyph_widgets/interact/density.rs
1//! [`Density`]: compact vs. relaxed sizing for interactive widgets.
2
3use retroglyph_core::Size;
4
5/// How much room an interactive widget's hit target should claim.
6///
7/// Not itself consulted by anything in this crate: there are no built-in
8/// interactive widgets yet to apply it to; every widget here is a free
9/// function or a thin, stateless composition of one (see the crate's module
10/// docs). It exists so an app choosing between a phone-sized and a
11/// desktop-sized layout has one place to ask "how big should this
12/// button/row/slider be", rather than inventing its own ad hoc breakpoint
13/// constants per widget (as e.g. `responsive_game_ui`'s own
14/// `MIN_TARGET_W`/`MIN_TARGET_H` do today). A future interactive widget in
15/// this crate (a checkbox, say) would read [`min_target_size`](Self::min_target_size)
16/// the same way it would read [`Sense`](crate::Sense).
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub enum Density {
19 /// Smaller interactive targets, for narrow or short terminals, or touch
20 /// input where every cell of screen space is scarce.
21 Compact,
22 /// Larger interactive targets, comfortable to hit with a mouse on a
23 /// normal desktop-sized terminal.
24 Relaxed,
25}
26
27impl Density {
28 /// The minimum size, in cells, an interactive target should claim at
29 /// this density.
30 ///
31 /// Counter-intuitively, [`Compact`](Self::Compact) targets are *taller*
32 /// than [`Relaxed`](Self::Relaxed) ones, not shorter: "compact" here
33 /// means a narrow, likely touch-driven layout (a phone-width terminal,
34 /// say), where a fingertip needs a noticeably taller row than a mouse
35 /// pointer does, at the cost of showing fewer rows at once.
36 /// [`Relaxed`](Self::Relaxed) assumes a normal desktop terminal with a
37 /// mouse, where dense, single-line rows are both legible and easy to
38 /// click precisely.
39 #[must_use]
40 pub const fn min_target_size(self) -> Size {
41 match self {
42 Self::Compact => Size {
43 width: 6,
44 height: 3,
45 },
46 Self::Relaxed => Size {
47 width: 6,
48 height: 1,
49 },
50 }
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn compact_rows_are_taller_than_relaxed_for_touch_targets() {
60 let compact = Density::Compact.min_target_size();
61 let relaxed = Density::Relaxed.min_target_size();
62 assert!(compact.height > relaxed.height);
63 }
64
65 #[test]
66 fn relaxed_still_claims_more_than_a_single_cell_wide() {
67 let size = Density::Relaxed.min_target_size();
68 assert!(size.width > 1);
69 }
70}