Skip to main content

cranpose_ui_layout/
alignment_lines.rs

1/// Text baselines measured down from a layout's top edge.
2///
3/// Containers inherit the smallest first baseline and largest last baseline of
4/// their placed children. A missing line remains unspecified through translation.
5#[derive(Clone, Copy, Debug)]
6pub struct AlignmentLines {
7    first: f32,
8    last: f32,
9}
10
11impl AlignmentLines {
12    /// Creates alignment lines. Non-finite coordinates are treated as unspecified.
13    pub fn new(first: Option<f32>, last: Option<f32>) -> Self {
14        Self {
15            first: first.filter(|value| value.is_finite()).unwrap_or(f32::NAN),
16            last: last.filter(|value| value.is_finite()).unwrap_or(f32::NAN),
17        }
18    }
19
20    /// The first drawn text baseline, when this layout provides one.
21    pub fn first_baseline(self) -> Option<f32> {
22        self.first.is_finite().then_some(self.first)
23    }
24
25    /// The last drawn text baseline, when this layout provides one.
26    pub fn last_baseline(self) -> Option<f32> {
27        self.last.is_finite().then_some(self.last)
28    }
29
30    /// Translates specified lines by a child's vertical placement.
31    pub fn translated(self, y: f32) -> Self {
32        Self {
33            first: self.first + y,
34            last: self.last + y,
35        }
36    }
37
38    /// Inherits the first and last lines of another placed child.
39    pub fn merge(&mut self, other: Self) {
40        // Most children provide no lines; their merge changes nothing.
41        if other.first.is_nan() && other.last.is_nan() {
42            return;
43        }
44        self.first = self.first.min(other.first);
45        self.last = self.last.max(other.last);
46    }
47
48    /// Replaces inherited lines with the lines explicitly provided by a layout.
49    pub fn with_overrides(self, explicit: Self) -> Self {
50        Self::new(
51            explicit.first_baseline().or_else(|| self.first_baseline()),
52            explicit.last_baseline().or_else(|| self.last_baseline()),
53        )
54    }
55}
56
57impl Default for AlignmentLines {
58    fn default() -> Self {
59        Self {
60            first: f32::NAN,
61            last: f32::NAN,
62        }
63    }
64}
65
66impl PartialEq for AlignmentLines {
67    fn eq(&self, other: &Self) -> bool {
68        self.first_baseline() == other.first_baseline()
69            && self.last_baseline() == other.last_baseline()
70    }
71}