Skip to main content

retroglyph_widgets/
align.rs

1//! [`Align`]: horizontal alignment of a single line of text within a
2//! fixed-width area.
3
4/// Horizontal alignment of one line of text within the columns it's rendered
5/// into.
6///
7/// A builder knob on the single-line text widgets ([`Text`](crate::Text),
8/// [`PrintLine`](crate::PrintLine)) and on the titles of [`Panel`](crate::Panel)
9/// and [`Modal`](crate::Modal). Text widgets default to [`Left`](Self::Left)
10/// (their long-standing behavior); panel/modal titles default to
11/// [`Center`](Self::Center) (theirs).
12#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
13pub enum Align {
14    /// Text starts at the left edge; leftover space trails on the right.
15    #[default]
16    Left,
17    /// Leftover space is split evenly on both sides (an odd extra column goes
18    /// on the right).
19    Center,
20    /// Text ends at the right edge; leftover space leads on the left.
21    Right,
22}
23
24impl Align {
25    /// The left offset, in columns, at which a `content_width`-column line
26    /// should start within an `area_width`-column area for this alignment.
27    ///
28    /// Saturates at `0` when the content is wider than the area, so the caller
29    /// clips from the left edge rather than underflowing.
30    #[must_use]
31    pub const fn offset(self, area_width: u16, content_width: u16) -> u16 {
32        let slack = area_width.saturating_sub(content_width);
33        match self {
34            Self::Left => 0,
35            Self::Center => slack / 2,
36            Self::Right => slack,
37        }
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn offset_places_content_per_alignment() {
47        // 4-column word in a 10-column area: 6 columns of slack.
48        assert_eq!(Align::Left.offset(10, 4), 0);
49        assert_eq!(Align::Center.offset(10, 4), 3);
50        assert_eq!(Align::Right.offset(10, 4), 6);
51    }
52
53    #[test]
54    fn center_puts_the_odd_column_on_the_right() {
55        // 4-column word in a 9-column area: 5 columns of slack, 2 on the left.
56        assert_eq!(Align::Center.offset(9, 4), 2);
57    }
58
59    #[test]
60    fn wider_than_area_saturates_to_zero() {
61        assert_eq!(Align::Left.offset(3, 8), 0);
62        assert_eq!(Align::Center.offset(3, 8), 0);
63        assert_eq!(Align::Right.offset(3, 8), 0);
64    }
65
66    #[test]
67    fn default_is_left() {
68        assert_eq!(Align::default(), Align::Left);
69    }
70}