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 measured_hold(&self) -> Option<(Size, crate::ConstraintsHold)> {
72 None
73 }
74
75 fn min_intrinsic_width(&self, height: f32) -> f32;
77
78 fn max_intrinsic_width(&self, height: f32) -> f32;
80
81 fn min_intrinsic_height(&self, width: f32) -> f32;
83
84 fn max_intrinsic_height(&self, width: f32) -> f32;
86
87 fn flex_parent_data(&self) -> Option<FlexParentData> {
90 None
91 }
92
93 fn parent_data(&self) -> ParentData {
98 self.flex_parent_data().map(Into::into).unwrap_or_default()
99 }
100}
101
102pub struct Placeable {
106 width: f32,
107 height: f32,
108 node_id: NodeId,
109 content_offset_x: f32,
110 content_offset_y: f32,
111 alignment_lines: crate::AlignmentLines,
112 place_target: Option<Rc<dyn PlaceTarget>>,
113}
114
115pub trait PlaceTarget {
117 fn place(&self, x: f32, y: f32);
119}
120
121impl<F: Fn(f32, f32)> PlaceTarget for F {
122 fn place(&self, x: f32, y: f32) {
123 self(x, y);
124 }
125}
126
127impl Placeable {
128 pub fn value(width: f32, height: f32, node_id: NodeId) -> Self {
130 Self {
131 width,
132 height,
133 node_id,
134 content_offset_x: 0.0,
135 content_offset_y: 0.0,
136 alignment_lines: crate::AlignmentLines::default(),
137 place_target: None,
138 }
139 }
140
141 pub fn value_with_offset(
143 width: f32,
144 height: f32,
145 node_id: NodeId,
146 content_offset: (f32, f32),
147 ) -> Self {
148 Self {
149 width,
150 height,
151 node_id,
152 content_offset_x: content_offset.0,
153 content_offset_y: content_offset.1,
154 alignment_lines: crate::AlignmentLines::default(),
155 place_target: None,
156 }
157 }
158
159 pub fn with_place_target(
163 width: f32,
164 height: f32,
165 node_id: NodeId,
166 target: Rc<dyn PlaceTarget>,
167 ) -> Self {
168 Self {
169 width,
170 height,
171 node_id,
172 content_offset_x: 0.0,
173 content_offset_y: 0.0,
174 alignment_lines: crate::AlignmentLines::default(),
175 place_target: Some(target),
176 }
177 }
178
179 pub fn place(&self, x: f32, y: f32) {
181 if let Some(target) = &self.place_target {
182 target.place(x, y);
183 }
184 }
185
186 pub fn width(&self) -> f32 {
188 self.width
189 }
190
191 pub fn height(&self) -> f32 {
193 self.height
194 }
195
196 pub fn node_id(&self) -> NodeId {
198 self.node_id
199 }
200
201 pub fn content_offset(&self) -> (f32, f32) {
203 (self.content_offset_x, self.content_offset_y)
204 }
205
206 pub fn with_alignment_lines(mut self, alignment_lines: crate::AlignmentLines) -> Self {
208 self.alignment_lines = alignment_lines;
209 self
210 }
211
212 pub fn alignment_lines(&self) -> crate::AlignmentLines {
214 self.alignment_lines
215 }
216}
217
218pub trait MeasureScope {
226 fn density(&self) -> f32;
228
229 fn font_scale(&self) -> f32;
231}
232
233pub trait MeasurePolicy {
235 fn measure(
237 &self,
238 scope: &dyn MeasureScope,
239 measurables: &[Box<dyn Measurable>],
240 constraints: Constraints,
241 ) -> MeasureResult;
242
243 fn measure_into(
249 &self,
250 scope: &dyn MeasureScope,
251 measurables: &[Box<dyn Measurable>],
252 constraints: Constraints,
253 placements: &mut Vec<Placement>,
254 ) -> Measurement {
255 let result = self.measure(scope, measurables, constraints);
256 placements.clear();
257 placements.extend(result.placements);
258 Measurement {
259 size: result.size,
260 alignment_lines: result.alignment_lines,
261 }
262 }
263
264 fn measure_hold(
269 &self,
270 _measurables: &[Box<dyn Measurable>],
271 _constraints: Constraints,
272 _size: Size,
273 ) -> Option<crate::ConstraintsHold> {
274 None
275 }
276
277 fn min_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32;
279
280 fn max_intrinsic_width(&self, measurables: &[Box<dyn Measurable>], height: f32) -> f32;
282
283 fn min_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32;
285
286 fn max_intrinsic_height(&self, measurables: &[Box<dyn Measurable>], width: f32) -> f32;
288}
289
290#[derive(Clone, Copy, Debug, Default, PartialEq)]
292pub struct Measurement {
293 pub size: Size,
295 pub alignment_lines: crate::AlignmentLines,
297}
298
299impl From<Size> for Measurement {
300 fn from(size: Size) -> Self {
301 Self {
302 size,
303 alignment_lines: crate::AlignmentLines::default(),
304 }
305 }
306}
307
308#[derive(Clone, Debug)]
310pub struct MeasureResult {
311 pub size: Size,
312 pub alignment_lines: crate::AlignmentLines,
314 pub placements: Vec<Placement>,
315}
316
317impl MeasureResult {
318 pub fn new(measurement: impl Into<Measurement>, placements: Vec<Placement>) -> Self {
320 let measurement = measurement.into();
321 Self {
322 size: measurement.size,
323 alignment_lines: measurement.alignment_lines,
324 placements,
325 }
326 }
327
328 pub fn with_alignment_lines(mut self, alignment_lines: crate::AlignmentLines) -> Self {
330 self.alignment_lines = alignment_lines;
331 self
332 }
333}
334
335#[derive(Clone, Copy, Debug)]
337pub struct Placement {
338 pub node_id: NodeId,
339 pub x: f32,
340 pub y: f32,
341 pub z_index: i32,
342}
343
344impl Placement {
345 pub fn new(node_id: NodeId, x: f32, y: f32, z_index: i32) -> Self {
346 Self {
347 node_id,
348 x,
349 y,
350 z_index,
351 }
352 }
353}
354
355#[derive(Clone, Copy, Debug)]
361pub struct LayoutModifierMeasureResult {
362 pub size: Size,
364 pub placement_offset_x: f32,
369 pub placement_offset_y: f32,
370 pub alignment_lines: crate::AlignmentLines,
372}
373
374impl LayoutModifierMeasureResult {
375 pub fn new(size: Size, placement_offset_x: f32, placement_offset_y: f32) -> Self {
376 Self {
377 size,
378 placement_offset_x,
379 placement_offset_y,
380 alignment_lines: crate::AlignmentLines::default(),
381 }
382 }
383
384 pub fn with_size(size: Size) -> Self {
386 Self {
387 size,
388 placement_offset_x: 0.0,
389 placement_offset_y: 0.0,
390 alignment_lines: crate::AlignmentLines::default(),
391 }
392 }
393
394 pub fn with_alignment_lines(mut self, alignment_lines: crate::AlignmentLines) -> Self {
396 self.alignment_lines = alignment_lines;
397 self
398 }
399}
400
401#[cfg(test)]
402#[path = "tests/core_tests.rs"]
403mod tests;