repose_core/
modifier.rs

1use std::rc::Rc;
2
3use taffy::AlignSelf;
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 background: Option<Color>,
33    pub border: Option<Border>,
34    pub flex_grow: Option<f32>,
35    pub flex_shrink: Option<f32>,
36    pub flex_basis: Option<f32>,
37    pub align_self: Option<AlignSelf>,
38    pub aspect_ratio: Option<f32>, // width/height
39    pub position_type: Option<PositionType>,
40    pub offset_left: Option<f32>,
41    pub offset_right: Option<f32>,
42    pub offset_top: Option<f32>,
43    pub offset_bottom: Option<f32>,
44    pub grid: Option<GridConfig>,
45    pub grid_col_span: Option<u16>,
46    pub grid_row_span: Option<u16>,
47    pub click: bool,
48    pub semantics_label: Option<String>,
49    pub z_index: f32,
50    pub clip_rounded: Option<f32>,
51    pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
52
53    // Pointer callbacks
54    pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
55    pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
56    pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
57    pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
58    pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
59
60    pub alpha: Option<f32>,
61    pub transform: Option<Transform>,
62
63    pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect)>>,
64}
65
66#[derive(Clone, Copy, Debug)]
67pub enum PositionType {
68    Relative,
69    Absolute,
70}
71
72#[derive(Clone, Copy, Debug)]
73pub struct GridConfig {
74    pub columns: usize, // e.g. 3 (auto 1fr tracks)
75    pub row_gap: f32,
76    pub column_gap: f32,
77}
78
79impl Default for Border {
80    fn default() -> Self {
81        Border {
82            width: 1.0,
83            color: Color::WHITE,
84            radius: 0.0,
85        }
86    }
87}
88
89impl std::fmt::Debug for Modifier {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        f.debug_struct("Modifier")
92            .field("padding", &self.padding)
93            .field("padding_values", &self.padding_values)
94            .field("size", &self.size)
95            .field("fill_max", &self.fill_max)
96            .field("background", &self.background)
97            .field("border", &self.border)
98            .field("click", &self.click)
99            .field("semantics_label", &self.semantics_label)
100            .field("z_index", &self.z_index)
101            .field("clip_rounded", &self.clip_rounded)
102            .field("alpha", &self.alpha)
103            .finish()
104    }
105}
106
107impl Modifier {
108    pub fn new() -> Self {
109        Self::default()
110    }
111    pub fn padding(mut self, px: f32) -> Self {
112        self.padding = Some(px);
113        self
114    }
115    pub fn padding_values(mut self, pv: PaddingValues) -> Self {
116        self.padding_values = Some(pv);
117        self
118    }
119    pub fn size(mut self, w: f32, h: f32) -> Self {
120        self.size = Some(Size {
121            width: w,
122            height: h,
123        });
124        self
125    }
126    pub fn fill_max_size(mut self) -> Self {
127        self.fill_max = true;
128        self
129    }
130    pub fn width(mut self, w: f32) -> Self {
131        self.width = Some(w);
132        self
133    }
134    pub fn height(mut self, h: f32) -> Self {
135        self.height = Some(h);
136        self
137    }
138    pub fn fill_max_width(mut self) -> Self {
139        self.fill_max_w = true;
140        self
141    }
142    pub fn fill_max_height(mut self) -> Self {
143        self.fill_max_h = true;
144        self
145    }
146    pub fn background(mut self, color: Color) -> Self {
147        self.background = Some(color);
148        self
149    }
150    pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
151        self.border = Some(Border {
152            width,
153            color,
154            radius,
155        });
156        self
157    }
158    pub fn clickable(mut self) -> Self {
159        self.click = true;
160        self
161    }
162    pub fn semantics(mut self, label: impl Into<String>) -> Self {
163        self.semantics_label = Some(label.into());
164        self
165    }
166    pub fn z_index(mut self, z: f32) -> Self {
167        self.z_index = z;
168        self
169    }
170    pub fn clip_rounded(mut self, r: f32) -> Self {
171        self.clip_rounded = Some(r);
172        self
173    }
174
175    pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
176        self.on_pointer_down = Some(Rc::new(f));
177        self
178    }
179    pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
180        self.on_pointer_move = Some(Rc::new(f));
181        self
182    }
183    pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
184        self.on_pointer_up = Some(Rc::new(f));
185        self
186    }
187    pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
188        self.on_pointer_enter = Some(Rc::new(f));
189        self
190    }
191    pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
192        self.on_pointer_leave = Some(Rc::new(f));
193        self
194    }
195    pub fn flex_grow(mut self, g: f32) -> Self {
196        self.flex_grow = Some(g);
197        self
198    }
199    pub fn flex_shrink(mut self, s: f32) -> Self {
200        self.flex_shrink = Some(s);
201        self
202    }
203    pub fn flex_basis(mut self, px: f32) -> Self {
204        self.flex_basis = Some(px);
205        self
206    }
207    pub fn align_self_baseline(mut self) -> Self {
208        self.align_self = Some(taffy::style::AlignSelf::Baseline);
209        self
210    }
211    pub fn align_self_center(mut self) -> Self {
212        self.align_self = Some(taffy::style::AlignSelf::Center);
213        self
214    }
215    pub fn aspect_ratio(mut self, ratio: f32) -> Self {
216        self.aspect_ratio = Some(ratio.max(0.0));
217        self
218    }
219    pub fn absolute(mut self) -> Self {
220        self.position_type = Some(PositionType::Absolute);
221        self
222    }
223    pub fn offset(
224        mut self,
225        left: Option<f32>,
226        top: Option<f32>,
227        right: Option<f32>,
228        bottom: Option<f32>,
229    ) -> Self {
230        self.offset_left = left;
231        self.offset_top = top;
232        self.offset_right = right;
233        self.offset_bottom = bottom;
234        self
235    }
236    pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
237        self.grid = Some(GridConfig {
238            columns: columns.max(1),
239            row_gap,
240            column_gap,
241        });
242        self
243    }
244    pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
245        self.grid_col_span = Some(col_span.max(1));
246        self.grid_row_span = Some(row_span.max(1));
247        self
248    }
249
250    pub fn alpha(mut self, a: f32) -> Self {
251        self.alpha = Some(a.clamp(0.0, 1.0));
252        self
253    }
254    pub fn translate(mut self, x: f32, y: f32) -> Self {
255        let t = self.transform.unwrap_or_else(Transform::identity);
256        self.transform = Some(t.combine(&Transform::translate(x, y)));
257        self
258    }
259    pub fn scale(mut self, s: f32) -> Self {
260        self.scale2(s, s)
261    }
262    pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
263        let mut t = self.transform.unwrap_or_else(Transform::identity);
264        t.scale_x *= sx;
265        t.scale_y *= sy;
266        self.transform = Some(t);
267        self
268    }
269    pub fn rotate(mut self, radians: f32) -> Self {
270        let mut t = self.transform.unwrap_or_else(Transform::identity);
271        t.rotate += radians;
272        self.transform = Some(t);
273        self
274    }
275    pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
276        self.on_scroll = Some(Rc::new(f));
277        self
278    }
279
280    pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect) + 'static) -> Self {
281        self.painter = Some(Rc::new(f));
282        self
283    }
284}