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, clip_rect, render_z_index,
66 on_scroll,
67 nested_scroll_connection,
68 scroll,
69 on_pointer_down, on_pointer_move, on_pointer_up,
70 on_pointer_enter, on_pointer_leave,
71 on_click, on_double_click, on_long_click,
72 semantics, alpha, transform,
73 grid, grid_col_span, grid_row_span,
74 position_type,
75 offset_left, offset_right, offset_top, offset_bottom,
76 margin_left, margin_right, margin_top, margin_bottom,
77 aspect_ratio, intrinsic_width, intrinsic_height,
78 painter,
79 on_drag_start, on_drag_end, on_drag_enter, on_drag_over, on_drag_leave, on_drop,
80 on_action, cursor, animate_content_size, focus_requester, on_focus_changed,
81 interaction_source, text_input,
82 );
83 merge_flags!(self, other;
84 hit_passthrough, input_blocker, repaint_boundary, click, disabled,
85 propagate_min, focus_group,
86 );
87
88 if let Some(f) = other.focusable {
89 self.focusable = Some(f);
90 }
91 if other.indication.is_some() {
92 self.indication = other.indication;
93 }
94 if other.z_index != 0.0 {
95 self.z_index = other.z_index;
96 }
97 self
98 }
99 }
100 };
101}
102
103#[derive(Clone, Copy, Debug, PartialEq, Eq)]
104pub enum ClipOp {
105 Intersect,
107 Difference,
109}
110
111impl Default for ClipOp {
112 fn default() -> Self {
113 Self::Intersect
114 }
115}
116
117#[derive(Clone, Copy, Debug)]
120pub struct ClipRect {
121 pub left: f32,
122 pub top: f32,
123 pub right: f32,
124 pub bottom: f32,
125 pub op: ClipOp,
126}
127
128#[derive(Clone, Debug)]
129pub struct Border {
130 pub width: f32,
131 pub color: Color,
132 pub radius: [f32; 4],
133}
134
135#[derive(Clone, Copy, Debug, Default)]
136pub struct PaddingValues {
137 pub left: f32,
138 pub right: f32,
139 pub top: f32,
140 pub bottom: f32,
141}
142
143#[derive(Clone, Debug)]
144pub struct GridConfig {
145 pub columns: usize,
146 pub row_gap: f32,
147 pub column_gap: f32,
148}
149
150#[derive(Clone, Copy, Debug, PartialEq)]
153pub enum BlurredEdgeTreatment {
154 Rectangle,
157 Unbounded,
160}
161
162#[derive(Clone, Copy, Debug)]
164pub struct BlurStyle {
165 pub radius_x: f32,
167 pub radius_y: f32,
169 pub edge_treatment: BlurredEdgeTreatment,
171}
172
173#[derive(Clone, Copy, Debug)]
178pub struct LayoutConstraints {
179 pub min_width: f32,
180 pub max_width: f32,
181 pub min_height: f32,
182 pub max_height: f32,
183}
184
185#[derive(Clone, Copy, Debug)]
192pub struct ShadowSpec {
193 pub blur_radius: f32,
194 pub offset_y: f32,
195 pub color: Color,
196}
197
198#[derive(Clone, Copy, Debug)]
199#[non_exhaustive]
200pub enum PositionType {
201 Relative,
202 Absolute,
203}
204
205#[derive(Clone)]
207pub struct TextInputConfig {
208 pub hint: String,
209 pub multiline: bool,
210 pub on_change: Option<Rc<dyn Fn(String)>>,
211 pub on_submit: Option<Rc<dyn Fn(String)>>,
212 pub focus_tracker: Option<Rc<Cell<bool>>>,
213 pub value: String,
214 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
215 pub keyboard_type: crate::text::KeyboardType,
216 pub capitalization: crate::text::KeyboardCapitalization,
217 pub ime_action: crate::text::ImeAction,
218 pub enabled: bool,
220 pub read_only: bool,
222 pub max_lines: Option<usize>,
224 pub min_lines: usize,
226 pub cursor_color: Option<Color>,
228 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
231 pub text_style: Option<crate::text::TextStyle>,
234 pub keyboard_actions: Option<crate::text::KeyboardActions>,
237 pub interaction_source: Option<InteractionSource>,
239 pub line_limits: Option<crate::text::TextFieldLineLimits>,
241}
242
243impl std::fmt::Debug for TextInputConfig {
244 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245 let mut s = f.debug_struct("TextInputConfig");
246 s.field("hint", &self.hint);
247 s.field("multiline", &self.multiline);
248 if self.on_change.is_some() {
249 s.field("on_change", &"…");
250 }
251 if self.on_submit.is_some() {
252 s.field("on_submit", &"…");
253 }
254 if self.focus_tracker.is_some() {
255 s.field("focus_tracker", &"…");
256 }
257 s.field("value", &self.value);
258 if self.visual_transformation.is_some() {
259 s.field("visual_transformation", &"…");
260 }
261 s.field("keyboard_type", &self.keyboard_type);
262 s.field("capitalization", &self.capitalization);
263 s.field("ime_action", &self.ime_action);
264 s.field("enabled", &self.enabled);
265 s.field("read_only", &self.read_only);
266 s.field("max_lines", &self.max_lines);
267 s.field("min_lines", &self.min_lines);
268 s.field("cursor_color", &self.cursor_color);
269 if self.on_text_layout.is_some() {
270 s.field("on_text_layout", &"…");
271 }
272 s.finish()
273 }
274}
275
276#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
279pub enum IntrinsicSize {
280 Min,
281 Max,
282}
283
284static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
285
286pub type PressId = u64;
288
289#[derive(Clone, Copy, Debug, PartialEq)]
297pub enum Interaction {
298 Press(PressId, Vec2),
301 Release(PressId),
303 Cancel(PressId),
306 HoverEnter,
307 HoverLeave,
308 Focus,
309 Unfocus,
310 DragStart,
311 DragStop,
312 DragCancel,
313}
314
315impl Interaction {
316 #[inline]
318 pub fn new_press(position: Vec2) -> Self {
319 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
320 }
321}
322
323#[derive(Clone)]
330pub struct InteractionSource {
331 pub(crate) state: Rc<RefCell<InteractionState>>,
332}
333
334impl InteractionSource {
335 pub fn collect_is_pressed(&self) -> bool {
336 self.state.borrow().pressed > 0
337 }
338 pub fn collect_is_hovered(&self) -> bool {
339 self.state.borrow().hovered
340 }
341 pub fn collect_is_focused(&self) -> bool {
342 self.state.borrow().focused
343 }
344 pub fn collect_is_dragged(&self) -> bool {
345 self.state.borrow().dragged > 0
346 }
347 pub fn collect_last_press_position(&self) -> Option<Vec2> {
348 self.state.borrow().last_press_position
349 }
350 pub fn collect_last_press_id(&self) -> Option<PressId> {
351 self.state.borrow().last_press_id
352 }
353 pub fn stable_id(&self) -> *const () {
355 Rc::as_ptr(&self.state) as *const ()
356 }
357 pub fn to_mutable(&self) -> MutableInteractionSource {
361 MutableInteractionSource {
362 state: self.state.clone(),
363 }
364 }
365}
366
367#[derive(Clone)]
377pub struct MutableInteractionSource {
378 pub(crate) state: Rc<RefCell<InteractionState>>,
379}
380
381impl std::fmt::Debug for MutableInteractionSource {
382 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
383 f.debug_struct("MutableInteractionSource")
384 .finish_non_exhaustive()
385 }
386}
387
388impl MutableInteractionSource {
389 pub fn new() -> Self {
390 Self {
391 state: Rc::new(RefCell::new(InteractionState::default())),
392 }
393 }
394
395 pub fn emit(&self, interaction: Interaction) {
397 let mut s = self.state.borrow_mut();
398 match interaction {
399 Interaction::Press(id, pos) => {
400 s.pressed = s.pressed.saturating_add(1);
401 s.last_press_id = Some(id);
402 s.last_press_position = Some(pos);
403 }
404 Interaction::Release(_) | Interaction::Cancel(_) => {
405 s.pressed = s.pressed.saturating_sub(1);
406 }
407 Interaction::HoverEnter => s.hovered = true,
408 Interaction::HoverLeave => s.hovered = false,
409 Interaction::Focus => s.focused = true,
410 Interaction::Unfocus => s.focused = false,
411 Interaction::DragStart => s.dragged = s.dragged.saturating_add(1),
412 Interaction::DragStop | Interaction::DragCancel => {
413 s.dragged = s.dragged.saturating_sub(1);
414 }
415 }
416 }
417
418 pub fn source(&self) -> InteractionSource {
420 InteractionSource {
421 state: self.state.clone(),
422 }
423 }
424}
425
426impl Default for MutableInteractionSource {
427 fn default() -> Self {
428 Self::new()
429 }
430}
431
432#[derive(Clone, Default)]
433pub(crate) struct InteractionState {
434 pressed: u32,
435 hovered: bool,
436 focused: bool,
437 dragged: u32,
438 pub(crate) last_press_position: Option<Vec2>,
440 pub(crate) last_press_id: Option<PressId>,
442}
443
444#[derive(Clone, Default)]
445pub struct Modifier {
446 pub key: Option<u64>,
452
453 pub size: Option<Size>,
454 pub width: Option<f32>,
455 pub height: Option<f32>,
456 pub required_size: Option<Size>,
457 pub fill_max: Option<f32>,
458 pub fill_max_w: Option<f32>,
459 pub fill_max_h: Option<f32>,
460 pub padding: Option<f32>,
461 pub padding_values: Option<PaddingValues>,
462 pub min_width: Option<f32>,
463 pub min_height: Option<f32>,
464 pub max_width: Option<f32>,
465 pub max_height: Option<f32>,
466 pub required_min_width: Option<f32>,
468 pub required_max_width: Option<f32>,
470 pub required_min_height: Option<f32>,
472 pub required_max_height: Option<f32>,
474 pub default_min_width: Option<f32>,
477 pub default_min_height: Option<f32>,
478 pub background: Option<Brush>,
479 pub state_colors: Option<StateColors>,
480 pub state_elevation: Option<StateElevation>,
481
482 pub border: Option<Border>,
483 pub flex_grow: Option<f32>,
484 pub flex_shrink: Option<f32>,
485 pub flex_basis: Option<f32>,
486 pub flex_wrap: Option<FlexWrap>,
487 pub flex_dir: Option<FlexDirection>,
488 pub gap: Option<f32>,
489 pub row_gap: Option<f32>,
490 pub column_gap: Option<f32>,
491 pub align_self: Option<AlignSelf>,
492 pub justify_content: Option<JustifyContent>,
493 pub align_items_container: Option<AlignItems>,
494 pub align_content: Option<AlignContent>,
495 pub clip_rounded: Option<[f32; 4]>,
496 pub clip_rect: Option<ClipRect>,
499 pub z_index: f32,
501 pub render_z_index: Option<f32>,
503 pub hit_passthrough: bool,
505 pub input_blocker: bool,
507 pub repaint_boundary: bool,
508 pub click: bool,
509 pub disabled: bool,
511 pub focusable: Option<bool>,
515 pub propagate_min: bool,
517 pub focus_group: bool,
520 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
521 pub scroll: Option<crate::scroll::ScrollBinding>,
527 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
536 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
537 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
538 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
539 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
540 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
541 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
542 pub on_click: Option<Rc<dyn Fn()>>,
544 pub on_double_click: Option<Rc<dyn Fn()>>,
546 pub on_long_click: Option<Rc<dyn Fn()>>,
548 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
551 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
554 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
557 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
560 pub blur: Option<BlurStyle>,
565 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (f32, f32)>>,
570 pub semantics: Option<crate::Semantics>,
571 pub alpha: Option<f32>,
572 pub graphics_layer: Option<f32>,
573 pub shadow: Option<ShadowSpec>,
574 pub transform: Option<Transform>,
575 pub grid: Option<GridConfig>,
576 pub grid_col_span: Option<u16>,
577 pub grid_row_span: Option<u16>,
578 pub position_type: Option<PositionType>,
579 pub offset_left: Option<f32>,
580 pub offset_right: Option<f32>,
581 pub offset_top: Option<f32>,
582 pub offset_bottom: Option<f32>,
583
584 pub margin_left: Option<f32>,
585 pub margin_right: Option<f32>,
586 pub margin_top: Option<f32>,
587 pub margin_bottom: Option<f32>,
588 pub aspect_ratio: Option<f32>,
589 pub intrinsic_width: Option<IntrinsicSize>,
591 pub intrinsic_height: Option<IntrinsicSize>,
593 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
594
595 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
597 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
598 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
599 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
600 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
601 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
602
603 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
604
605 pub cursor: Option<crate::CursorIcon>,
607
608 pub animate_content_size: Option<AnimationSpec>,
611
612 pub focus_requester: Option<crate::runtime::FocusRequester>,
616
617 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
620
621 pub interaction_source: Option<InteractionSource>,
628
629 pub text_input: Option<TextInputConfig>,
631
632 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
634}
635
636impl std::fmt::Debug for Modifier {
637 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
638 let mut s = f.debug_struct("Modifier");
639
640 macro_rules! opt_val {
641 ($($name:ident),+ $(,)?) => {
642 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
643 };
644 }
645 if self.indication.is_some() {
646 s.field("indication", &"…");
647 }
648
649 opt_val!(
650 key,
651 size,
652 width,
653 height,
654 required_size,
655 padding,
656 padding_values,
657 min_width,
658 min_height,
659 max_width,
660 max_height,
661 required_min_width,
662 required_max_width,
663 required_min_height,
664 required_max_height,
665 default_min_width,
666 default_min_height,
667 fill_max,
668 fill_max_w,
669 fill_max_h,
670 background,
671 state_colors,
672 state_elevation,
673 border,
674 flex_grow,
675 flex_shrink,
676 flex_basis,
677 flex_wrap,
678 flex_dir,
679 gap,
680 row_gap,
681 column_gap,
682 align_self,
683 justify_content,
684 align_items_container,
685 align_content,
686 clip_rounded,
687 clip_rect,
688 render_z_index,
689 semantics,
690 alpha,
691 transform,
692 grid,
693 grid_col_span,
694 grid_row_span,
695 position_type,
696 offset_left,
697 offset_right,
698 offset_top,
699 offset_bottom,
700 margin_left,
701 margin_right,
702 margin_top,
703 margin_bottom,
704 aspect_ratio,
705 intrinsic_width,
706 intrinsic_height,
707 cursor,
708 animate_content_size,
709 blur,
710 );
711
712 macro_rules! opt_cb {
713 ($($name:ident),+ $(,)?) => {
714 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
715 };
716 }
717 opt_cb!(
718 on_scroll,
719 scroll,
720 nested_scroll_connection,
721 on_pointer_down,
722 on_pointer_move,
723 on_pointer_up,
724 on_pointer_cancel,
725 on_pointer_enter,
726 on_pointer_leave,
727 on_click,
728 on_double_click,
729 on_long_click,
730 on_globally_positioned,
731 on_size_changed,
732 on_key_event,
733 on_preview_key_event,
734 painter,
735 on_drag_start,
736 on_drag_end,
737 on_drag_enter,
738 on_drag_over,
739 on_drag_leave,
740 on_drop,
741 on_action,
742 on_focus_changed,
743 interaction_source,
744 text_input,
745 layout,
746 );
747
748 macro_rules! flag {
749 ($($name:ident),+ $(,)?) => {
750 $( if self.$name { s.field(stringify!($name), &true); } )+
751 };
752 }
753 flag!(
754 hit_passthrough,
755 input_blocker,
756 repaint_boundary,
757 click,
758 disabled,
759 propagate_min,
760 focus_group,
761 );
762
763 if let Some(f) = self.focusable {
764 s.field("focusable", &f);
765 }
766 if self.z_index != 0.0 {
767 s.field("z_index", &self.z_index);
768 }
769
770 s.finish()
771 }
772}
773
774impl_option_fields!(Modifier);
775
776impl Modifier {
777 pub fn new() -> Self {
778 Self::default()
779 }
780
781 pub fn key(mut self, key: u64) -> Self {
784 self.key = Some(key);
785 self
786 }
787
788 pub fn size(mut self, w: f32, h: f32) -> Self {
789 self.size = Some(Size {
790 width: w,
791 height: h,
792 });
793 self
794 }
795 pub fn width(mut self, w: f32) -> Self {
796 self.width = Some(w);
797 self
798 }
799 pub fn height(mut self, h: f32) -> Self {
800 self.height = Some(h);
801 self
802 }
803 pub fn required_size(mut self, w: f32, h: f32) -> Self {
808 self.required_size = Some(Size {
809 width: w,
810 height: h,
811 });
812 self
813 }
814 pub fn required_width_in(mut self, min: f32, max: f32) -> Self {
815 self.required_min_width = Some(min.max(0.0));
816 self.required_max_width = Some(max.max(0.0));
817 self
818 }
819 pub fn required_height_in(mut self, min: f32, max: f32) -> Self {
820 self.required_min_height = Some(min.max(0.0));
821 self.required_max_height = Some(max.max(0.0));
822 self
823 }
824 pub fn required_min_width(mut self, w: f32) -> Self {
825 self.required_min_width = Some(w.max(0.0));
826 self
827 }
828 pub fn required_max_width(mut self, w: f32) -> Self {
829 self.required_max_width = Some(w.max(0.0));
830 self
831 }
832 pub fn required_min_height(mut self, h: f32) -> Self {
833 self.required_min_height = Some(h.max(0.0));
834 self
835 }
836 pub fn required_max_height(mut self, h: f32) -> Self {
837 self.required_max_height = Some(h.max(0.0));
838 self
839 }
840 pub fn default_min_size(mut self, w: f32, h: f32) -> Self {
842 self.default_min_width = Some(w.max(0.0));
843 self.default_min_height = Some(h.max(0.0));
844 self
845 }
846 pub fn fill_max_size(mut self) -> Self {
849 self.fill_max = Some(1.0);
850 self
851 }
852 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
853 self.fill_max = Some(fraction.clamp(0.0, 1.0));
854 self
855 }
856 pub fn fill_max_width(mut self) -> Self {
858 self.fill_max_w = Some(1.0);
859 self
860 }
861 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
862 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
863 self
864 }
865 pub fn fill_max_height(mut self) -> Self {
867 self.fill_max_h = Some(1.0);
868 self
869 }
870 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
871 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
872 self
873 }
874 pub fn padding(mut self, v: f32) -> Self {
875 self.padding = Some(v);
876 self
877 }
878 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
879 self.padding_values = Some(padding);
880 self
881 }
882 pub fn ime_padding(mut self) -> Self {
885 let insets = crate::locals::window_insets();
886 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
887 let mut p = self.padding_values.unwrap_or_default();
888 p.bottom += insets.ime_bottom / scale;
889 self.padding_values = Some(p);
890 self
891 }
892 pub fn system_bars_padding(mut self) -> Self {
894 let insets = crate::locals::window_insets();
895 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
896 let mut p = self.padding_values.unwrap_or_default();
897 p.top += insets.top / scale;
898 p.bottom += insets.bottom / scale;
899 self.padding_values = Some(p);
900 self
901 }
902 pub fn status_bars_padding(mut self) -> Self {
904 let insets = crate::locals::window_insets();
905 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
906 let mut p = self.padding_values.unwrap_or_default();
907 p.top += insets.top / scale;
908 self.padding_values = Some(p);
909 self
910 }
911 pub fn navigation_bars_padding(mut self) -> Self {
913 let insets = crate::locals::window_insets();
914 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
915 let mut p = self.padding_values.unwrap_or_default();
916 p.bottom += insets.bottom / scale;
917 self.padding_values = Some(p);
918 self
919 }
920 pub fn min_size(mut self, w: f32, h: f32) -> Self {
921 self.min_width = Some(w);
922 self.min_height = Some(h);
923 self
924 }
925 pub fn max_size(mut self, w: f32, h: f32) -> Self {
926 self.max_width = Some(w);
927 self.max_height = Some(h);
928 self
929 }
930 pub fn min_width(mut self, w: f32) -> Self {
931 self.min_width = Some(w);
932 self
933 }
934 pub fn min_height(mut self, h: f32) -> Self {
935 self.min_height = Some(h);
936 self
937 }
938 pub fn max_width(mut self, w: f32) -> Self {
939 self.max_width = Some(w);
940 self
941 }
942 pub fn max_height(mut self, h: f32) -> Self {
943 self.max_height = Some(h);
944 self
945 }
946 pub fn background(mut self, color: Color) -> Self {
948 self.background = Some(Brush::Solid(color));
949 self
950 }
951 pub fn background_brush(mut self, brush: Brush) -> Self {
953 self.background = Some(brush);
954 self
955 }
956 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
957 self.border = Some(Border {
958 width,
959 color,
960 radius: [radius; 4],
961 });
962 self
963 }
964 pub fn border_radii(mut self, width: f32, color: Color, radii: [f32; 4]) -> Self {
965 self.border = Some(Border {
966 width,
967 color,
968 radius: radii,
969 });
970 self
971 }
972 pub fn flex_grow(mut self, v: f32) -> Self {
973 self.flex_grow = Some(v);
974 self
975 }
976 pub fn flex_shrink(mut self, v: f32) -> Self {
977 self.flex_shrink = Some(v);
978 self
979 }
980 pub fn flex_basis(mut self, v: f32) -> Self {
981 self.flex_basis = Some(v);
982 self
983 }
984 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
985 self.flex_wrap = Some(w);
986 self
987 }
988 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
989 self.flex_dir = Some(d);
990 self
991 }
992 pub fn gap(mut self, v: f32) -> Self {
993 let v = v.max(0.0);
994 self.gap = Some(v);
995 self.row_gap = Some(v);
996 self.column_gap = Some(v);
997 self
998 }
999 pub fn row_gap(mut self, v: f32) -> Self {
1000 self.row_gap = Some(v.max(0.0));
1001 self
1002 }
1003 pub fn column_gap(mut self, v: f32) -> Self {
1004 self.column_gap = Some(v.max(0.0));
1005 self
1006 }
1007 pub fn align_self(mut self, a: AlignSelf) -> Self {
1008 self.align_self = Some(a);
1009 self
1010 }
1011 pub fn align_self_center(mut self) -> Self {
1012 self.align_self = Some(AlignSelf::CENTER);
1013 self
1014 }
1015 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1016 self.justify_content = Some(j);
1017 self
1018 }
1019 pub fn align_items(mut self, a: AlignItems) -> Self {
1020 self.align_items_container = Some(a);
1021 self
1022 }
1023 pub fn align_content(mut self, a: AlignContent) -> Self {
1024 self.align_content = Some(a);
1025 self
1026 }
1027 pub fn clip_rounded(mut self, radius: f32) -> Self {
1028 self.clip_rounded = Some([radius; 4]);
1029 self
1030 }
1031 pub fn clip_rounded_radii(mut self, radii: [f32; 4]) -> Self {
1032 self.clip_rounded = Some(radii);
1033 self
1034 }
1035 pub fn clip_rect(mut self, left: f32, top: f32, right: f32, bottom: f32, op: ClipOp) -> Self {
1038 self.clip_rect = Some(ClipRect {
1039 left,
1040 top,
1041 right,
1042 bottom,
1043 op,
1044 });
1045 self
1046 }
1047 pub fn z_index(mut self, z: f32) -> Self {
1048 self.z_index = z;
1049 self
1050 }
1051
1052 pub fn render_z_index(mut self, z: f32) -> Self {
1055 self.render_z_index = Some(z);
1056 self
1057 }
1058
1059 pub fn input_blocker(mut self) -> Self {
1061 self.input_blocker = true;
1062 self
1063 }
1064
1065 pub fn hit_passthrough(mut self) -> Self {
1066 self.hit_passthrough = true;
1067 self
1068 }
1069 pub fn clickable(mut self) -> Self {
1070 self.click = true;
1071 self
1072 }
1073 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1076 self.click = true;
1077 self.interaction_source = Some(source.source());
1078 self
1079 }
1080 pub fn state_colors(mut self, colors: StateColors) -> Self {
1083 self.state_colors = Some(colors);
1084 self
1085 }
1086 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1088 self.state_elevation = Some(elev);
1089 self
1090 }
1091 pub fn disabled(mut self) -> Self {
1093 self.disabled = true;
1094 self
1095 }
1096 pub fn enabled(mut self, enabled: bool) -> Self {
1098 self.disabled = !enabled;
1099 self
1100 }
1101 pub fn focusable(mut self, focusable: bool) -> Self {
1106 self.focusable = Some(focusable);
1107 self
1108 }
1109 pub fn focus_group(mut self) -> Self {
1112 self.focus_group = true;
1113 self
1114 }
1115 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1124 self.interaction_source = Some(source.source());
1125 self
1126 }
1127 pub fn hoverable(
1130 mut self,
1131 on_enter: impl Fn() + 'static,
1132 on_leave: impl Fn() + 'static,
1133 ) -> Self {
1134 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1135 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1136 self
1137 }
1138 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1142 self.interaction_source = Some(source.source());
1143 self
1144 }
1145 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1148 self.propagate_min = propagate;
1149 self
1150 }
1151 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1152 self.on_scroll = Some(Rc::new(f));
1153 self
1154 }
1155 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1159 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1160 self
1161 }
1162 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1164 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1165 self
1166 }
1167 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1169 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1170 self
1171 }
1172 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1179 self.nested_scroll_connection = Some(conn);
1180 self
1181 }
1182 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1183 self.on_pointer_down = Some(Rc::new(f));
1184 self
1185 }
1186 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1187 self.on_pointer_move = Some(Rc::new(f));
1188 self
1189 }
1190 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1191 self.on_pointer_up = Some(Rc::new(f));
1192 self
1193 }
1194 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1195 self.on_pointer_cancel = Some(Rc::new(f));
1196 self
1197 }
1198 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1199 self.on_pointer_enter = Some(Rc::new(f));
1200 self
1201 }
1202 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1203 self.on_pointer_leave = Some(Rc::new(f));
1204 self
1205 }
1206 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1207 self.on_click = Some(Rc::new(f));
1208 self.click = true;
1209 self
1210 }
1211 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1212 self.on_double_click = Some(Rc::new(f));
1213 self
1214 }
1215 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1216 self.on_long_click = Some(Rc::new(f));
1217 self
1218 }
1219 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1220 self.semantics = Some(s);
1221 self
1222 }
1223 pub fn alpha(mut self, a: f32) -> Self {
1224 self.alpha = Some(a);
1225 self
1226 }
1227 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1232 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1233 self
1234 }
1235 pub fn shadow(mut self, blur_radius: f32, offset_y: f32) -> Self {
1239 self.shadow = Some(ShadowSpec {
1240 blur_radius: blur_radius.max(0.0),
1241 offset_y,
1242 color: Color(0, 0, 0, 64),
1243 });
1244 self
1245 }
1246 pub fn shadow_with_color(mut self, blur_radius: f32, offset_y: f32, color: Color) -> Self {
1248 self.shadow = Some(ShadowSpec {
1249 blur_radius: blur_radius.max(0.0),
1250 offset_y,
1251 color,
1252 });
1253 self
1254 }
1255 pub fn elevation(mut self, level: f32) -> Self {
1259 if level <= 0.0 {
1260 self.shadow = None;
1261 return self;
1262 }
1263 self.shadow = Some(ShadowSpec {
1264 blur_radius: level * 2.0,
1265 offset_y: level * 0.5,
1266 color: Color(0, 0, 0, (level * 8.0).clamp(8.0, 80.0) as u8),
1267 });
1268 self
1269 }
1270 pub fn transform(mut self, t: Transform) -> Self {
1271 self.transform = Some(t);
1272 self
1273 }
1274 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
1275 self.grid = Some(GridConfig {
1276 columns,
1277 row_gap,
1278 column_gap,
1279 });
1280 self
1281 }
1282 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1283 self.grid_col_span = Some(col_span);
1284 self.grid_row_span = Some(row_span);
1285 self
1286 }
1287 pub fn absolute(mut self) -> Self {
1288 self.position_type = Some(PositionType::Absolute);
1289 self
1290 }
1291 pub fn offset(
1292 mut self,
1293 left: Option<f32>,
1294 top: Option<f32>,
1295 right: Option<f32>,
1296 bottom: Option<f32>,
1297 ) -> Self {
1298 self.offset_left = left;
1299 self.offset_top = top;
1300 self.offset_right = right;
1301 self.offset_bottom = bottom;
1302 self
1303 }
1304 pub fn offset_left(mut self, v: f32) -> Self {
1305 self.offset_left = Some(v);
1306 self
1307 }
1308 pub fn offset_right(mut self, v: f32) -> Self {
1309 self.offset_right = Some(v);
1310 self
1311 }
1312 pub fn offset_top(mut self, v: f32) -> Self {
1313 self.offset_top = Some(v);
1314 self
1315 }
1316 pub fn offset_bottom(mut self, v: f32) -> Self {
1317 self.offset_bottom = Some(v);
1318 self
1319 }
1320 pub fn margin(mut self, v: f32) -> Self {
1321 self.margin_left = Some(v);
1322 self.margin_right = Some(v);
1323 self.margin_top = Some(v);
1324 self.margin_bottom = Some(v);
1325 self
1326 }
1327
1328 pub fn margin_horizontal(mut self, v: f32) -> Self {
1329 self.margin_left = Some(v);
1330 self.margin_right = Some(v);
1331 self
1332 }
1333
1334 pub fn margin_vertical(mut self, v: f32) -> Self {
1335 self.margin_top = Some(v);
1336 self.margin_bottom = Some(v);
1337 self
1338 }
1339 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1340 self.aspect_ratio = Some(ratio);
1341 self
1342 }
1343 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1345 self.intrinsic_width = Some(mode);
1346 self
1347 }
1348 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1350 self.intrinsic_height = Some(mode);
1351 self
1352 }
1353 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1354 self.painter = Some(Rc::new(f));
1355 self
1356 }
1357 pub fn scale(self, s: f32) -> Self {
1358 self.scale2(s, s)
1359 }
1360 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1361 let mut t = self.transform.unwrap_or_else(Transform::identity);
1362 t.scale_x *= sx;
1363 t.scale_y *= sy;
1364 self.transform = Some(t);
1365 self
1366 }
1367 pub fn translate(mut self, x: f32, y: f32) -> Self {
1368 let t = self.transform.unwrap_or_else(Transform::identity);
1369 self.transform = Some(t.combine(&Transform::translate(x, y)));
1370 self
1371 }
1372 pub fn translate_vec2(self, v: Vec2) -> Self {
1373 self.translate(v.x, v.y)
1374 }
1375 pub fn rotate(mut self, radians: f32) -> Self {
1376 let mut t = self.transform.unwrap_or_else(Transform::identity);
1377 t.rotate += radians;
1378 self.transform = Some(t);
1379 self
1380 }
1381 pub fn weight(mut self, w: f32) -> Self {
1382 let w = w.max(0.0);
1383 self.flex_grow = Some(w);
1384 self.flex_shrink = Some(1.0);
1385 self.flex_basis = Some(0.0);
1387 self
1388 }
1389 pub fn repaint_boundary(mut self) -> Self {
1393 self.repaint_boundary = true;
1394 self
1395 }
1396 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1397 self.on_action = Some(Rc::new(f));
1398 self
1399 }
1400
1401 pub fn on_drag_start(
1403 mut self,
1404 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1405 ) -> Self {
1406 self.on_drag_start = Some(Rc::new(f));
1407 self
1408 }
1409
1410 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1412 self.on_drag_end = Some(Rc::new(f));
1413 self
1414 }
1415
1416 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1418 self.on_drag_enter = Some(Rc::new(f));
1419 self
1420 }
1421
1422 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1424 self.on_drag_over = Some(Rc::new(f));
1425 self
1426 }
1427
1428 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1430 self.on_drag_leave = Some(Rc::new(f));
1431 self
1432 }
1433
1434 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1437 self.on_drop = Some(Rc::new(f));
1438 self
1439 }
1440
1441 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1443 self.cursor = Some(c);
1444 self
1445 }
1446
1447 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1451 self.animate_content_size = Some(spec);
1452 self
1453 }
1454
1455 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1458 self.focus_requester = Some(fr);
1459 self
1460 }
1461
1462 pub fn focus_target(mut self) -> Self {
1465 self.focusable = Some(true);
1466 self
1467 }
1468
1469 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1472 self.on_focus_changed = Some(Rc::new(f));
1473 self
1474 }
1475
1476 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
1480 self.on_globally_positioned = Some(Rc::new(f));
1481 self
1482 }
1483
1484 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
1487 self.on_size_changed = Some(Rc::new(f));
1488 self
1489 }
1490
1491 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
1495 self.on_key_event = Some(Rc::new(f));
1496 self
1497 }
1498
1499 pub fn on_preview_key_event(
1503 mut self,
1504 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
1505 ) -> Self {
1506 self.on_preview_key_event = Some(Rc::new(f));
1507 self
1508 }
1509
1510 pub fn blur(mut self, radius_dp: f32) -> Self {
1517 self.blur = Some(BlurStyle {
1518 radius_x: radius_dp.max(0.0),
1519 radius_y: radius_dp.max(0.0),
1520 edge_treatment: BlurredEdgeTreatment::Rectangle,
1521 });
1522 self
1523 }
1524
1525 pub fn blur_with_edge(
1530 mut self,
1531 radius_x: f32,
1532 radius_y: f32,
1533 edge_treatment: BlurredEdgeTreatment,
1534 ) -> Self {
1535 self.blur = Some(BlurStyle {
1536 radius_x: radius_x.max(0.0),
1537 radius_y: radius_y.max(0.0),
1538 edge_treatment,
1539 });
1540 self
1541 }
1542
1543 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (f32, f32) + 'static) -> Self {
1551 self.layout = Some(Rc::new(f));
1552 self
1553 }
1554
1555 pub fn text_input(mut self, config: TextInputConfig) -> Self {
1557 self.text_input = Some(config);
1558 self
1559 }
1560
1561 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
1565 self.indication = Some(factory);
1566 self
1567 }
1568}