1use std::rc::Rc;
4
5use cranpose_core::NodeId;
6use cranpose_ui_graphics::Size;
7
8use crate::{Alignment, HorizontalAlignment, VerticalAlignment, constraints::Constraints};
9
10#[derive(Clone, Copy, Debug, Default)]
12pub struct FlexParentData {
13 pub weight: f32,
16
17 pub fill: bool,
20}
21
22impl FlexParentData {
23 pub fn new(weight: f32, fill: bool) -> Self {
24 Self { weight, fill }
25 }
26
27 pub fn has_weight(&self) -> bool {
28 self.weight > 0.0
29 }
30}
31
32#[derive(Clone, Copy, Debug, Default, PartialEq)]
37pub struct ParentData {
38 pub weight: f32,
39 pub fill: bool,
40 pub box_alignment: Option<Alignment>,
41 pub row_alignment: Option<VerticalAlignment>,
42 pub row_baseline: bool,
44 pub column_alignment: Option<HorizontalAlignment>,
45}
46
47impl From<FlexParentData> for ParentData {
48 fn from(value: FlexParentData) -> Self {
49 Self {
50 weight: value.weight,
51 fill: value.fill,
52 ..Self::default()
53 }
54 }
55}
56
57impl ParentData {
58 pub fn has_weight(&self) -> bool {
59 self.weight > 0.0
60 }
61}
62
63pub trait Measurable {
65 fn measure(&self, constraints: Constraints) -> Placeable;
67
68 fn min_intrinsic_width(&self, height: f32) -> f32;
70
71 fn max_intrinsic_width(&self, height: f32) -> f32;
73
74 fn min_intrinsic_height(&self, width: f32) -> f32;
76
77 fn max_intrinsic_height(&self, width: f32) -> f32;
79
80 fn flex_parent_data(&self) -> Option<FlexParentData> {
83 None
84 }
85
86 fn parent_data(&self) -> ParentData {
91 self.flex_parent_data().map(Into::into).unwrap_or_default()
92 }
93}
94
95pub struct Placeable {
99 width: f32,
100 height: f32,
101 node_id: NodeId,
102 content_offset_x: f32,
103 content_offset_y: f32,
104 alignment_lines: crate::AlignmentLines,
105 place_target: Option<Rc<dyn PlaceTarget>>,
106}
107
108pub trait PlaceTarget {
110 fn place(&self, x: f32, y: f32);
112}
113
114impl<F: Fn(f32, f32)> PlaceTarget for F {
115 fn place(&self, x: f32, y: f32) {
116 self(x, y);
117 }
118}
119
120impl Placeable {
121 pub fn value(width: f32, height: f32, node_id: NodeId) -> Self {
123 Self {
124 width,
125 height,
126 node_id,
127 content_offset_x: 0.0,
128 content_offset_y: 0.0,
129 alignment_lines: crate::AlignmentLines::default(),
130 place_target: None,
131 }
132 }
133
134 pub fn value_with_offset(
136 width: f32,
137 height: f32,
138 node_id: NodeId,
139 content_offset: (f32, f32),
140 ) -> Self {
141 Self {
142 width,
143 height,
144 node_id,
145 content_offset_x: content_offset.0,
146 content_offset_y: content_offset.1,
147 alignment_lines: crate::AlignmentLines::default(),
148 place_target: None,
149 }
150 }
151
152 pub fn with_place_target(
156 width: f32,
157 height: f32,
158 node_id: NodeId,
159 target: Rc<dyn PlaceTarget>,
160 ) -> Self {
161 Self {
162 width,
163 height,
164 node_id,
165 content_offset_x: 0.0,
166 content_offset_y: 0.0,
167 alignment_lines: crate::AlignmentLines::default(),
168 place_target: Some(target),
169 }
170 }
171
172 pub fn place(&self, x: f32, y: f32) {
174 if let Some(target) = &self.place_target {
175 target.place(x, y);
176 }
177 }
178
179 pub fn width(&self) -> f32 {
181 self.width
182 }
183
184 pub fn height(&self) -> f32 {
186 self.height
187 }
188
189 pub fn node_id(&self) -> NodeId {
191 self.node_id
192 }
193
194 pub fn content_offset(&self) -> (f32, f32) {
196 (self.content_offset_x, self.content_offset_y)
197 }
198
199 pub fn with_alignment_lines(mut self, alignment_lines: crate::AlignmentLines) -> Self {
201 self.alignment_lines = alignment_lines;
202 self
203 }
204
205 pub fn alignment_lines(&self) -> crate::AlignmentLines {
207 self.alignment_lines
208 }
209}
210
211pub trait MeasureScope {
219 fn density(&self) -> f32;
221
222 fn font_scale(&self) -> f32;
224}
225
226pub trait MeasurePolicy {
228 fn measure(
230 &self,
231 scope: &dyn MeasureScope,
232 measurables: &[Box<dyn Measurable>],
233 constraints: Constraints,
234 ) -> MeasureResult;
235
236 fn measure_into(
242 &self,
243 scope: &dyn MeasureScope,
244 measurables: &[Box<dyn Measurable>],
245 constraints: Constraints,
246 placements: &mut Vec<Placement>,
247 ) -> Measurement {
248 let result = self.measure(scope, measurables, constraints);
249 placements.clear();
250 placements.extend(result.placements);
251 Measurement {
252 size: result.size,
253 alignment_lines: result.alignment_lines,
254 }
255 }
256
257 fn min_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32;
259
260 fn max_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32;
262
263 fn min_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32;
265
266 fn max_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32;
268}
269
270#[derive(Clone, Copy, Debug, Default, PartialEq)]
272pub struct Measurement {
273 pub size: Size,
275 pub alignment_lines: crate::AlignmentLines,
277}
278
279impl From<Size> for Measurement {
280 fn from(size: Size) -> Self {
281 Self {
282 size,
283 alignment_lines: crate::AlignmentLines::default(),
284 }
285 }
286}
287
288#[derive(Clone, Debug)]
290pub struct MeasureResult {
291 pub size: Size,
292 pub alignment_lines: crate::AlignmentLines,
294 pub placements: Vec<Placement>,
295}
296
297impl MeasureResult {
298 pub fn new(measurement: impl Into<Measurement>, placements: Vec<Placement>) -> Self {
300 let measurement = measurement.into();
301 Self {
302 size: measurement.size,
303 alignment_lines: measurement.alignment_lines,
304 placements,
305 }
306 }
307
308 pub fn with_alignment_lines(mut self, alignment_lines: crate::AlignmentLines) -> Self {
310 self.alignment_lines = alignment_lines;
311 self
312 }
313}
314
315#[derive(Clone, Copy, Debug)]
317pub struct Placement {
318 pub node_id: NodeId,
319 pub x: f32,
320 pub y: f32,
321 pub z_index: i32,
322}
323
324impl Placement {
325 pub fn new(node_id: NodeId, x: f32, y: f32, z_index: i32) -> Self {
326 Self {
327 node_id,
328 x,
329 y,
330 z_index,
331 }
332 }
333}
334
335#[derive(Clone, Copy, Debug)]
341pub struct LayoutModifierMeasureResult {
342 pub size: Size,
344 pub placement_offset_x: f32,
349 pub placement_offset_y: f32,
350 pub alignment_lines: crate::AlignmentLines,
352}
353
354impl LayoutModifierMeasureResult {
355 pub fn new(size: Size, placement_offset_x: f32, placement_offset_y: f32) -> Self {
356 Self {
357 size,
358 placement_offset_x,
359 placement_offset_y,
360 alignment_lines: crate::AlignmentLines::default(),
361 }
362 }
363
364 pub fn with_size(size: Size) -> Self {
366 Self {
367 size,
368 placement_offset_x: 0.0,
369 placement_offset_y: 0.0,
370 alignment_lines: crate::AlignmentLines::default(),
371 }
372 }
373
374 pub fn with_alignment_lines(mut self, alignment_lines: crate::AlignmentLines) -> Self {
376 self.alignment_lines = alignment_lines;
377 self
378 }
379}
380
381#[cfg(test)]
382#[path = "tests/core_tests.rs"]
383mod tests;