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, PartialEq)]
126pub enum BlurredEdgeTreatment {
127 Rectangle,
130 Unbounded,
133}
134
135#[derive(Clone, Copy, Debug)]
137pub struct BlurStyle {
138 pub radius_x: f32,
140 pub radius_y: f32,
142 pub edge_treatment: BlurredEdgeTreatment,
144}
145
146#[derive(Clone, Copy, Debug)]
151pub struct LayoutConstraints {
152 pub min_width: f32,
153 pub max_width: f32,
154 pub min_height: f32,
155 pub max_height: f32,
156}
157
158#[derive(Clone, Copy, Debug)]
165pub struct ShadowSpec {
166 pub blur_radius: f32,
167 pub offset_y: f32,
168 pub color: Color,
169}
170
171#[derive(Clone, Copy, Debug)]
172#[non_exhaustive]
173pub enum PositionType {
174 Relative,
175 Absolute,
176}
177
178#[derive(Clone)]
180pub struct TextInputConfig {
181 pub hint: String,
182 pub multiline: bool,
183 pub on_change: Option<Rc<dyn Fn(String)>>,
184 pub on_submit: Option<Rc<dyn Fn(String)>>,
185 pub focus_tracker: Option<Rc<Cell<bool>>>,
186 pub value: String,
187 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
188 pub keyboard_type: crate::text::KeyboardType,
189 pub capitalization: crate::text::KeyboardCapitalization,
190 pub ime_action: crate::text::ImeAction,
191 pub enabled: bool,
193 pub read_only: bool,
195 pub max_lines: Option<usize>,
197 pub min_lines: usize,
199 pub cursor_color: Option<Color>,
201 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
204 pub text_style: Option<crate::text::TextStyle>,
207 pub keyboard_actions: Option<crate::text::KeyboardActions>,
210 pub interaction_source: Option<InteractionSource>,
212 pub line_limits: Option<crate::text::TextFieldLineLimits>,
214}
215
216impl std::fmt::Debug for TextInputConfig {
217 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218 let mut s = f.debug_struct("TextInputConfig");
219 s.field("hint", &self.hint);
220 s.field("multiline", &self.multiline);
221 if self.on_change.is_some() {
222 s.field("on_change", &"…");
223 }
224 if self.on_submit.is_some() {
225 s.field("on_submit", &"…");
226 }
227 if self.focus_tracker.is_some() {
228 s.field("focus_tracker", &"…");
229 }
230 s.field("value", &self.value);
231 if self.visual_transformation.is_some() {
232 s.field("visual_transformation", &"…");
233 }
234 s.field("keyboard_type", &self.keyboard_type);
235 s.field("capitalization", &self.capitalization);
236 s.field("ime_action", &self.ime_action);
237 s.field("enabled", &self.enabled);
238 s.field("read_only", &self.read_only);
239 s.field("max_lines", &self.max_lines);
240 s.field("min_lines", &self.min_lines);
241 s.field("cursor_color", &self.cursor_color);
242 if self.on_text_layout.is_some() {
243 s.field("on_text_layout", &"…");
244 }
245 s.finish()
246 }
247}
248
249#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
252pub enum IntrinsicSize {
253 Min,
254 Max,
255}
256
257static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
258
259pub type PressId = u64;
261
262#[derive(Clone, Copy, Debug, PartialEq)]
270pub enum Interaction {
271 Press(PressId, Vec2),
274 Release(PressId),
276 Cancel(PressId),
279 HoverEnter,
280 HoverLeave,
281 Focus,
282 Unfocus,
283 DragStart,
284 DragStop,
285 DragCancel,
286}
287
288impl Interaction {
289 #[inline]
291 pub fn new_press(position: Vec2) -> Self {
292 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
293 }
294}
295
296#[derive(Clone)]
303pub struct InteractionSource {
304 pub(crate) state: Rc<RefCell<InteractionState>>,
305}
306
307impl InteractionSource {
308 pub fn collect_is_pressed(&self) -> bool {
309 self.state.borrow().pressed > 0
310 }
311 pub fn collect_is_hovered(&self) -> bool {
312 self.state.borrow().hovered
313 }
314 pub fn collect_is_focused(&self) -> bool {
315 self.state.borrow().focused
316 }
317 pub fn collect_is_dragged(&self) -> bool {
318 self.state.borrow().dragged > 0
319 }
320 pub fn collect_last_press_position(&self) -> Option<Vec2> {
321 self.state.borrow().last_press_position
322 }
323 pub fn collect_last_press_id(&self) -> Option<PressId> {
324 self.state.borrow().last_press_id
325 }
326 pub fn stable_id(&self) -> *const () {
328 Rc::as_ptr(&self.state) as *const ()
329 }
330 pub fn to_mutable(&self) -> MutableInteractionSource {
334 MutableInteractionSource {
335 state: self.state.clone(),
336 }
337 }
338}
339
340#[derive(Clone)]
350pub struct MutableInteractionSource {
351 pub(crate) state: Rc<RefCell<InteractionState>>,
352}
353
354impl std::fmt::Debug for MutableInteractionSource {
355 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
356 f.debug_struct("MutableInteractionSource")
357 .finish_non_exhaustive()
358 }
359}
360
361impl MutableInteractionSource {
362 pub fn new() -> Self {
363 Self {
364 state: Rc::new(RefCell::new(InteractionState::default())),
365 }
366 }
367
368 pub fn emit(&self, interaction: Interaction) {
370 let mut s = self.state.borrow_mut();
371 match interaction {
372 Interaction::Press(id, pos) => {
373 s.pressed = s.pressed.saturating_add(1);
374 s.last_press_id = Some(id);
375 s.last_press_position = Some(pos);
376 }
377 Interaction::Release(_) | Interaction::Cancel(_) => {
378 s.pressed = s.pressed.saturating_sub(1);
379 }
380 Interaction::HoverEnter => s.hovered = true,
381 Interaction::HoverLeave => s.hovered = false,
382 Interaction::Focus => s.focused = true,
383 Interaction::Unfocus => s.focused = false,
384 Interaction::DragStart => s.dragged = s.dragged.saturating_add(1),
385 Interaction::DragStop | Interaction::DragCancel => {
386 s.dragged = s.dragged.saturating_sub(1);
387 }
388 }
389 }
390
391 pub fn source(&self) -> InteractionSource {
393 InteractionSource {
394 state: self.state.clone(),
395 }
396 }
397}
398
399impl Default for MutableInteractionSource {
400 fn default() -> Self {
401 Self::new()
402 }
403}
404
405#[derive(Clone, Default)]
406pub(crate) struct InteractionState {
407 pressed: u32,
408 hovered: bool,
409 focused: bool,
410 dragged: u32,
411 pub(crate) last_press_position: Option<Vec2>,
413 pub(crate) last_press_id: Option<PressId>,
415}
416
417#[derive(Clone, Default)]
418pub struct Modifier {
419 pub key: Option<u64>,
425
426 pub size: Option<Size>,
427 pub width: Option<f32>,
428 pub height: Option<f32>,
429 pub required_size: Option<Size>,
430 pub fill_max: Option<f32>,
431 pub fill_max_w: Option<f32>,
432 pub fill_max_h: Option<f32>,
433 pub padding: Option<f32>,
434 pub padding_values: Option<PaddingValues>,
435 pub min_width: Option<f32>,
436 pub min_height: Option<f32>,
437 pub max_width: Option<f32>,
438 pub max_height: Option<f32>,
439 pub required_min_width: Option<f32>,
441 pub required_max_width: Option<f32>,
443 pub required_min_height: Option<f32>,
445 pub required_max_height: Option<f32>,
447 pub default_min_width: Option<f32>,
450 pub default_min_height: Option<f32>,
451 pub background: Option<Brush>,
452 pub state_colors: Option<StateColors>,
453 pub state_elevation: Option<StateElevation>,
454
455 pub border: Option<Border>,
456 pub flex_grow: Option<f32>,
457 pub flex_shrink: Option<f32>,
458 pub flex_basis: Option<f32>,
459 pub flex_wrap: Option<FlexWrap>,
460 pub flex_dir: Option<FlexDirection>,
461 pub gap: Option<f32>,
462 pub row_gap: Option<f32>,
463 pub column_gap: Option<f32>,
464 pub align_self: Option<AlignSelf>,
465 pub justify_content: Option<JustifyContent>,
466 pub align_items_container: Option<AlignItems>,
467 pub align_content: Option<AlignContent>,
468 pub clip_rounded: Option<[f32; 4]>,
469 pub z_index: f32,
471 pub render_z_index: Option<f32>,
473 pub hit_passthrough: bool,
475 pub input_blocker: bool,
477 pub repaint_boundary: bool,
478 pub click: bool,
479 pub disabled: bool,
481 pub focusable: Option<bool>,
485 pub propagate_min: bool,
487 pub focus_group: bool,
490 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
491 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
492 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
493 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
494 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
495 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
496 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
497 pub on_click: Option<Rc<dyn Fn()>>,
499 pub on_double_click: Option<Rc<dyn Fn()>>,
501 pub on_long_click: Option<Rc<dyn Fn()>>,
503 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
506 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
509 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
512 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
515 pub blur: Option<BlurStyle>,
520 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (f32, f32)>>,
525 pub semantics: Option<crate::Semantics>,
526 pub alpha: Option<f32>,
527 pub graphics_layer: Option<f32>,
528 pub shadow: Option<ShadowSpec>,
529 pub transform: Option<Transform>,
530 pub grid: Option<GridConfig>,
531 pub grid_col_span: Option<u16>,
532 pub grid_row_span: Option<u16>,
533 pub position_type: Option<PositionType>,
534 pub offset_left: Option<f32>,
535 pub offset_right: Option<f32>,
536 pub offset_top: Option<f32>,
537 pub offset_bottom: Option<f32>,
538
539 pub margin_left: Option<f32>,
540 pub margin_right: Option<f32>,
541 pub margin_top: Option<f32>,
542 pub margin_bottom: Option<f32>,
543 pub aspect_ratio: Option<f32>,
544 pub intrinsic_width: Option<IntrinsicSize>,
546 pub intrinsic_height: Option<IntrinsicSize>,
548 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
549
550 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
552 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
553 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
554 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
555 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
556 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
557
558 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
559
560 pub cursor: Option<crate::CursorIcon>,
562
563 pub animate_content_size: Option<AnimationSpec>,
566
567 pub focus_requester: Option<crate::runtime::FocusRequester>,
571
572 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
575
576 pub interaction_source: Option<InteractionSource>,
583
584 pub text_input: Option<TextInputConfig>,
586
587 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
589}
590
591impl std::fmt::Debug for Modifier {
592 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
593 let mut s = f.debug_struct("Modifier");
594
595 macro_rules! opt_val {
596 ($($name:ident),+ $(,)?) => {
597 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
598 };
599 }
600 if self.indication.is_some() {
601 s.field("indication", &"…");
602 }
603
604 opt_val!(
605 key,
606 size,
607 width,
608 height,
609 required_size,
610 padding,
611 padding_values,
612 min_width,
613 min_height,
614 max_width,
615 max_height,
616 required_min_width,
617 required_max_width,
618 required_min_height,
619 required_max_height,
620 default_min_width,
621 default_min_height,
622 fill_max,
623 fill_max_w,
624 fill_max_h,
625 background,
626 state_colors,
627 state_elevation,
628 border,
629 flex_grow,
630 flex_shrink,
631 flex_basis,
632 flex_wrap,
633 flex_dir,
634 gap,
635 row_gap,
636 column_gap,
637 align_self,
638 justify_content,
639 align_items_container,
640 align_content,
641 clip_rounded,
642 render_z_index,
643 semantics,
644 alpha,
645 transform,
646 grid,
647 grid_col_span,
648 grid_row_span,
649 position_type,
650 offset_left,
651 offset_right,
652 offset_top,
653 offset_bottom,
654 margin_left,
655 margin_right,
656 margin_top,
657 margin_bottom,
658 aspect_ratio,
659 intrinsic_width,
660 intrinsic_height,
661 cursor,
662 animate_content_size,
663 blur,
664 );
665
666 macro_rules! opt_cb {
667 ($($name:ident),+ $(,)?) => {
668 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
669 };
670 }
671 opt_cb!(
672 on_scroll,
673 on_pointer_down,
674 on_pointer_move,
675 on_pointer_up,
676 on_pointer_cancel,
677 on_pointer_enter,
678 on_pointer_leave,
679 on_click,
680 on_double_click,
681 on_long_click,
682 on_globally_positioned,
683 on_size_changed,
684 on_key_event,
685 on_preview_key_event,
686 painter,
687 on_drag_start,
688 on_drag_end,
689 on_drag_enter,
690 on_drag_over,
691 on_drag_leave,
692 on_drop,
693 on_action,
694 on_focus_changed,
695 interaction_source,
696 text_input,
697 layout,
698 );
699
700 macro_rules! flag {
701 ($($name:ident),+ $(,)?) => {
702 $( if self.$name { s.field(stringify!($name), &true); } )+
703 };
704 }
705 flag!(
706 hit_passthrough,
707 input_blocker,
708 repaint_boundary,
709 click,
710 disabled,
711 propagate_min,
712 focus_group,
713 );
714
715 if let Some(f) = self.focusable {
716 s.field("focusable", &f);
717 }
718 if self.z_index != 0.0 {
719 s.field("z_index", &self.z_index);
720 }
721
722 s.finish()
723 }
724}
725
726impl_option_fields!(Modifier);
727
728impl Modifier {
729 pub fn new() -> Self {
730 Self::default()
731 }
732
733 pub fn key(mut self, key: u64) -> Self {
736 self.key = Some(key);
737 self
738 }
739
740 pub fn size(mut self, w: f32, h: f32) -> Self {
741 self.size = Some(Size {
742 width: w,
743 height: h,
744 });
745 self
746 }
747 pub fn width(mut self, w: f32) -> Self {
748 self.width = Some(w);
749 self
750 }
751 pub fn height(mut self, h: f32) -> Self {
752 self.height = Some(h);
753 self
754 }
755 pub fn required_size(mut self, w: f32, h: f32) -> Self {
760 self.required_size = Some(Size {
761 width: w,
762 height: h,
763 });
764 self
765 }
766 pub fn required_width_in(mut self, min: f32, max: f32) -> Self {
767 self.required_min_width = Some(min.max(0.0));
768 self.required_max_width = Some(max.max(0.0));
769 self
770 }
771 pub fn required_height_in(mut self, min: f32, max: f32) -> Self {
772 self.required_min_height = Some(min.max(0.0));
773 self.required_max_height = Some(max.max(0.0));
774 self
775 }
776 pub fn required_min_width(mut self, w: f32) -> Self {
777 self.required_min_width = Some(w.max(0.0));
778 self
779 }
780 pub fn required_max_width(mut self, w: f32) -> Self {
781 self.required_max_width = Some(w.max(0.0));
782 self
783 }
784 pub fn required_min_height(mut self, h: f32) -> Self {
785 self.required_min_height = Some(h.max(0.0));
786 self
787 }
788 pub fn required_max_height(mut self, h: f32) -> Self {
789 self.required_max_height = Some(h.max(0.0));
790 self
791 }
792 pub fn default_min_size(mut self, w: f32, h: f32) -> Self {
794 self.default_min_width = Some(w.max(0.0));
795 self.default_min_height = Some(h.max(0.0));
796 self
797 }
798 pub fn fill_max_size(mut self) -> Self {
801 self.fill_max = Some(1.0);
802 self
803 }
804 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
805 self.fill_max = Some(fraction.clamp(0.0, 1.0));
806 self
807 }
808 pub fn fill_max_width(mut self) -> Self {
810 self.fill_max_w = Some(1.0);
811 self
812 }
813 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
814 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
815 self
816 }
817 pub fn fill_max_height(mut self) -> Self {
819 self.fill_max_h = Some(1.0);
820 self
821 }
822 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
823 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
824 self
825 }
826 pub fn padding(mut self, v: f32) -> Self {
827 self.padding = Some(v);
828 self
829 }
830 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
831 self.padding_values = Some(padding);
832 self
833 }
834 pub fn ime_padding(mut self) -> Self {
837 let insets = crate::locals::window_insets();
838 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
839 let mut p = self.padding_values.unwrap_or_default();
840 p.bottom += insets.ime_bottom / scale;
841 self.padding_values = Some(p);
842 self
843 }
844 pub fn system_bars_padding(mut self) -> Self {
846 let insets = crate::locals::window_insets();
847 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
848 let mut p = self.padding_values.unwrap_or_default();
849 p.top += insets.top / scale;
850 p.bottom += insets.bottom / scale;
851 self.padding_values = Some(p);
852 self
853 }
854 pub fn status_bars_padding(mut self) -> Self {
856 let insets = crate::locals::window_insets();
857 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
858 let mut p = self.padding_values.unwrap_or_default();
859 p.top += insets.top / scale;
860 self.padding_values = Some(p);
861 self
862 }
863 pub fn navigation_bars_padding(mut self) -> Self {
865 let insets = crate::locals::window_insets();
866 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
867 let mut p = self.padding_values.unwrap_or_default();
868 p.bottom += insets.bottom / scale;
869 self.padding_values = Some(p);
870 self
871 }
872 pub fn min_size(mut self, w: f32, h: f32) -> Self {
873 self.min_width = Some(w);
874 self.min_height = Some(h);
875 self
876 }
877 pub fn max_size(mut self, w: f32, h: f32) -> Self {
878 self.max_width = Some(w);
879 self.max_height = Some(h);
880 self
881 }
882 pub fn min_width(mut self, w: f32) -> Self {
883 self.min_width = Some(w);
884 self
885 }
886 pub fn min_height(mut self, h: f32) -> Self {
887 self.min_height = Some(h);
888 self
889 }
890 pub fn max_width(mut self, w: f32) -> Self {
891 self.max_width = Some(w);
892 self
893 }
894 pub fn max_height(mut self, h: f32) -> Self {
895 self.max_height = Some(h);
896 self
897 }
898 pub fn background(mut self, color: Color) -> Self {
900 self.background = Some(Brush::Solid(color));
901 self
902 }
903 pub fn background_brush(mut self, brush: Brush) -> Self {
905 self.background = Some(brush);
906 self
907 }
908 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
909 self.border = Some(Border {
910 width,
911 color,
912 radius: [radius; 4],
913 });
914 self
915 }
916 pub fn border_radii(mut self, width: f32, color: Color, radii: [f32; 4]) -> Self {
917 self.border = Some(Border {
918 width,
919 color,
920 radius: radii,
921 });
922 self
923 }
924 pub fn flex_grow(mut self, v: f32) -> Self {
925 self.flex_grow = Some(v);
926 self
927 }
928 pub fn flex_shrink(mut self, v: f32) -> Self {
929 self.flex_shrink = Some(v);
930 self
931 }
932 pub fn flex_basis(mut self, v: f32) -> Self {
933 self.flex_basis = Some(v);
934 self
935 }
936 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
937 self.flex_wrap = Some(w);
938 self
939 }
940 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
941 self.flex_dir = Some(d);
942 self
943 }
944 pub fn gap(mut self, v: f32) -> Self {
945 let v = v.max(0.0);
946 self.gap = Some(v);
947 self.row_gap = Some(v);
948 self.column_gap = Some(v);
949 self
950 }
951 pub fn row_gap(mut self, v: f32) -> Self {
952 self.row_gap = Some(v.max(0.0));
953 self
954 }
955 pub fn column_gap(mut self, v: f32) -> Self {
956 self.column_gap = Some(v.max(0.0));
957 self
958 }
959 pub fn align_self(mut self, a: AlignSelf) -> Self {
960 self.align_self = Some(a);
961 self
962 }
963 pub fn align_self_center(mut self) -> Self {
964 self.align_self = Some(AlignSelf::Center);
965 self
966 }
967 pub fn justify_content(mut self, j: JustifyContent) -> Self {
968 self.justify_content = Some(j);
969 self
970 }
971 pub fn align_items(mut self, a: AlignItems) -> Self {
972 self.align_items_container = Some(a);
973 self
974 }
975 pub fn align_content(mut self, a: AlignContent) -> Self {
976 self.align_content = Some(a);
977 self
978 }
979 pub fn clip_rounded(mut self, radius: f32) -> Self {
980 self.clip_rounded = Some([radius; 4]);
981 self
982 }
983 pub fn clip_rounded_radii(mut self, radii: [f32; 4]) -> Self {
984 self.clip_rounded = Some(radii);
985 self
986 }
987 pub fn z_index(mut self, z: f32) -> Self {
988 self.z_index = z;
989 self
990 }
991
992 pub fn render_z_index(mut self, z: f32) -> Self {
995 self.render_z_index = Some(z);
996 self
997 }
998
999 pub fn input_blocker(mut self) -> Self {
1001 self.input_blocker = true;
1002 self
1003 }
1004
1005 pub fn hit_passthrough(mut self) -> Self {
1006 self.hit_passthrough = true;
1007 self
1008 }
1009 pub fn clickable(mut self) -> Self {
1010 self.click = true;
1011 self
1012 }
1013 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1016 self.click = true;
1017 self.interaction_source = Some(source.source());
1018 self
1019 }
1020 pub fn state_colors(mut self, colors: StateColors) -> Self {
1023 self.state_colors = Some(colors);
1024 self
1025 }
1026 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1028 self.state_elevation = Some(elev);
1029 self
1030 }
1031 pub fn disabled(mut self) -> Self {
1033 self.disabled = true;
1034 self
1035 }
1036 pub fn enabled(mut self, enabled: bool) -> Self {
1038 self.disabled = !enabled;
1039 self
1040 }
1041 pub fn focusable(mut self, focusable: bool) -> Self {
1046 self.focusable = Some(focusable);
1047 self
1048 }
1049 pub fn focus_group(mut self) -> Self {
1052 self.focus_group = true;
1053 self
1054 }
1055 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1064 self.interaction_source = Some(source.source());
1065 self
1066 }
1067 pub fn hoverable(
1070 mut self,
1071 on_enter: impl Fn() + 'static,
1072 on_leave: impl Fn() + 'static,
1073 ) -> Self {
1074 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1075 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1076 self
1077 }
1078 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1082 self.interaction_source = Some(source.source());
1083 self
1084 }
1085 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1088 self.propagate_min = propagate;
1089 self
1090 }
1091 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1092 self.on_scroll = Some(Rc::new(f));
1093 self
1094 }
1095 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1096 self.on_pointer_down = Some(Rc::new(f));
1097 self
1098 }
1099 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1100 self.on_pointer_move = Some(Rc::new(f));
1101 self
1102 }
1103 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1104 self.on_pointer_up = Some(Rc::new(f));
1105 self
1106 }
1107 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1108 self.on_pointer_cancel = Some(Rc::new(f));
1109 self
1110 }
1111 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1112 self.on_pointer_enter = Some(Rc::new(f));
1113 self
1114 }
1115 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1116 self.on_pointer_leave = Some(Rc::new(f));
1117 self
1118 }
1119 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1120 self.on_click = Some(Rc::new(f));
1121 self.click = true;
1122 self
1123 }
1124 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1125 self.on_double_click = Some(Rc::new(f));
1126 self
1127 }
1128 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1129 self.on_long_click = Some(Rc::new(f));
1130 self
1131 }
1132 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1133 self.semantics = Some(s);
1134 self
1135 }
1136 pub fn alpha(mut self, a: f32) -> Self {
1137 self.alpha = Some(a);
1138 self
1139 }
1140 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1145 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1146 self
1147 }
1148 pub fn shadow(mut self, blur_radius: f32, offset_y: f32) -> Self {
1152 self.shadow = Some(ShadowSpec {
1153 blur_radius: blur_radius.max(0.0),
1154 offset_y,
1155 color: Color(0, 0, 0, 64),
1156 });
1157 self
1158 }
1159 pub fn shadow_with_color(mut self, blur_radius: f32, offset_y: f32, color: Color) -> Self {
1161 self.shadow = Some(ShadowSpec {
1162 blur_radius: blur_radius.max(0.0),
1163 offset_y,
1164 color,
1165 });
1166 self
1167 }
1168 pub fn elevation(mut self, level: f32) -> Self {
1172 if level <= 0.0 {
1173 self.shadow = None;
1174 return self;
1175 }
1176 self.shadow = Some(ShadowSpec {
1177 blur_radius: level * 2.0,
1178 offset_y: level * 0.5,
1179 color: Color(0, 0, 0, (level * 8.0).clamp(8.0, 80.0) as u8),
1180 });
1181 self
1182 }
1183 pub fn transform(mut self, t: Transform) -> Self {
1184 self.transform = Some(t);
1185 self
1186 }
1187 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
1188 self.grid = Some(GridConfig {
1189 columns,
1190 row_gap,
1191 column_gap,
1192 });
1193 self
1194 }
1195 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1196 self.grid_col_span = Some(col_span);
1197 self.grid_row_span = Some(row_span);
1198 self
1199 }
1200 pub fn absolute(mut self) -> Self {
1201 self.position_type = Some(PositionType::Absolute);
1202 self
1203 }
1204 pub fn offset(
1205 mut self,
1206 left: Option<f32>,
1207 top: Option<f32>,
1208 right: Option<f32>,
1209 bottom: Option<f32>,
1210 ) -> Self {
1211 self.offset_left = left;
1212 self.offset_top = top;
1213 self.offset_right = right;
1214 self.offset_bottom = bottom;
1215 self
1216 }
1217 pub fn offset_left(mut self, v: f32) -> Self {
1218 self.offset_left = Some(v);
1219 self
1220 }
1221 pub fn offset_right(mut self, v: f32) -> Self {
1222 self.offset_right = Some(v);
1223 self
1224 }
1225 pub fn offset_top(mut self, v: f32) -> Self {
1226 self.offset_top = Some(v);
1227 self
1228 }
1229 pub fn offset_bottom(mut self, v: f32) -> Self {
1230 self.offset_bottom = Some(v);
1231 self
1232 }
1233 pub fn margin(mut self, v: f32) -> Self {
1234 self.margin_left = Some(v);
1235 self.margin_right = Some(v);
1236 self.margin_top = Some(v);
1237 self.margin_bottom = Some(v);
1238 self
1239 }
1240
1241 pub fn margin_horizontal(mut self, v: f32) -> Self {
1242 self.margin_left = Some(v);
1243 self.margin_right = Some(v);
1244 self
1245 }
1246
1247 pub fn margin_vertical(mut self, v: f32) -> Self {
1248 self.margin_top = Some(v);
1249 self.margin_bottom = Some(v);
1250 self
1251 }
1252 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1253 self.aspect_ratio = Some(ratio);
1254 self
1255 }
1256 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1258 self.intrinsic_width = Some(mode);
1259 self
1260 }
1261 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1263 self.intrinsic_height = Some(mode);
1264 self
1265 }
1266 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1267 self.painter = Some(Rc::new(f));
1268 self
1269 }
1270 pub fn scale(self, s: f32) -> Self {
1271 self.scale2(s, s)
1272 }
1273 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1274 let mut t = self.transform.unwrap_or_else(Transform::identity);
1275 t.scale_x *= sx;
1276 t.scale_y *= sy;
1277 self.transform = Some(t);
1278 self
1279 }
1280 pub fn translate(mut self, x: f32, y: f32) -> Self {
1281 let t = self.transform.unwrap_or_else(Transform::identity);
1282 self.transform = Some(t.combine(&Transform::translate(x, y)));
1283 self
1284 }
1285 pub fn translate_vec2(self, v: Vec2) -> Self {
1286 self.translate(v.x, v.y)
1287 }
1288 pub fn rotate(mut self, radians: f32) -> Self {
1289 let mut t = self.transform.unwrap_or_else(Transform::identity);
1290 t.rotate += radians;
1291 self.transform = Some(t);
1292 self
1293 }
1294 pub fn weight(mut self, w: f32) -> Self {
1295 let w = w.max(0.0);
1296 self.flex_grow = Some(w);
1297 self.flex_shrink = Some(1.0);
1298 self.flex_basis = Some(0.0);
1300 self
1301 }
1302 pub fn repaint_boundary(mut self) -> Self {
1306 self.repaint_boundary = true;
1307 self
1308 }
1309 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1310 self.on_action = Some(Rc::new(f));
1311 self
1312 }
1313
1314 pub fn on_drag_start(
1316 mut self,
1317 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1318 ) -> Self {
1319 self.on_drag_start = Some(Rc::new(f));
1320 self
1321 }
1322
1323 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1325 self.on_drag_end = Some(Rc::new(f));
1326 self
1327 }
1328
1329 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1331 self.on_drag_enter = Some(Rc::new(f));
1332 self
1333 }
1334
1335 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1337 self.on_drag_over = Some(Rc::new(f));
1338 self
1339 }
1340
1341 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1343 self.on_drag_leave = Some(Rc::new(f));
1344 self
1345 }
1346
1347 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1350 self.on_drop = Some(Rc::new(f));
1351 self
1352 }
1353
1354 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1356 self.cursor = Some(c);
1357 self
1358 }
1359
1360 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1364 self.animate_content_size = Some(spec);
1365 self
1366 }
1367
1368 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1371 self.focus_requester = Some(fr);
1372 self
1373 }
1374
1375 pub fn focus_target(mut self) -> Self {
1378 self.focusable = Some(true);
1379 self
1380 }
1381
1382 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1385 self.on_focus_changed = Some(Rc::new(f));
1386 self
1387 }
1388
1389 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
1393 self.on_globally_positioned = Some(Rc::new(f));
1394 self
1395 }
1396
1397 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
1400 self.on_size_changed = Some(Rc::new(f));
1401 self
1402 }
1403
1404 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
1408 self.on_key_event = Some(Rc::new(f));
1409 self
1410 }
1411
1412 pub fn on_preview_key_event(
1416 mut self,
1417 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
1418 ) -> Self {
1419 self.on_preview_key_event = Some(Rc::new(f));
1420 self
1421 }
1422
1423 pub fn blur(mut self, radius_dp: f32) -> Self {
1430 self.blur = Some(BlurStyle {
1431 radius_x: radius_dp.max(0.0),
1432 radius_y: radius_dp.max(0.0),
1433 edge_treatment: BlurredEdgeTreatment::Rectangle,
1434 });
1435 self
1436 }
1437
1438 pub fn blur_with_edge(
1443 mut self,
1444 radius_x: f32,
1445 radius_y: f32,
1446 edge_treatment: BlurredEdgeTreatment,
1447 ) -> Self {
1448 self.blur = Some(BlurStyle {
1449 radius_x: radius_x.max(0.0),
1450 radius_y: radius_y.max(0.0),
1451 edge_treatment,
1452 });
1453 self
1454 }
1455
1456 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (f32, f32) + 'static) -> Self {
1464 self.layout = Some(Rc::new(f));
1465 self
1466 }
1467
1468 pub fn text_input(mut self, config: TextInputConfig) -> Self {
1470 self.text_input = Some(config);
1471 self
1472 }
1473
1474 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
1478 self.indication = Some(factory);
1479 self
1480 }
1481}