1use std::cell::{Cell, RefCell};
2use std::collections::HashSet;
3use std::rc::Rc;
4use std::sync::atomic::{AtomicU64, Ordering};
5
6use taffy::{AlignContent, AlignItems, AlignSelf, FlexDirection, FlexWrap, JustifyContent};
7
8use crate::animation::AnimationSpec;
9use crate::indication::IndicationNodeFactory;
10use crate::{Brush, Color, PointerEvent, Size, Transform, Vec2};
11
12#[derive(Clone, Copy, Debug)]
18pub struct StateColors {
19 pub default: Color,
20 pub hovered: Color,
21 pub focused: Color,
23 pub pressed: Color,
24 pub disabled: Color,
25 pub dragged: Color,
27}
28
29#[derive(Clone, Copy, Debug)]
32pub struct StateElevation {
33 pub default: f32,
34 pub hovered: f32,
35 pub focused: f32,
37 pub pressed: f32,
38 pub disabled: f32,
39 pub dragged: f32,
41}
42
43impl StateColors {
44 pub const fn transparent() -> Self {
46 Self {
47 default: Color::TRANSPARENT,
48 hovered: Color::TRANSPARENT,
49 focused: Color::TRANSPARENT,
50 pressed: Color::TRANSPARENT,
51 disabled: Color::TRANSPARENT,
52 dragged: Color::TRANSPARENT,
53 }
54 }
55}
56
57impl StateElevation {
58 pub const fn zero() -> Self {
60 Self {
61 default: 0.0,
62 hovered: 0.0,
63 focused: 0.0,
64 pressed: 0.0,
65 disabled: 0.0,
66 dragged: 0.0,
67 }
68 }
69}
70
71macro_rules! merge_opts {
72 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
73 $( $dst.$f = $src.$f.or($dst.$f); )+
74 };
75}
76macro_rules! merge_flags {
77 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
78 $( $dst.$f |= $src.$f; )+
79 };
80}
81
82macro_rules! impl_option_fields {
83 ($ty:ty, $fn:ident) => {
84 impl $ty {
85 $fn!(replace);
86 }
87 };
88 ($ty:ident) => {
89 impl $ty {
90 pub fn then(mut self, other: Self) -> Self {
93 merge_opts!(self, other;
94 key, size, width, height, required_size,
95 padding, padding_values,
96 min_width, min_height, max_width, max_height,
97 required_min_width, required_max_width,
98 required_min_height, required_max_height,
99 default_min_width, default_min_height,
100 fill_max, fill_max_w, fill_max_h,
101 background, state_colors, state_elevation, border,
102 flex_grow, flex_shrink, flex_basis, flex_wrap, flex_dir,
103 gap, row_gap, column_gap,
104 align_self, justify_content, align_items_container, align_content,
105 clip_rounded, clip_rect, overflow, render_z_index,
106 on_scroll,
107 nested_scroll_connection,
108 scroll,
109 on_pointer_down, on_pointer_move, on_pointer_up,
110 on_pointer_enter, on_pointer_leave,
111 on_click, on_double_click, on_long_click,
112 semantics, alpha, transform,
113 grid, grid_col_span, grid_row_span,
114 position_type,
115 offset_left, offset_right, offset_top, offset_bottom,
116 margin_left, margin_right, margin_top, margin_bottom,
117 aspect_ratio, intrinsic_width, intrinsic_height,
118 painter,
119 on_drag_start, on_drag_end, on_drag_enter, on_drag_over, on_drag_leave, on_drop,
120 drag_preview,
121 on_action, cursor, animate_content_size, focus_requester, on_focus_changed,
122 interaction_source, text_input,
123 );
124 merge_flags!(self, other;
125 hit_passthrough, input_blocker, repaint_boundary, click, disabled,
126 propagate_min, focus_group,
127 );
128
129 if let Some(f) = other.focusable {
130 self.focusable = Some(f);
131 }
132 if other.indication.is_some() {
133 self.indication = other.indication;
134 }
135 if other.z_index != 0.0 {
136 self.z_index = other.z_index;
137 }
138 self
139 }
140 }
141 };
142}
143
144#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
145pub enum ClipOp {
146 #[default]
148 Intersect,
149 Difference,
151}
152
153#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
159pub enum Overflow {
160 #[default]
161 Clip,
162 Visible,
163}
164
165#[derive(Clone, Copy, Debug)]
168pub struct ClipRect {
169 pub left: f32,
170 pub top: f32,
171 pub right: f32,
172 pub bottom: f32,
173 pub op: ClipOp,
174}
175
176#[derive(Clone, Debug)]
177pub struct Border {
178 pub width: f32,
179 pub color: Color,
180 pub radius: [f32; 4],
181}
182
183#[derive(Clone, Copy, Debug, Default)]
184pub struct PaddingValues {
185 pub left: f32,
186 pub right: f32,
187 pub top: f32,
188 pub bottom: f32,
189}
190
191#[derive(Clone, Debug)]
192pub struct GridConfig {
193 pub columns: usize,
194 pub row_gap: f32,
195 pub column_gap: f32,
196}
197
198#[derive(Clone, Copy, Debug, PartialEq)]
201pub enum BlurredEdgeTreatment {
202 Rectangle,
205 Unbounded,
208}
209
210#[derive(Clone, Copy, Debug)]
212pub struct BlurStyle {
213 pub radius_x: f32,
215 pub radius_y: f32,
217 pub edge_treatment: BlurredEdgeTreatment,
219}
220
221#[derive(Clone, Copy, Debug)]
226pub struct LayoutConstraints {
227 pub min_width: f32,
228 pub max_width: f32,
229 pub min_height: f32,
230 pub max_height: f32,
231}
232
233#[derive(Clone, Copy, Debug)]
240pub struct ShadowSpec {
241 pub blur_radius: f32,
242 pub offset_y: f32,
243 pub color: Color,
244}
245
246#[derive(Clone, Copy, Debug)]
247#[non_exhaustive]
248pub enum PositionType {
249 Relative,
250 Absolute,
251}
252
253#[derive(Clone)]
255pub struct TextInputConfig {
256 pub hint: String,
257 pub multiline: bool,
258 pub on_change: Option<Rc<dyn Fn(String)>>,
259 pub on_submit: Option<Rc<dyn Fn(String)>>,
260 pub focus_tracker: Option<Rc<Cell<bool>>>,
261 pub value: String,
262 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
263 pub keyboard_type: crate::text::KeyboardType,
264 pub capitalization: crate::text::KeyboardCapitalization,
265 pub ime_action: crate::text::ImeAction,
266 pub auto_correct_enabled: Option<bool>,
269 pub enabled: bool,
271 pub read_only: bool,
273 pub max_lines: Option<usize>,
275 pub min_lines: usize,
277 pub cursor_color: Option<Color>,
279 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
282 pub text_style: Option<crate::text::TextStyle>,
285 pub keyboard_actions: Option<crate::text::KeyboardActions>,
288 pub interaction_source: Option<InteractionSource>,
290 pub line_limits: Option<crate::text::TextFieldLineLimits>,
292}
293
294impl Default for TextInputConfig {
295 fn default() -> Self {
296 Self {
297 hint: String::new(),
298 multiline: false,
299 on_change: None,
300 on_submit: None,
301 focus_tracker: None,
302 value: String::new(),
303 visual_transformation: None,
304 keyboard_type: crate::text::KeyboardType::default(),
305 capitalization: crate::text::KeyboardCapitalization::default(),
306 ime_action: crate::text::ImeAction::default(),
307 auto_correct_enabled: None,
308 enabled: true,
309 read_only: false,
310 max_lines: None,
311 min_lines: 1,
312 cursor_color: None,
313 on_text_layout: None,
314 text_style: None,
315 keyboard_actions: None,
316 interaction_source: None,
317 line_limits: None,
318 }
319 }
320}
321
322impl std::fmt::Debug for TextInputConfig {
323 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
324 let mut s = f.debug_struct("TextInputConfig");
325 s.field("hint", &self.hint);
326 s.field("multiline", &self.multiline);
327 if self.on_change.is_some() {
328 s.field("on_change", &"…");
329 }
330 if self.on_submit.is_some() {
331 s.field("on_submit", &"…");
332 }
333 if self.focus_tracker.is_some() {
334 s.field("focus_tracker", &"…");
335 }
336 s.field("value", &self.value);
337 if self.visual_transformation.is_some() {
338 s.field("visual_transformation", &"…");
339 }
340 s.field("keyboard_type", &self.keyboard_type);
341 s.field("capitalization", &self.capitalization);
342 s.field("ime_action", &self.ime_action);
343 s.field("auto_correct_enabled", &self.auto_correct_enabled);
344 s.field("enabled", &self.enabled);
345 s.field("read_only", &self.read_only);
346 s.field("max_lines", &self.max_lines);
347 s.field("min_lines", &self.min_lines);
348 s.field("cursor_color", &self.cursor_color);
349 if self.on_text_layout.is_some() {
350 s.field("on_text_layout", &"…");
351 }
352 s.finish()
353 }
354}
355
356#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
359pub enum IntrinsicSize {
360 Min,
361 Max,
362}
363
364static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
365
366pub type PressId = u64;
368
369#[derive(Clone, Copy, Debug, PartialEq)]
377pub enum Interaction {
378 Press(PressId, Vec2),
381 Release(PressId),
383 Cancel(PressId),
386 HoverEnter,
387 HoverLeave,
388 Focus,
389 Unfocus,
390 DragStart,
391 DragStop,
392 DragCancel,
393}
394
395impl Interaction {
396 #[inline]
398 pub fn new_press(position: Vec2) -> Self {
399 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
400 }
401}
402
403#[derive(Clone)]
410pub struct InteractionSource {
411 pub(crate) state: Rc<RefCell<InteractionState>>,
412}
413
414impl InteractionSource {
415 pub fn collect_is_pressed(&self) -> bool {
416 !self.state.borrow().active_presses.is_empty()
417 }
418 pub fn collect_is_hovered(&self) -> bool {
419 self.state.borrow().hovered
420 }
421 pub fn collect_is_focused(&self) -> bool {
422 self.state.borrow().focused
423 }
424
425 pub fn collect_is_focus_visible(&self) -> bool {
427 crate::input::is_focus_visible(self.collect_is_focused())
428 }
429
430 pub fn collect_is_dragged(&self) -> bool {
431 self.state.borrow().dragged > 0
432 }
433 pub fn collect_last_press_position(&self) -> Option<Vec2> {
434 self.state.borrow().last_press_position
435 }
436 pub fn collect_last_press_id(&self) -> Option<PressId> {
437 self.state.borrow().last_press_id
438 }
439 pub fn stable_id(&self) -> *const () {
441 Rc::as_ptr(&self.state) as *const ()
442 }
443 pub fn to_mutable(&self) -> MutableInteractionSource {
447 MutableInteractionSource {
448 state: self.state.clone(),
449 }
450 }
451
452 pub fn reset(&self) {
454 self.to_mutable().reset();
455 }
456
457 pub fn reset_hover(&self) {
459 self.to_mutable().reset_hover();
460 }
461}
462
463#[derive(Clone)]
473pub struct MutableInteractionSource {
474 pub(crate) state: Rc<RefCell<InteractionState>>,
475}
476
477impl std::fmt::Debug for MutableInteractionSource {
478 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
479 f.debug_struct("MutableInteractionSource")
480 .finish_non_exhaustive()
481 }
482}
483
484impl MutableInteractionSource {
485 pub fn new() -> Self {
486 Self {
487 state: Rc::new(RefCell::new(InteractionState::default())),
488 }
489 }
490
491 pub fn emit(&self, interaction: Interaction) {
493 let changed = {
494 let mut s = self.state.borrow_mut();
495 match interaction {
496 Interaction::Press(id, pos) => {
497 let inserted = s.active_presses.insert(id);
498 s.last_press_id = Some(id);
499 s.last_press_position = Some(pos);
500 inserted
501 }
502 Interaction::Release(id) | Interaction::Cancel(id) => {
503 if s.active_presses.remove(&id) {
504 true
505 } else if id == 0 {
506 if let Some(any) = s.active_presses.iter().next().copied() {
507 s.active_presses.remove(&any);
508 true
509 } else {
510 false
511 }
512 } else {
513 false
514 }
515 }
516 Interaction::HoverEnter => {
517 let changed = !s.hovered;
518 s.hovered = true;
519 changed
520 }
521 Interaction::HoverLeave => {
522 let changed = s.hovered;
523 s.hovered = false;
524 if !s.active_presses.is_empty() {
526 s.active_presses.clear();
527 true
528 } else {
529 changed
530 }
531 }
532 Interaction::Focus => {
533 let changed = !s.focused;
534 s.focused = true;
535 changed
536 }
537 Interaction::Unfocus => {
538 let changed = s.focused;
539 s.focused = false;
540 changed
541 }
542 Interaction::DragStart => {
543 let changed = s.dragged == 0;
544 s.dragged = s.dragged.saturating_add(1);
545 changed
546 }
547 Interaction::DragStop | Interaction::DragCancel => {
548 let was = s.dragged;
549 s.dragged = s.dragged.saturating_sub(1);
550 was != s.dragged
551 }
552 }
553 };
554 if changed {
555 crate::frame_clock::request_frame();
557 }
558 }
559
560 pub fn source(&self) -> InteractionSource {
562 InteractionSource {
563 state: self.state.clone(),
564 }
565 }
566
567 pub fn reset(&self) {
569 let mut s = self.state.borrow_mut();
570 *s = InteractionState::default();
571 crate::frame_clock::request_frame();
572 }
573
574 pub fn reset_hover(&self) {
576 let mut s = self.state.borrow_mut();
577 if s.hovered {
578 s.hovered = false;
579 crate::frame_clock::request_frame();
580 }
581 }
582}
583
584impl Default for MutableInteractionSource {
585 fn default() -> Self {
586 Self::new()
587 }
588}
589
590#[derive(Clone, Default)]
591pub(crate) struct InteractionState {
592 active_presses: HashSet<PressId>,
594 hovered: bool,
595 focused: bool,
596 dragged: u32,
597 pub(crate) last_press_position: Option<Vec2>,
599 pub(crate) last_press_id: Option<PressId>,
601}
602
603#[derive(Clone, Default)]
604pub struct Modifier {
605 pub key: Option<u64>,
611
612 pub size: Option<Size>,
613 pub width: Option<f32>,
614 pub height: Option<f32>,
615 pub required_size: Option<Size>,
616 pub fill_max: Option<f32>,
617 pub fill_max_w: Option<f32>,
618 pub fill_max_h: Option<f32>,
619 pub padding: Option<f32>,
620 pub padding_values: Option<PaddingValues>,
621 pub min_width: Option<f32>,
622 pub min_height: Option<f32>,
623 pub max_width: Option<f32>,
624 pub max_height: Option<f32>,
625 pub required_min_width: Option<f32>,
627 pub required_max_width: Option<f32>,
629 pub required_min_height: Option<f32>,
631 pub required_max_height: Option<f32>,
633 pub default_min_width: Option<f32>,
636 pub default_min_height: Option<f32>,
637 pub background: Option<Brush>,
638 pub state_colors: Option<StateColors>,
639 pub state_elevation: Option<StateElevation>,
640
641 pub border: Option<Border>,
642 pub flex_grow: Option<f32>,
643 pub flex_shrink: Option<f32>,
644 pub flex_basis: Option<f32>,
645 pub flex_wrap: Option<FlexWrap>,
646 pub flex_dir: Option<FlexDirection>,
647 pub gap: Option<f32>,
648 pub row_gap: Option<f32>,
649 pub column_gap: Option<f32>,
650 pub align_self: Option<AlignSelf>,
651 pub justify_content: Option<JustifyContent>,
652 pub align_items_container: Option<AlignItems>,
653 pub align_content: Option<AlignContent>,
654 pub clip_rounded: Option<[f32; 4]>,
655 pub clip_rect: Option<ClipRect>,
658 pub overflow: Option<Overflow>,
663 pub z_index: f32,
665 pub render_z_index: Option<f32>,
667 pub hit_passthrough: bool,
669 pub input_blocker: bool,
671 pub repaint_boundary: bool,
672 pub click: bool,
673 pub disabled: bool,
675 pub focusable: Option<bool>,
679 pub propagate_min: bool,
681 pub focus_group: bool,
684 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
685 pub scroll: Option<crate::scroll::ScrollBinding>,
691 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
700 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
701 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
702 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
703 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
704 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
705 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
706 pub on_click: Option<Rc<dyn Fn()>>,
708 pub on_double_click: Option<Rc<dyn Fn()>>,
710 pub on_long_click: Option<Rc<dyn Fn()>>,
712 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
715 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
718 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
721 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
724 pub blur: Option<BlurStyle>,
729 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (f32, f32)>>,
734 pub semantics: Option<crate::Semantics>,
735 pub alpha: Option<f32>,
736 pub graphics_layer: Option<f32>,
737 pub shadow: Option<ShadowSpec>,
738 pub transform: Option<Transform>,
739 pub grid: Option<GridConfig>,
740 pub grid_col_span: Option<u16>,
741 pub grid_row_span: Option<u16>,
742 pub position_type: Option<PositionType>,
743 pub offset_left: Option<f32>,
744 pub offset_right: Option<f32>,
745 pub offset_top: Option<f32>,
746 pub offset_bottom: Option<f32>,
747
748 pub margin_left: Option<f32>,
749 pub margin_right: Option<f32>,
750 pub margin_top: Option<f32>,
751 pub margin_bottom: Option<f32>,
752 pub aspect_ratio: Option<f32>,
753 pub intrinsic_width: Option<IntrinsicSize>,
755 pub intrinsic_height: Option<IntrinsicSize>,
757 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
758
759 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
761 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
762 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
763 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
764 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
765 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
766 pub drag_preview: Option<crate::dnd::DragPreview>,
768
769 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
770
771 pub cursor: Option<crate::CursorIcon>,
773
774 pub animate_content_size: Option<AnimationSpec>,
777
778 pub focus_requester: Option<crate::runtime::FocusRequester>,
782
783 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
786
787 pub interaction_source: Option<InteractionSource>,
794
795 pub text_input: Option<TextInputConfig>,
797
798 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
800}
801
802impl std::fmt::Debug for Modifier {
803 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
804 let mut s = f.debug_struct("Modifier");
805
806 macro_rules! opt_val {
807 ($($name:ident),+ $(,)?) => {
808 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
809 };
810 }
811 if self.indication.is_some() {
812 s.field("indication", &"…");
813 }
814
815 opt_val!(
816 key,
817 size,
818 width,
819 height,
820 required_size,
821 padding,
822 padding_values,
823 min_width,
824 min_height,
825 max_width,
826 max_height,
827 required_min_width,
828 required_max_width,
829 required_min_height,
830 required_max_height,
831 default_min_width,
832 default_min_height,
833 fill_max,
834 fill_max_w,
835 fill_max_h,
836 background,
837 state_colors,
838 state_elevation,
839 border,
840 flex_grow,
841 flex_shrink,
842 flex_basis,
843 flex_wrap,
844 flex_dir,
845 gap,
846 row_gap,
847 column_gap,
848 align_self,
849 justify_content,
850 align_items_container,
851 align_content,
852 clip_rounded,
853 clip_rect,
854 render_z_index,
855 semantics,
856 alpha,
857 transform,
858 grid,
859 grid_col_span,
860 grid_row_span,
861 position_type,
862 offset_left,
863 offset_right,
864 offset_top,
865 offset_bottom,
866 margin_left,
867 margin_right,
868 margin_top,
869 margin_bottom,
870 aspect_ratio,
871 intrinsic_width,
872 intrinsic_height,
873 cursor,
874 animate_content_size,
875 blur,
876 );
877
878 macro_rules! opt_cb {
879 ($($name:ident),+ $(,)?) => {
880 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
881 };
882 }
883 opt_cb!(
884 on_scroll,
885 scroll,
886 nested_scroll_connection,
887 on_pointer_down,
888 on_pointer_move,
889 on_pointer_up,
890 on_pointer_cancel,
891 on_pointer_enter,
892 on_pointer_leave,
893 on_click,
894 on_double_click,
895 on_long_click,
896 on_globally_positioned,
897 on_size_changed,
898 on_key_event,
899 on_preview_key_event,
900 painter,
901 on_drag_start,
902 on_drag_end,
903 on_drag_enter,
904 on_drag_over,
905 on_drag_leave,
906 on_drop,
907 drag_preview,
908 on_action,
909 on_focus_changed,
910 interaction_source,
911 text_input,
912 layout,
913 );
914
915 macro_rules! flag {
916 ($($name:ident),+ $(,)?) => {
917 $( if self.$name { s.field(stringify!($name), &true); } )+
918 };
919 }
920 flag!(
921 hit_passthrough,
922 input_blocker,
923 repaint_boundary,
924 click,
925 disabled,
926 propagate_min,
927 focus_group,
928 );
929
930 if let Some(f) = self.focusable {
931 s.field("focusable", &f);
932 }
933 if self.z_index != 0.0 {
934 s.field("z_index", &self.z_index);
935 }
936
937 s.finish()
938 }
939}
940
941impl_option_fields!(Modifier);
942
943#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
947pub enum Alignment {
948 TopStart,
949 TopCenter,
950 TopEnd,
951 CenterStart,
952 #[default]
953 Center,
954 CenterEnd,
955 BottomStart,
956 BottomCenter,
957 BottomEnd,
958}
959
960impl Alignment {
961 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
963 use AlignItems as AI;
964 use JustifyContent as JC;
965 match self {
966 Self::TopStart => (AI::START, JC::START),
967 Self::TopCenter => (AI::START, JC::CENTER),
968 Self::TopEnd => (AI::START, JC::END),
969 Self::CenterStart => (AI::CENTER, JC::START),
970 Self::Center => (AI::CENTER, JC::CENTER),
971 Self::CenterEnd => (AI::CENTER, JC::END),
972 Self::BottomStart => (AI::END, JC::START),
973 Self::BottomCenter => (AI::END, JC::CENTER),
974 Self::BottomEnd => (AI::END, JC::END),
975 }
976 }
977}
978
979impl Modifier {
980 pub fn new() -> Self {
981 Self::default()
982 }
983
984 pub fn key(mut self, key: u64) -> Self {
987 self.key = Some(key);
988 self
989 }
990
991 pub fn size(mut self, w: f32, h: f32) -> Self {
992 self.size = Some(Size {
993 width: w,
994 height: h,
995 });
996 self
997 }
998 pub fn width(mut self, w: f32) -> Self {
999 self.width = Some(w);
1000 self
1001 }
1002 pub fn height(mut self, h: f32) -> Self {
1003 self.height = Some(h);
1004 self
1005 }
1006 pub fn required_size(mut self, w: f32, h: f32) -> Self {
1011 self.required_size = Some(Size {
1012 width: w,
1013 height: h,
1014 });
1015 self
1016 }
1017 pub fn required_width_in(mut self, min: f32, max: f32) -> Self {
1018 self.required_min_width = Some(min.max(0.0));
1019 self.required_max_width = Some(max.max(0.0));
1020 self
1021 }
1022 pub fn required_height_in(mut self, min: f32, max: f32) -> Self {
1023 self.required_min_height = Some(min.max(0.0));
1024 self.required_max_height = Some(max.max(0.0));
1025 self
1026 }
1027 pub fn required_min_width(mut self, w: f32) -> Self {
1028 self.required_min_width = Some(w.max(0.0));
1029 self
1030 }
1031 pub fn required_max_width(mut self, w: f32) -> Self {
1032 self.required_max_width = Some(w.max(0.0));
1033 self
1034 }
1035 pub fn required_min_height(mut self, h: f32) -> Self {
1036 self.required_min_height = Some(h.max(0.0));
1037 self
1038 }
1039 pub fn required_max_height(mut self, h: f32) -> Self {
1040 self.required_max_height = Some(h.max(0.0));
1041 self
1042 }
1043 pub fn default_min_size(mut self, w: f32, h: f32) -> Self {
1045 self.default_min_width = Some(w.max(0.0));
1046 self.default_min_height = Some(h.max(0.0));
1047 self
1048 }
1049 pub fn fill_max_size(mut self) -> Self {
1052 self.fill_max = Some(1.0);
1053 self
1054 }
1055 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
1056 self.fill_max = Some(fraction.clamp(0.0, 1.0));
1057 self
1058 }
1059 pub fn fill_max_width(mut self) -> Self {
1061 self.fill_max_w = Some(1.0);
1062 self
1063 }
1064 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
1065 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
1066 self
1067 }
1068 pub fn fill_max_height(mut self) -> Self {
1070 self.fill_max_h = Some(1.0);
1071 self
1072 }
1073 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
1074 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
1075 self
1076 }
1077 pub fn padding(mut self, v: f32) -> Self {
1078 self.padding = Some(v);
1079 self
1080 }
1081 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
1082 self.padding_values = Some(padding);
1083 self
1084 }
1085 pub fn ime_padding(mut self) -> Self {
1088 let insets = crate::locals::window_insets();
1089 let scale = crate::locals::effective_density_scale();
1090 let mut p = self.padding_values.unwrap_or_default();
1091 p.bottom += insets.ime_bottom / scale;
1092 self.padding_values = Some(p);
1093 self
1094 }
1095 pub fn system_bars_padding(mut self) -> Self {
1097 let insets = crate::locals::window_insets();
1098 let scale = crate::locals::effective_density_scale();
1099 let mut p = self.padding_values.unwrap_or_default();
1100 p.top += insets.top / scale;
1101 p.bottom += insets.bottom / scale;
1102 self.padding_values = Some(p);
1103 self
1104 }
1105 pub fn status_bars_padding(mut self) -> Self {
1107 let insets = crate::locals::window_insets();
1108 let scale = crate::locals::effective_density_scale();
1109 let mut p = self.padding_values.unwrap_or_default();
1110 p.top += insets.top / scale;
1111 self.padding_values = Some(p);
1112 self
1113 }
1114 pub fn navigation_bars_padding(mut self) -> Self {
1116 let insets = crate::locals::window_insets();
1117 let scale = crate::locals::effective_density_scale();
1118 let mut p = self.padding_values.unwrap_or_default();
1119 p.bottom += insets.bottom / scale;
1120 self.padding_values = Some(p);
1121 self
1122 }
1123 pub fn min_size(mut self, w: f32, h: f32) -> Self {
1124 self.min_width = Some(w);
1125 self.min_height = Some(h);
1126 self
1127 }
1128 pub fn max_size(mut self, w: f32, h: f32) -> Self {
1129 self.max_width = Some(w);
1130 self.max_height = Some(h);
1131 self
1132 }
1133 pub fn min_width(mut self, w: f32) -> Self {
1134 self.min_width = Some(w);
1135 self
1136 }
1137 pub fn min_height(mut self, h: f32) -> Self {
1138 self.min_height = Some(h);
1139 self
1140 }
1141 pub fn max_width(mut self, w: f32) -> Self {
1142 self.max_width = Some(w);
1143 self
1144 }
1145 pub fn max_height(mut self, h: f32) -> Self {
1146 self.max_height = Some(h);
1147 self
1148 }
1149 pub fn background(mut self, color: Color) -> Self {
1151 self.background = Some(Brush::Solid(color));
1152 self
1153 }
1154 pub fn background_brush(mut self, brush: Brush) -> Self {
1156 self.background = Some(brush);
1157 self
1158 }
1159 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
1160 self.border = Some(Border {
1161 width,
1162 color,
1163 radius: [radius; 4],
1164 });
1165 self
1166 }
1167 pub fn border_radii(mut self, width: f32, color: Color, radii: [f32; 4]) -> Self {
1168 self.border = Some(Border {
1169 width,
1170 color,
1171 radius: radii,
1172 });
1173 self
1174 }
1175 pub fn flex_grow(mut self, v: f32) -> Self {
1176 self.flex_grow = Some(v);
1177 self
1178 }
1179 pub fn flex_shrink(mut self, v: f32) -> Self {
1180 self.flex_shrink = Some(v);
1181 self
1182 }
1183 pub fn flex_basis(mut self, v: f32) -> Self {
1184 self.flex_basis = Some(v);
1185 self
1186 }
1187 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1188 self.flex_wrap = Some(w);
1189 self
1190 }
1191 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1192 self.flex_dir = Some(d);
1193 self
1194 }
1195 pub fn gap(mut self, v: f32) -> Self {
1196 let v = v.max(0.0);
1197 self.gap = Some(v);
1198 self.row_gap = Some(v);
1199 self.column_gap = Some(v);
1200 self
1201 }
1202 pub fn row_gap(mut self, v: f32) -> Self {
1203 self.row_gap = Some(v.max(0.0));
1204 self
1205 }
1206 pub fn column_gap(mut self, v: f32) -> Self {
1207 self.column_gap = Some(v.max(0.0));
1208 self
1209 }
1210 pub fn align_self(mut self, a: AlignSelf) -> Self {
1211 self.align_self = Some(a);
1212 self
1213 }
1214 pub fn align_self_center(mut self) -> Self {
1215 self.align_self = Some(AlignSelf::CENTER);
1216 self
1217 }
1218 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1219 self.justify_content = Some(j);
1220 self
1221 }
1222 pub fn align_items(mut self, a: AlignItems) -> Self {
1223 self.align_items_container = Some(a);
1224 self
1225 }
1226 pub fn content_alignment(self, alignment: Alignment) -> Self {
1229 let (ai, jc) = alignment.to_flex();
1230 self.align_items(ai).justify_content(jc)
1231 }
1232 pub fn align_content(mut self, a: AlignContent) -> Self {
1233 self.align_content = Some(a);
1234 self
1235 }
1236 pub fn clip_rounded(mut self, radius: f32) -> Self {
1237 self.clip_rounded = Some([radius; 4]);
1238 self
1239 }
1240 pub fn clip_rounded_radii(mut self, radii: [f32; 4]) -> Self {
1241 self.clip_rounded = Some(radii);
1242 self
1243 }
1244 pub fn clip_rect(mut self, left: f32, top: f32, right: f32, bottom: f32, op: ClipOp) -> Self {
1247 self.clip_rect = Some(ClipRect {
1248 left,
1249 top,
1250 right,
1251 bottom,
1252 op,
1253 });
1254 self
1255 }
1256 pub fn overflow(mut self, overflow: Overflow) -> Self {
1257 self.overflow = Some(overflow);
1258 self
1259 }
1260 pub fn z_index(mut self, z: f32) -> Self {
1261 self.z_index = z;
1262 self
1263 }
1264
1265 pub fn render_z_index(mut self, z: f32) -> Self {
1268 self.render_z_index = Some(z);
1269 self
1270 }
1271
1272 pub fn input_blocker(mut self) -> Self {
1274 self.input_blocker = true;
1275 self
1276 }
1277
1278 pub fn hit_passthrough(mut self) -> Self {
1279 self.hit_passthrough = true;
1280 self
1281 }
1282 pub fn clickable(mut self) -> Self {
1283 self.click = true;
1284 if self.indication.is_none() {
1285 self.indication = crate::locals::local_indication();
1286 }
1287 self
1288 }
1289 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1292 self.click = true;
1293 self.interaction_source = Some(source.source());
1294 if self.indication.is_none() {
1295 self.indication = crate::locals::local_indication();
1296 }
1297 self
1298 }
1299 pub fn state_colors(mut self, colors: StateColors) -> Self {
1302 self.state_colors = Some(colors);
1303 self
1304 }
1305 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1307 self.state_elevation = Some(elev);
1308 self
1309 }
1310 pub fn disabled(mut self) -> Self {
1312 self.disabled = true;
1313 self
1314 }
1315 pub fn enabled(mut self, enabled: bool) -> Self {
1317 self.disabled = !enabled;
1318 self
1319 }
1320 pub fn focusable(mut self, focusable: bool) -> Self {
1325 self.focusable = Some(focusable);
1326 self
1327 }
1328 pub fn focus_group(mut self) -> Self {
1331 self.focus_group = true;
1332 self
1333 }
1334 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1345 self.interaction_source = Some(source.source());
1346 self
1347 }
1348 pub fn hoverable(
1351 mut self,
1352 on_enter: impl Fn() + 'static,
1353 on_leave: impl Fn() + 'static,
1354 ) -> Self {
1355 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1356 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1357 self
1358 }
1359 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1363 self.interaction_source = Some(source.source());
1364 self
1365 }
1366 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1369 self.propagate_min = propagate;
1370 self
1371 }
1372 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1373 self.on_scroll = Some(Rc::new(f));
1374 self
1375 }
1376 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1380 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1381 self
1382 }
1383 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1385 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1386 self
1387 }
1388 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1390 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1391 self
1392 }
1393 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1400 self.nested_scroll_connection = Some(conn);
1401 self
1402 }
1403 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1404 self.on_pointer_down = Some(Rc::new(f));
1405 self
1406 }
1407 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1408 self.on_pointer_move = Some(Rc::new(f));
1409 self
1410 }
1411 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1412 self.on_pointer_up = Some(Rc::new(f));
1413 self
1414 }
1415 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1416 self.on_pointer_cancel = Some(Rc::new(f));
1417 self
1418 }
1419 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1420 self.on_pointer_enter = Some(Rc::new(f));
1421 self
1422 }
1423 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1424 self.on_pointer_leave = Some(Rc::new(f));
1425 self
1426 }
1427 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1428 self.on_click = Some(Rc::new(f));
1429 self.click = true;
1430 if self.semantics.is_none() {
1431 self.semantics = Some(crate::Semantics::new(crate::Role::Button));
1432 }
1433 self
1434 }
1435 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1436 self.on_double_click = Some(Rc::new(f));
1437 self.click = true;
1438 self
1439 }
1440 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1441 self.on_long_click = Some(Rc::new(f));
1442 self.click = true;
1443 self
1444 }
1445 pub fn clickable_ext(
1446 mut self,
1447 enabled: bool,
1448 on_click_label: Option<String>,
1449 role: Option<crate::semantics::Role>,
1450 on_click: impl Fn() + 'static,
1451 ) -> Self {
1452 if !enabled {
1453 let mut s = self.semantics.clone().unwrap_or_else(|| {
1454 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1455 });
1456 s.enabled = false;
1457 if let Some(r) = role {
1458 s.role = r;
1459 }
1460 if let Some(l) = on_click_label {
1461 s.label = Some(l);
1462 }
1463 return self
1464 .clickable()
1465 .enabled(false)
1466 .default_min_size(48.0, 48.0)
1467 .semantics(s);
1468 }
1469 self = self.clickable().on_click(on_click);
1470 if role.is_some() || on_click_label.is_some() {
1471 let mut s = self.semantics.clone().unwrap_or_else(|| {
1472 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1473 });
1474 s.enabled = true;
1475 if let Some(r) = role {
1476 s.role = r;
1477 }
1478 if let Some(l) = on_click_label {
1479 s.label = Some(l);
1480 }
1481 self = self.semantics(s);
1482 }
1483 self.default_min_size(48.0, 48.0)
1484 }
1485 pub fn combined_clickable(
1486 mut self,
1487 enabled: bool,
1488 on_click_label: Option<String>,
1489 role: Option<crate::semantics::Role>,
1490 on_long_click_label: Option<String>,
1491 on_click: impl Fn() + 'static,
1492 on_long_click: Option<impl Fn() + 'static>,
1493 on_double_click: Option<impl Fn() + 'static>,
1494 ) -> Self {
1495 let _ = on_long_click_label;
1496 if !enabled {
1497 return self.clickable_ext(false, on_click_label, role, || {});
1498 }
1499 self = self.clickable_ext(true, on_click_label, role, on_click);
1500 if let Some(f) = on_long_click {
1501 self = self.on_long_click(f);
1502 }
1503 if let Some(f) = on_double_click {
1504 self = self.on_double_click(f);
1505 }
1506 self.default_min_size(48.0, 48.0)
1507 }
1508 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1509 self.semantics = Some(s);
1510 self
1511 }
1512 pub fn alpha(mut self, a: f32) -> Self {
1513 self.alpha = Some(a);
1514 self
1515 }
1516 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1521 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1522 self
1523 }
1524 pub fn shadow(mut self, blur_radius: f32, offset_y: f32) -> Self {
1528 self.shadow = Some(ShadowSpec {
1529 blur_radius: blur_radius.max(0.0),
1530 offset_y,
1531 color: Color(0, 0, 0, 64),
1532 });
1533 self
1534 }
1535 pub fn shadow_with_color(mut self, blur_radius: f32, offset_y: f32, color: Color) -> Self {
1537 self.shadow = Some(ShadowSpec {
1538 blur_radius: blur_radius.max(0.0),
1539 offset_y,
1540 color,
1541 });
1542 self
1543 }
1544 pub fn elevation(mut self, level: f32) -> Self {
1548 if level <= 0.0 {
1549 self.shadow = None;
1550 return self;
1551 }
1552 self.shadow = Some(ShadowSpec {
1553 blur_radius: level * 2.0,
1554 offset_y: level * 0.5,
1555 color: Color(0, 0, 0, (level * 8.0).clamp(8.0, 80.0) as u8),
1556 });
1557 self
1558 }
1559 pub fn transform(mut self, t: Transform) -> Self {
1560 self.transform = Some(t);
1561 self
1562 }
1563 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
1564 self.grid = Some(GridConfig {
1565 columns,
1566 row_gap,
1567 column_gap,
1568 });
1569 self
1570 }
1571 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1572 self.grid_col_span = Some(col_span);
1573 self.grid_row_span = Some(row_span);
1574 self
1575 }
1576 pub fn absolute(mut self) -> Self {
1577 self.position_type = Some(PositionType::Absolute);
1578 self
1579 }
1580 pub fn offset(
1581 mut self,
1582 left: Option<f32>,
1583 top: Option<f32>,
1584 right: Option<f32>,
1585 bottom: Option<f32>,
1586 ) -> Self {
1587 self.offset_left = left;
1588 self.offset_top = top;
1589 self.offset_right = right;
1590 self.offset_bottom = bottom;
1591 self
1592 }
1593 pub fn offset_left(mut self, v: f32) -> Self {
1594 self.offset_left = Some(v);
1595 self
1596 }
1597 pub fn offset_right(mut self, v: f32) -> Self {
1598 self.offset_right = Some(v);
1599 self
1600 }
1601 pub fn offset_top(mut self, v: f32) -> Self {
1602 self.offset_top = Some(v);
1603 self
1604 }
1605 pub fn offset_bottom(mut self, v: f32) -> Self {
1606 self.offset_bottom = Some(v);
1607 self
1608 }
1609 pub fn margin(mut self, v: f32) -> Self {
1610 self.margin_left = Some(v);
1611 self.margin_right = Some(v);
1612 self.margin_top = Some(v);
1613 self.margin_bottom = Some(v);
1614 self
1615 }
1616
1617 pub fn margin_horizontal(mut self, v: f32) -> Self {
1618 self.margin_left = Some(v);
1619 self.margin_right = Some(v);
1620 self
1621 }
1622
1623 pub fn margin_vertical(mut self, v: f32) -> Self {
1624 self.margin_top = Some(v);
1625 self.margin_bottom = Some(v);
1626 self
1627 }
1628 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1629 self.aspect_ratio = Some(ratio);
1630 self
1631 }
1632 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1634 self.intrinsic_width = Some(mode);
1635 self
1636 }
1637 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1639 self.intrinsic_height = Some(mode);
1640 self
1641 }
1642 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1643 self.painter = Some(Rc::new(f));
1644 self
1645 }
1646 pub fn scale(self, s: f32) -> Self {
1647 self.scale2(s, s)
1648 }
1649 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1650 let mut t = self.transform.unwrap_or_else(Transform::identity);
1651 t.scale_x *= sx;
1652 t.scale_y *= sy;
1653 self.transform = Some(t);
1654 self
1655 }
1656 pub fn translate(mut self, x: f32, y: f32) -> Self {
1657 let t = self.transform.unwrap_or_else(Transform::identity);
1658 self.transform = Some(t.combine(&Transform::translate(x, y)));
1659 self
1660 }
1661 pub fn translate_vec2(self, v: Vec2) -> Self {
1662 self.translate(v.x, v.y)
1663 }
1664 pub fn rotate(mut self, radians: f32) -> Self {
1665 let mut t = self.transform.unwrap_or_else(Transform::identity);
1666 t.rotate += radians;
1667 self.transform = Some(t);
1668 self
1669 }
1670 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1671 let mut t = self.transform.unwrap_or_else(Transform::identity);
1672 t.origin_x = x;
1673 t.origin_y = y;
1674 self.transform = Some(t);
1675 self
1676 }
1677 pub fn weight(mut self, w: f32) -> Self {
1678 let w = w.max(0.0);
1679 self.flex_grow = Some(w);
1680 self.flex_shrink = Some(1.0);
1681 self.flex_basis = Some(0.0);
1683 self
1684 }
1685 pub fn repaint_boundary(mut self) -> Self {
1689 self.repaint_boundary = true;
1690 self
1691 }
1692 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1693 self.on_action = Some(Rc::new(f));
1694 self
1695 }
1696
1697 pub fn on_drag_start(
1699 mut self,
1700 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1701 ) -> Self {
1702 self.on_drag_start = Some(Rc::new(f));
1703 self
1704 }
1705
1706 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1708 self.on_drag_end = Some(Rc::new(f));
1709 self
1710 }
1711
1712 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1714 self.on_drag_enter = Some(Rc::new(f));
1715 self
1716 }
1717
1718 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1720 self.on_drag_over = Some(Rc::new(f));
1721 self
1722 }
1723
1724 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1726 self.on_drag_leave = Some(Rc::new(f));
1727 self
1728 }
1729
1730 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1733 self.on_drop = Some(Rc::new(f));
1734 self
1735 }
1736
1737 pub fn draw_drag_decoration(
1742 mut self,
1743 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
1744 ) -> Self {
1745 self.drag_preview = Some(Rc::new(f));
1746 self
1747 }
1748
1749 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
1751 self.drag_preview = Some(preview);
1752 self
1753 }
1754
1755 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
1757 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
1758 }
1759
1760 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
1762 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
1763 }
1764
1765 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1767 self.cursor = Some(c);
1768 self
1769 }
1770
1771 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1775 self.animate_content_size = Some(spec);
1776 self
1777 }
1778
1779 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1782 self.focus_requester = Some(fr);
1783 self
1784 }
1785
1786 pub fn focus_target(mut self) -> Self {
1789 self.focusable = Some(true);
1790 self
1791 }
1792
1793 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1796 self.on_focus_changed = Some(Rc::new(f));
1797 self
1798 }
1799
1800 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
1804 self.on_globally_positioned = Some(Rc::new(f));
1805 self
1806 }
1807
1808 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
1811 self.on_size_changed = Some(Rc::new(f));
1812 self
1813 }
1814
1815 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
1819 self.on_key_event = Some(Rc::new(f));
1820 self
1821 }
1822
1823 pub fn on_preview_key_event(
1827 mut self,
1828 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
1829 ) -> Self {
1830 self.on_preview_key_event = Some(Rc::new(f));
1831 self
1832 }
1833
1834 pub fn blur(mut self, radius_dp: f32) -> Self {
1841 self.blur = Some(BlurStyle {
1842 radius_x: radius_dp.max(0.0),
1843 radius_y: radius_dp.max(0.0),
1844 edge_treatment: BlurredEdgeTreatment::Rectangle,
1845 });
1846 self
1847 }
1848
1849 pub fn blur_with_edge(
1854 mut self,
1855 radius_x: f32,
1856 radius_y: f32,
1857 edge_treatment: BlurredEdgeTreatment,
1858 ) -> Self {
1859 self.blur = Some(BlurStyle {
1860 radius_x: radius_x.max(0.0),
1861 radius_y: radius_y.max(0.0),
1862 edge_treatment,
1863 });
1864 self
1865 }
1866
1867 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (f32, f32) + 'static) -> Self {
1875 self.layout = Some(Rc::new(f));
1876 self
1877 }
1878
1879 pub fn text_input(mut self, config: TextInputConfig) -> Self {
1881 self.text_input = Some(config);
1882 self
1883 }
1884
1885 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
1889 self.indication = Some(factory);
1890 self
1891 }
1892}