repose_core/
modifier.rs

1use std::rc::Rc;
2
3use taffy::{AlignContent, AlignItems, AlignSelf, JustifyContent};
4
5use crate::{Color, PointerEvent, Size, Transform, Vec2};
6
7#[derive(Clone, Debug)]
8pub struct Border {
9    pub width: f32,
10    pub color: Color,
11    pub radius: f32,
12}
13
14#[derive(Clone, Copy, Debug, Default)]
15pub struct PaddingValues {
16    pub left: f32,
17    pub right: f32,
18    pub top: f32,
19    pub bottom: f32,
20}
21
22#[derive(Clone, Default)]
23pub struct Modifier {
24    pub padding: Option<f32>,
25    pub padding_values: Option<PaddingValues>,
26    pub size: Option<Size>,
27    pub fill_max: bool,
28    pub fill_max_w: bool,
29    pub fill_max_h: bool,
30    pub width: Option<f32>,
31    pub height: Option<f32>,
32    pub min_width: Option<f32>,
33    pub min_height: Option<f32>,
34    pub max_width: Option<f32>,
35    pub max_height: Option<f32>,
36    pub background: Option<Color>,
37    pub border: Option<Border>,
38    pub flex_grow: Option<f32>,
39    pub flex_shrink: Option<f32>,
40    pub flex_basis: Option<f32>,
41    pub align_self: Option<AlignSelf>,
42    pub justify_content: Option<JustifyContent>, // main-axis
43    pub align_items_container: Option<AlignItems>, // cross-axis
44    pub aspect_ratio: Option<f32>,               // width/height
45    pub position_type: Option<PositionType>,
46    pub offset_left: Option<f32>,
47    pub offset_right: Option<f32>,
48    pub offset_top: Option<f32>,
49    pub offset_bottom: Option<f32>,
50    pub grid: Option<GridConfig>,
51    pub grid_col_span: Option<u16>,
52    pub grid_row_span: Option<u16>,
53    pub click: bool,
54    pub semantics_label: Option<String>,
55    /// Works for hit-testing only, draw order is not changed.
56    pub z_index: f32,
57    pub clip_rounded: Option<f32>,
58    pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
59
60    // Pointer callbacks
61    pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
62    pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
63    pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
64    pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
65    pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
66
67    pub alpha: Option<f32>,
68    pub transform: Option<Transform>,
69
70    pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect)>>,
71}
72
73#[derive(Clone, Copy, Debug)]
74pub enum PositionType {
75    Relative,
76    Absolute,
77}
78
79#[derive(Clone, Copy, Debug)]
80pub struct GridConfig {
81    pub columns: usize, // e.g. 3 (auto 1fr tracks)
82    pub row_gap: f32,
83    pub column_gap: f32,
84}
85
86impl Default for Border {
87    fn default() -> Self {
88        Border {
89            width: 1.0,
90            color: Color::WHITE,
91            radius: 0.0,
92        }
93    }
94}
95
96impl std::fmt::Debug for Modifier {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        f.debug_struct("Modifier")
99            .field("padding", &self.padding)
100            .field("padding_values", &self.padding_values)
101            .field("size", &self.size)
102            .field("max_height", &self.max_height)
103            .field("max_width", &self.max_width)
104            .field("min_height", &self.min_height)
105            .field("min_width", &self.min_width)
106            .field("fill_max", &self.fill_max)
107            .field("background", &self.background)
108            .field("border", &self.border)
109            .field("click", &self.click)
110            .field("semantics_label", &self.semantics_label)
111            .field("z_index", &self.z_index)
112            .field("clip_rounded", &self.clip_rounded)
113            .field("alpha", &self.alpha)
114            .finish()
115    }
116}
117
118impl Modifier {
119    pub fn new() -> Self {
120        Self::default()
121    }
122    pub fn padding(mut self, px: f32) -> Self {
123        self.padding = Some(px);
124        self
125    }
126    pub fn padding_values(mut self, pv: PaddingValues) -> Self {
127        self.padding_values = Some(pv);
128        self
129    }
130    pub fn size(mut self, w: f32, h: f32) -> Self {
131        self.size = Some(Size {
132            width: w,
133            height: h,
134        });
135        self
136    }
137    pub fn fill_max_size(mut self) -> Self {
138        self.fill_max = true;
139        self
140    }
141    pub fn width(mut self, w: f32) -> Self {
142        self.width = Some(w);
143        self
144    }
145    pub fn height(mut self, h: f32) -> Self {
146        self.height = Some(h);
147        self
148    }
149    pub fn fill_max_width(mut self) -> Self {
150        self.fill_max_w = true;
151        self
152    }
153    pub fn fill_max_height(mut self) -> Self {
154        self.fill_max_h = true;
155        self
156    }
157    pub fn min_size(mut self, w: f32, h: f32) -> Self {
158        self.min_width = Some(w.max(0.0));
159        self.min_height = Some(h.max(0.0));
160        self
161    }
162    pub fn max_size(mut self, w: f32, h: f32) -> Self {
163        self.max_width = Some(w.max(0.0));
164        self.max_height = Some(h.max(0.0));
165        self
166    }
167    pub fn min_width(mut self, w: f32) -> Self {
168        self.min_width = Some(w.max(0.0));
169        self
170    }
171    pub fn min_height(mut self, h: f32) -> Self {
172        self.min_height = Some(h.max(0.0));
173        self
174    }
175    pub fn max_width(mut self, w: f32) -> Self {
176        self.max_width = Some(w.max(0.0));
177        self
178    }
179    pub fn max_height(mut self, h: f32) -> Self {
180        self.max_height = Some(h.max(0.0));
181        self
182    }
183    pub fn background(mut self, color: Color) -> Self {
184        self.background = Some(color);
185        self
186    }
187    pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
188        self.border = Some(Border {
189            width,
190            color,
191            radius,
192        });
193        self
194    }
195    pub fn clickable(mut self) -> Self {
196        self.click = true;
197        self
198    }
199    pub fn semantics(mut self, label: impl Into<String>) -> Self {
200        self.semantics_label = Some(label.into());
201        self
202    }
203    pub fn z_index(mut self, z: f32) -> Self {
204        self.z_index = z;
205        self
206    }
207    pub fn clip_rounded(mut self, r: f32) -> Self {
208        self.clip_rounded = Some(r);
209        self
210    }
211
212    pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
213        self.on_pointer_down = Some(Rc::new(f));
214        self
215    }
216    pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
217        self.on_pointer_move = Some(Rc::new(f));
218        self
219    }
220    pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
221        self.on_pointer_up = Some(Rc::new(f));
222        self
223    }
224    pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
225        self.on_pointer_enter = Some(Rc::new(f));
226        self
227    }
228    pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
229        self.on_pointer_leave = Some(Rc::new(f));
230        self
231    }
232    pub fn flex_grow(mut self, g: f32) -> Self {
233        self.flex_grow = Some(g);
234        self
235    }
236    pub fn flex_shrink(mut self, s: f32) -> Self {
237        self.flex_shrink = Some(s);
238        self
239    }
240    pub fn flex_basis(mut self, px: f32) -> Self {
241        self.flex_basis = Some(px);
242        self
243    }
244    pub fn align_self_baseline(mut self) -> Self {
245        self.align_self = Some(AlignSelf::Baseline);
246        self
247    }
248    pub fn align_self_center(mut self) -> Self {
249        self.align_self = Some(AlignSelf::Center);
250        self
251    }
252    pub fn align_self(mut self, align: AlignSelf) -> Self {
253        self.align_self = Some(align);
254        self
255    }
256    pub fn justify_content(mut self, justify_content: AlignContent) -> Self {
257        self.justify_content = Some(justify_content);
258        self
259    }
260    pub fn align_items(mut self, align_items: AlignItems) -> Self {
261        self.align_items_container = Some(align_items);
262        self
263    }
264    pub fn aspect_ratio(mut self, ratio: f32) -> Self {
265        self.aspect_ratio = Some(ratio.max(0.0));
266        self
267    }
268    pub fn absolute(mut self) -> Self {
269        self.position_type = Some(PositionType::Absolute);
270        self
271    }
272    pub fn offset(
273        mut self,
274        left: Option<f32>,
275        top: Option<f32>,
276        right: Option<f32>,
277        bottom: Option<f32>,
278    ) -> Self {
279        self.offset_left = left;
280        self.offset_top = top;
281        self.offset_right = right;
282        self.offset_bottom = bottom;
283        self
284    }
285    pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
286        self.grid = Some(GridConfig {
287            columns: columns.max(1),
288            row_gap,
289            column_gap,
290        });
291        self
292    }
293    pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
294        self.grid_col_span = Some(col_span.max(1));
295        self.grid_row_span = Some(row_span.max(1));
296        self
297    }
298
299    pub fn alpha(mut self, a: f32) -> Self {
300        self.alpha = Some(a.clamp(0.0, 1.0));
301        self
302    }
303    /// Broken currently?
304    pub fn translate(mut self, x: f32, y: f32) -> Self {
305        let t = self.transform.unwrap_or_else(Transform::identity);
306        self.transform = Some(t.combine(&Transform::translate(x, y)));
307        self
308    }
309    pub fn scale(mut self, s: f32) -> Self {
310        self.scale2(s, s)
311    }
312    pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
313        let mut t = self.transform.unwrap_or_else(Transform::identity);
314        t.scale_x *= sx;
315        t.scale_y *= sy;
316        self.transform = Some(t);
317        self
318    }
319    pub fn rotate(mut self, radians: f32) -> Self {
320        let mut t = self.transform.unwrap_or_else(Transform::identity);
321        t.rotate += radians;
322        self.transform = Some(t);
323        self
324    }
325    pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
326        self.on_scroll = Some(Rc::new(f));
327        self
328    }
329
330    pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect) + 'static) -> Self {
331        self.painter = Some(Rc::new(f));
332        self
333    }
334}