1use std::rc::Rc;
2
3use taffy::{AlignContent, AlignItems, AlignSelf, FlexDirection, FlexWrap, JustifyContent};
4
5use crate::{Brush, 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, Debug)]
23pub struct GridConfig {
24 pub columns: usize,
25 pub row_gap: f32,
26 pub column_gap: f32,
27}
28
29#[derive(Clone, Copy, Debug)]
30pub enum PositionType {
31 Relative,
32 Absolute,
33}
34
35#[derive(Clone, Default)]
36pub struct Modifier {
37 pub key: Option<u64>,
43
44 pub size: Option<Size>,
45 pub width: Option<f32>,
46 pub height: Option<f32>,
47 pub fill_max: bool,
48 pub fill_max_w: bool,
49 pub fill_max_h: bool,
50 pub padding: Option<f32>,
51 pub padding_values: Option<PaddingValues>,
52 pub min_width: Option<f32>,
53 pub min_height: Option<f32>,
54 pub max_width: Option<f32>,
55 pub max_height: Option<f32>,
56 pub background: Option<Brush>,
57 pub border: Option<Border>,
58 pub flex_grow: Option<f32>,
59 pub flex_shrink: Option<f32>,
60 pub flex_basis: Option<f32>,
61 pub flex_wrap: Option<FlexWrap>,
62 pub flex_dir: Option<FlexDirection>,
63 pub gap: Option<f32>,
64 pub row_gap: Option<f32>,
65 pub column_gap: Option<f32>,
66 pub align_self: Option<AlignSelf>,
67 pub justify_content: Option<JustifyContent>,
68 pub align_items_container: Option<AlignItems>,
69 pub align_content: Option<AlignContent>,
70 pub clip_rounded: Option<f32>,
71 pub z_index: f32,
73 pub render_z_index: Option<f32>,
75 pub hit_passthrough: bool,
77 pub input_blocker: bool,
79 pub repaint_boundary: bool,
80 pub click: bool,
81 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
82 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
83 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
84 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
85 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
86 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
87 pub semantics: Option<crate::Semantics>,
88 pub alpha: Option<f32>,
89 pub transform: Option<Transform>,
90 pub grid: Option<GridConfig>,
91 pub grid_col_span: Option<u16>,
92 pub grid_row_span: Option<u16>,
93 pub position_type: Option<PositionType>,
94 pub offset_left: Option<f32>,
95 pub offset_right: Option<f32>,
96 pub offset_top: Option<f32>,
97 pub offset_bottom: Option<f32>,
98 pub margin_left: Option<f32>,
99 pub margin_right: Option<f32>,
100 pub margin_top: Option<f32>,
101 pub margin_bottom: Option<f32>,
102 pub aspect_ratio: Option<f32>,
103 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect)>>,
104
105 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
107 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
108 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
109 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
110 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
111 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
112
113 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
114
115 pub cursor: Option<crate::CursorIcon>,
117}
118
119impl std::fmt::Debug for Modifier {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 f.debug_struct("Modifier")
122 .field("key", &self.key)
123 .field("size", &self.size)
124 .field("width", &self.width)
125 .field("height", &self.height)
126 .field("fill_max", &self.fill_max)
127 .field("fill_max_w", &self.fill_max_w)
128 .field("fill_max_h", &self.fill_max_h)
129 .field("padding", &self.padding)
130 .field("padding_values", &self.padding_values)
131 .field("min_width", &self.min_width)
132 .field("min_height", &self.min_height)
133 .field("max_width", &self.max_width)
134 .field("max_height", &self.max_height)
135 .field("background", &self.background)
136 .field("border", &self.border)
137 .field("flex_grow", &self.flex_grow)
138 .field("flex_shrink", &self.flex_shrink)
139 .field("flex_basis", &self.flex_basis)
140 .field("gap", &self.gap)
141 .field("row_gap", &self.row_gap)
142 .field("column_gap", &self.column_gap)
143 .field("align_self", &self.align_self)
144 .field("justify_content", &self.justify_content)
145 .field("align_items_container", &self.align_items_container)
146 .field("align_content", &self.align_content)
147 .field("clip_rounded", &self.clip_rounded)
148 .field("z_index", &self.z_index)
149 .field("render_z_index", &self.render_z_index)
150 .field("hit_passthrough", &self.hit_passthrough)
151 .field("input_blocker", &self.input_blocker)
152 .field("repaint_boundary", &self.repaint_boundary)
153 .field("click", &self.click)
154 .field("on_scroll", &self.on_scroll.as_ref().map(|_| "..."))
155 .field(
156 "on_pointer_down",
157 &self.on_pointer_down.as_ref().map(|_| "..."),
158 )
159 .field(
160 "on_pointer_move",
161 &self.on_pointer_move.as_ref().map(|_| "..."),
162 )
163 .field("on_pointer_up", &self.on_pointer_up.as_ref().map(|_| "..."))
164 .field(
165 "on_pointer_enter",
166 &self.on_pointer_enter.as_ref().map(|_| "..."),
167 )
168 .field(
169 "on_pointer_leave",
170 &self.on_pointer_leave.as_ref().map(|_| "..."),
171 )
172 .field("semantics", &self.semantics)
173 .field("alpha", &self.alpha)
174 .field("transform", &self.transform)
175 .field("grid", &self.grid)
176 .field("grid_col_span", &self.grid_col_span)
177 .field("grid_row_span", &self.grid_row_span)
178 .field("position_type", &self.position_type)
179 .field("offset_left", &self.offset_left)
180 .field("offset_right", &self.offset_right)
181 .field("offset_top", &self.offset_top)
182 .field("offset_bottom", &self.offset_bottom)
183 .field("aspect_ratio", &self.aspect_ratio)
184 .field("painter", &self.painter.as_ref().map(|_| "..."))
185 .field("on_drag_start", &self.on_drag_start.as_ref().map(|_| "..."))
186 .field("on_drag_end", &self.on_drag_end.as_ref().map(|_| "..."))
187 .field("on_drag_enter", &self.on_drag_enter.as_ref().map(|_| "..."))
188 .field("on_drag_over", &self.on_drag_over.as_ref().map(|_| "..."))
189 .field("on_drag_leave", &self.on_drag_leave.as_ref().map(|_| "..."))
190 .field("on_drop", &self.on_drop.as_ref().map(|_| "..."))
191 .field("on_action", &self.on_action.as_ref().map(|_| "..."))
192 .finish()
193 }
194}
195
196impl Modifier {
197 pub fn new() -> Self {
198 Self::default()
199 }
200
201 pub fn key(mut self, key: u64) -> Self {
204 self.key = Some(key);
205 self
206 }
207
208 pub fn size(mut self, w: f32, h: f32) -> Self {
209 self.size = Some(Size {
210 width: w,
211 height: h,
212 });
213 self
214 }
215 pub fn width(mut self, w: f32) -> Self {
216 self.width = Some(w);
217 self
218 }
219 pub fn height(mut self, h: f32) -> Self {
220 self.height = Some(h);
221 self
222 }
223 pub fn fill_max_size(mut self) -> Self {
224 self.fill_max = true;
225 self
226 }
227 pub fn fill_max_width(mut self) -> Self {
228 self.fill_max_w = true;
229 self
230 }
231 pub fn fill_max_height(mut self) -> Self {
232 self.fill_max_h = true;
233 self
234 }
235 pub fn padding(mut self, v: f32) -> Self {
236 self.padding = Some(v);
237 self
238 }
239 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
240 self.padding_values = Some(padding);
241 self
242 }
243 pub fn min_size(mut self, w: f32, h: f32) -> Self {
244 self.min_width = Some(w);
245 self.min_height = Some(h);
246 self
247 }
248 pub fn max_size(mut self, w: f32, h: f32) -> Self {
249 self.max_width = Some(w);
250 self.max_height = Some(h);
251 self
252 }
253 pub fn min_width(mut self, w: f32) -> Self {
254 self.min_width = Some(w);
255 self
256 }
257 pub fn min_height(mut self, h: f32) -> Self {
258 self.min_height = Some(h);
259 self
260 }
261 pub fn max_width(mut self, w: f32) -> Self {
262 self.max_width = Some(w);
263 self
264 }
265 pub fn max_height(mut self, h: f32) -> Self {
266 self.max_height = Some(h);
267 self
268 }
269 pub fn background(mut self, color: Color) -> Self {
271 self.background = Some(Brush::Solid(color));
272 self
273 }
274 pub fn background_brush(mut self, brush: Brush) -> Self {
276 self.background = Some(brush);
277 self
278 }
279 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
280 self.border = Some(Border {
281 width,
282 color,
283 radius,
284 });
285 self
286 }
287 pub fn flex_grow(mut self, v: f32) -> Self {
288 self.flex_grow = Some(v);
289 self
290 }
291 pub fn flex_shrink(mut self, v: f32) -> Self {
292 self.flex_shrink = Some(v);
293 self
294 }
295 pub fn flex_basis(mut self, v: f32) -> Self {
296 self.flex_basis = Some(v);
297 self
298 }
299 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
300 self.flex_wrap = Some(w);
301 self
302 }
303 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
304 self.flex_dir = Some(d);
305 self
306 }
307 pub fn gap(mut self, v: f32) -> Self {
308 let v = v.max(0.0);
309 self.gap = Some(v);
310 self.row_gap = Some(v);
311 self.column_gap = Some(v);
312 self
313 }
314 pub fn row_gap(mut self, v: f32) -> Self {
315 self.row_gap = Some(v.max(0.0));
316 self
317 }
318 pub fn column_gap(mut self, v: f32) -> Self {
319 self.column_gap = Some(v.max(0.0));
320 self
321 }
322 pub fn align_self(mut self, a: AlignSelf) -> Self {
323 self.align_self = Some(a);
324 self
325 }
326 pub fn align_self_center(mut self) -> Self {
327 self.align_self = Some(AlignSelf::Center);
328 self
329 }
330 pub fn justify_content(mut self, j: JustifyContent) -> Self {
331 self.justify_content = Some(j);
332 self
333 }
334 pub fn align_items(mut self, a: AlignItems) -> Self {
335 self.align_items_container = Some(a);
336 self
337 }
338 pub fn align_content(mut self, a: AlignContent) -> Self {
339 self.align_content = Some(a);
340 self
341 }
342 pub fn clip_rounded(mut self, radius: f32) -> Self {
343 self.clip_rounded = Some(radius);
344 self
345 }
346 pub fn z_index(mut self, z: f32) -> Self {
347 self.z_index = z;
348 self
349 }
350
351 pub fn render_z_index(mut self, z: f32) -> Self {
354 self.render_z_index = Some(z);
355 self
356 }
357
358 pub fn input_blocker(mut self) -> Self {
360 self.input_blocker = true;
361 self
362 }
363
364 pub fn hit_passthrough(mut self) -> Self {
365 self.hit_passthrough = true;
366 self
367 }
368 pub fn clickable(mut self) -> Self {
369 self.click = true;
370 self
371 }
372 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
373 self.on_scroll = Some(Rc::new(f));
374 self
375 }
376 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
377 self.on_pointer_down = Some(Rc::new(f));
378 self
379 }
380 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
381 self.on_pointer_move = Some(Rc::new(f));
382 self
383 }
384 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
385 self.on_pointer_up = Some(Rc::new(f));
386 self
387 }
388 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
389 self.on_pointer_enter = Some(Rc::new(f));
390 self
391 }
392 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
393 self.on_pointer_leave = Some(Rc::new(f));
394 self
395 }
396 pub fn semantics(mut self, s: crate::Semantics) -> Self {
397 self.semantics = Some(s);
398 self
399 }
400 pub fn alpha(mut self, a: f32) -> Self {
401 self.alpha = Some(a);
402 self
403 }
404 pub fn transform(mut self, t: Transform) -> Self {
405 self.transform = Some(t);
406 self
407 }
408 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
409 self.grid = Some(GridConfig {
410 columns,
411 row_gap,
412 column_gap,
413 });
414 self
415 }
416 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
417 self.grid_col_span = Some(col_span);
418 self.grid_row_span = Some(row_span);
419 self
420 }
421 pub fn absolute(mut self) -> Self {
422 self.position_type = Some(PositionType::Absolute);
423 self
424 }
425 pub fn offset(
426 mut self,
427 left: Option<f32>,
428 top: Option<f32>,
429 right: Option<f32>,
430 bottom: Option<f32>,
431 ) -> Self {
432 self.offset_left = left;
433 self.offset_top = top;
434 self.offset_right = right;
435 self.offset_bottom = bottom;
436 self
437 }
438 pub fn offset_left(mut self, v: f32) -> Self {
439 self.offset_left = Some(v);
440 self
441 }
442 pub fn offset_right(mut self, v: f32) -> Self {
443 self.offset_right = Some(v);
444 self
445 }
446 pub fn offset_top(mut self, v: f32) -> Self {
447 self.offset_top = Some(v);
448 self
449 }
450 pub fn offset_bottom(mut self, v: f32) -> Self {
451 self.offset_bottom = Some(v);
452 self
453 }
454
455 pub fn margin(mut self, v: f32) -> Self {
456 self.margin_left = Some(v);
457 self.margin_right = Some(v);
458 self.margin_top = Some(v);
459 self.margin_bottom = Some(v);
460 self
461 }
462
463 pub fn margin_horizontal(mut self, v: f32) -> Self {
464 self.margin_left = Some(v);
465 self.margin_right = Some(v);
466 self
467 }
468
469 pub fn margin_vertical(mut self, v: f32) -> Self {
470 self.margin_top = Some(v);
471 self.margin_bottom = Some(v);
472 self
473 }
474 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
475 self.aspect_ratio = Some(ratio);
476 self
477 }
478 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect) + 'static) -> Self {
479 self.painter = Some(Rc::new(f));
480 self
481 }
482 pub fn scale(self, s: f32) -> Self {
483 self.scale2(s, s)
484 }
485 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
486 let mut t = self.transform.unwrap_or_else(Transform::identity);
487 t.scale_x *= sx;
488 t.scale_y *= sy;
489 self.transform = Some(t);
490 self
491 }
492 pub fn translate(mut self, x: f32, y: f32) -> Self {
493 let t = self.transform.unwrap_or_else(Transform::identity);
494 self.transform = Some(t.combine(&Transform::translate(x, y)));
495 self
496 }
497 pub fn rotate(mut self, radians: f32) -> Self {
498 let mut t = self.transform.unwrap_or_else(Transform::identity);
499 t.rotate += radians;
500 self.transform = Some(t);
501 self
502 }
503 pub fn weight(mut self, w: f32) -> Self {
504 let w = w.max(0.0);
505 self.flex_grow = Some(w);
506 self.flex_shrink = Some(1.0);
507 self.flex_basis = Some(0.0);
509 self
510 }
511 pub fn repaint_boundary(mut self) -> Self {
515 self.repaint_boundary = true;
516 self
517 }
518 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
519 self.on_action = Some(Rc::new(f));
520 self
521 }
522
523 pub fn on_drag_start(
525 mut self,
526 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
527 ) -> Self {
528 self.on_drag_start = Some(Rc::new(f));
529 self
530 }
531
532 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
534 self.on_drag_end = Some(Rc::new(f));
535 self
536 }
537
538 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
540 self.on_drag_enter = Some(Rc::new(f));
541 self
542 }
543
544 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
546 self.on_drag_over = Some(Rc::new(f));
547 self
548 }
549
550 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
552 self.on_drag_leave = Some(Rc::new(f));
553 self
554 }
555
556 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
559 self.on_drop = Some(Rc::new(f));
560 self
561 }
562
563 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
565 self.cursor = Some(c);
566 self
567 }
568}