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, Copy, Debug)]
11pub struct StateColors {
12 pub default: Color,
13 pub hovered: Color,
14 pub pressed: Color,
15 pub disabled: Color,
16}
17
18#[derive(Clone, Copy, Debug)]
21pub struct StateElevation {
22 pub default: f32,
23 pub hovered: f32,
24 pub pressed: f32,
25 pub disabled: f32,
26}
27
28macro_rules! merge_opts {
29 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
30 $( $dst.$f = $src.$f.or($dst.$f); )+
31 };
32}
33macro_rules! merge_flags {
34 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
35 $( $dst.$f |= $src.$f; )+
36 };
37}
38
39macro_rules! impl_option_fields {
40 ($ty:ty, $fn:ident) => {
41 impl $ty {
42 $fn!(replace);
43 }
44 };
45 ($ty:ident) => {
46 impl $ty {
47 pub fn then(mut self, other: Self) -> Self {
50 merge_opts!(self, other;
51 key, size, width, height,
52 padding, padding_values,
53 min_width, min_height, max_width, max_height,
54 background, state_colors, state_elevation, border,
55 flex_grow, flex_shrink, flex_basis, flex_wrap, flex_dir,
56 gap, row_gap, column_gap,
57 align_self, justify_content, align_items_container, align_content,
58 clip_rounded, render_z_index,
59 on_scroll,
60 on_pointer_down, on_pointer_move, on_pointer_up,
61 on_pointer_enter, on_pointer_leave,
62 semantics, alpha, transform,
63 grid, grid_col_span, grid_row_span,
64 position_type,
65 offset_left, offset_right, offset_top, offset_bottom,
66 margin_left, margin_right, margin_top, margin_bottom,
67 aspect_ratio, painter,
68 on_drag_start, on_drag_end, on_drag_enter, on_drag_over, on_drag_leave, on_drop,
69 on_action, cursor,
70 );
71 merge_flags!(self, other;
72 fill_max, fill_max_w, fill_max_h,
73 hit_passthrough, input_blocker, repaint_boundary, click, disabled,
74 );
75 if other.z_index != 0.0 {
76 self.z_index = other.z_index;
77 }
78 self
79 }
80 }
81 };
82}
83
84#[derive(Clone, Debug)]
85pub struct Border {
86 pub width: f32,
87 pub color: Color,
88 pub radius: f32,
89}
90
91#[derive(Clone, Copy, Debug, Default)]
92pub struct PaddingValues {
93 pub left: f32,
94 pub right: f32,
95 pub top: f32,
96 pub bottom: f32,
97}
98
99#[derive(Clone, Debug)]
100pub struct GridConfig {
101 pub columns: usize,
102 pub row_gap: f32,
103 pub column_gap: f32,
104}
105
106#[derive(Clone, Copy, Debug)]
107pub enum PositionType {
108 Relative,
109 Absolute,
110}
111
112#[derive(Clone, Default)]
113pub struct Modifier {
114 pub key: Option<u64>,
120
121 pub size: Option<Size>,
122 pub width: Option<f32>,
123 pub height: Option<f32>,
124 pub fill_max: bool,
125 pub fill_max_w: bool,
126 pub fill_max_h: bool,
127 pub padding: Option<f32>,
128 pub padding_values: Option<PaddingValues>,
129 pub min_width: Option<f32>,
130 pub min_height: Option<f32>,
131 pub max_width: Option<f32>,
132 pub max_height: Option<f32>,
133 pub background: Option<Brush>,
134 pub state_colors: Option<StateColors>,
135 pub state_elevation: Option<StateElevation>,
136
137 pub border: Option<Border>,
138 pub flex_grow: Option<f32>,
139 pub flex_shrink: Option<f32>,
140 pub flex_basis: Option<f32>,
141 pub flex_wrap: Option<FlexWrap>,
142 pub flex_dir: Option<FlexDirection>,
143 pub gap: Option<f32>,
144 pub row_gap: Option<f32>,
145 pub column_gap: Option<f32>,
146 pub align_self: Option<AlignSelf>,
147 pub justify_content: Option<JustifyContent>,
148 pub align_items_container: Option<AlignItems>,
149 pub align_content: Option<AlignContent>,
150 pub clip_rounded: Option<f32>,
151 pub z_index: f32,
153 pub render_z_index: Option<f32>,
155 pub hit_passthrough: bool,
157 pub input_blocker: bool,
159 pub repaint_boundary: bool,
160 pub click: bool,
161 pub disabled: bool,
163 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
164 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
165 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
166 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
167 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
168 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
169 pub semantics: Option<crate::Semantics>,
170 pub alpha: Option<f32>,
171 pub transform: Option<Transform>,
172 pub grid: Option<GridConfig>,
173 pub grid_col_span: Option<u16>,
174 pub grid_row_span: Option<u16>,
175 pub position_type: Option<PositionType>,
176 pub offset_left: Option<f32>,
177 pub offset_right: Option<f32>,
178 pub offset_top: Option<f32>,
179 pub offset_bottom: Option<f32>,
180 pub margin_left: Option<f32>,
181 pub margin_right: Option<f32>,
182 pub margin_top: Option<f32>,
183 pub margin_bottom: Option<f32>,
184 pub aspect_ratio: Option<f32>,
185 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect)>>,
186
187 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
189 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
190 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
191 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
192 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
193 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
194
195 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
196
197 pub cursor: Option<crate::CursorIcon>,
199}
200
201impl std::fmt::Debug for Modifier {
202 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203 let mut s = f.debug_struct("Modifier");
204
205 macro_rules! opt_val {
206 ($($name:ident),+ $(,)?) => {
207 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
208 };
209 }
210 opt_val!(
211 key,
212 size,
213 width,
214 height,
215 padding,
216 padding_values,
217 min_width,
218 min_height,
219 max_width,
220 max_height,
221 background,
222 state_colors,
223 state_elevation,
224
225 border,
226 flex_grow,
227 flex_shrink,
228 flex_basis,
229 flex_wrap,
230 flex_dir,
231 gap,
232 row_gap,
233 column_gap,
234 align_self,
235 justify_content,
236 align_items_container,
237 align_content,
238 clip_rounded,
239 render_z_index,
240 semantics,
241 alpha,
242 transform,
243 grid,
244 grid_col_span,
245 grid_row_span,
246 position_type,
247 offset_left,
248 offset_right,
249 offset_top,
250 offset_bottom,
251 margin_left,
252 margin_right,
253 margin_top,
254 margin_bottom,
255 aspect_ratio,
256 cursor,
257 );
258
259 macro_rules! opt_cb {
260 ($($name:ident),+ $(,)?) => {
261 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
262 };
263 }
264 opt_cb!(
265 on_scroll,
266 on_pointer_down,
267 on_pointer_move,
268 on_pointer_up,
269 on_pointer_enter,
270 on_pointer_leave,
271 painter,
272 on_drag_start,
273 on_drag_end,
274 on_drag_enter,
275 on_drag_over,
276 on_drag_leave,
277 on_drop,
278 on_action,
279 );
280
281 macro_rules! flag {
282 ($($name:ident),+ $(,)?) => {
283 $( if self.$name { s.field(stringify!($name), &true); } )+
284 };
285 }
286 flag!(
287 fill_max,
288 fill_max_w,
289 fill_max_h,
290 hit_passthrough,
291 input_blocker,
292 repaint_boundary,
293 click,
294 disabled,
295 );
296
297 if self.z_index != 0.0 {
298 s.field("z_index", &self.z_index);
299 }
300
301 s.finish()
302 }
303}
304
305impl_option_fields!(Modifier);
306
307impl Modifier {
308 pub fn new() -> Self {
309 Self::default()
310 }
311
312 pub fn key(mut self, key: u64) -> Self {
315 self.key = Some(key);
316 self
317 }
318
319 pub fn size(mut self, w: f32, h: f32) -> Self {
320 self.size = Some(Size {
321 width: w,
322 height: h,
323 });
324 self
325 }
326 pub fn width(mut self, w: f32) -> Self {
327 self.width = Some(w);
328 self
329 }
330 pub fn height(mut self, h: f32) -> Self {
331 self.height = Some(h);
332 self
333 }
334 pub fn fill_max_size(mut self) -> Self {
335 self.fill_max = true;
336 self
337 }
338 pub fn fill_max_width(mut self) -> Self {
339 self.fill_max_w = true;
340 self
341 }
342 pub fn fill_max_height(mut self) -> Self {
343 self.fill_max_h = true;
344 self
345 }
346 pub fn padding(mut self, v: f32) -> Self {
347 self.padding = Some(v);
348 self
349 }
350 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
351 self.padding_values = Some(padding);
352 self
353 }
354 pub fn min_size(mut self, w: f32, h: f32) -> Self {
355 self.min_width = Some(w);
356 self.min_height = Some(h);
357 self
358 }
359 pub fn max_size(mut self, w: f32, h: f32) -> Self {
360 self.max_width = Some(w);
361 self.max_height = Some(h);
362 self
363 }
364 pub fn min_width(mut self, w: f32) -> Self {
365 self.min_width = Some(w);
366 self
367 }
368 pub fn min_height(mut self, h: f32) -> Self {
369 self.min_height = Some(h);
370 self
371 }
372 pub fn max_width(mut self, w: f32) -> Self {
373 self.max_width = Some(w);
374 self
375 }
376 pub fn max_height(mut self, h: f32) -> Self {
377 self.max_height = Some(h);
378 self
379 }
380 pub fn background(mut self, color: Color) -> Self {
382 self.background = Some(Brush::Solid(color));
383 self
384 }
385 pub fn background_brush(mut self, brush: Brush) -> Self {
387 self.background = Some(brush);
388 self
389 }
390 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
391 self.border = Some(Border {
392 width,
393 color,
394 radius,
395 });
396 self
397 }
398 pub fn flex_grow(mut self, v: f32) -> Self {
399 self.flex_grow = Some(v);
400 self
401 }
402 pub fn flex_shrink(mut self, v: f32) -> Self {
403 self.flex_shrink = Some(v);
404 self
405 }
406 pub fn flex_basis(mut self, v: f32) -> Self {
407 self.flex_basis = Some(v);
408 self
409 }
410 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
411 self.flex_wrap = Some(w);
412 self
413 }
414 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
415 self.flex_dir = Some(d);
416 self
417 }
418 pub fn gap(mut self, v: f32) -> Self {
419 let v = v.max(0.0);
420 self.gap = Some(v);
421 self.row_gap = Some(v);
422 self.column_gap = Some(v);
423 self
424 }
425 pub fn row_gap(mut self, v: f32) -> Self {
426 self.row_gap = Some(v.max(0.0));
427 self
428 }
429 pub fn column_gap(mut self, v: f32) -> Self {
430 self.column_gap = Some(v.max(0.0));
431 self
432 }
433 pub fn align_self(mut self, a: AlignSelf) -> Self {
434 self.align_self = Some(a);
435 self
436 }
437 pub fn align_self_center(mut self) -> Self {
438 self.align_self = Some(AlignSelf::Center);
439 self
440 }
441 pub fn justify_content(mut self, j: JustifyContent) -> Self {
442 self.justify_content = Some(j);
443 self
444 }
445 pub fn align_items(mut self, a: AlignItems) -> Self {
446 self.align_items_container = Some(a);
447 self
448 }
449 pub fn align_content(mut self, a: AlignContent) -> Self {
450 self.align_content = Some(a);
451 self
452 }
453 pub fn clip_rounded(mut self, radius: f32) -> Self {
454 self.clip_rounded = Some(radius);
455 self
456 }
457 pub fn z_index(mut self, z: f32) -> Self {
458 self.z_index = z;
459 self
460 }
461
462 pub fn render_z_index(mut self, z: f32) -> Self {
465 self.render_z_index = Some(z);
466 self
467 }
468
469 pub fn input_blocker(mut self) -> Self {
471 self.input_blocker = true;
472 self
473 }
474
475 pub fn hit_passthrough(mut self) -> Self {
476 self.hit_passthrough = true;
477 self
478 }
479 pub fn clickable(mut self) -> Self {
480 self.click = true;
481 self
482 }
483 pub fn state_colors(mut self, colors: StateColors) -> Self {
486 self.state_colors = Some(colors);
487 self
488 }
489 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
491 self.state_elevation = Some(elev);
492 self
493 }
494 pub fn disabled(mut self) -> Self {
496 self.disabled = true;
497 self
498 }
499 pub fn enabled(mut self, enabled: bool) -> Self {
501 self.disabled = !enabled;
502 self
503 }
504 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
505 self.on_scroll = Some(Rc::new(f));
506 self
507 }
508 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
509 self.on_pointer_down = Some(Rc::new(f));
510 self
511 }
512 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
513 self.on_pointer_move = Some(Rc::new(f));
514 self
515 }
516 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
517 self.on_pointer_up = Some(Rc::new(f));
518 self
519 }
520 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
521 self.on_pointer_enter = Some(Rc::new(f));
522 self
523 }
524 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
525 self.on_pointer_leave = Some(Rc::new(f));
526 self
527 }
528 pub fn semantics(mut self, s: crate::Semantics) -> Self {
529 self.semantics = Some(s);
530 self
531 }
532 pub fn alpha(mut self, a: f32) -> Self {
533 self.alpha = Some(a);
534 self
535 }
536 pub fn transform(mut self, t: Transform) -> Self {
537 self.transform = Some(t);
538 self
539 }
540 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
541 self.grid = Some(GridConfig {
542 columns,
543 row_gap,
544 column_gap,
545 });
546 self
547 }
548 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
549 self.grid_col_span = Some(col_span);
550 self.grid_row_span = Some(row_span);
551 self
552 }
553 pub fn absolute(mut self) -> Self {
554 self.position_type = Some(PositionType::Absolute);
555 self
556 }
557 pub fn offset(
558 mut self,
559 left: Option<f32>,
560 top: Option<f32>,
561 right: Option<f32>,
562 bottom: Option<f32>,
563 ) -> Self {
564 self.offset_left = left;
565 self.offset_top = top;
566 self.offset_right = right;
567 self.offset_bottom = bottom;
568 self
569 }
570 pub fn offset_left(mut self, v: f32) -> Self {
571 self.offset_left = Some(v);
572 self
573 }
574 pub fn offset_right(mut self, v: f32) -> Self {
575 self.offset_right = Some(v);
576 self
577 }
578 pub fn offset_top(mut self, v: f32) -> Self {
579 self.offset_top = Some(v);
580 self
581 }
582 pub fn offset_bottom(mut self, v: f32) -> Self {
583 self.offset_bottom = Some(v);
584 self
585 }
586
587 pub fn margin(mut self, v: f32) -> Self {
588 self.margin_left = Some(v);
589 self.margin_right = Some(v);
590 self.margin_top = Some(v);
591 self.margin_bottom = Some(v);
592 self
593 }
594
595 pub fn margin_horizontal(mut self, v: f32) -> Self {
596 self.margin_left = Some(v);
597 self.margin_right = Some(v);
598 self
599 }
600
601 pub fn margin_vertical(mut self, v: f32) -> Self {
602 self.margin_top = Some(v);
603 self.margin_bottom = Some(v);
604 self
605 }
606 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
607 self.aspect_ratio = Some(ratio);
608 self
609 }
610 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect) + 'static) -> Self {
611 self.painter = Some(Rc::new(f));
612 self
613 }
614 pub fn scale(self, s: f32) -> Self {
615 self.scale2(s, s)
616 }
617 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
618 let mut t = self.transform.unwrap_or_else(Transform::identity);
619 t.scale_x *= sx;
620 t.scale_y *= sy;
621 self.transform = Some(t);
622 self
623 }
624 pub fn translate(mut self, x: f32, y: f32) -> Self {
625 let t = self.transform.unwrap_or_else(Transform::identity);
626 self.transform = Some(t.combine(&Transform::translate(x, y)));
627 self
628 }
629 pub fn rotate(mut self, radians: f32) -> Self {
630 let mut t = self.transform.unwrap_or_else(Transform::identity);
631 t.rotate += radians;
632 self.transform = Some(t);
633 self
634 }
635 pub fn weight(mut self, w: f32) -> Self {
636 let w = w.max(0.0);
637 self.flex_grow = Some(w);
638 self.flex_shrink = Some(1.0);
639 self.flex_basis = Some(0.0);
641 self
642 }
643 pub fn repaint_boundary(mut self) -> Self {
647 self.repaint_boundary = true;
648 self
649 }
650 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
651 self.on_action = Some(Rc::new(f));
652 self
653 }
654
655 pub fn on_drag_start(
657 mut self,
658 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
659 ) -> Self {
660 self.on_drag_start = Some(Rc::new(f));
661 self
662 }
663
664 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
666 self.on_drag_end = Some(Rc::new(f));
667 self
668 }
669
670 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
672 self.on_drag_enter = Some(Rc::new(f));
673 self
674 }
675
676 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
678 self.on_drag_over = Some(Rc::new(f));
679 self
680 }
681
682 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
684 self.on_drag_leave = Some(Rc::new(f));
685 self
686 }
687
688 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
691 self.on_drop = Some(Rc::new(f));
692 self
693 }
694
695 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
697 self.cursor = Some(c);
698 self
699 }
700}