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 f.debug_struct("Modifier")
178 .field("key", &self.key)
179 .field("size", &self.size)
180 .field("width", &self.width)
181 .field("height", &self.height)
182 .field("fill_max", &self.fill_max)
183 .field("fill_max_w", &self.fill_max_w)
184 .field("fill_max_h", &self.fill_max_h)
185 .field("padding", &self.padding)
186 .field("padding_values", &self.padding_values)
187 .field("min_width", &self.min_width)
188 .field("min_height", &self.min_height)
189 .field("max_width", &self.max_width)
190 .field("max_height", &self.max_height)
191 .field("background", &self.background)
192 .field("border", &self.border)
193 .field("flex_grow", &self.flex_grow)
194 .field("flex_shrink", &self.flex_shrink)
195 .field("flex_basis", &self.flex_basis)
196 .field("gap", &self.gap)
197 .field("row_gap", &self.row_gap)
198 .field("column_gap", &self.column_gap)
199 .field("align_self", &self.align_self)
200 .field("justify_content", &self.justify_content)
201 .field("align_items_container", &self.align_items_container)
202 .field("align_content", &self.align_content)
203 .field("clip_rounded", &self.clip_rounded)
204 .field("z_index", &self.z_index)
205 .field("render_z_index", &self.render_z_index)
206 .field("hit_passthrough", &self.hit_passthrough)
207 .field("input_blocker", &self.input_blocker)
208 .field("repaint_boundary", &self.repaint_boundary)
209 .field("click", &self.click)
210 .field("on_scroll", &self.on_scroll.as_ref().map(|_| "..."))
211 .field(
212 "on_pointer_down",
213 &self.on_pointer_down.as_ref().map(|_| "..."),
214 )
215 .field(
216 "on_pointer_move",
217 &self.on_pointer_move.as_ref().map(|_| "..."),
218 )
219 .field("on_pointer_up", &self.on_pointer_up.as_ref().map(|_| "..."))
220 .field(
221 "on_pointer_enter",
222 &self.on_pointer_enter.as_ref().map(|_| "..."),
223 )
224 .field(
225 "on_pointer_leave",
226 &self.on_pointer_leave.as_ref().map(|_| "..."),
227 )
228 .field("semantics", &self.semantics)
229 .field("alpha", &self.alpha)
230 .field("transform", &self.transform)
231 .field("grid", &self.grid)
232 .field("grid_col_span", &self.grid_col_span)
233 .field("grid_row_span", &self.grid_row_span)
234 .field("position_type", &self.position_type)
235 .field("offset_left", &self.offset_left)
236 .field("offset_right", &self.offset_right)
237 .field("offset_top", &self.offset_top)
238 .field("offset_bottom", &self.offset_bottom)
239 .field("aspect_ratio", &self.aspect_ratio)
240 .field("painter", &self.painter.as_ref().map(|_| "..."))
241 .field("on_drag_start", &self.on_drag_start.as_ref().map(|_| "..."))
242 .field("on_drag_end", &self.on_drag_end.as_ref().map(|_| "..."))
243 .field("on_drag_enter", &self.on_drag_enter.as_ref().map(|_| "..."))
244 .field("on_drag_over", &self.on_drag_over.as_ref().map(|_| "..."))
245 .field("on_drag_leave", &self.on_drag_leave.as_ref().map(|_| "..."))
246 .field("on_drop", &self.on_drop.as_ref().map(|_| "..."))
247 .field("on_action", &self.on_action.as_ref().map(|_| "..."))
248 .finish()
249 }
250}
251
252impl_option_fields!(Modifier);
253
254impl Modifier {
255 pub fn new() -> Self {
256 Self::default()
257 }
258
259 pub fn key(mut self, key: u64) -> Self {
262 self.key = Some(key);
263 self
264 }
265
266 pub fn size(mut self, w: f32, h: f32) -> Self {
267 self.size = Some(Size {
268 width: w,
269 height: h,
270 });
271 self
272 }
273 pub fn width(mut self, w: f32) -> Self {
274 self.width = Some(w);
275 self
276 }
277 pub fn height(mut self, h: f32) -> Self {
278 self.height = Some(h);
279 self
280 }
281 pub fn fill_max_size(mut self) -> Self {
282 self.fill_max = true;
283 self
284 }
285 pub fn fill_max_width(mut self) -> Self {
286 self.fill_max_w = true;
287 self
288 }
289 pub fn fill_max_height(mut self) -> Self {
290 self.fill_max_h = true;
291 self
292 }
293 pub fn padding(mut self, v: f32) -> Self {
294 self.padding = Some(v);
295 self
296 }
297 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
298 self.padding_values = Some(padding);
299 self
300 }
301 pub fn min_size(mut self, w: f32, h: f32) -> Self {
302 self.min_width = Some(w);
303 self.min_height = Some(h);
304 self
305 }
306 pub fn max_size(mut self, w: f32, h: f32) -> Self {
307 self.max_width = Some(w);
308 self.max_height = Some(h);
309 self
310 }
311 pub fn min_width(mut self, w: f32) -> Self {
312 self.min_width = Some(w);
313 self
314 }
315 pub fn min_height(mut self, h: f32) -> Self {
316 self.min_height = Some(h);
317 self
318 }
319 pub fn max_width(mut self, w: f32) -> Self {
320 self.max_width = Some(w);
321 self
322 }
323 pub fn max_height(mut self, h: f32) -> Self {
324 self.max_height = Some(h);
325 self
326 }
327 pub fn background(mut self, color: Color) -> Self {
329 self.background = Some(Brush::Solid(color));
330 self
331 }
332 pub fn background_brush(mut self, brush: Brush) -> Self {
334 self.background = Some(brush);
335 self
336 }
337 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
338 self.border = Some(Border {
339 width,
340 color,
341 radius,
342 });
343 self
344 }
345 pub fn flex_grow(mut self, v: f32) -> Self {
346 self.flex_grow = Some(v);
347 self
348 }
349 pub fn flex_shrink(mut self, v: f32) -> Self {
350 self.flex_shrink = Some(v);
351 self
352 }
353 pub fn flex_basis(mut self, v: f32) -> Self {
354 self.flex_basis = Some(v);
355 self
356 }
357 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
358 self.flex_wrap = Some(w);
359 self
360 }
361 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
362 self.flex_dir = Some(d);
363 self
364 }
365 pub fn gap(mut self, v: f32) -> Self {
366 let v = v.max(0.0);
367 self.gap = Some(v);
368 self.row_gap = Some(v);
369 self.column_gap = Some(v);
370 self
371 }
372 pub fn row_gap(mut self, v: f32) -> Self {
373 self.row_gap = Some(v.max(0.0));
374 self
375 }
376 pub fn column_gap(mut self, v: f32) -> Self {
377 self.column_gap = Some(v.max(0.0));
378 self
379 }
380 pub fn align_self(mut self, a: AlignSelf) -> Self {
381 self.align_self = Some(a);
382 self
383 }
384 pub fn align_self_center(mut self) -> Self {
385 self.align_self = Some(AlignSelf::Center);
386 self
387 }
388 pub fn justify_content(mut self, j: JustifyContent) -> Self {
389 self.justify_content = Some(j);
390 self
391 }
392 pub fn align_items(mut self, a: AlignItems) -> Self {
393 self.align_items_container = Some(a);
394 self
395 }
396 pub fn align_content(mut self, a: AlignContent) -> Self {
397 self.align_content = Some(a);
398 self
399 }
400 pub fn clip_rounded(mut self, radius: f32) -> Self {
401 self.clip_rounded = Some(radius);
402 self
403 }
404 pub fn z_index(mut self, z: f32) -> Self {
405 self.z_index = z;
406 self
407 }
408
409 pub fn render_z_index(mut self, z: f32) -> Self {
412 self.render_z_index = Some(z);
413 self
414 }
415
416 pub fn input_blocker(mut self) -> Self {
418 self.input_blocker = true;
419 self
420 }
421
422 pub fn hit_passthrough(mut self) -> Self {
423 self.hit_passthrough = true;
424 self
425 }
426 pub fn clickable(mut self) -> Self {
427 self.click = true;
428 self
429 }
430 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
431 self.on_scroll = Some(Rc::new(f));
432 self
433 }
434 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
435 self.on_pointer_down = Some(Rc::new(f));
436 self
437 }
438 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
439 self.on_pointer_move = Some(Rc::new(f));
440 self
441 }
442 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
443 self.on_pointer_up = Some(Rc::new(f));
444 self
445 }
446 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
447 self.on_pointer_enter = Some(Rc::new(f));
448 self
449 }
450 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
451 self.on_pointer_leave = Some(Rc::new(f));
452 self
453 }
454 pub fn semantics(mut self, s: crate::Semantics) -> Self {
455 self.semantics = Some(s);
456 self
457 }
458 pub fn alpha(mut self, a: f32) -> Self {
459 self.alpha = Some(a);
460 self
461 }
462 pub fn transform(mut self, t: Transform) -> Self {
463 self.transform = Some(t);
464 self
465 }
466 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
467 self.grid = Some(GridConfig {
468 columns,
469 row_gap,
470 column_gap,
471 });
472 self
473 }
474 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
475 self.grid_col_span = Some(col_span);
476 self.grid_row_span = Some(row_span);
477 self
478 }
479 pub fn absolute(mut self) -> Self {
480 self.position_type = Some(PositionType::Absolute);
481 self
482 }
483 pub fn offset(
484 mut self,
485 left: Option<f32>,
486 top: Option<f32>,
487 right: Option<f32>,
488 bottom: Option<f32>,
489 ) -> Self {
490 self.offset_left = left;
491 self.offset_top = top;
492 self.offset_right = right;
493 self.offset_bottom = bottom;
494 self
495 }
496 pub fn offset_left(mut self, v: f32) -> Self {
497 self.offset_left = Some(v);
498 self
499 }
500 pub fn offset_right(mut self, v: f32) -> Self {
501 self.offset_right = Some(v);
502 self
503 }
504 pub fn offset_top(mut self, v: f32) -> Self {
505 self.offset_top = Some(v);
506 self
507 }
508 pub fn offset_bottom(mut self, v: f32) -> Self {
509 self.offset_bottom = Some(v);
510 self
511 }
512
513 pub fn margin(mut self, v: f32) -> Self {
514 self.margin_left = Some(v);
515 self.margin_right = Some(v);
516 self.margin_top = Some(v);
517 self.margin_bottom = Some(v);
518 self
519 }
520
521 pub fn margin_horizontal(mut self, v: f32) -> Self {
522 self.margin_left = Some(v);
523 self.margin_right = Some(v);
524 self
525 }
526
527 pub fn margin_vertical(mut self, v: f32) -> Self {
528 self.margin_top = Some(v);
529 self.margin_bottom = Some(v);
530 self
531 }
532 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
533 self.aspect_ratio = Some(ratio);
534 self
535 }
536 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect) + 'static) -> Self {
537 self.painter = Some(Rc::new(f));
538 self
539 }
540 pub fn scale(self, s: f32) -> Self {
541 self.scale2(s, s)
542 }
543 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
544 let mut t = self.transform.unwrap_or_else(Transform::identity);
545 t.scale_x *= sx;
546 t.scale_y *= sy;
547 self.transform = Some(t);
548 self
549 }
550 pub fn translate(mut self, x: f32, y: f32) -> Self {
551 let t = self.transform.unwrap_or_else(Transform::identity);
552 self.transform = Some(t.combine(&Transform::translate(x, y)));
553 self
554 }
555 pub fn rotate(mut self, radians: f32) -> Self {
556 let mut t = self.transform.unwrap_or_else(Transform::identity);
557 t.rotate += radians;
558 self.transform = Some(t);
559 self
560 }
561 pub fn weight(mut self, w: f32) -> Self {
562 let w = w.max(0.0);
563 self.flex_grow = Some(w);
564 self.flex_shrink = Some(1.0);
565 self.flex_basis = Some(0.0);
567 self
568 }
569 pub fn repaint_boundary(mut self) -> Self {
573 self.repaint_boundary = true;
574 self
575 }
576 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
577 self.on_action = Some(Rc::new(f));
578 self
579 }
580
581 pub fn on_drag_start(
583 mut self,
584 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
585 ) -> Self {
586 self.on_drag_start = Some(Rc::new(f));
587 self
588 }
589
590 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
592 self.on_drag_end = Some(Rc::new(f));
593 self
594 }
595
596 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
598 self.on_drag_enter = Some(Rc::new(f));
599 self
600 }
601
602 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
604 self.on_drag_over = Some(Rc::new(f));
605 self
606 }
607
608 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
610 self.on_drag_leave = Some(Rc::new(f));
611 self
612 }
613
614 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
617 self.on_drop = Some(Rc::new(f));
618 self
619 }
620
621 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
623 self.cursor = Some(c);
624 self
625 }
626}