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)]
16pub struct StateColors {
17 pub default: Color,
18 pub hovered: Color,
19 pub focused: Color,
21 pub pressed: Color,
22 pub disabled: Color,
23 pub dragged: Color,
25}
26
27#[derive(Clone, Copy, Debug)]
29pub struct StateElevation {
30 pub default: f32,
31 pub hovered: f32,
32 pub focused: f32,
34 pub pressed: f32,
35 pub disabled: f32,
36 pub dragged: f32,
38}
39
40impl StateColors {
41 pub const fn transparent() -> Self {
42 Self {
43 default: Color::TRANSPARENT,
44 hovered: Color::TRANSPARENT,
45 focused: Color::TRANSPARENT,
46 pressed: Color::TRANSPARENT,
47 disabled: Color::TRANSPARENT,
48 dragged: Color::TRANSPARENT,
49 }
50 }
51}
52
53impl StateElevation {
54 pub const fn zero() -> Self {
55 Self {
56 default: 0.0,
57 hovered: 0.0,
58 focused: 0.0,
59 pressed: 0.0,
60 disabled: 0.0,
61 dragged: 0.0,
62 }
63 }
64}
65
66macro_rules! merge_opts {
67 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
68 $( $dst.$f = $src.$f.or($dst.$f); )+
69 };
70}
71macro_rules! merge_flags {
72 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
73 $( $dst.$f |= $src.$f; )+
74 };
75}
76
77macro_rules! impl_option_fields {
78 ($ty:ty, $fn:ident) => {
79 impl $ty {
80 $fn!(replace);
81 }
82 };
83 ($ty:ident) => {
84 impl $ty {
85 pub fn then(mut self, other: Self) -> Self {
88 merge_opts!(self, other;
89 key, size, width, height, required_size,
90 padding, padding_values,
91 min_width, min_height, max_width, max_height,
92 required_min_width, required_max_width,
93 required_min_height, required_max_height,
94 default_min_width, default_min_height,
95 fill_max, fill_max_w, fill_max_h,
96 background, state_colors, state_elevation, border,
97 flex_grow, flex_shrink, flex_basis, flex_wrap, flex_dir,
98 gap, row_gap, column_gap,
99 align_self, justify_content, align_items_container, align_content,
100 clip_rounded, clip_rect, overflow, render_z_index,
101 on_scroll,
102 nested_scroll_connection,
103 scroll,
104 on_pointer_down, on_pointer_move, on_pointer_up,
105 on_pointer_enter, on_pointer_leave,
106 on_click, on_double_click, on_long_click,
107 semantics, alpha, transform,
108 grid, grid_col_span, grid_row_span,
109 position_type,
110 offset_left, offset_right, offset_top, offset_bottom,
111 margin_left, margin_right, margin_top, margin_bottom,
112 aspect_ratio, intrinsic_width, intrinsic_height,
113 painter,
114 on_drag_start, on_drag_end, on_drag_enter, on_drag_over, on_drag_leave, on_drop,
115 drag_preview,
116 on_action, cursor, animate_content_size, focus_requester, on_focus_changed,
117 interaction_source, text_input,
118 );
119 merge_flags!(self, other;
120 hit_passthrough, input_blocker, repaint_boundary, click, disabled,
121 propagate_min, focus_group,
122 );
123
124 if let Some(f) = other.focusable {
125 self.focusable = Some(f);
126 }
127 if other.indication.is_some() {
128 self.indication = other.indication;
129 }
130 if other.z_index != 0.0 {
131 self.z_index = other.z_index;
132 }
133 self
134 }
135 }
136 };
137}
138
139#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
140pub enum ClipOp {
141 #[default]
143 Intersect,
144 Difference,
146}
147
148#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
154pub enum Overflow {
155 #[default]
156 Clip,
157 Visible,
158}
159
160#[derive(Clone, Copy, Debug)]
163pub struct ClipRect {
164 pub left: f32,
165 pub top: f32,
166 pub right: f32,
167 pub bottom: f32,
168 pub op: ClipOp,
169}
170
171#[derive(Clone, Debug)]
172pub struct Border {
173 pub width: f32,
174 pub color: Color,
175 pub radius: [f32; 4],
176}
177
178#[derive(Clone, Copy, Debug, Default)]
179pub struct PaddingValues {
180 pub left: f32,
181 pub right: f32,
182 pub top: f32,
183 pub bottom: f32,
184}
185
186#[derive(Clone, Debug)]
187pub struct GridConfig {
188 pub columns: usize,
189 pub row_gap: f32,
190 pub column_gap: f32,
191}
192
193#[derive(Clone, Copy, Debug, PartialEq)]
196pub enum BlurredEdgeTreatment {
197 Rectangle,
200 Unbounded,
203}
204
205#[derive(Clone, Copy, Debug)]
207pub struct BlurStyle {
208 pub radius_x: f32,
210 pub radius_y: f32,
212 pub edge_treatment: BlurredEdgeTreatment,
214}
215
216#[derive(Clone, Copy, Debug)]
221pub struct LayoutConstraints {
222 pub min_width: f32,
223 pub max_width: f32,
224 pub min_height: f32,
225 pub max_height: f32,
226}
227
228#[derive(Clone, Copy, Debug)]
235pub struct ShadowSpec {
236 pub blur_radius: f32,
237 pub offset_y: f32,
238 pub color: Color,
239}
240
241#[derive(Clone, Copy, Debug)]
242#[non_exhaustive]
243pub enum PositionType {
244 Relative,
245 Absolute,
246}
247
248#[derive(Clone)]
250pub struct TextInputConfig {
251 pub hint: String,
252 pub multiline: bool,
253 pub on_change: Option<Rc<dyn Fn(String)>>,
254 pub on_submit: Option<Rc<dyn Fn(String)>>,
255 pub focus_tracker: Option<Rc<Cell<bool>>>,
256 pub value: String,
257 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
258 pub keyboard_type: crate::text::KeyboardType,
259 pub capitalization: crate::text::KeyboardCapitalization,
260 pub ime_action: crate::text::ImeAction,
261 pub auto_correct_enabled: Option<bool>,
264 pub enabled: bool,
266 pub read_only: bool,
268 pub max_lines: Option<usize>,
270 pub min_lines: usize,
272 pub cursor_color: Option<Color>,
274 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
277 pub text_style: Option<crate::text::TextStyle>,
280 pub keyboard_actions: Option<crate::text::KeyboardActions>,
283 pub interaction_source: Option<InteractionSource>,
285 pub line_limits: Option<crate::text::TextFieldLineLimits>,
287}
288
289impl Default for TextInputConfig {
290 fn default() -> Self {
291 Self {
292 hint: String::new(),
293 multiline: false,
294 on_change: None,
295 on_submit: None,
296 focus_tracker: None,
297 value: String::new(),
298 visual_transformation: None,
299 keyboard_type: crate::text::KeyboardType::default(),
300 capitalization: crate::text::KeyboardCapitalization::default(),
301 ime_action: crate::text::ImeAction::default(),
302 auto_correct_enabled: None,
303 enabled: true,
304 read_only: false,
305 max_lines: None,
306 min_lines: 1,
307 cursor_color: None,
308 on_text_layout: None,
309 text_style: None,
310 keyboard_actions: None,
311 interaction_source: None,
312 line_limits: None,
313 }
314 }
315}
316
317impl std::fmt::Debug for TextInputConfig {
318 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
319 let mut s = f.debug_struct("TextInputConfig");
320 s.field("hint", &self.hint);
321 s.field("multiline", &self.multiline);
322 if self.on_change.is_some() {
323 s.field("on_change", &"…");
324 }
325 if self.on_submit.is_some() {
326 s.field("on_submit", &"…");
327 }
328 if self.focus_tracker.is_some() {
329 s.field("focus_tracker", &"…");
330 }
331 s.field("value", &self.value);
332 if self.visual_transformation.is_some() {
333 s.field("visual_transformation", &"…");
334 }
335 s.field("keyboard_type", &self.keyboard_type);
336 s.field("capitalization", &self.capitalization);
337 s.field("ime_action", &self.ime_action);
338 s.field("auto_correct_enabled", &self.auto_correct_enabled);
339 s.field("enabled", &self.enabled);
340 s.field("read_only", &self.read_only);
341 s.field("max_lines", &self.max_lines);
342 s.field("min_lines", &self.min_lines);
343 s.field("cursor_color", &self.cursor_color);
344 if self.on_text_layout.is_some() {
345 s.field("on_text_layout", &"…");
346 }
347 s.finish()
348 }
349}
350
351#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
354pub enum IntrinsicSize {
355 Min,
356 Max,
357}
358
359static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
360
361pub type PressId = u64;
363
364#[derive(Clone, Copy, Debug, PartialEq)]
372pub enum Interaction {
373 Press(PressId, Vec2),
376 Release(PressId),
378 Cancel(PressId),
381 HoverEnter,
382 HoverLeave,
383 Focus,
384 Unfocus,
385 DragStart,
386 DragStop,
387 DragCancel,
388}
389
390impl Interaction {
391 #[inline]
393 pub fn new_press(position: Vec2) -> Self {
394 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
395 }
396}
397
398#[derive(Clone)]
405pub struct InteractionSource {
406 pub(crate) state: Rc<RefCell<InteractionState>>,
407}
408
409impl InteractionSource {
410 pub fn collect_is_pressed(&self) -> bool {
411 !self.state.borrow().active_presses.is_empty()
412 }
413 pub fn collect_is_hovered(&self) -> bool {
414 self.state.borrow().hovered
415 }
416 pub fn collect_is_focused(&self) -> bool {
417 self.state.borrow().focused
418 }
419
420 pub fn collect_is_focus_visible(&self) -> bool {
422 crate::input::is_focus_visible(self.collect_is_focused())
423 }
424
425 pub fn collect_is_dragged(&self) -> bool {
426 self.state.borrow().dragged > 0
427 }
428 pub fn collect_last_press_position(&self) -> Option<Vec2> {
429 self.state.borrow().last_press_position
430 }
431 pub fn collect_last_press_id(&self) -> Option<PressId> {
432 self.state.borrow().last_press_id
433 }
434 pub fn stable_id(&self) -> *const () {
436 Rc::as_ptr(&self.state) as *const ()
437 }
438 pub fn to_mutable(&self) -> MutableInteractionSource {
442 MutableInteractionSource {
443 state: self.state.clone(),
444 }
445 }
446
447 pub fn reset(&self) {
449 self.to_mutable().reset();
450 }
451
452 pub fn reset_hover(&self) {
454 self.to_mutable().reset_hover();
455 }
456}
457
458#[derive(Clone)]
468pub struct MutableInteractionSource {
469 pub(crate) state: Rc<RefCell<InteractionState>>,
470}
471
472impl std::fmt::Debug for MutableInteractionSource {
473 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
474 f.debug_struct("MutableInteractionSource")
475 .finish_non_exhaustive()
476 }
477}
478
479impl MutableInteractionSource {
480 pub fn new() -> Self {
481 Self {
482 state: Rc::new(RefCell::new(InteractionState::default())),
483 }
484 }
485
486 pub fn emit(&self, interaction: Interaction) {
488 let changed = {
489 let mut s = self.state.borrow_mut();
490 match interaction {
491 Interaction::Press(id, pos) => {
492 let inserted = s.active_presses.insert(id);
493 s.last_press_id = Some(id);
494 s.last_press_position = Some(pos);
495 inserted
496 }
497 Interaction::Release(id) | Interaction::Cancel(id) => {
498 if s.active_presses.remove(&id) {
499 true
500 } else if id == 0 {
501 if let Some(any) = s.active_presses.iter().next().copied() {
502 s.active_presses.remove(&any);
503 true
504 } else {
505 false
506 }
507 } else {
508 false
509 }
510 }
511 Interaction::HoverEnter => {
512 let changed = !s.hovered;
513 s.hovered = true;
514 changed
515 }
516 Interaction::HoverLeave => {
517 let changed = s.hovered;
518 s.hovered = false;
519 if !s.active_presses.is_empty() {
521 s.active_presses.clear();
522 true
523 } else {
524 changed
525 }
526 }
527 Interaction::Focus => {
528 let changed = !s.focused;
529 s.focused = true;
530 changed
531 }
532 Interaction::Unfocus => {
533 let changed = s.focused;
534 s.focused = false;
535 changed
536 }
537 Interaction::DragStart => {
538 let changed = s.dragged == 0;
539 s.dragged = s.dragged.saturating_add(1);
540 changed
541 }
542 Interaction::DragStop | Interaction::DragCancel => {
543 let was = s.dragged;
544 s.dragged = s.dragged.saturating_sub(1);
545 was != s.dragged
546 }
547 }
548 };
549 if changed {
550 crate::frame_clock::request_frame();
552 }
553 }
554
555 pub fn source(&self) -> InteractionSource {
557 InteractionSource {
558 state: self.state.clone(),
559 }
560 }
561
562 pub fn reset(&self) {
564 let mut s = self.state.borrow_mut();
565 *s = InteractionState::default();
566 crate::frame_clock::request_frame();
567 }
568
569 pub fn reset_hover(&self) {
571 let mut s = self.state.borrow_mut();
572 if s.hovered {
573 s.hovered = false;
574 crate::frame_clock::request_frame();
575 }
576 }
577}
578
579impl Default for MutableInteractionSource {
580 fn default() -> Self {
581 Self::new()
582 }
583}
584
585#[derive(Clone, Default)]
586pub(crate) struct InteractionState {
587 active_presses: HashSet<PressId>,
589 hovered: bool,
590 focused: bool,
591 dragged: u32,
592 pub(crate) last_press_position: Option<Vec2>,
594 pub(crate) last_press_id: Option<PressId>,
596}
597
598#[derive(Clone, Default)]
599pub struct Modifier {
600 pub key: Option<u64>,
606
607 pub size: Option<Size>,
608 pub width: Option<f32>,
609 pub height: Option<f32>,
610 pub required_size: Option<Size>,
611 pub fill_max: Option<f32>,
612 pub fill_max_w: Option<f32>,
613 pub fill_max_h: Option<f32>,
614 pub padding: Option<f32>,
615 pub padding_values: Option<PaddingValues>,
616 pub min_width: Option<f32>,
617 pub min_height: Option<f32>,
618 pub max_width: Option<f32>,
619 pub max_height: Option<f32>,
620 pub required_min_width: Option<f32>,
622 pub required_max_width: Option<f32>,
624 pub required_min_height: Option<f32>,
626 pub required_max_height: Option<f32>,
628 pub default_min_width: Option<f32>,
631 pub default_min_height: Option<f32>,
632 pub background: Option<Brush>,
633 pub state_colors: Option<StateColors>,
634 pub state_elevation: Option<StateElevation>,
635
636 pub border: Option<Border>,
637 pub flex_grow: Option<f32>,
638 pub flex_shrink: Option<f32>,
639 pub flex_basis: Option<f32>,
640 pub flex_wrap: Option<FlexWrap>,
641 pub flex_dir: Option<FlexDirection>,
642 pub gap: Option<f32>,
643 pub row_gap: Option<f32>,
644 pub column_gap: Option<f32>,
645 pub align_self: Option<AlignSelf>,
646 pub justify_content: Option<JustifyContent>,
647 pub align_items_container: Option<AlignItems>,
648 pub align_content: Option<AlignContent>,
649 pub clip_rounded: Option<[f32; 4]>,
650 pub clip_rect: Option<ClipRect>,
653 pub overflow: Option<Overflow>,
658 pub z_index: f32,
660 pub render_z_index: Option<f32>,
662 pub hit_passthrough: bool,
664 pub input_blocker: bool,
666 pub repaint_boundary: bool,
667 pub click: bool,
668 pub disabled: bool,
670 pub focusable: Option<bool>,
674 pub propagate_min: bool,
676 pub focus_group: bool,
679 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
680 pub scroll: Option<crate::scroll::ScrollBinding>,
686 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
695 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
696 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
697 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
698 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
699 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
700 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
701 pub on_click: Option<Rc<dyn Fn()>>,
703 pub on_double_click: Option<Rc<dyn Fn()>>,
705 pub on_long_click: Option<Rc<dyn Fn()>>,
707 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
710 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
713 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
716 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
719 pub blur: Option<BlurStyle>,
724 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (f32, f32)>>,
729 pub semantics: Option<crate::Semantics>,
730 pub alpha: Option<f32>,
731 pub graphics_layer: Option<f32>,
732 pub shadow: Option<ShadowSpec>,
733 pub transform: Option<Transform>,
734 pub grid: Option<GridConfig>,
735 pub grid_col_span: Option<u16>,
736 pub grid_row_span: Option<u16>,
737 pub position_type: Option<PositionType>,
738 pub offset_left: Option<f32>,
739 pub offset_right: Option<f32>,
740 pub offset_top: Option<f32>,
741 pub offset_bottom: Option<f32>,
742
743 pub margin_left: Option<f32>,
744 pub margin_right: Option<f32>,
745 pub margin_top: Option<f32>,
746 pub margin_bottom: Option<f32>,
747 pub aspect_ratio: Option<f32>,
748 pub intrinsic_width: Option<IntrinsicSize>,
750 pub intrinsic_height: Option<IntrinsicSize>,
752 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
753
754 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
756 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
757 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
758 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
759 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
760 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
761 pub drag_preview: Option<crate::dnd::DragPreview>,
763
764 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
765
766 pub cursor: Option<crate::CursorIcon>,
768
769 pub animate_content_size: Option<AnimationSpec>,
772
773 pub focus_requester: Option<crate::runtime::FocusRequester>,
777
778 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
781
782 pub interaction_source: Option<InteractionSource>,
789
790 pub text_input: Option<TextInputConfig>,
792
793 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
795}
796
797impl std::fmt::Debug for Modifier {
798 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
799 let mut s = f.debug_struct("Modifier");
800
801 macro_rules! opt_val {
802 ($($name:ident),+ $(,)?) => {
803 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
804 };
805 }
806 if self.indication.is_some() {
807 s.field("indication", &"…");
808 }
809
810 opt_val!(
811 key,
812 size,
813 width,
814 height,
815 required_size,
816 padding,
817 padding_values,
818 min_width,
819 min_height,
820 max_width,
821 max_height,
822 required_min_width,
823 required_max_width,
824 required_min_height,
825 required_max_height,
826 default_min_width,
827 default_min_height,
828 fill_max,
829 fill_max_w,
830 fill_max_h,
831 background,
832 state_colors,
833 state_elevation,
834 border,
835 flex_grow,
836 flex_shrink,
837 flex_basis,
838 flex_wrap,
839 flex_dir,
840 gap,
841 row_gap,
842 column_gap,
843 align_self,
844 justify_content,
845 align_items_container,
846 align_content,
847 clip_rounded,
848 clip_rect,
849 render_z_index,
850 semantics,
851 alpha,
852 transform,
853 grid,
854 grid_col_span,
855 grid_row_span,
856 position_type,
857 offset_left,
858 offset_right,
859 offset_top,
860 offset_bottom,
861 margin_left,
862 margin_right,
863 margin_top,
864 margin_bottom,
865 aspect_ratio,
866 intrinsic_width,
867 intrinsic_height,
868 cursor,
869 animate_content_size,
870 blur,
871 );
872
873 macro_rules! opt_cb {
874 ($($name:ident),+ $(,)?) => {
875 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
876 };
877 }
878 opt_cb!(
879 on_scroll,
880 scroll,
881 nested_scroll_connection,
882 on_pointer_down,
883 on_pointer_move,
884 on_pointer_up,
885 on_pointer_cancel,
886 on_pointer_enter,
887 on_pointer_leave,
888 on_click,
889 on_double_click,
890 on_long_click,
891 on_globally_positioned,
892 on_size_changed,
893 on_key_event,
894 on_preview_key_event,
895 painter,
896 on_drag_start,
897 on_drag_end,
898 on_drag_enter,
899 on_drag_over,
900 on_drag_leave,
901 on_drop,
902 drag_preview,
903 on_action,
904 on_focus_changed,
905 interaction_source,
906 text_input,
907 layout,
908 );
909
910 macro_rules! flag {
911 ($($name:ident),+ $(,)?) => {
912 $( if self.$name { s.field(stringify!($name), &true); } )+
913 };
914 }
915 flag!(
916 hit_passthrough,
917 input_blocker,
918 repaint_boundary,
919 click,
920 disabled,
921 propagate_min,
922 focus_group,
923 );
924
925 if let Some(f) = self.focusable {
926 s.field("focusable", &f);
927 }
928 if self.z_index != 0.0 {
929 s.field("z_index", &self.z_index);
930 }
931
932 s.finish()
933 }
934}
935
936impl_option_fields!(Modifier);
937
938#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
942pub enum Alignment {
943 TopStart,
944 TopCenter,
945 TopEnd,
946 CenterStart,
947 #[default]
948 Center,
949 CenterEnd,
950 BottomStart,
951 BottomCenter,
952 BottomEnd,
953}
954
955impl Alignment {
956 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
958 use AlignItems as AI;
959 use JustifyContent as JC;
960 match self {
961 Self::TopStart => (AI::START, JC::START),
962 Self::TopCenter => (AI::START, JC::CENTER),
963 Self::TopEnd => (AI::START, JC::END),
964 Self::CenterStart => (AI::CENTER, JC::START),
965 Self::Center => (AI::CENTER, JC::CENTER),
966 Self::CenterEnd => (AI::CENTER, JC::END),
967 Self::BottomStart => (AI::END, JC::START),
968 Self::BottomCenter => (AI::END, JC::CENTER),
969 Self::BottomEnd => (AI::END, JC::END),
970 }
971 }
972}
973
974impl Modifier {
975 pub fn new() -> Self {
976 Self::default()
977 }
978
979 pub fn key(mut self, key: u64) -> Self {
982 self.key = Some(key);
983 self
984 }
985
986 pub fn size(mut self, w: f32, h: f32) -> Self {
987 self.size = Some(Size {
988 width: w,
989 height: h,
990 });
991 self
992 }
993 pub fn width(mut self, w: f32) -> Self {
994 self.width = Some(w);
995 self
996 }
997 pub fn height(mut self, h: f32) -> Self {
998 self.height = Some(h);
999 self
1000 }
1001 pub fn required_size(mut self, w: f32, h: f32) -> Self {
1006 self.required_size = Some(Size {
1007 width: w,
1008 height: h,
1009 });
1010 self
1011 }
1012 pub fn required_width_in(mut self, min: f32, max: f32) -> Self {
1013 self.required_min_width = Some(min.max(0.0));
1014 self.required_max_width = Some(max.max(0.0));
1015 self
1016 }
1017 pub fn required_height_in(mut self, min: f32, max: f32) -> Self {
1018 self.required_min_height = Some(min.max(0.0));
1019 self.required_max_height = Some(max.max(0.0));
1020 self
1021 }
1022 pub fn required_min_width(mut self, w: f32) -> Self {
1023 self.required_min_width = Some(w.max(0.0));
1024 self
1025 }
1026 pub fn required_max_width(mut self, w: f32) -> Self {
1027 self.required_max_width = Some(w.max(0.0));
1028 self
1029 }
1030 pub fn required_min_height(mut self, h: f32) -> Self {
1031 self.required_min_height = Some(h.max(0.0));
1032 self
1033 }
1034 pub fn required_max_height(mut self, h: f32) -> Self {
1035 self.required_max_height = Some(h.max(0.0));
1036 self
1037 }
1038 pub fn default_min_size(mut self, w: f32, h: f32) -> Self {
1040 self.default_min_width = Some(w.max(0.0));
1041 self.default_min_height = Some(h.max(0.0));
1042 self
1043 }
1044 pub fn fill_max_size(mut self) -> Self {
1047 self.fill_max = Some(1.0);
1048 self
1049 }
1050 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
1051 self.fill_max = Some(fraction.clamp(0.0, 1.0));
1052 self
1053 }
1054 pub fn fill_max_width(mut self) -> Self {
1056 self.fill_max_w = Some(1.0);
1057 self
1058 }
1059 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
1060 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
1061 self
1062 }
1063 pub fn fill_max_height(mut self) -> Self {
1065 self.fill_max_h = Some(1.0);
1066 self
1067 }
1068 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
1069 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
1070 self
1071 }
1072 pub fn padding(mut self, v: f32) -> Self {
1073 self.padding = Some(v);
1074 self
1075 }
1076 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
1077 self.padding_values = Some(padding);
1078 self
1079 }
1080 pub fn ime_padding(mut self) -> Self {
1083 let insets = crate::locals::window_insets();
1084 let scale = crate::locals::effective_density_scale();
1085 let mut p = self.padding_values.unwrap_or_default();
1086 p.bottom += insets.ime_bottom / scale;
1087 self.padding_values = Some(p);
1088 self
1089 }
1090 pub fn system_bars_padding(mut self) -> Self {
1092 let insets = crate::locals::window_insets();
1093 let scale = crate::locals::effective_density_scale();
1094 let mut p = self.padding_values.unwrap_or_default();
1095 p.top += insets.top / scale;
1096 p.bottom += insets.bottom / scale;
1097 self.padding_values = Some(p);
1098 self
1099 }
1100 pub fn status_bars_padding(mut self) -> Self {
1102 let insets = crate::locals::window_insets();
1103 let scale = crate::locals::effective_density_scale();
1104 let mut p = self.padding_values.unwrap_or_default();
1105 p.top += insets.top / scale;
1106 self.padding_values = Some(p);
1107 self
1108 }
1109 pub fn navigation_bars_padding(mut self) -> Self {
1111 let insets = crate::locals::window_insets();
1112 let scale = crate::locals::effective_density_scale();
1113 let mut p = self.padding_values.unwrap_or_default();
1114 p.bottom += insets.bottom / scale;
1115 self.padding_values = Some(p);
1116 self
1117 }
1118 pub fn min_size(mut self, w: f32, h: f32) -> Self {
1119 self.min_width = Some(w);
1120 self.min_height = Some(h);
1121 self
1122 }
1123 pub fn max_size(mut self, w: f32, h: f32) -> Self {
1124 self.max_width = Some(w);
1125 self.max_height = Some(h);
1126 self
1127 }
1128 pub fn min_width(mut self, w: f32) -> Self {
1129 self.min_width = Some(w);
1130 self
1131 }
1132 pub fn min_height(mut self, h: f32) -> Self {
1133 self.min_height = Some(h);
1134 self
1135 }
1136 pub fn max_width(mut self, w: f32) -> Self {
1137 self.max_width = Some(w);
1138 self
1139 }
1140 pub fn max_height(mut self, h: f32) -> Self {
1141 self.max_height = Some(h);
1142 self
1143 }
1144 pub fn background(mut self, color: Color) -> Self {
1146 self.background = Some(Brush::Solid(color));
1147 self
1148 }
1149 pub fn background_brush(mut self, brush: Brush) -> Self {
1151 self.background = Some(brush);
1152 self
1153 }
1154 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
1155 self.border = Some(Border {
1156 width,
1157 color,
1158 radius: [radius; 4],
1159 });
1160 self
1161 }
1162 pub fn border_radii(mut self, width: f32, color: Color, radii: [f32; 4]) -> Self {
1163 self.border = Some(Border {
1164 width,
1165 color,
1166 radius: radii,
1167 });
1168 self
1169 }
1170 pub fn flex_grow(mut self, v: f32) -> Self {
1171 self.flex_grow = Some(v);
1172 self
1173 }
1174 pub fn flex_shrink(mut self, v: f32) -> Self {
1175 self.flex_shrink = Some(v);
1176 self
1177 }
1178 pub fn flex_basis(mut self, v: f32) -> Self {
1179 self.flex_basis = Some(v);
1180 self
1181 }
1182 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1183 self.flex_wrap = Some(w);
1184 self
1185 }
1186 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1187 self.flex_dir = Some(d);
1188 self
1189 }
1190 pub fn gap(mut self, v: f32) -> Self {
1191 let v = v.max(0.0);
1192 self.gap = Some(v);
1193 self.row_gap = Some(v);
1194 self.column_gap = Some(v);
1195 self
1196 }
1197 pub fn row_gap(mut self, v: f32) -> Self {
1198 self.row_gap = Some(v.max(0.0));
1199 self
1200 }
1201 pub fn column_gap(mut self, v: f32) -> Self {
1202 self.column_gap = Some(v.max(0.0));
1203 self
1204 }
1205 pub fn align_self(mut self, a: AlignSelf) -> Self {
1206 self.align_self = Some(a);
1207 self
1208 }
1209 pub fn align_self_center(mut self) -> Self {
1210 self.align_self = Some(AlignSelf::CENTER);
1211 self
1212 }
1213 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1214 self.justify_content = Some(j);
1215 self
1216 }
1217 pub fn align_items(mut self, a: AlignItems) -> Self {
1218 self.align_items_container = Some(a);
1219 self
1220 }
1221 pub fn content_alignment(self, alignment: Alignment) -> Self {
1224 let (ai, jc) = alignment.to_flex();
1225 self.align_items(ai).justify_content(jc)
1226 }
1227 pub fn align_content(mut self, a: AlignContent) -> Self {
1228 self.align_content = Some(a);
1229 self
1230 }
1231 pub fn clip_rounded(mut self, radius: f32) -> Self {
1232 self.clip_rounded = Some([radius; 4]);
1233 self
1234 }
1235 pub fn clip_rounded_radii(mut self, radii: [f32; 4]) -> Self {
1236 self.clip_rounded = Some(radii);
1237 self
1238 }
1239 pub fn clip_rect(mut self, left: f32, top: f32, right: f32, bottom: f32, op: ClipOp) -> Self {
1242 self.clip_rect = Some(ClipRect {
1243 left,
1244 top,
1245 right,
1246 bottom,
1247 op,
1248 });
1249 self
1250 }
1251 pub fn overflow(mut self, overflow: Overflow) -> Self {
1252 self.overflow = Some(overflow);
1253 self
1254 }
1255 pub fn z_index(mut self, z: f32) -> Self {
1256 self.z_index = z;
1257 self
1258 }
1259
1260 pub fn render_z_index(mut self, z: f32) -> Self {
1263 self.render_z_index = Some(z);
1264 self
1265 }
1266
1267 pub fn input_blocker(mut self) -> Self {
1269 self.input_blocker = true;
1270 self
1271 }
1272
1273 pub fn hit_passthrough(mut self) -> Self {
1274 self.hit_passthrough = true;
1275 self
1276 }
1277 pub fn clickable(mut self) -> Self {
1278 self.click = true;
1279 if self.indication.is_none() {
1280 self.indication = crate::locals::local_indication();
1281 }
1282 self
1283 }
1284 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1287 self.click = true;
1288 self.interaction_source = Some(source.source());
1289 if self.indication.is_none() {
1290 self.indication = crate::locals::local_indication();
1291 }
1292 self
1293 }
1294 pub fn state_colors(mut self, colors: StateColors) -> Self {
1297 self.state_colors = Some(colors);
1298 self
1299 }
1300 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1302 self.state_elevation = Some(elev);
1303 self
1304 }
1305 pub fn disabled(mut self) -> Self {
1307 self.disabled = true;
1308 self
1309 }
1310 pub fn enabled(mut self, enabled: bool) -> Self {
1312 self.disabled = !enabled;
1313 self
1314 }
1315 pub fn focusable(mut self, focusable: bool) -> Self {
1320 self.focusable = Some(focusable);
1321 self
1322 }
1323 pub fn focus_group(mut self) -> Self {
1326 self.focus_group = true;
1327 self
1328 }
1329 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1340 self.interaction_source = Some(source.source());
1341 self
1342 }
1343 pub fn hoverable(
1346 mut self,
1347 on_enter: impl Fn() + 'static,
1348 on_leave: impl Fn() + 'static,
1349 ) -> Self {
1350 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1351 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1352 self
1353 }
1354 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1358 self.interaction_source = Some(source.source());
1359 self
1360 }
1361 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1364 self.propagate_min = propagate;
1365 self
1366 }
1367 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1368 self.on_scroll = Some(Rc::new(f));
1369 self
1370 }
1371 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1375 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1376 self
1377 }
1378 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1380 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1381 self
1382 }
1383 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1385 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1386 self
1387 }
1388 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1395 self.nested_scroll_connection = Some(conn);
1396 self
1397 }
1398 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1399 self.on_pointer_down = Some(Rc::new(f));
1400 self
1401 }
1402 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1403 self.on_pointer_move = Some(Rc::new(f));
1404 self
1405 }
1406 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1407 self.on_pointer_up = Some(Rc::new(f));
1408 self
1409 }
1410 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1411 self.on_pointer_cancel = Some(Rc::new(f));
1412 self
1413 }
1414 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1415 self.on_pointer_enter = Some(Rc::new(f));
1416 self
1417 }
1418 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1419 self.on_pointer_leave = Some(Rc::new(f));
1420 self
1421 }
1422 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1423 self.on_click = Some(Rc::new(f));
1424 self.click = true;
1425 if self.semantics.is_none() {
1426 self.semantics = Some(crate::Semantics::new(crate::Role::Button));
1427 }
1428 self
1429 }
1430 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1431 self.on_double_click = Some(Rc::new(f));
1432 self.click = true;
1433 self
1434 }
1435 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1436 self.on_long_click = Some(Rc::new(f));
1437 self.click = true;
1438 self
1439 }
1440 pub fn clickable_ext(
1441 mut self,
1442 enabled: bool,
1443 on_click_label: Option<String>,
1444 role: Option<crate::semantics::Role>,
1445 on_click: impl Fn() + 'static,
1446 ) -> Self {
1447 if !enabled {
1448 let mut s = self.semantics.clone().unwrap_or_else(|| {
1449 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1450 });
1451 s.enabled = false;
1452 if let Some(r) = role {
1453 s.role = r;
1454 }
1455 if let Some(l) = on_click_label {
1456 s.label = Some(l);
1457 }
1458 return self
1459 .clickable()
1460 .enabled(false)
1461 .default_min_size(48.0, 48.0)
1462 .semantics(s);
1463 }
1464 self = self.clickable().on_click(on_click);
1465 if role.is_some() || on_click_label.is_some() {
1466 let mut s = self.semantics.clone().unwrap_or_else(|| {
1467 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1468 });
1469 s.enabled = true;
1470 if let Some(r) = role {
1471 s.role = r;
1472 }
1473 if let Some(l) = on_click_label {
1474 s.label = Some(l);
1475 }
1476 self = self.semantics(s);
1477 }
1478 self.default_min_size(48.0, 48.0)
1479 }
1480 pub fn combined_clickable(
1481 mut self,
1482 enabled: bool,
1483 on_click_label: Option<String>,
1484 role: Option<crate::semantics::Role>,
1485 on_long_click_label: Option<String>,
1486 on_click: impl Fn() + 'static,
1487 on_long_click: Option<impl Fn() + 'static>,
1488 on_double_click: Option<impl Fn() + 'static>,
1489 ) -> Self {
1490 let _ = on_long_click_label;
1491 if !enabled {
1492 return self.clickable_ext(false, on_click_label, role, || {});
1493 }
1494 self = self.clickable_ext(true, on_click_label, role, on_click);
1495 if let Some(f) = on_long_click {
1496 self = self.on_long_click(f);
1497 }
1498 if let Some(f) = on_double_click {
1499 self = self.on_double_click(f);
1500 }
1501 self.default_min_size(48.0, 48.0)
1502 }
1503 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1504 self.semantics = Some(s);
1505 self
1506 }
1507 pub fn alpha(mut self, a: f32) -> Self {
1508 self.alpha = Some(a);
1509 self
1510 }
1511 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1516 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1517 self
1518 }
1519 pub fn shadow(mut self, blur_radius: f32, offset_y: f32) -> Self {
1523 self.shadow = Some(ShadowSpec {
1524 blur_radius: blur_radius.max(0.0),
1525 offset_y,
1526 color: Color(0, 0, 0, 64),
1527 });
1528 self
1529 }
1530 pub fn shadow_with_color(mut self, blur_radius: f32, offset_y: f32, color: Color) -> Self {
1532 self.shadow = Some(ShadowSpec {
1533 blur_radius: blur_radius.max(0.0),
1534 offset_y,
1535 color,
1536 });
1537 self
1538 }
1539 pub fn elevation(mut self, level: f32) -> Self {
1543 if level <= 0.0 {
1544 self.shadow = None;
1545 return self;
1546 }
1547 self.shadow = Some(ShadowSpec {
1548 blur_radius: level * 2.0,
1549 offset_y: level * 0.5,
1550 color: Color(0, 0, 0, (level * 8.0).clamp(8.0, 80.0) as u8),
1551 });
1552 self
1553 }
1554 pub fn transform(mut self, t: Transform) -> Self {
1555 self.transform = Some(t);
1556 self
1557 }
1558 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
1559 self.grid = Some(GridConfig {
1560 columns,
1561 row_gap,
1562 column_gap,
1563 });
1564 self
1565 }
1566 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1567 self.grid_col_span = Some(col_span);
1568 self.grid_row_span = Some(row_span);
1569 self
1570 }
1571 pub fn absolute(mut self) -> Self {
1572 self.position_type = Some(PositionType::Absolute);
1573 self
1574 }
1575 pub fn offset(
1576 mut self,
1577 left: Option<f32>,
1578 top: Option<f32>,
1579 right: Option<f32>,
1580 bottom: Option<f32>,
1581 ) -> Self {
1582 self.offset_left = left;
1583 self.offset_top = top;
1584 self.offset_right = right;
1585 self.offset_bottom = bottom;
1586 self
1587 }
1588 pub fn offset_left(mut self, v: f32) -> Self {
1589 self.offset_left = Some(v);
1590 self
1591 }
1592 pub fn offset_right(mut self, v: f32) -> Self {
1593 self.offset_right = Some(v);
1594 self
1595 }
1596 pub fn offset_top(mut self, v: f32) -> Self {
1597 self.offset_top = Some(v);
1598 self
1599 }
1600 pub fn offset_bottom(mut self, v: f32) -> Self {
1601 self.offset_bottom = Some(v);
1602 self
1603 }
1604 pub fn margin(mut self, v: f32) -> Self {
1605 self.margin_left = Some(v);
1606 self.margin_right = Some(v);
1607 self.margin_top = Some(v);
1608 self.margin_bottom = Some(v);
1609 self
1610 }
1611
1612 pub fn margin_horizontal(mut self, v: f32) -> Self {
1613 self.margin_left = Some(v);
1614 self.margin_right = Some(v);
1615 self
1616 }
1617
1618 pub fn margin_vertical(mut self, v: f32) -> Self {
1619 self.margin_top = Some(v);
1620 self.margin_bottom = Some(v);
1621 self
1622 }
1623 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1624 self.aspect_ratio = Some(ratio);
1625 self
1626 }
1627 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1629 self.intrinsic_width = Some(mode);
1630 self
1631 }
1632 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1634 self.intrinsic_height = Some(mode);
1635 self
1636 }
1637 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1638 self.painter = Some(Rc::new(f));
1639 self
1640 }
1641 pub fn scale(self, s: f32) -> Self {
1642 self.scale2(s, s)
1643 }
1644 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1645 let mut t = self.transform.unwrap_or_else(Transform::identity);
1646 t.scale_x *= sx;
1647 t.scale_y *= sy;
1648 self.transform = Some(t);
1649 self
1650 }
1651 pub fn translate(mut self, x: f32, y: f32) -> Self {
1652 let t = self.transform.unwrap_or_else(Transform::identity);
1653 self.transform = Some(t.combine(&Transform::translate(x, y)));
1654 self
1655 }
1656 pub fn translate_vec2(self, v: Vec2) -> Self {
1657 self.translate(v.x, v.y)
1658 }
1659 pub fn rotate(mut self, radians: f32) -> Self {
1660 let mut t = self.transform.unwrap_or_else(Transform::identity);
1661 t.rotate += radians;
1662 self.transform = Some(t);
1663 self
1664 }
1665 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1666 let mut t = self.transform.unwrap_or_else(Transform::identity);
1667 t.origin_x = x;
1668 t.origin_y = y;
1669 self.transform = Some(t);
1670 self
1671 }
1672 pub fn weight(mut self, w: f32) -> Self {
1673 let w = w.max(0.0);
1674 self.flex_grow = Some(w);
1675 self.flex_shrink = Some(1.0);
1676 self.flex_basis = Some(0.0);
1678 self
1679 }
1680 pub fn repaint_boundary(mut self) -> Self {
1684 self.repaint_boundary = true;
1685 self
1686 }
1687 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1688 self.on_action = Some(Rc::new(f));
1689 self
1690 }
1691
1692 pub fn on_drag_start(
1694 mut self,
1695 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1696 ) -> Self {
1697 self.on_drag_start = Some(Rc::new(f));
1698 self
1699 }
1700
1701 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1703 self.on_drag_end = Some(Rc::new(f));
1704 self
1705 }
1706
1707 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1709 self.on_drag_enter = Some(Rc::new(f));
1710 self
1711 }
1712
1713 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1715 self.on_drag_over = Some(Rc::new(f));
1716 self
1717 }
1718
1719 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1721 self.on_drag_leave = Some(Rc::new(f));
1722 self
1723 }
1724
1725 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1728 self.on_drop = Some(Rc::new(f));
1729 self
1730 }
1731
1732 pub fn draw_drag_decoration(
1737 mut self,
1738 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
1739 ) -> Self {
1740 self.drag_preview = Some(Rc::new(f));
1741 self
1742 }
1743
1744 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
1746 self.drag_preview = Some(preview);
1747 self
1748 }
1749
1750 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
1752 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
1753 }
1754
1755 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
1757 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
1758 }
1759
1760 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1762 self.cursor = Some(c);
1763 self
1764 }
1765
1766 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1770 self.animate_content_size = Some(spec);
1771 self
1772 }
1773
1774 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1777 self.focus_requester = Some(fr);
1778 self
1779 }
1780
1781 pub fn focus_target(mut self) -> Self {
1784 self.focusable = Some(true);
1785 self
1786 }
1787
1788 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1791 self.on_focus_changed = Some(Rc::new(f));
1792 self
1793 }
1794
1795 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
1799 self.on_globally_positioned = Some(Rc::new(f));
1800 self
1801 }
1802
1803 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
1806 self.on_size_changed = Some(Rc::new(f));
1807 self
1808 }
1809
1810 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
1814 self.on_key_event = Some(Rc::new(f));
1815 self
1816 }
1817
1818 pub fn on_preview_key_event(
1822 mut self,
1823 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
1824 ) -> Self {
1825 self.on_preview_key_event = Some(Rc::new(f));
1826 self
1827 }
1828
1829 pub fn blur(mut self, radius_dp: f32) -> Self {
1836 self.blur = Some(BlurStyle {
1837 radius_x: radius_dp.max(0.0),
1838 radius_y: radius_dp.max(0.0),
1839 edge_treatment: BlurredEdgeTreatment::Rectangle,
1840 });
1841 self
1842 }
1843
1844 pub fn blur_with_edge(
1849 mut self,
1850 radius_x: f32,
1851 radius_y: f32,
1852 edge_treatment: BlurredEdgeTreatment,
1853 ) -> Self {
1854 self.blur = Some(BlurStyle {
1855 radius_x: radius_x.max(0.0),
1856 radius_y: radius_y.max(0.0),
1857 edge_treatment,
1858 });
1859 self
1860 }
1861
1862 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (f32, f32) + 'static) -> Self {
1870 self.layout = Some(Rc::new(f));
1871 self
1872 }
1873
1874 pub fn text_input(mut self, config: TextInputConfig) -> Self {
1876 self.text_input = Some(config);
1877 self
1878 }
1879
1880 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
1884 self.indication = Some(factory);
1885 self
1886 }
1887}