Skip to main content

waterui_layout/
alignment.rs

1//! Alignment tokens: unit values that name one position and convert into
2//! exactly the alignment types that position is legal for.
3//!
4//! `vstack(..).alignment(Leading)` reads as the intent; `vstack(..).alignment(Top)`
5//! does not compile, because `Top` has no `Into<HorizontalAlignment>`. The
6//! per-container methods (`.leading()`, `.top()`, `.top_leading()`, …) are the
7//! same positions spelled without an argument.
8
9use waterui_core::layout::{Alignment, HorizontalAlignment, VerticalAlignment};
10
11/// Declares one alignment token and the conversions it is legal for.
12macro_rules! token {
13    ($(#[$meta:meta])* $name:ident => $($target:ident),+) => {
14        $(#[$meta])*
15        #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
16        pub struct $name;
17
18        $(
19            impl From<$name> for $target {
20                fn from(_: $name) -> Self {
21                    Self::$name
22                }
23            }
24        )+
25    };
26}
27
28token!(
29    /// The leading edge: a `VStack` column, or a `ZStack`/`Frame`/`Grid`
30    /// cell centered vertically.
31    Leading => HorizontalAlignment, Alignment
32);
33token!(
34    /// The trailing edge: a `VStack` column, or a two-dimensional cell
35    /// centered vertically.
36    Trailing => HorizontalAlignment, Alignment
37);
38token!(
39    /// The center on whichever axes the container aligns.
40    Center => HorizontalAlignment, VerticalAlignment, Alignment
41);
42token!(
43    /// The top edge: an `HStack` row, or a two-dimensional cell centered
44    /// horizontally.
45    Top => VerticalAlignment, Alignment
46);
47token!(
48    /// The bottom edge: an `HStack` row, or a two-dimensional cell centered
49    /// horizontally.
50    Bottom => VerticalAlignment, Alignment
51);
52token!(
53    /// The first text baseline of an `HStack` row.
54    FirstBaseline => VerticalAlignment
55);
56token!(
57    /// The last text baseline of an `HStack` row.
58    LastBaseline => VerticalAlignment
59);
60token!(
61    /// The top-leading corner of a two-dimensional cell.
62    TopLeading => Alignment
63);
64token!(
65    /// The top-trailing corner of a two-dimensional cell.
66    TopTrailing => Alignment
67);
68token!(
69    /// The bottom-leading corner of a two-dimensional cell.
70    BottomLeading => Alignment
71);
72token!(
73    /// The bottom-trailing corner of a two-dimensional cell.
74    BottomTrailing => Alignment
75);
76
77/// The horizontal positions, as methods: `.leading()`, `.centered()`,
78/// `.trailing()`. Expands inside an `impl` block whose type has
79/// `fn alignment(self, impl Into<HorizontalAlignment>) -> Self`.
80macro_rules! horizontal_alignment_methods {
81    () => {
82        /// Aligns children to the leading edge.
83        #[must_use]
84        pub fn leading(self) -> Self {
85            self.alignment($crate::alignment::Leading)
86        }
87
88        /// Centers children horizontally.
89        #[must_use]
90        pub fn centered(self) -> Self {
91            self.alignment($crate::alignment::Center)
92        }
93
94        /// Aligns children to the trailing edge.
95        #[must_use]
96        pub fn trailing(self) -> Self {
97            self.alignment($crate::alignment::Trailing)
98        }
99    };
100}
101
102/// The vertical positions, as methods: `.top()`, `.centered()`, `.bottom()`,
103/// `.first_baseline()`, `.last_baseline()`. Expands inside an `impl` block
104/// whose type has `fn alignment(self, impl Into<VerticalAlignment>) -> Self`.
105macro_rules! vertical_alignment_methods {
106    () => {
107        /// Aligns children to the top edge.
108        #[must_use]
109        pub fn top(self) -> Self {
110            self.alignment($crate::alignment::Top)
111        }
112
113        /// Centers children vertically.
114        #[must_use]
115        pub fn centered(self) -> Self {
116            self.alignment($crate::alignment::Center)
117        }
118
119        /// Aligns children to the bottom edge.
120        #[must_use]
121        pub fn bottom(self) -> Self {
122            self.alignment($crate::alignment::Bottom)
123        }
124
125        /// Aligns children on their first text baseline.
126        #[must_use]
127        pub fn first_baseline(self) -> Self {
128            self.alignment($crate::alignment::FirstBaseline)
129        }
130
131        /// Aligns children on their last text baseline.
132        #[must_use]
133        pub fn last_baseline(self) -> Self {
134            self.alignment($crate::alignment::LastBaseline)
135        }
136    };
137}
138
139/// The nine two-dimensional positions, as methods. Expands inside an `impl`
140/// block whose type has `fn alignment(self, impl Into<Alignment>) -> Self`.
141macro_rules! two_dimensional_alignment_methods {
142    () => {
143        /// Aligns content to the top-leading corner.
144        #[must_use]
145        pub fn top_leading(self) -> Self {
146            self.alignment($crate::alignment::TopLeading)
147        }
148
149        /// Aligns content to the top edge, centered horizontally.
150        #[must_use]
151        pub fn top(self) -> Self {
152            self.alignment($crate::alignment::Top)
153        }
154
155        /// Aligns content to the top-trailing corner.
156        #[must_use]
157        pub fn top_trailing(self) -> Self {
158            self.alignment($crate::alignment::TopTrailing)
159        }
160
161        /// Aligns content to the leading edge, centered vertically.
162        #[must_use]
163        pub fn leading(self) -> Self {
164            self.alignment($crate::alignment::Leading)
165        }
166
167        /// Centers content on both axes.
168        #[must_use]
169        pub fn centered(self) -> Self {
170            self.alignment($crate::alignment::Center)
171        }
172
173        /// Aligns content to the trailing edge, centered vertically.
174        #[must_use]
175        pub fn trailing(self) -> Self {
176            self.alignment($crate::alignment::Trailing)
177        }
178
179        /// Aligns content to the bottom-leading corner.
180        #[must_use]
181        pub fn bottom_leading(self) -> Self {
182            self.alignment($crate::alignment::BottomLeading)
183        }
184
185        /// Aligns content to the bottom edge, centered horizontally.
186        #[must_use]
187        pub fn bottom(self) -> Self {
188            self.alignment($crate::alignment::Bottom)
189        }
190
191        /// Aligns content to the bottom-trailing corner.
192        #[must_use]
193        pub fn bottom_trailing(self) -> Self {
194            self.alignment($crate::alignment::BottomTrailing)
195        }
196    };
197}
198
199pub(crate) use {
200    horizontal_alignment_methods, two_dimensional_alignment_methods, vertical_alignment_methods,
201};
202
203#[cfg(test)]
204mod tests {
205    use super::*;
206
207    #[test]
208    fn tokens_convert_to_the_positions_they_name() {
209        assert_eq!(
210            HorizontalAlignment::from(Leading),
211            HorizontalAlignment::Leading
212        );
213        assert_eq!(VerticalAlignment::from(Bottom), VerticalAlignment::Bottom);
214        assert_eq!(Alignment::from(Center), Alignment::Center);
215        assert_eq!(Alignment::from(Leading), Alignment::Leading);
216        assert_eq!(Alignment::from(BottomTrailing), Alignment::BottomTrailing);
217    }
218}