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 paint_callback,
115 on_drag_start, on_drag_end, on_drag_enter, on_drag_over, on_drag_leave, on_drop,
116 drag_preview,
117 on_action, cursor, animate_content_size, focus_requester, on_focus_changed,
118 interaction_source, text_input,
119 );
120 merge_flags!(self, other;
121 hit_passthrough, input_blocker, repaint_boundary, click, disabled,
122 propagate_min, focus_group,
123 );
124
125 if let Some(f) = other.focusable {
126 self.focusable = Some(f);
127 }
128 if other.indication.is_some() {
129 self.indication = other.indication;
130 }
131 if other.z_index != 0.0 {
132 self.z_index = other.z_index;
133 }
134 self
135 }
136 }
137 };
138}
139
140#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
141pub enum ClipOp {
142 #[default]
144 Intersect,
145 Difference,
147}
148
149#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
155pub enum Overflow {
156 #[default]
157 Clip,
158 Visible,
159}
160
161#[derive(Clone, Copy, Debug)]
164pub struct ClipRect {
165 pub left: f32,
166 pub top: f32,
167 pub right: f32,
168 pub bottom: f32,
169 pub op: ClipOp,
170}
171
172#[derive(Clone, Debug)]
173pub struct Border {
174 pub width: f32,
175 pub color: Color,
176 pub radius: [f32; 4],
177}
178
179#[derive(Clone, Copy, Debug, Default)]
180pub struct PaddingValues {
181 pub left: f32,
182 pub right: f32,
183 pub top: f32,
184 pub bottom: f32,
185}
186
187#[derive(Clone, Debug)]
188pub struct GridConfig {
189 pub columns: usize,
190 pub row_gap: f32,
191 pub column_gap: f32,
192}
193
194#[derive(Clone, Copy, Debug, PartialEq)]
197pub enum BlurredEdgeTreatment {
198 Rectangle,
201 Unbounded,
204}
205
206#[derive(Clone, Copy, Debug)]
208pub struct BlurStyle {
209 pub radius_x: f32,
211 pub radius_y: f32,
213 pub edge_treatment: BlurredEdgeTreatment,
215}
216
217#[derive(Clone, Copy, Debug)]
222pub struct LayoutConstraints {
223 pub min_width: f32,
224 pub max_width: f32,
225 pub min_height: f32,
226 pub max_height: f32,
227}
228
229#[derive(Clone, Copy, Debug)]
236pub struct ShadowSpec {
237 pub blur_radius: f32,
238 pub offset_y: f32,
239 pub color: Color,
240}
241
242#[derive(Clone, Copy, Debug)]
243#[non_exhaustive]
244pub enum PositionType {
245 Relative,
246 Absolute,
247}
248
249#[derive(Clone)]
251pub struct TextInputConfig {
252 pub hint: String,
253 pub multiline: bool,
254 pub on_change: Option<Rc<dyn Fn(String)>>,
255 pub on_submit: Option<Rc<dyn Fn(String)>>,
256 pub focus_tracker: Option<Rc<Cell<bool>>>,
257 pub value: String,
258 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
259 pub keyboard_type: crate::text::KeyboardType,
260 pub capitalization: crate::text::KeyboardCapitalization,
261 pub ime_action: crate::text::ImeAction,
262 pub auto_correct_enabled: Option<bool>,
265 pub enabled: bool,
267 pub read_only: bool,
269 pub max_lines: Option<usize>,
271 pub min_lines: usize,
273 pub cursor_color: Option<Color>,
275 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
278 pub text_style: Option<crate::text::TextStyle>,
281 pub keyboard_actions: Option<crate::text::KeyboardActions>,
284 pub interaction_source: Option<InteractionSource>,
286 pub line_limits: Option<crate::text::TextFieldLineLimits>,
288}
289
290impl Default for TextInputConfig {
291 fn default() -> Self {
292 Self {
293 hint: String::new(),
294 multiline: false,
295 on_change: None,
296 on_submit: None,
297 focus_tracker: None,
298 value: String::new(),
299 visual_transformation: None,
300 keyboard_type: crate::text::KeyboardType::default(),
301 capitalization: crate::text::KeyboardCapitalization::default(),
302 ime_action: crate::text::ImeAction::default(),
303 auto_correct_enabled: None,
304 enabled: true,
305 read_only: false,
306 max_lines: None,
307 min_lines: 1,
308 cursor_color: None,
309 on_text_layout: None,
310 text_style: None,
311 keyboard_actions: None,
312 interaction_source: None,
313 line_limits: None,
314 }
315 }
316}
317
318impl std::fmt::Debug for TextInputConfig {
319 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
320 let mut s = f.debug_struct("TextInputConfig");
321 s.field("hint", &self.hint);
322 s.field("multiline", &self.multiline);
323 if self.on_change.is_some() {
324 s.field("on_change", &"…");
325 }
326 if self.on_submit.is_some() {
327 s.field("on_submit", &"…");
328 }
329 if self.focus_tracker.is_some() {
330 s.field("focus_tracker", &"…");
331 }
332 s.field("value", &self.value);
333 if self.visual_transformation.is_some() {
334 s.field("visual_transformation", &"…");
335 }
336 s.field("keyboard_type", &self.keyboard_type);
337 s.field("capitalization", &self.capitalization);
338 s.field("ime_action", &self.ime_action);
339 s.field("auto_correct_enabled", &self.auto_correct_enabled);
340 s.field("enabled", &self.enabled);
341 s.field("read_only", &self.read_only);
342 s.field("max_lines", &self.max_lines);
343 s.field("min_lines", &self.min_lines);
344 s.field("cursor_color", &self.cursor_color);
345 if self.on_text_layout.is_some() {
346 s.field("on_text_layout", &"…");
347 }
348 s.finish()
349 }
350}
351
352#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
355pub enum IntrinsicSize {
356 Min,
357 Max,
358}
359
360static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
361
362pub type PressId = u64;
364
365#[derive(Clone, Copy, Debug, PartialEq)]
373pub enum Interaction {
374 Press(PressId, Vec2),
377 Release(PressId),
379 Cancel(PressId),
382 HoverEnter,
383 HoverLeave,
384 Focus,
385 Unfocus,
386 DragStart,
387 DragStop,
388 DragCancel,
389}
390
391impl Interaction {
392 #[inline]
394 pub fn new_press(position: Vec2) -> Self {
395 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
396 }
397}
398
399#[derive(Clone)]
406pub struct InteractionSource {
407 pub(crate) state: Rc<RefCell<InteractionState>>,
408}
409
410impl InteractionSource {
411 pub fn collect_is_pressed(&self) -> bool {
412 !self.state.borrow().active_presses.is_empty()
413 }
414 pub fn collect_is_hovered(&self) -> bool {
415 self.state.borrow().hovered
416 }
417 pub fn collect_is_focused(&self) -> bool {
418 self.state.borrow().focused
419 }
420
421 pub fn collect_is_focus_visible(&self) -> bool {
423 crate::input::is_focus_visible(self.collect_is_focused())
424 }
425
426 pub fn collect_is_dragged(&self) -> bool {
427 self.state.borrow().dragged > 0
428 }
429 pub fn collect_last_press_position(&self) -> Option<Vec2> {
430 self.state.borrow().last_press_position
431 }
432 pub fn collect_last_press_id(&self) -> Option<PressId> {
433 self.state.borrow().last_press_id
434 }
435 pub fn stable_id(&self) -> *const () {
437 Rc::as_ptr(&self.state) as *const ()
438 }
439 pub fn to_mutable(&self) -> MutableInteractionSource {
443 MutableInteractionSource {
444 state: self.state.clone(),
445 }
446 }
447
448 pub fn reset(&self) {
450 self.to_mutable().reset();
451 }
452
453 pub fn reset_hover(&self) {
455 self.to_mutable().reset_hover();
456 }
457}
458
459#[derive(Clone)]
469pub struct MutableInteractionSource {
470 pub(crate) state: Rc<RefCell<InteractionState>>,
471}
472
473impl std::fmt::Debug for MutableInteractionSource {
474 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
475 f.debug_struct("MutableInteractionSource")
476 .finish_non_exhaustive()
477 }
478}
479
480impl MutableInteractionSource {
481 pub fn new() -> Self {
482 Self {
483 state: Rc::new(RefCell::new(InteractionState::default())),
484 }
485 }
486
487 pub fn emit(&self, interaction: Interaction) {
489 let changed = {
490 let mut s = self.state.borrow_mut();
491 match interaction {
492 Interaction::Press(id, pos) => {
493 let inserted = s.active_presses.insert(id);
494 s.last_press_id = Some(id);
495 s.last_press_position = Some(pos);
496 inserted
497 }
498 Interaction::Release(id) | Interaction::Cancel(id) => {
499 if s.active_presses.remove(&id) {
500 true
501 } else if id == 0 {
502 if let Some(any) = s.active_presses.iter().next().copied() {
503 s.active_presses.remove(&any);
504 true
505 } else {
506 false
507 }
508 } else {
509 false
510 }
511 }
512 Interaction::HoverEnter => {
513 let changed = !s.hovered;
514 s.hovered = true;
515 changed
516 }
517 Interaction::HoverLeave => {
518 let changed = s.hovered;
519 s.hovered = false;
520 if !s.active_presses.is_empty() {
522 s.active_presses.clear();
523 true
524 } else {
525 changed
526 }
527 }
528 Interaction::Focus => {
529 let changed = !s.focused;
530 s.focused = true;
531 changed
532 }
533 Interaction::Unfocus => {
534 let changed = s.focused;
535 s.focused = false;
536 changed
537 }
538 Interaction::DragStart => {
539 let changed = s.dragged == 0;
540 s.dragged = s.dragged.saturating_add(1);
541 changed
542 }
543 Interaction::DragStop | Interaction::DragCancel => {
544 let was = s.dragged;
545 s.dragged = s.dragged.saturating_sub(1);
546 was != s.dragged
547 }
548 }
549 };
550 if changed {
551 crate::frame_clock::request_frame();
553 }
554 }
555
556 pub fn source(&self) -> InteractionSource {
558 InteractionSource {
559 state: self.state.clone(),
560 }
561 }
562
563 pub fn reset(&self) {
565 let mut s = self.state.borrow_mut();
566 *s = InteractionState::default();
567 crate::frame_clock::request_frame();
568 }
569
570 pub fn reset_hover(&self) {
572 let mut s = self.state.borrow_mut();
573 if s.hovered {
574 s.hovered = false;
575 crate::frame_clock::request_frame();
576 }
577 }
578}
579
580impl Default for MutableInteractionSource {
581 fn default() -> Self {
582 Self::new()
583 }
584}
585
586#[derive(Clone, Default)]
587pub(crate) struct InteractionState {
588 active_presses: HashSet<PressId>,
590 hovered: bool,
591 focused: bool,
592 dragged: u32,
593 pub(crate) last_press_position: Option<Vec2>,
595 pub(crate) last_press_id: Option<PressId>,
597}
598
599#[derive(Clone, Default)]
600pub struct Modifier {
601 pub key: Option<u64>,
607
608 pub size: Option<Size>,
609 pub width: Option<f32>,
610 pub height: Option<f32>,
611 pub required_size: Option<Size>,
612 pub fill_max: Option<f32>,
613 pub fill_max_w: Option<f32>,
614 pub fill_max_h: Option<f32>,
615 pub padding: Option<f32>,
616 pub padding_values: Option<PaddingValues>,
617 pub min_width: Option<f32>,
618 pub min_height: Option<f32>,
619 pub max_width: Option<f32>,
620 pub max_height: Option<f32>,
621 pub required_min_width: Option<f32>,
623 pub required_max_width: Option<f32>,
625 pub required_min_height: Option<f32>,
627 pub required_max_height: Option<f32>,
629 pub default_min_width: Option<f32>,
632 pub default_min_height: Option<f32>,
633 pub background: Option<Brush>,
634 pub state_colors: Option<StateColors>,
635 pub state_elevation: Option<StateElevation>,
636
637 pub border: Option<Border>,
638 pub flex_grow: Option<f32>,
639 pub flex_shrink: Option<f32>,
640 pub flex_basis: Option<f32>,
641 pub flex_wrap: Option<FlexWrap>,
642 pub flex_dir: Option<FlexDirection>,
643 pub gap: Option<f32>,
644 pub row_gap: Option<f32>,
645 pub column_gap: Option<f32>,
646 pub align_self: Option<AlignSelf>,
647 pub justify_content: Option<JustifyContent>,
648 pub align_items_container: Option<AlignItems>,
649 pub align_content: Option<AlignContent>,
650 pub clip_rounded: Option<[f32; 4]>,
651 pub clip_rect: Option<ClipRect>,
654 pub overflow: Option<Overflow>,
659 pub z_index: f32,
661 pub render_z_index: Option<f32>,
663 pub hit_passthrough: bool,
665 pub input_blocker: bool,
667 pub repaint_boundary: bool,
668 pub click: bool,
669 pub disabled: bool,
671 pub focusable: Option<bool>,
675 pub propagate_min: bool,
677 pub focus_group: bool,
680 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
681 pub scroll: Option<crate::scroll::ScrollBinding>,
687 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
696 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
697 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
698 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
699 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
700 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
701 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
702 pub on_click: Option<Rc<dyn Fn()>>,
704 pub on_double_click: Option<Rc<dyn Fn()>>,
706 pub on_long_click: Option<Rc<dyn Fn()>>,
708 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
711 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
714 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
717 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
720 pub blur: Option<BlurStyle>,
725 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (f32, f32)>>,
730 pub semantics: Option<crate::Semantics>,
731 pub alpha: Option<f32>,
732 pub graphics_layer: Option<f32>,
733 pub shadow: Option<ShadowSpec>,
734 pub transform: Option<Transform>,
735 pub grid: Option<GridConfig>,
736 pub grid_col_span: Option<u16>,
737 pub grid_row_span: Option<u16>,
738 pub position_type: Option<PositionType>,
739 pub offset_left: Option<f32>,
740 pub offset_right: Option<f32>,
741 pub offset_top: Option<f32>,
742 pub offset_bottom: Option<f32>,
743
744 pub margin_left: Option<f32>,
745 pub margin_right: Option<f32>,
746 pub margin_top: Option<f32>,
747 pub margin_bottom: Option<f32>,
748 pub aspect_ratio: Option<f32>,
749 pub intrinsic_width: Option<IntrinsicSize>,
751 pub intrinsic_height: Option<IntrinsicSize>,
753 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
754 pub paint_callback: Option<crate::PaintCallbackPayload>,
755
756 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
758 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
759 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
760 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
761 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
762 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
763 pub drag_preview: Option<crate::dnd::DragPreview>,
765
766 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
767
768 pub cursor: Option<crate::CursorIcon>,
770
771 pub animate_content_size: Option<AnimationSpec>,
774
775 pub focus_requester: Option<crate::runtime::FocusRequester>,
779
780 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
783
784 pub interaction_source: Option<InteractionSource>,
791
792 pub text_input: Option<TextInputConfig>,
794
795 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
797}
798
799impl std::fmt::Debug for Modifier {
800 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
801 let mut s = f.debug_struct("Modifier");
802
803 macro_rules! opt_val {
804 ($($name:ident),+ $(,)?) => {
805 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
806 };
807 }
808 if self.indication.is_some() {
809 s.field("indication", &"…");
810 }
811
812 opt_val!(
813 key,
814 size,
815 width,
816 height,
817 required_size,
818 padding,
819 padding_values,
820 min_width,
821 min_height,
822 max_width,
823 max_height,
824 required_min_width,
825 required_max_width,
826 required_min_height,
827 required_max_height,
828 default_min_width,
829 default_min_height,
830 fill_max,
831 fill_max_w,
832 fill_max_h,
833 background,
834 state_colors,
835 state_elevation,
836 border,
837 flex_grow,
838 flex_shrink,
839 flex_basis,
840 flex_wrap,
841 flex_dir,
842 gap,
843 row_gap,
844 column_gap,
845 align_self,
846 justify_content,
847 align_items_container,
848 align_content,
849 clip_rounded,
850 clip_rect,
851 render_z_index,
852 semantics,
853 alpha,
854 transform,
855 grid,
856 grid_col_span,
857 grid_row_span,
858 position_type,
859 offset_left,
860 offset_right,
861 offset_top,
862 offset_bottom,
863 margin_left,
864 margin_right,
865 margin_top,
866 margin_bottom,
867 aspect_ratio,
868 intrinsic_width,
869 intrinsic_height,
870 cursor,
871 animate_content_size,
872 blur,
873 );
874
875 macro_rules! opt_cb {
876 ($($name:ident),+ $(,)?) => {
877 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
878 };
879 }
880 opt_cb!(
881 on_scroll,
882 scroll,
883 nested_scroll_connection,
884 on_pointer_down,
885 on_pointer_move,
886 on_pointer_up,
887 on_pointer_cancel,
888 on_pointer_enter,
889 on_pointer_leave,
890 on_click,
891 on_double_click,
892 on_long_click,
893 on_globally_positioned,
894 on_size_changed,
895 on_key_event,
896 on_preview_key_event,
897 painter,
898 paint_callback,
899 on_drag_start,
900 on_drag_end,
901 on_drag_enter,
902 on_drag_over,
903 on_drag_leave,
904 on_drop,
905 drag_preview,
906 on_action,
907 on_focus_changed,
908 interaction_source,
909 text_input,
910 layout,
911 );
912
913 macro_rules! flag {
914 ($($name:ident),+ $(,)?) => {
915 $( if self.$name { s.field(stringify!($name), &true); } )+
916 };
917 }
918 flag!(
919 hit_passthrough,
920 input_blocker,
921 repaint_boundary,
922 click,
923 disabled,
924 propagate_min,
925 focus_group,
926 );
927
928 if let Some(f) = self.focusable {
929 s.field("focusable", &f);
930 }
931 if self.z_index != 0.0 {
932 s.field("z_index", &self.z_index);
933 }
934
935 s.finish()
936 }
937}
938
939impl_option_fields!(Modifier);
940
941#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
945pub enum Alignment {
946 TopStart,
947 TopCenter,
948 TopEnd,
949 CenterStart,
950 #[default]
951 Center,
952 CenterEnd,
953 BottomStart,
954 BottomCenter,
955 BottomEnd,
956}
957
958impl Alignment {
959 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
961 use AlignItems as AI;
962 use JustifyContent as JC;
963 match self {
964 Self::TopStart => (AI::START, JC::START),
965 Self::TopCenter => (AI::START, JC::CENTER),
966 Self::TopEnd => (AI::START, JC::END),
967 Self::CenterStart => (AI::CENTER, JC::START),
968 Self::Center => (AI::CENTER, JC::CENTER),
969 Self::CenterEnd => (AI::CENTER, JC::END),
970 Self::BottomStart => (AI::END, JC::START),
971 Self::BottomCenter => (AI::END, JC::CENTER),
972 Self::BottomEnd => (AI::END, JC::END),
973 }
974 }
975}
976
977impl Modifier {
978 pub fn new() -> Self {
979 Self::default()
980 }
981
982 pub fn key(mut self, key: u64) -> Self {
985 self.key = Some(key);
986 self
987 }
988
989 pub fn size(mut self, w: f32, h: f32) -> Self {
990 self.size = Some(Size {
991 width: w,
992 height: h,
993 });
994 self
995 }
996 pub fn width(mut self, w: f32) -> Self {
997 self.width = Some(w);
998 self
999 }
1000 pub fn height(mut self, h: f32) -> Self {
1001 self.height = Some(h);
1002 self
1003 }
1004 pub fn required_size(mut self, w: f32, h: f32) -> Self {
1009 self.required_size = Some(Size {
1010 width: w,
1011 height: h,
1012 });
1013 self
1014 }
1015 pub fn required_width_in(mut self, min: f32, max: f32) -> Self {
1016 self.required_min_width = Some(min.max(0.0));
1017 self.required_max_width = Some(max.max(0.0));
1018 self
1019 }
1020 pub fn required_height_in(mut self, min: f32, max: f32) -> Self {
1021 self.required_min_height = Some(min.max(0.0));
1022 self.required_max_height = Some(max.max(0.0));
1023 self
1024 }
1025 pub fn required_min_width(mut self, w: f32) -> Self {
1026 self.required_min_width = Some(w.max(0.0));
1027 self
1028 }
1029 pub fn required_max_width(mut self, w: f32) -> Self {
1030 self.required_max_width = Some(w.max(0.0));
1031 self
1032 }
1033 pub fn required_min_height(mut self, h: f32) -> Self {
1034 self.required_min_height = Some(h.max(0.0));
1035 self
1036 }
1037 pub fn required_max_height(mut self, h: f32) -> Self {
1038 self.required_max_height = Some(h.max(0.0));
1039 self
1040 }
1041 pub fn default_min_size(mut self, w: f32, h: f32) -> Self {
1043 self.default_min_width = Some(w.max(0.0));
1044 self.default_min_height = Some(h.max(0.0));
1045 self
1046 }
1047 pub fn fill_max_size(mut self) -> Self {
1050 self.fill_max = Some(1.0);
1051 self
1052 }
1053 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
1054 self.fill_max = Some(fraction.clamp(0.0, 1.0));
1055 self
1056 }
1057 pub fn fill_max_width(mut self) -> Self {
1059 self.fill_max_w = Some(1.0);
1060 self
1061 }
1062 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
1063 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
1064 self
1065 }
1066 pub fn fill_max_height(mut self) -> Self {
1068 self.fill_max_h = Some(1.0);
1069 self
1070 }
1071 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
1072 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
1073 self
1074 }
1075 pub fn padding(mut self, v: f32) -> Self {
1076 self.padding = Some(v);
1077 self
1078 }
1079 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
1080 self.padding_values = Some(padding);
1081 self
1082 }
1083 pub fn ime_padding(mut self) -> Self {
1086 let insets = crate::locals::window_insets();
1087 let scale = crate::locals::effective_density_scale();
1088 let mut p = self.padding_values.unwrap_or_default();
1089 p.bottom += insets.ime_bottom / scale;
1090 self.padding_values = Some(p);
1091 self
1092 }
1093 pub fn system_bars_padding(mut self) -> Self {
1095 let insets = crate::locals::window_insets();
1096 let scale = crate::locals::effective_density_scale();
1097 let mut p = self.padding_values.unwrap_or_default();
1098 p.top += insets.top / scale;
1099 p.bottom += insets.bottom / scale;
1100 self.padding_values = Some(p);
1101 self
1102 }
1103 pub fn status_bars_padding(mut self) -> Self {
1105 let insets = crate::locals::window_insets();
1106 let scale = crate::locals::effective_density_scale();
1107 let mut p = self.padding_values.unwrap_or_default();
1108 p.top += insets.top / scale;
1109 self.padding_values = Some(p);
1110 self
1111 }
1112 pub fn navigation_bars_padding(mut self) -> Self {
1114 let insets = crate::locals::window_insets();
1115 let scale = crate::locals::effective_density_scale();
1116 let mut p = self.padding_values.unwrap_or_default();
1117 p.bottom += insets.bottom / scale;
1118 self.padding_values = Some(p);
1119 self
1120 }
1121 pub fn min_size(mut self, w: f32, h: f32) -> Self {
1122 self.min_width = Some(w);
1123 self.min_height = Some(h);
1124 self
1125 }
1126 pub fn max_size(mut self, w: f32, h: f32) -> Self {
1127 self.max_width = Some(w);
1128 self.max_height = Some(h);
1129 self
1130 }
1131 pub fn min_width(mut self, w: f32) -> Self {
1132 self.min_width = Some(w);
1133 self
1134 }
1135 pub fn min_height(mut self, h: f32) -> Self {
1136 self.min_height = Some(h);
1137 self
1138 }
1139 pub fn max_width(mut self, w: f32) -> Self {
1140 self.max_width = Some(w);
1141 self
1142 }
1143 pub fn max_height(mut self, h: f32) -> Self {
1144 self.max_height = Some(h);
1145 self
1146 }
1147 pub fn background(mut self, color: Color) -> Self {
1149 self.background = Some(Brush::Solid(color));
1150 self
1151 }
1152 pub fn background_brush(mut self, brush: Brush) -> Self {
1154 self.background = Some(brush);
1155 self
1156 }
1157 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
1158 self.border = Some(Border {
1159 width,
1160 color,
1161 radius: [radius; 4],
1162 });
1163 self
1164 }
1165 pub fn border_radii(mut self, width: f32, color: Color, radii: [f32; 4]) -> Self {
1166 self.border = Some(Border {
1167 width,
1168 color,
1169 radius: radii,
1170 });
1171 self
1172 }
1173 pub fn flex_grow(mut self, v: f32) -> Self {
1174 self.flex_grow = Some(v);
1175 self
1176 }
1177 pub fn flex_shrink(mut self, v: f32) -> Self {
1178 self.flex_shrink = Some(v);
1179 self
1180 }
1181 pub fn flex_basis(mut self, v: f32) -> Self {
1182 self.flex_basis = Some(v);
1183 self
1184 }
1185 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1186 self.flex_wrap = Some(w);
1187 self
1188 }
1189 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1190 self.flex_dir = Some(d);
1191 self
1192 }
1193 pub fn gap(mut self, v: f32) -> Self {
1194 let v = v.max(0.0);
1195 self.gap = Some(v);
1196 self.row_gap = Some(v);
1197 self.column_gap = Some(v);
1198 self
1199 }
1200 pub fn row_gap(mut self, v: f32) -> Self {
1201 self.row_gap = Some(v.max(0.0));
1202 self
1203 }
1204 pub fn column_gap(mut self, v: f32) -> Self {
1205 self.column_gap = Some(v.max(0.0));
1206 self
1207 }
1208 pub fn align_self(mut self, a: AlignSelf) -> Self {
1209 self.align_self = Some(a);
1210 self
1211 }
1212 pub fn align_self_center(mut self) -> Self {
1213 self.align_self = Some(AlignSelf::CENTER);
1214 self
1215 }
1216 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1217 self.justify_content = Some(j);
1218 self
1219 }
1220 pub fn align_items(mut self, a: AlignItems) -> Self {
1221 self.align_items_container = Some(a);
1222 self
1223 }
1224 pub fn content_alignment(self, alignment: Alignment) -> Self {
1227 let (ai, jc) = alignment.to_flex();
1228 self.align_items(ai).justify_content(jc)
1229 }
1230 pub fn align_content(mut self, a: AlignContent) -> Self {
1231 self.align_content = Some(a);
1232 self
1233 }
1234 pub fn clip_rounded(mut self, radius: f32) -> Self {
1235 self.clip_rounded = Some([radius; 4]);
1236 self
1237 }
1238 pub fn clip_rounded_radii(mut self, radii: [f32; 4]) -> Self {
1239 self.clip_rounded = Some(radii);
1240 self
1241 }
1242 pub fn clip_rect(mut self, left: f32, top: f32, right: f32, bottom: f32, op: ClipOp) -> Self {
1245 self.clip_rect = Some(ClipRect {
1246 left,
1247 top,
1248 right,
1249 bottom,
1250 op,
1251 });
1252 self
1253 }
1254 pub fn overflow(mut self, overflow: Overflow) -> Self {
1255 self.overflow = Some(overflow);
1256 self
1257 }
1258 pub fn z_index(mut self, z: f32) -> Self {
1259 self.z_index = z;
1260 self
1261 }
1262
1263 pub fn render_z_index(mut self, z: f32) -> Self {
1266 self.render_z_index = Some(z);
1267 self
1268 }
1269
1270 pub fn input_blocker(mut self) -> Self {
1272 self.input_blocker = true;
1273 self
1274 }
1275
1276 pub fn hit_passthrough(mut self) -> Self {
1277 self.hit_passthrough = true;
1278 self
1279 }
1280 pub fn clickable(mut self) -> Self {
1281 self.click = true;
1282 if self.indication.is_none() {
1283 self.indication = crate::locals::local_indication();
1284 }
1285 self
1286 }
1287 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1290 self.click = true;
1291 self.interaction_source = Some(source.source());
1292 if self.indication.is_none() {
1293 self.indication = crate::locals::local_indication();
1294 }
1295 self
1296 }
1297 pub fn state_colors(mut self, colors: StateColors) -> Self {
1300 self.state_colors = Some(colors);
1301 self
1302 }
1303 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1305 self.state_elevation = Some(elev);
1306 self
1307 }
1308 pub fn disabled(mut self) -> Self {
1310 self.disabled = true;
1311 self
1312 }
1313 pub fn enabled(mut self, enabled: bool) -> Self {
1315 self.disabled = !enabled;
1316 self
1317 }
1318 pub fn focusable(mut self, focusable: bool) -> Self {
1323 self.focusable = Some(focusable);
1324 self
1325 }
1326 pub fn focus_group(mut self) -> Self {
1329 self.focus_group = true;
1330 self
1331 }
1332 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1343 self.interaction_source = Some(source.source());
1344 self
1345 }
1346 pub fn hoverable(
1349 mut self,
1350 on_enter: impl Fn() + 'static,
1351 on_leave: impl Fn() + 'static,
1352 ) -> Self {
1353 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1354 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1355 self
1356 }
1357 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1361 self.interaction_source = Some(source.source());
1362 self
1363 }
1364 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1367 self.propagate_min = propagate;
1368 self
1369 }
1370 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1371 self.on_scroll = Some(Rc::new(f));
1372 self
1373 }
1374 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1378 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1379 self
1380 }
1381 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1383 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1384 self
1385 }
1386 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1388 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1389 self
1390 }
1391 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1398 self.nested_scroll_connection = Some(conn);
1399 self
1400 }
1401 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1402 self.on_pointer_down = Some(Rc::new(f));
1403 self
1404 }
1405 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1406 self.on_pointer_move = Some(Rc::new(f));
1407 self
1408 }
1409 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1410 self.on_pointer_up = Some(Rc::new(f));
1411 self
1412 }
1413 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1414 self.on_pointer_cancel = Some(Rc::new(f));
1415 self
1416 }
1417
1418 pub fn draggable(self, on_drag: impl Fn(Vec2) + 'static) -> Self {
1419 let drag_pos = crate::state::remember_mutable(|| Vec2::default());
1420 let is_dragging = crate::state::remember_mutable(|| false);
1421 let on_drag = Rc::new(on_drag);
1422 self.on_pointer_down({
1423 let drag_pos = drag_pos.clone();
1424 let is_dragging = is_dragging.clone();
1425 move |ev| {
1426 is_dragging.set(true);
1427 drag_pos.set(ev.position);
1428 }
1429 })
1430 .on_pointer_up({
1431 let is_dragging = is_dragging.clone();
1432 move |_| is_dragging.set(false)
1433 })
1434 .on_pointer_cancel({
1435 let is_dragging = is_dragging.clone();
1436 move |_| is_dragging.set(false)
1437 })
1438 .on_pointer_move({
1439 let drag_pos = drag_pos.clone();
1440 let is_dragging = is_dragging.clone();
1441 let on_drag = on_drag.clone();
1442 move |ev| {
1443 if !*is_dragging.get() {
1444 return;
1445 }
1446 let prev = *drag_pos.get();
1447 let cur = ev.position;
1448 let delta = Vec2 {
1449 x: cur.x - prev.x,
1450 y: cur.y - prev.y,
1451 };
1452 drag_pos.set(cur);
1453 on_drag(delta);
1454 crate::frame_clock::request_frame();
1455 }
1456 })
1457 }
1458 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1459 self.on_pointer_enter = Some(Rc::new(f));
1460 self
1461 }
1462 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1463 self.on_pointer_leave = Some(Rc::new(f));
1464 self
1465 }
1466 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1467 self.on_click = Some(Rc::new(f));
1468 self.click = true;
1469 if self.semantics.is_none() {
1470 self.semantics = Some(crate::Semantics::new(crate::Role::Button));
1471 }
1472 self
1473 }
1474 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1475 self.on_double_click = Some(Rc::new(f));
1476 self.click = true;
1477 self
1478 }
1479 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1480 self.on_long_click = Some(Rc::new(f));
1481 self.click = true;
1482 self
1483 }
1484 pub fn clickable_ext(
1485 mut self,
1486 enabled: bool,
1487 on_click_label: Option<String>,
1488 role: Option<crate::semantics::Role>,
1489 on_click: impl Fn() + 'static,
1490 ) -> Self {
1491 if !enabled {
1492 let mut s = self.semantics.clone().unwrap_or_else(|| {
1493 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1494 });
1495 s.enabled = false;
1496 if let Some(r) = role {
1497 s.role = r;
1498 }
1499 if let Some(l) = on_click_label {
1500 s.label = Some(l);
1501 }
1502 return self
1503 .clickable()
1504 .enabled(false)
1505 .default_min_size(48.0, 48.0)
1506 .semantics(s);
1507 }
1508 self = self.clickable().on_click(on_click);
1509 if role.is_some() || on_click_label.is_some() {
1510 let mut s = self.semantics.clone().unwrap_or_else(|| {
1511 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1512 });
1513 s.enabled = true;
1514 if let Some(r) = role {
1515 s.role = r;
1516 }
1517 if let Some(l) = on_click_label {
1518 s.label = Some(l);
1519 }
1520 self = self.semantics(s);
1521 }
1522 self.default_min_size(48.0, 48.0)
1523 }
1524 pub fn combined_clickable(
1525 mut self,
1526 enabled: bool,
1527 on_click_label: Option<String>,
1528 role: Option<crate::semantics::Role>,
1529 on_long_click_label: Option<String>,
1530 on_click: impl Fn() + 'static,
1531 on_long_click: Option<impl Fn() + 'static>,
1532 on_double_click: Option<impl Fn() + 'static>,
1533 ) -> Self {
1534 let _ = on_long_click_label;
1535 if !enabled {
1536 return self.clickable_ext(false, on_click_label, role, || {});
1537 }
1538 self = self.clickable_ext(true, on_click_label, role, on_click);
1539 if let Some(f) = on_long_click {
1540 self = self.on_long_click(f);
1541 }
1542 if let Some(f) = on_double_click {
1543 self = self.on_double_click(f);
1544 }
1545 self.default_min_size(48.0, 48.0)
1546 }
1547 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1548 self.semantics = Some(s);
1549 self
1550 }
1551 pub fn alpha(mut self, a: f32) -> Self {
1552 self.alpha = Some(a);
1553 self
1554 }
1555 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1560 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1561 self
1562 }
1563 pub fn shadow(mut self, blur_radius: f32, offset_y: f32) -> Self {
1567 self.shadow = Some(ShadowSpec {
1568 blur_radius: blur_radius.max(0.0),
1569 offset_y,
1570 color: Color(0, 0, 0, 64),
1571 });
1572 self
1573 }
1574 pub fn shadow_with_color(mut self, blur_radius: f32, offset_y: f32, color: Color) -> Self {
1576 self.shadow = Some(ShadowSpec {
1577 blur_radius: blur_radius.max(0.0),
1578 offset_y,
1579 color,
1580 });
1581 self
1582 }
1583 pub fn elevation(mut self, level: f32) -> Self {
1587 if level <= 0.0 {
1588 self.shadow = None;
1589 return self;
1590 }
1591 self.shadow = Some(ShadowSpec {
1592 blur_radius: level * 2.0,
1593 offset_y: level * 0.5,
1594 color: Color(0, 0, 0, (level * 8.0).clamp(8.0, 80.0) as u8),
1595 });
1596 self
1597 }
1598 pub fn transform(mut self, t: Transform) -> Self {
1599 self.transform = Some(t);
1600 self
1601 }
1602 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
1603 self.grid = Some(GridConfig {
1604 columns,
1605 row_gap,
1606 column_gap,
1607 });
1608 self
1609 }
1610 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1611 self.grid_col_span = Some(col_span);
1612 self.grid_row_span = Some(row_span);
1613 self
1614 }
1615 pub fn absolute(mut self) -> Self {
1616 self.position_type = Some(PositionType::Absolute);
1617 self
1618 }
1619 pub fn offset(
1620 mut self,
1621 left: Option<f32>,
1622 top: Option<f32>,
1623 right: Option<f32>,
1624 bottom: Option<f32>,
1625 ) -> Self {
1626 self.offset_left = left;
1627 self.offset_top = top;
1628 self.offset_right = right;
1629 self.offset_bottom = bottom;
1630 self
1631 }
1632 pub fn offset_left(mut self, v: f32) -> Self {
1633 self.offset_left = Some(v);
1634 self
1635 }
1636 pub fn offset_right(mut self, v: f32) -> Self {
1637 self.offset_right = Some(v);
1638 self
1639 }
1640 pub fn offset_top(mut self, v: f32) -> Self {
1641 self.offset_top = Some(v);
1642 self
1643 }
1644 pub fn offset_bottom(mut self, v: f32) -> Self {
1645 self.offset_bottom = Some(v);
1646 self
1647 }
1648 pub fn margin(mut self, v: f32) -> Self {
1649 self.margin_left = Some(v);
1650 self.margin_right = Some(v);
1651 self.margin_top = Some(v);
1652 self.margin_bottom = Some(v);
1653 self
1654 }
1655
1656 pub fn margin_horizontal(mut self, v: f32) -> Self {
1657 self.margin_left = Some(v);
1658 self.margin_right = Some(v);
1659 self
1660 }
1661
1662 pub fn margin_vertical(mut self, v: f32) -> Self {
1663 self.margin_top = Some(v);
1664 self.margin_bottom = Some(v);
1665 self
1666 }
1667 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1668 self.aspect_ratio = Some(ratio);
1669 self
1670 }
1671 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1673 self.intrinsic_width = Some(mode);
1674 self
1675 }
1676 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1678 self.intrinsic_height = Some(mode);
1679 self
1680 }
1681 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1682 self.painter = Some(Rc::new(f));
1683 self
1684 }
1685 pub fn paint_callback(mut self, payload: crate::PaintCallbackPayload) -> Self {
1691 self.paint_callback = Some(payload);
1692 self
1693 }
1694 pub fn scale(self, s: f32) -> Self {
1695 self.scale2(s, s)
1696 }
1697 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1698 let mut t = self.transform.unwrap_or_else(Transform::identity);
1699 t.scale_x *= sx;
1700 t.scale_y *= sy;
1701 self.transform = Some(t);
1702 self
1703 }
1704 pub fn translate(mut self, x: f32, y: f32) -> Self {
1705 let t = self.transform.unwrap_or_else(Transform::identity);
1706 self.transform = Some(t.combine(&Transform::translate(x, y)));
1707 self
1708 }
1709 pub fn translate_vec2(self, v: Vec2) -> Self {
1710 self.translate(v.x, v.y)
1711 }
1712 pub fn rotate(mut self, radians: f32) -> Self {
1713 let mut t = self.transform.unwrap_or_else(Transform::identity);
1714 t.rotate += radians;
1715 self.transform = Some(t);
1716 self
1717 }
1718 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1719 let mut t = self.transform.unwrap_or_else(Transform::identity);
1720 t.origin_x = x;
1721 t.origin_y = y;
1722 self.transform = Some(t);
1723 self
1724 }
1725 pub fn weight(mut self, w: f32) -> Self {
1726 let w = w.max(0.0);
1727 self.flex_grow = Some(w);
1728 self.flex_shrink = Some(1.0);
1729 self.flex_basis = Some(0.0);
1731 self
1732 }
1733 pub fn repaint_boundary(mut self) -> Self {
1737 self.repaint_boundary = true;
1738 self
1739 }
1740 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1741 self.on_action = Some(Rc::new(f));
1742 self
1743 }
1744
1745 pub fn on_drag_start(
1747 mut self,
1748 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1749 ) -> Self {
1750 self.on_drag_start = Some(Rc::new(f));
1751 self
1752 }
1753
1754 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1756 self.on_drag_end = Some(Rc::new(f));
1757 self
1758 }
1759
1760 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1762 self.on_drag_enter = Some(Rc::new(f));
1763 self
1764 }
1765
1766 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1768 self.on_drag_over = Some(Rc::new(f));
1769 self
1770 }
1771
1772 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1774 self.on_drag_leave = Some(Rc::new(f));
1775 self
1776 }
1777
1778 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1781 self.on_drop = Some(Rc::new(f));
1782 self
1783 }
1784
1785 pub fn draw_drag_decoration(
1790 mut self,
1791 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
1792 ) -> Self {
1793 self.drag_preview = Some(Rc::new(f));
1794 self
1795 }
1796
1797 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
1799 self.drag_preview = Some(preview);
1800 self
1801 }
1802
1803 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
1805 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
1806 }
1807
1808 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
1810 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
1811 }
1812
1813 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1815 self.cursor = Some(c);
1816 self
1817 }
1818
1819 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1823 self.animate_content_size = Some(spec);
1824 self
1825 }
1826
1827 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1830 self.focus_requester = Some(fr);
1831 self
1832 }
1833
1834 pub fn focus_target(mut self) -> Self {
1837 self.focusable = Some(true);
1838 self
1839 }
1840
1841 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1844 self.on_focus_changed = Some(Rc::new(f));
1845 self
1846 }
1847
1848 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
1852 self.on_globally_positioned = Some(Rc::new(f));
1853 self
1854 }
1855
1856 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
1859 self.on_size_changed = Some(Rc::new(f));
1860 self
1861 }
1862
1863 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
1867 self.on_key_event = Some(Rc::new(f));
1868 self
1869 }
1870
1871 pub fn on_preview_key_event(
1875 mut self,
1876 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
1877 ) -> Self {
1878 self.on_preview_key_event = Some(Rc::new(f));
1879 self
1880 }
1881
1882 pub fn blur(mut self, radius_dp: f32) -> Self {
1889 self.blur = Some(BlurStyle {
1890 radius_x: radius_dp.max(0.0),
1891 radius_y: radius_dp.max(0.0),
1892 edge_treatment: BlurredEdgeTreatment::Rectangle,
1893 });
1894 self
1895 }
1896
1897 pub fn blur_with_edge(
1902 mut self,
1903 radius_x: f32,
1904 radius_y: f32,
1905 edge_treatment: BlurredEdgeTreatment,
1906 ) -> Self {
1907 self.blur = Some(BlurStyle {
1908 radius_x: radius_x.max(0.0),
1909 radius_y: radius_y.max(0.0),
1910 edge_treatment,
1911 });
1912 self
1913 }
1914
1915 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (f32, f32) + 'static) -> Self {
1923 self.layout = Some(Rc::new(f));
1924 self
1925 }
1926
1927 pub fn text_input(mut self, config: TextInputConfig) -> Self {
1929 self.text_input = Some(config);
1930 self
1931 }
1932
1933 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
1937 self.indication = Some(factory);
1938 self
1939 }
1940}