1use std::cell::{Cell, RefCell};
2use std::rc::Rc;
3use std::sync::atomic::{AtomicU64, Ordering};
4
5use taffy::{AlignContent, AlignItems, AlignSelf, FlexDirection, FlexWrap, JustifyContent};
6
7use crate::animation::AnimationSpec;
8use crate::indication::IndicationNodeFactory;
9use crate::{Brush, Color, PointerEvent, Size, Transform, Vec2};
10
11#[derive(Clone, Copy, Debug)]
15pub struct StateColors {
16 pub default: Color,
17 pub hovered: Color,
18 pub pressed: Color,
19 pub disabled: Color,
20}
21
22#[derive(Clone, Copy, Debug)]
24pub struct StateElevation {
25 pub default: f32,
26 pub hovered: f32,
27 pub pressed: f32,
28 pub disabled: f32,
29}
30
31macro_rules! merge_opts {
32 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
33 $( $dst.$f = $src.$f.or($dst.$f); )+
34 };
35}
36macro_rules! merge_flags {
37 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
38 $( $dst.$f |= $src.$f; )+
39 };
40}
41
42macro_rules! impl_option_fields {
43 ($ty:ty, $fn:ident) => {
44 impl $ty {
45 $fn!(replace);
46 }
47 };
48 ($ty:ident) => {
49 impl $ty {
50 pub fn then(mut self, other: Self) -> Self {
53 merge_opts!(self, other;
54 key, size, width, height, required_size,
55 padding, padding_values,
56 min_width, min_height, max_width, max_height,
57 required_min_width, required_max_width,
58 required_min_height, required_max_height,
59 default_min_width, default_min_height,
60 fill_max, fill_max_w, fill_max_h,
61 background, state_colors, state_elevation, border,
62 flex_grow, flex_shrink, flex_basis, flex_wrap, flex_dir,
63 gap, row_gap, column_gap,
64 align_self, justify_content, align_items_container, align_content,
65 clip_rounded, render_z_index,
66 on_scroll,
67 on_pointer_down, on_pointer_move, on_pointer_up,
68 on_pointer_enter, on_pointer_leave,
69 on_click, on_double_click, on_long_click,
70 semantics, alpha, transform,
71 grid, grid_col_span, grid_row_span,
72 position_type,
73 offset_left, offset_right, offset_top, offset_bottom,
74 margin_left, margin_right, margin_top, margin_bottom,
75 aspect_ratio, intrinsic_width, intrinsic_height,
76 painter,
77 on_drag_start, on_drag_end, on_drag_enter, on_drag_over, on_drag_leave, on_drop,
78 on_action, cursor, animate_content_size, focus_requester, on_focus_changed,
79 interaction_source, text_input,
80 );
81 merge_flags!(self, other;
82 hit_passthrough, input_blocker, repaint_boundary, click, disabled,
83 propagate_min, focus_group,
84 );
85
86 if let Some(f) = other.focusable {
87 self.focusable = Some(f);
88 }
89 if other.indication.is_some() {
90 self.indication = other.indication;
91 }
92 if other.z_index != 0.0 {
93 self.z_index = other.z_index;
94 }
95 self
96 }
97 }
98 };
99}
100
101#[derive(Clone, Debug)]
102pub struct Border {
103 pub width: f32,
104 pub color: Color,
105 pub radius: [f32; 4],
106}
107
108#[derive(Clone, Copy, Debug, Default)]
109pub struct PaddingValues {
110 pub left: f32,
111 pub right: f32,
112 pub top: f32,
113 pub bottom: f32,
114}
115
116#[derive(Clone, Debug)]
117pub struct GridConfig {
118 pub columns: usize,
119 pub row_gap: f32,
120 pub column_gap: f32,
121}
122
123#[derive(Clone, Copy, Debug)]
130pub struct ShadowSpec {
131 pub blur_radius: f32,
132 pub offset_y: f32,
133 pub color: Color,
134}
135
136#[derive(Clone, Copy, Debug)]
137#[non_exhaustive]
138pub enum PositionType {
139 Relative,
140 Absolute,
141}
142
143#[derive(Clone)]
145pub struct TextInputConfig {
146 pub hint: String,
147 pub multiline: bool,
148 pub on_change: Option<Rc<dyn Fn(String)>>,
149 pub on_submit: Option<Rc<dyn Fn(String)>>,
150 pub focus_tracker: Option<Rc<Cell<bool>>>,
151 pub value: String,
152 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
153 pub keyboard_type: Option<crate::text::KeyboardType>,
154 pub ime_action: Option<crate::text::ImeAction>,
155 pub enabled: bool,
157 pub read_only: bool,
159 pub max_lines: Option<usize>,
161 pub min_lines: Option<usize>,
163 pub cursor_color: Option<Color>,
165 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
168}
169
170impl std::fmt::Debug for TextInputConfig {
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 let mut s = f.debug_struct("TextInputConfig");
173 s.field("hint", &self.hint);
174 s.field("multiline", &self.multiline);
175 if self.on_change.is_some() {
176 s.field("on_change", &"…");
177 }
178 if self.on_submit.is_some() {
179 s.field("on_submit", &"…");
180 }
181 if self.focus_tracker.is_some() {
182 s.field("focus_tracker", &"…");
183 }
184 s.field("value", &self.value);
185 if self.visual_transformation.is_some() {
186 s.field("visual_transformation", &"…");
187 }
188 s.field("keyboard_type", &self.keyboard_type);
189 s.field("ime_action", &self.ime_action);
190 s.field("enabled", &self.enabled);
191 s.field("read_only", &self.read_only);
192 s.field("max_lines", &self.max_lines);
193 s.field("min_lines", &self.min_lines);
194 s.field("cursor_color", &self.cursor_color);
195 if self.on_text_layout.is_some() {
196 s.field("on_text_layout", &"…");
197 }
198 s.finish()
199 }
200}
201
202#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
205pub enum IntrinsicSize {
206 Min,
207 Max,
208}
209
210static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
211
212pub type PressId = u64;
214
215#[derive(Clone, Copy, Debug, PartialEq)]
223pub enum Interaction {
224 Press(PressId, Vec2),
227 Release(PressId),
229 Cancel(PressId),
232 HoverEnter,
233 HoverLeave,
234 Focus,
235 Unfocus,
236 DragStart,
237 DragStop,
238 DragCancel,
239}
240
241impl Interaction {
242 #[inline]
244 pub fn new_press(position: Vec2) -> Self {
245 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
246 }
247}
248
249#[derive(Clone)]
256pub struct InteractionSource {
257 pub(crate) state: Rc<RefCell<InteractionState>>,
258}
259
260impl InteractionSource {
261 pub fn collect_is_pressed(&self) -> bool {
262 self.state.borrow().pressed > 0
263 }
264 pub fn collect_is_hovered(&self) -> bool {
265 self.state.borrow().hovered
266 }
267 pub fn collect_is_focused(&self) -> bool {
268 self.state.borrow().focused
269 }
270 pub fn collect_is_dragged(&self) -> bool {
271 self.state.borrow().dragged > 0
272 }
273 pub fn collect_last_press_position(&self) -> Option<Vec2> {
274 self.state.borrow().last_press_position
275 }
276 pub fn collect_last_press_id(&self) -> Option<PressId> {
277 self.state.borrow().last_press_id
278 }
279 pub fn stable_id(&self) -> *const () {
281 Rc::as_ptr(&self.state) as *const ()
282 }
283 pub fn to_mutable(&self) -> MutableInteractionSource {
287 MutableInteractionSource {
288 state: self.state.clone(),
289 }
290 }
291}
292
293#[derive(Clone)]
303pub struct MutableInteractionSource {
304 pub(crate) state: Rc<RefCell<InteractionState>>,
305}
306
307impl MutableInteractionSource {
308 pub fn new() -> Self {
309 Self {
310 state: Rc::new(RefCell::new(InteractionState::default())),
311 }
312 }
313
314 pub fn emit(&self, interaction: Interaction) {
316 let mut s = self.state.borrow_mut();
317 match interaction {
318 Interaction::Press(id, pos) => {
319 s.pressed = s.pressed.saturating_add(1);
320 s.last_press_id = Some(id);
321 s.last_press_position = Some(pos);
322 }
323 Interaction::Release(_) | Interaction::Cancel(_) => {
324 s.pressed = s.pressed.saturating_sub(1);
325 }
326 Interaction::HoverEnter => s.hovered = true,
327 Interaction::HoverLeave => s.hovered = false,
328 Interaction::Focus => s.focused = true,
329 Interaction::Unfocus => s.focused = false,
330 Interaction::DragStart => s.dragged = s.dragged.saturating_add(1),
331 Interaction::DragStop | Interaction::DragCancel => {
332 s.dragged = s.dragged.saturating_sub(1);
333 }
334 }
335 }
336
337 pub fn source(&self) -> InteractionSource {
339 InteractionSource {
340 state: self.state.clone(),
341 }
342 }
343}
344
345impl Default for MutableInteractionSource {
346 fn default() -> Self {
347 Self::new()
348 }
349}
350
351#[derive(Clone, Default)]
352pub(crate) struct InteractionState {
353 pressed: u32,
354 hovered: bool,
355 focused: bool,
356 dragged: u32,
357 pub(crate) last_press_position: Option<Vec2>,
359 pub(crate) last_press_id: Option<PressId>,
361}
362
363#[derive(Clone, Default)]
364pub struct Modifier {
365 pub key: Option<u64>,
371
372 pub size: Option<Size>,
373 pub width: Option<f32>,
374 pub height: Option<f32>,
375 pub required_size: Option<Size>,
376 pub fill_max: Option<f32>,
377 pub fill_max_w: Option<f32>,
378 pub fill_max_h: Option<f32>,
379 pub padding: Option<f32>,
380 pub padding_values: Option<PaddingValues>,
381 pub min_width: Option<f32>,
382 pub min_height: Option<f32>,
383 pub max_width: Option<f32>,
384 pub max_height: Option<f32>,
385 pub required_min_width: Option<f32>,
387 pub required_max_width: Option<f32>,
389 pub required_min_height: Option<f32>,
391 pub required_max_height: Option<f32>,
393 pub default_min_width: Option<f32>,
396 pub default_min_height: Option<f32>,
397 pub background: Option<Brush>,
398 pub state_colors: Option<StateColors>,
399 pub state_elevation: Option<StateElevation>,
400
401 pub border: Option<Border>,
402 pub flex_grow: Option<f32>,
403 pub flex_shrink: Option<f32>,
404 pub flex_basis: Option<f32>,
405 pub flex_wrap: Option<FlexWrap>,
406 pub flex_dir: Option<FlexDirection>,
407 pub gap: Option<f32>,
408 pub row_gap: Option<f32>,
409 pub column_gap: Option<f32>,
410 pub align_self: Option<AlignSelf>,
411 pub justify_content: Option<JustifyContent>,
412 pub align_items_container: Option<AlignItems>,
413 pub align_content: Option<AlignContent>,
414 pub clip_rounded: Option<[f32; 4]>,
415 pub z_index: f32,
417 pub render_z_index: Option<f32>,
419 pub hit_passthrough: bool,
421 pub input_blocker: bool,
423 pub repaint_boundary: bool,
424 pub click: bool,
425 pub disabled: bool,
427 pub focusable: Option<bool>,
431 pub propagate_min: bool,
433 pub focus_group: bool,
436 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
437 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
438 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
439 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
440 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
441 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
442 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
443 pub on_click: Option<Rc<dyn Fn()>>,
446 pub on_double_click: Option<Rc<dyn Fn()>>,
448 pub on_long_click: Option<Rc<dyn Fn()>>,
450 pub semantics: Option<crate::Semantics>,
451 pub alpha: Option<f32>,
452 pub graphics_layer: Option<f32>,
453 pub shadow: Option<ShadowSpec>,
454 pub transform: Option<Transform>,
455 pub grid: Option<GridConfig>,
456 pub grid_col_span: Option<u16>,
457 pub grid_row_span: Option<u16>,
458 pub position_type: Option<PositionType>,
459 pub offset_left: Option<f32>,
460 pub offset_right: Option<f32>,
461 pub offset_top: Option<f32>,
462 pub offset_bottom: Option<f32>,
463
464 pub margin_left: Option<f32>,
465 pub margin_right: Option<f32>,
466 pub margin_top: Option<f32>,
467 pub margin_bottom: Option<f32>,
468 pub aspect_ratio: Option<f32>,
469 pub intrinsic_width: Option<IntrinsicSize>,
471 pub intrinsic_height: Option<IntrinsicSize>,
473 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
474
475 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
477 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
478 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
479 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
480 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
481 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
482
483 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
484
485 pub cursor: Option<crate::CursorIcon>,
487
488 pub animate_content_size: Option<AnimationSpec>,
491
492 pub focus_requester: Option<crate::runtime::FocusRequester>,
496
497 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
500
501 pub interaction_source: Option<InteractionSource>,
508
509 pub text_input: Option<TextInputConfig>,
511
512 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
514}
515
516impl std::fmt::Debug for Modifier {
517 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
518 let mut s = f.debug_struct("Modifier");
519
520 macro_rules! opt_val {
521 ($($name:ident),+ $(,)?) => {
522 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
523 };
524 }
525 if self.indication.is_some() {
526 s.field("indication", &"…");
527 }
528
529 opt_val!(
530 key,
531 size,
532 width,
533 height,
534 required_size,
535 padding,
536 padding_values,
537 min_width,
538 min_height,
539 max_width,
540 max_height,
541 required_min_width,
542 required_max_width,
543 required_min_height,
544 required_max_height,
545 default_min_width,
546 default_min_height,
547 fill_max,
548 fill_max_w,
549 fill_max_h,
550 background,
551 state_colors,
552 state_elevation,
553 border,
554 flex_grow,
555 flex_shrink,
556 flex_basis,
557 flex_wrap,
558 flex_dir,
559 gap,
560 row_gap,
561 column_gap,
562 align_self,
563 justify_content,
564 align_items_container,
565 align_content,
566 clip_rounded,
567 render_z_index,
568 semantics,
569 alpha,
570 transform,
571 grid,
572 grid_col_span,
573 grid_row_span,
574 position_type,
575 offset_left,
576 offset_right,
577 offset_top,
578 offset_bottom,
579 margin_left,
580 margin_right,
581 margin_top,
582 margin_bottom,
583 aspect_ratio,
584 intrinsic_width,
585 intrinsic_height,
586 cursor,
587 animate_content_size,
588 );
589
590 macro_rules! opt_cb {
591 ($($name:ident),+ $(,)?) => {
592 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
593 };
594 }
595 opt_cb!(
596 on_scroll,
597 on_pointer_down,
598 on_pointer_move,
599 on_pointer_up,
600 on_pointer_cancel,
601 on_pointer_enter,
602 on_pointer_leave,
603 on_click,
604 on_double_click,
605 on_long_click,
606 painter,
607 on_drag_start,
608 on_drag_end,
609 on_drag_enter,
610 on_drag_over,
611 on_drag_leave,
612 on_drop,
613 on_action,
614 on_focus_changed,
615 interaction_source,
616 text_input,
617 );
618
619 macro_rules! flag {
620 ($($name:ident),+ $(,)?) => {
621 $( if self.$name { s.field(stringify!($name), &true); } )+
622 };
623 }
624 flag!(
625 hit_passthrough,
626 input_blocker,
627 repaint_boundary,
628 click,
629 disabled,
630 propagate_min,
631 focus_group,
632 );
633
634 if let Some(f) = self.focusable {
635 s.field("focusable", &f);
636 }
637 if self.z_index != 0.0 {
638 s.field("z_index", &self.z_index);
639 }
640
641 s.finish()
642 }
643}
644
645impl_option_fields!(Modifier);
646
647impl Modifier {
648 pub fn new() -> Self {
649 Self::default()
650 }
651
652 pub fn key(mut self, key: u64) -> Self {
655 self.key = Some(key);
656 self
657 }
658
659 pub fn size(mut self, w: f32, h: f32) -> Self {
660 self.size = Some(Size {
661 width: w,
662 height: h,
663 });
664 self
665 }
666 pub fn width(mut self, w: f32) -> Self {
667 self.width = Some(w);
668 self
669 }
670 pub fn height(mut self, h: f32) -> Self {
671 self.height = Some(h);
672 self
673 }
674 pub fn required_size(mut self, w: f32, h: f32) -> Self {
679 self.required_size = Some(Size {
680 width: w,
681 height: h,
682 });
683 self
684 }
685 pub fn required_width_in(mut self, min: f32, max: f32) -> Self {
686 self.required_min_width = Some(min.max(0.0));
687 self.required_max_width = Some(max.max(0.0));
688 self
689 }
690 pub fn required_height_in(mut self, min: f32, max: f32) -> Self {
691 self.required_min_height = Some(min.max(0.0));
692 self.required_max_height = Some(max.max(0.0));
693 self
694 }
695 pub fn required_min_width(mut self, w: f32) -> Self {
696 self.required_min_width = Some(w.max(0.0));
697 self
698 }
699 pub fn required_max_width(mut self, w: f32) -> Self {
700 self.required_max_width = Some(w.max(0.0));
701 self
702 }
703 pub fn required_min_height(mut self, h: f32) -> Self {
704 self.required_min_height = Some(h.max(0.0));
705 self
706 }
707 pub fn required_max_height(mut self, h: f32) -> Self {
708 self.required_max_height = Some(h.max(0.0));
709 self
710 }
711 pub fn default_min_size(mut self, w: f32, h: f32) -> Self {
713 self.default_min_width = Some(w.max(0.0));
714 self.default_min_height = Some(h.max(0.0));
715 self
716 }
717 pub fn fill_max_size(mut self) -> Self {
720 self.fill_max = Some(1.0);
721 self
722 }
723 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
724 self.fill_max = Some(fraction.clamp(0.0, 1.0));
725 self
726 }
727 pub fn fill_max_width(mut self) -> Self {
729 self.fill_max_w = Some(1.0);
730 self
731 }
732 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
733 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
734 self
735 }
736 pub fn fill_max_height(mut self) -> Self {
738 self.fill_max_h = Some(1.0);
739 self
740 }
741 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
742 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
743 self
744 }
745 pub fn padding(mut self, v: f32) -> Self {
746 self.padding = Some(v);
747 self
748 }
749 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
750 self.padding_values = Some(padding);
751 self
752 }
753 pub fn ime_padding(mut self) -> Self {
756 let insets = crate::locals::window_insets();
757 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
758 let mut p = self.padding_values.unwrap_or_default();
759 p.bottom += insets.ime_bottom / scale;
760 self.padding_values = Some(p);
761 self
762 }
763 pub fn system_bars_padding(mut self) -> Self {
765 let insets = crate::locals::window_insets();
766 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
767 let mut p = self.padding_values.unwrap_or_default();
768 p.top += insets.top / scale;
769 p.bottom += insets.bottom / scale;
770 self.padding_values = Some(p);
771 self
772 }
773 pub fn status_bars_padding(mut self) -> Self {
775 let insets = crate::locals::window_insets();
776 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
777 let mut p = self.padding_values.unwrap_or_default();
778 p.top += insets.top / scale;
779 self.padding_values = Some(p);
780 self
781 }
782 pub fn navigation_bars_padding(mut self) -> Self {
784 let insets = crate::locals::window_insets();
785 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
786 let mut p = self.padding_values.unwrap_or_default();
787 p.bottom += insets.bottom / scale;
788 self.padding_values = Some(p);
789 self
790 }
791 pub fn min_size(mut self, w: f32, h: f32) -> Self {
792 self.min_width = Some(w);
793 self.min_height = Some(h);
794 self
795 }
796 pub fn max_size(mut self, w: f32, h: f32) -> Self {
797 self.max_width = Some(w);
798 self.max_height = Some(h);
799 self
800 }
801 pub fn min_width(mut self, w: f32) -> Self {
802 self.min_width = Some(w);
803 self
804 }
805 pub fn min_height(mut self, h: f32) -> Self {
806 self.min_height = Some(h);
807 self
808 }
809 pub fn max_width(mut self, w: f32) -> Self {
810 self.max_width = Some(w);
811 self
812 }
813 pub fn max_height(mut self, h: f32) -> Self {
814 self.max_height = Some(h);
815 self
816 }
817 pub fn background(mut self, color: Color) -> Self {
819 self.background = Some(Brush::Solid(color));
820 self
821 }
822 pub fn background_brush(mut self, brush: Brush) -> Self {
824 self.background = Some(brush);
825 self
826 }
827 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
828 self.border = Some(Border {
829 width,
830 color,
831 radius: [radius; 4],
832 });
833 self
834 }
835 pub fn border_radii(mut self, width: f32, color: Color, radii: [f32; 4]) -> Self {
836 self.border = Some(Border {
837 width,
838 color,
839 radius: radii,
840 });
841 self
842 }
843 pub fn flex_grow(mut self, v: f32) -> Self {
844 self.flex_grow = Some(v);
845 self
846 }
847 pub fn flex_shrink(mut self, v: f32) -> Self {
848 self.flex_shrink = Some(v);
849 self
850 }
851 pub fn flex_basis(mut self, v: f32) -> Self {
852 self.flex_basis = Some(v);
853 self
854 }
855 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
856 self.flex_wrap = Some(w);
857 self
858 }
859 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
860 self.flex_dir = Some(d);
861 self
862 }
863 pub fn gap(mut self, v: f32) -> Self {
864 let v = v.max(0.0);
865 self.gap = Some(v);
866 self.row_gap = Some(v);
867 self.column_gap = Some(v);
868 self
869 }
870 pub fn row_gap(mut self, v: f32) -> Self {
871 self.row_gap = Some(v.max(0.0));
872 self
873 }
874 pub fn column_gap(mut self, v: f32) -> Self {
875 self.column_gap = Some(v.max(0.0));
876 self
877 }
878 pub fn align_self(mut self, a: AlignSelf) -> Self {
879 self.align_self = Some(a);
880 self
881 }
882 pub fn align_self_center(mut self) -> Self {
883 self.align_self = Some(AlignSelf::Center);
884 self
885 }
886 pub fn justify_content(mut self, j: JustifyContent) -> Self {
887 self.justify_content = Some(j);
888 self
889 }
890 pub fn align_items(mut self, a: AlignItems) -> Self {
891 self.align_items_container = Some(a);
892 self
893 }
894 pub fn align_content(mut self, a: AlignContent) -> Self {
895 self.align_content = Some(a);
896 self
897 }
898 pub fn clip_rounded(mut self, radius: f32) -> Self {
899 self.clip_rounded = Some([radius; 4]);
900 self
901 }
902 pub fn clip_rounded_radii(mut self, radii: [f32; 4]) -> Self {
903 self.clip_rounded = Some(radii);
904 self
905 }
906 pub fn z_index(mut self, z: f32) -> Self {
907 self.z_index = z;
908 self
909 }
910
911 pub fn render_z_index(mut self, z: f32) -> Self {
914 self.render_z_index = Some(z);
915 self
916 }
917
918 pub fn input_blocker(mut self) -> Self {
920 self.input_blocker = true;
921 self
922 }
923
924 pub fn hit_passthrough(mut self) -> Self {
925 self.hit_passthrough = true;
926 self
927 }
928 pub fn clickable(mut self) -> Self {
929 self.click = true;
930 self
931 }
932 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
935 self.click = true;
936 self.interaction_source = Some(source.source());
937 self
938 }
939 pub fn state_colors(mut self, colors: StateColors) -> Self {
942 self.state_colors = Some(colors);
943 self
944 }
945 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
947 self.state_elevation = Some(elev);
948 self
949 }
950 pub fn disabled(mut self) -> Self {
952 self.disabled = true;
953 self
954 }
955 pub fn enabled(mut self, enabled: bool) -> Self {
957 self.disabled = !enabled;
958 self
959 }
960 pub fn focusable(mut self, focusable: bool) -> Self {
965 self.focusable = Some(focusable);
966 self
967 }
968 pub fn focus_group(mut self) -> Self {
971 self.focus_group = true;
972 self
973 }
974 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
983 self.interaction_source = Some(source.source());
984 self
985 }
986 pub fn hoverable(
989 mut self,
990 on_enter: impl Fn() + 'static,
991 on_leave: impl Fn() + 'static,
992 ) -> Self {
993 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
994 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
995 self
996 }
997 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1001 self.interaction_source = Some(source.source());
1002 self
1003 }
1004 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1007 self.propagate_min = propagate;
1008 self
1009 }
1010 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1011 self.on_scroll = Some(Rc::new(f));
1012 self
1013 }
1014 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1015 self.on_pointer_down = Some(Rc::new(f));
1016 self
1017 }
1018 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1019 self.on_pointer_move = Some(Rc::new(f));
1020 self
1021 }
1022 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1023 self.on_pointer_up = Some(Rc::new(f));
1024 self
1025 }
1026 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1027 self.on_pointer_cancel = Some(Rc::new(f));
1028 self
1029 }
1030 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1031 self.on_pointer_enter = Some(Rc::new(f));
1032 self
1033 }
1034 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1035 self.on_pointer_leave = Some(Rc::new(f));
1036 self
1037 }
1038 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1039 self.on_click = Some(Rc::new(f));
1040 self
1041 }
1042 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1043 self.on_double_click = Some(Rc::new(f));
1044 self
1045 }
1046 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1047 self.on_long_click = Some(Rc::new(f));
1048 self
1049 }
1050 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1051 self.semantics = Some(s);
1052 self
1053 }
1054 pub fn alpha(mut self, a: f32) -> Self {
1055 self.alpha = Some(a);
1056 self
1057 }
1058 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1063 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1064 self
1065 }
1066 pub fn shadow(mut self, blur_radius: f32, offset_y: f32) -> Self {
1070 self.shadow = Some(ShadowSpec {
1071 blur_radius: blur_radius.max(0.0),
1072 offset_y,
1073 color: Color(0, 0, 0, 64),
1074 });
1075 self
1076 }
1077 pub fn shadow_with_color(mut self, blur_radius: f32, offset_y: f32, color: Color) -> Self {
1079 self.shadow = Some(ShadowSpec {
1080 blur_radius: blur_radius.max(0.0),
1081 offset_y,
1082 color,
1083 });
1084 self
1085 }
1086 pub fn elevation(mut self, level: f32) -> Self {
1090 if level <= 0.0 {
1091 self.shadow = None;
1092 return self;
1093 }
1094 self.shadow = Some(ShadowSpec {
1095 blur_radius: level * 2.0,
1096 offset_y: level * 0.5,
1097 color: Color(0, 0, 0, (level * 8.0).clamp(8.0, 80.0) as u8),
1098 });
1099 self
1100 }
1101 pub fn transform(mut self, t: Transform) -> Self {
1102 self.transform = Some(t);
1103 self
1104 }
1105 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
1106 self.grid = Some(GridConfig {
1107 columns,
1108 row_gap,
1109 column_gap,
1110 });
1111 self
1112 }
1113 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1114 self.grid_col_span = Some(col_span);
1115 self.grid_row_span = Some(row_span);
1116 self
1117 }
1118 pub fn absolute(mut self) -> Self {
1119 self.position_type = Some(PositionType::Absolute);
1120 self
1121 }
1122 pub fn offset(
1123 mut self,
1124 left: Option<f32>,
1125 top: Option<f32>,
1126 right: Option<f32>,
1127 bottom: Option<f32>,
1128 ) -> Self {
1129 self.offset_left = left;
1130 self.offset_top = top;
1131 self.offset_right = right;
1132 self.offset_bottom = bottom;
1133 self
1134 }
1135 pub fn offset_left(mut self, v: f32) -> Self {
1136 self.offset_left = Some(v);
1137 self
1138 }
1139 pub fn offset_right(mut self, v: f32) -> Self {
1140 self.offset_right = Some(v);
1141 self
1142 }
1143 pub fn offset_top(mut self, v: f32) -> Self {
1144 self.offset_top = Some(v);
1145 self
1146 }
1147 pub fn offset_bottom(mut self, v: f32) -> Self {
1148 self.offset_bottom = Some(v);
1149 self
1150 }
1151 pub fn margin(mut self, v: f32) -> Self {
1152 self.margin_left = Some(v);
1153 self.margin_right = Some(v);
1154 self.margin_top = Some(v);
1155 self.margin_bottom = Some(v);
1156 self
1157 }
1158
1159 pub fn margin_horizontal(mut self, v: f32) -> Self {
1160 self.margin_left = Some(v);
1161 self.margin_right = Some(v);
1162 self
1163 }
1164
1165 pub fn margin_vertical(mut self, v: f32) -> Self {
1166 self.margin_top = Some(v);
1167 self.margin_bottom = Some(v);
1168 self
1169 }
1170 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1171 self.aspect_ratio = Some(ratio);
1172 self
1173 }
1174 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1176 self.intrinsic_width = Some(mode);
1177 self
1178 }
1179 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1181 self.intrinsic_height = Some(mode);
1182 self
1183 }
1184 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1185 self.painter = Some(Rc::new(f));
1186 self
1187 }
1188 pub fn scale(self, s: f32) -> Self {
1189 self.scale2(s, s)
1190 }
1191 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1192 let mut t = self.transform.unwrap_or_else(Transform::identity);
1193 t.scale_x *= sx;
1194 t.scale_y *= sy;
1195 self.transform = Some(t);
1196 self
1197 }
1198 pub fn translate(mut self, x: f32, y: f32) -> Self {
1199 let t = self.transform.unwrap_or_else(Transform::identity);
1200 self.transform = Some(t.combine(&Transform::translate(x, y)));
1201 self
1202 }
1203 pub fn translate_vec2(self, v: Vec2) -> Self {
1204 self.translate(v.x, v.y)
1205 }
1206 pub fn rotate(mut self, radians: f32) -> Self {
1207 let mut t = self.transform.unwrap_or_else(Transform::identity);
1208 t.rotate += radians;
1209 self.transform = Some(t);
1210 self
1211 }
1212 pub fn weight(mut self, w: f32) -> Self {
1213 let w = w.max(0.0);
1214 self.flex_grow = Some(w);
1215 self.flex_shrink = Some(1.0);
1216 self.flex_basis = Some(0.0);
1218 self
1219 }
1220 pub fn repaint_boundary(mut self) -> Self {
1224 self.repaint_boundary = true;
1225 self
1226 }
1227 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1228 self.on_action = Some(Rc::new(f));
1229 self
1230 }
1231
1232 pub fn on_drag_start(
1234 mut self,
1235 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1236 ) -> Self {
1237 self.on_drag_start = Some(Rc::new(f));
1238 self
1239 }
1240
1241 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1243 self.on_drag_end = Some(Rc::new(f));
1244 self
1245 }
1246
1247 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1249 self.on_drag_enter = Some(Rc::new(f));
1250 self
1251 }
1252
1253 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1255 self.on_drag_over = Some(Rc::new(f));
1256 self
1257 }
1258
1259 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1261 self.on_drag_leave = Some(Rc::new(f));
1262 self
1263 }
1264
1265 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1268 self.on_drop = Some(Rc::new(f));
1269 self
1270 }
1271
1272 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1274 self.cursor = Some(c);
1275 self
1276 }
1277
1278 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1282 self.animate_content_size = Some(spec);
1283 self
1284 }
1285
1286 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1289 self.focus_requester = Some(fr);
1290 self
1291 }
1292
1293 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1296 self.on_focus_changed = Some(Rc::new(f));
1297 self
1298 }
1299
1300 pub fn text_input(mut self, config: TextInputConfig) -> Self {
1302 self.text_input = Some(config);
1303 self
1304 }
1305
1306 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
1310 self.indication = Some(factory);
1311 self
1312 }
1313}