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