1use nalgebra::Vector2;
2pub use taffy::{
3 AlignContent, AlignItems, AlignSelf, Dimension, Display, FlexDirection, FlexWrap, GridAutoFlow,
4 GridPlacement, JustifyContent, JustifyItems, JustifySelf, Layout, LengthPercentage,
5 LengthPercentageAuto, Line, NodeId, Overflow, Position, Rect, TaffyError, TaffyResult,
6 TaffyTree,
7};
8
9pub const LAYOUT_EPSILON: f32 = 0.5;
19
20#[inline(always)]
37pub const fn equal(x: f32, y: f32) -> bool {
38 (x - y).abs() < LAYOUT_EPSILON
39}
40
41#[inline(always)]
58pub fn intersects(point: Vector2<f32>, layout: &Layout) -> bool {
59 point.x >= layout.location.x
60 && point.x <= layout.location.x + layout.size.width
61 && point.y >= layout.location.y
62 && point.y <= layout.location.y + layout.size.height
63}
64
65#[derive(Clone, PartialEq, Debug)]
67pub struct LayoutStyle {
68 pub display: Display,
70
71 pub overflow: (Overflow, Overflow),
73
74 pub scrollbar_width: f32,
76
77 pub position: Position,
79
80 pub inset: Rect<LengthPercentageAuto>,
82
83 pub size: Vector2<Dimension>,
85
86 pub min_size: Vector2<Dimension>,
88
89 pub max_size: Vector2<Dimension>,
91
92 pub aspect_ratio: Option<f32>,
96
97 pub margin: Rect<LengthPercentageAuto>,
99
100 pub padding: Rect<LengthPercentage>,
102
103 pub border: Rect<LengthPercentage>,
105
106 pub align_items: Option<AlignItems>,
108
109 pub align_self: Option<AlignSelf>,
112
113 pub justify_items: Option<AlignItems>,
115
116 pub justify_self: Option<AlignSelf>,
119
120 pub align_content: Option<AlignContent>,
122
123 pub justify_content: Option<JustifyContent>,
125
126 pub gap: Vector2<LengthPercentage>,
128
129 pub flex_direction: FlexDirection,
131
132 pub flex_wrap: FlexWrap,
134
135 pub flex_basis: Dimension,
137
138 pub flex_grow: f32,
142
143 pub flex_shrink: f32,
147
148 pub grid_auto_flow: GridAutoFlow,
150
151 pub grid_row: Line<GridPlacement>,
153
154 pub grid_column: Line<GridPlacement>,
156}
157
158impl Default for LayoutStyle {
159 #[inline(always)]
160 fn default() -> Self {
161 LayoutStyle {
162 display: Display::Flex,
163 overflow: (Overflow::Visible, Overflow::Visible),
164 scrollbar_width: 0.0,
165 position: Position::Relative,
166 inset: Rect::auto(),
167 margin: Rect::zero(),
168 padding: Rect::zero(),
169 border: Rect::zero(),
170 size: Vector2::new(Dimension::auto(), Dimension::auto()),
171 min_size: Vector2::new(Dimension::auto(), Dimension::auto()),
172 max_size: Vector2::new(Dimension::auto(), Dimension::auto()),
173 aspect_ratio: None,
174 gap: Vector2::new(LengthPercentage::length(0.0), LengthPercentage::length(0.0)),
175 align_items: None,
176 align_self: None,
177 justify_items: None,
178 justify_self: None,
179 align_content: None,
180 justify_content: None,
181 flex_direction: FlexDirection::Row,
182 flex_wrap: FlexWrap::NoWrap,
183 flex_grow: 0.0,
184 flex_shrink: 1.0,
185 flex_basis: Dimension::auto(),
186 grid_auto_flow: GridAutoFlow::Row,
187 grid_row: Line {
188 start: GridPlacement::Auto,
189 end: GridPlacement::Auto,
190 },
191 grid_column: Line {
192 start: GridPlacement::Auto,
193 end: GridPlacement::Auto,
194 },
195 }
196 }
197}
198
199impl From<LayoutStyle> for taffy::Style {
200 #[inline(always)]
201 fn from(value: LayoutStyle) -> Self {
202 taffy::Style {
203 display: value.display,
204 overflow: taffy::Point {
205 x: value.overflow.0,
206 y: value.overflow.1,
207 },
208 scrollbar_width: value.scrollbar_width,
209 position: value.position,
210 inset: value.inset,
211 margin: value.margin,
212 padding: value.padding,
213 border: value.border,
214 size: taffy::Size {
215 width: value.size.x,
216 height: value.size.y,
217 },
218 min_size: taffy::Size {
219 width: value.min_size.x,
220 height: value.min_size.y,
221 },
222 max_size: taffy::Size {
223 width: value.max_size.x,
224 height: value.max_size.y,
225 },
226 aspect_ratio: value.aspect_ratio,
227 gap: taffy::Size {
228 width: value.gap.x,
229 height: value.gap.y,
230 },
231 align_items: value.align_items,
232 align_self: value.align_self,
233 justify_items: value.justify_items,
234 justify_self: value.justify_self,
235 align_content: value.align_content,
236 justify_content: value.justify_content,
237 flex_direction: value.flex_direction,
238 flex_wrap: value.flex_wrap,
239 flex_grow: value.flex_grow,
240 flex_shrink: value.flex_shrink,
241 flex_basis: value.flex_basis,
242 grid_auto_flow: value.grid_auto_flow,
243 grid_row: value.grid_row,
244 grid_column: value.grid_column,
245 ..Default::default()
246 }
247 }
248}
249
250#[derive(Debug)]
252pub struct LayoutNode {
253 pub layout: Layout,
255 pub children: Vec<LayoutNode>,
257}
258
259pub struct StyleNode {
261 pub style: LayoutStyle,
263 pub children: Vec<StyleNode>,
265}
266
267#[cfg(all(test, feature = "test"))]
268mod tests {
269 use crate::layout::{equal, intersects};
270 use nalgebra::Vector2;
271 use taffy::{Layout, Point, Size};
272
273 #[test_case::test_case(1.0, 1.0, true; "when equal and true")]
275 #[test_case::test_case(12.0, 12.4, true; "when positive and true")]
276 #[test_case::test_case(123.0, 123.5, false; "when positive and false")]
277 #[test_case::test_case(-1234.0, -1234.4, true; "when negative and true")]
278 #[test_case::test_case(-10.0, -10.5, false; "when negative and false")]
279 #[test_case::test_case(-1.0, 0.3, false; "when different and true")]
280 #[test_case::test_case(-0.25, 0.25, false; "when different and false")]
281 fn test_equal(x: f32, y: f32, eq: bool) {
282 assert_eq!(equal(x, y), eq);
283 }
284
285 #[test_case::test_case(100.0, 500.0, true; "when point is on border")]
287 #[test_case::test_case(150.0, 550.0, true; "when point is inside")]
288 #[test_case::test_case(700.0, 700.0, false; "when point is outside")]
289 fn test_intersects(x: f32, y: f32, eq: bool) {
290 let layout = Layout {
291 location: Point { x: 100.0, y: 500.0 },
292 size: Size {
293 width: 500.0,
294 height: 100.0,
295 },
296 ..Default::default()
297 };
298
299 assert_eq!(intersects(Vector2::new(x, y), &layout), eq);
300 }
301}