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}