1use std::cell::{Cell, RefCell};
2use std::collections::HashSet;
3use std::rc::Rc;
4use std::sync::atomic::{AtomicU64, Ordering};
5
6use taffy::{
7 AlignContent, AlignItems, AlignSelf, Contain, FlexDirection, FlexWrap, JustifyContent,
8};
9
10use crate::animation::AnimationSpec;
11use crate::indication::IndicationNodeFactory;
12use crate::{Brush, Color, PointerEvent, Size, Transform, Vec2};
13
14#[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)]
31pub struct StateElevation {
32 pub default: f32,
33 pub hovered: f32,
34 pub focused: f32,
36 pub pressed: f32,
37 pub disabled: f32,
38 pub dragged: f32,
40}
41
42impl StateColors {
43 pub const fn transparent() -> Self {
44 Self {
45 default: Color::TRANSPARENT,
46 hovered: Color::TRANSPARENT,
47 focused: Color::TRANSPARENT,
48 pressed: Color::TRANSPARENT,
49 disabled: Color::TRANSPARENT,
50 dragged: Color::TRANSPARENT,
51 }
52 }
53}
54
55impl StateElevation {
56 pub const fn zero() -> Self {
57 Self {
58 default: 0.0,
59 hovered: 0.0,
60 focused: 0.0,
61 pressed: 0.0,
62 disabled: 0.0,
63 dragged: 0.0,
64 }
65 }
66}
67
68macro_rules! merge_opts {
69 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
70 $( $dst.$f = $src.$f.or($dst.$f); )+
71 };
72}
73macro_rules! merge_flags {
74 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
75 $( $dst.$f |= $src.$f; )+
76 };
77}
78
79macro_rules! impl_option_fields {
80 ($ty:ty, $fn:ident) => {
81 impl $ty {
82 $fn!(replace);
83 }
84 };
85 ($ty:ident) => {
86 impl $ty {
87 pub fn then(mut self, other: Self) -> Self {
90 merge_opts!(self, other;
91 key, size, width, height, required_size,
92 padding, padding_values,
93 min_width, min_height, max_width, max_height,
94 required_min_width, required_max_width,
95 required_min_height, required_max_height,
96 default_min_width, default_min_height,
97 fill_max, fill_max_w, fill_max_h,
98 background, state_colors, state_elevation, border,
99 flex_grow, flex_shrink, flex_basis, flex_wrap, flex_dir,
100 gap, row_gap, column_gap,
101 align_self, justify_content, align_items_container, align_content,
102 clip_rounded, clip_rect, overflow, render_z_index,
103 on_scroll,
104 nested_scroll_connection,
105 scroll,
106 on_pointer_down, on_pointer_move, on_pointer_up,
107 on_pointer_enter, on_pointer_leave,
108 on_click, on_double_click, on_long_click,
109 semantics, alpha, transform,
110 grid, grid_col_span, grid_row_span,
111 position_type,
112 offset_left, offset_right, offset_top, offset_bottom,
113 margin_left, margin_right, margin_top, margin_bottom,
114 aspect_ratio, intrinsic_width, intrinsic_height,
115 painter,
116 paint_callback,
117 on_drag_start, on_drag_end, on_drag_enter, on_drag_over, on_drag_leave, on_drop,
118 drag_preview,
119 on_action, cursor, animate_content_size, focus_requester, on_focus_changed,
120 interaction_source, text_input,
121 );
122 merge_flags!(self, other;
123 hit_passthrough, input_blocker, repaint_boundary, click, disabled,
124 propagate_min, focus_group,
125 );
126
127 if let Some(f) = other.focusable {
128 self.focusable = Some(f);
129 }
130 if other.indication.is_some() {
131 self.indication = other.indication;
132 }
133 if other.z_index != 0.0 {
134 self.z_index = other.z_index;
135 }
136 self
137 }
138 }
139 };
140}
141
142#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
143pub enum ClipOp {
144 #[default]
146 Intersect,
147 Difference,
149}
150
151#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
157pub enum Overflow {
158 #[default]
159 Clip,
160 Visible,
161}
162
163#[derive(Clone, Copy, Debug)]
166pub struct ClipRect {
167 pub left: f32,
168 pub top: f32,
169 pub right: f32,
170 pub bottom: f32,
171 pub op: ClipOp,
172}
173
174#[derive(Clone, Debug)]
175pub struct Border {
176 pub width: f32,
177 pub color: Color,
178 pub radius: [f32; 4],
179}
180
181#[derive(Clone, Copy, Debug, Default)]
182pub struct PaddingValues {
183 pub left: f32,
184 pub right: f32,
185 pub top: f32,
186 pub bottom: f32,
187}
188
189#[derive(Clone, Debug)]
190pub struct GridConfig {
191 pub columns: usize,
192 pub row_gap: f32,
193 pub column_gap: f32,
194}
195
196#[derive(Clone, Copy, Debug, PartialEq)]
199pub enum BlurredEdgeTreatment {
200 Rectangle,
203 Unbounded,
206}
207
208#[derive(Clone, Copy, Debug)]
210pub struct BlurStyle {
211 pub radius_x: f32,
213 pub radius_y: f32,
215 pub edge_treatment: BlurredEdgeTreatment,
217}
218
219#[derive(Clone, Copy, Debug)]
224pub struct LayoutConstraints {
225 pub min_width: f32,
226 pub max_width: f32,
227 pub min_height: f32,
228 pub max_height: f32,
229}
230
231#[derive(Clone, Copy, Debug)]
238pub struct ShadowSpec {
239 pub blur_radius: f32,
240 pub offset_y: f32,
241 pub color: Color,
242}
243
244#[derive(Clone, Copy, Debug)]
245#[non_exhaustive]
246pub enum PositionType {
247 Relative,
248 Absolute,
249}
250
251#[derive(Clone)]
253pub struct TextInputConfig {
254 pub hint: String,
255 pub multiline: bool,
256 pub on_change: Option<Rc<dyn Fn(String)>>,
257 pub on_submit: Option<Rc<dyn Fn(String)>>,
258 pub focus_tracker: Option<Rc<Cell<bool>>>,
259 pub value: String,
260 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
261 pub keyboard_type: crate::text::KeyboardType,
262 pub capitalization: crate::text::KeyboardCapitalization,
263 pub ime_action: crate::text::ImeAction,
264 pub auto_correct_enabled: Option<bool>,
267 pub enabled: bool,
269 pub read_only: bool,
271 pub max_lines: Option<usize>,
273 pub min_lines: usize,
275 pub cursor_color: Option<Color>,
277 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
280 pub text_style: Option<crate::text::TextStyle>,
283 pub keyboard_actions: Option<crate::text::KeyboardActions>,
286 pub interaction_source: Option<InteractionSource>,
288 pub line_limits: Option<crate::text::TextFieldLineLimits>,
290}
291
292impl Default for TextInputConfig {
293 fn default() -> Self {
294 Self {
295 hint: String::new(),
296 multiline: false,
297 on_change: None,
298 on_submit: None,
299 focus_tracker: None,
300 value: String::new(),
301 visual_transformation: None,
302 keyboard_type: crate::text::KeyboardType::default(),
303 capitalization: crate::text::KeyboardCapitalization::default(),
304 ime_action: crate::text::ImeAction::default(),
305 auto_correct_enabled: None,
306 enabled: true,
307 read_only: false,
308 max_lines: None,
309 min_lines: 1,
310 cursor_color: None,
311 on_text_layout: None,
312 text_style: None,
313 keyboard_actions: None,
314 interaction_source: None,
315 line_limits: None,
316 }
317 }
318}
319
320impl std::fmt::Debug for TextInputConfig {
321 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
322 let mut s = f.debug_struct("TextInputConfig");
323 s.field("hint", &self.hint);
324 s.field("multiline", &self.multiline);
325 if self.on_change.is_some() {
326 s.field("on_change", &"…");
327 }
328 if self.on_submit.is_some() {
329 s.field("on_submit", &"…");
330 }
331 if self.focus_tracker.is_some() {
332 s.field("focus_tracker", &"…");
333 }
334 s.field("value", &self.value);
335 if self.visual_transformation.is_some() {
336 s.field("visual_transformation", &"…");
337 }
338 s.field("keyboard_type", &self.keyboard_type);
339 s.field("capitalization", &self.capitalization);
340 s.field("ime_action", &self.ime_action);
341 s.field("auto_correct_enabled", &self.auto_correct_enabled);
342 s.field("enabled", &self.enabled);
343 s.field("read_only", &self.read_only);
344 s.field("max_lines", &self.max_lines);
345 s.field("min_lines", &self.min_lines);
346 s.field("cursor_color", &self.cursor_color);
347 if self.on_text_layout.is_some() {
348 s.field("on_text_layout", &"…");
349 }
350 s.finish()
351 }
352}
353
354#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
357pub enum IntrinsicSize {
358 Min,
359 Max,
360}
361
362#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
370pub enum BaselineAlign {
371 FirstBaseline,
372 LastBaseline,
373}
374
375static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
376
377pub type PressId = u64;
379
380#[derive(Clone, Copy, Debug, PartialEq)]
388pub enum Interaction {
389 Press(PressId, Vec2),
392 Release(PressId),
394 Cancel(PressId),
397 HoverEnter,
398 HoverLeave,
399 Focus,
400 Unfocus,
401 DragStart,
402 DragStop,
403 DragCancel,
404}
405
406impl Interaction {
407 #[inline]
409 pub fn new_press(position: Vec2) -> Self {
410 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
411 }
412}
413
414#[derive(Clone)]
421pub struct InteractionSource {
422 pub(crate) state: Rc<RefCell<InteractionState>>,
423}
424
425impl InteractionSource {
426 pub fn collect_is_pressed(&self) -> bool {
427 !self.state.borrow().active_presses.is_empty()
428 }
429 pub fn collect_is_hovered(&self) -> bool {
430 self.state.borrow().hovered
431 }
432 pub fn collect_is_focused(&self) -> bool {
433 self.state.borrow().focused
434 }
435
436 pub fn collect_is_focus_visible(&self) -> bool {
438 crate::input::is_focus_visible(self.collect_is_focused())
439 }
440
441 pub fn collect_is_dragged(&self) -> bool {
442 self.state.borrow().dragged > 0
443 }
444 pub fn collect_last_press_position(&self) -> Option<Vec2> {
445 self.state.borrow().last_press_position
446 }
447 pub fn collect_last_press_id(&self) -> Option<PressId> {
448 self.state.borrow().last_press_id
449 }
450 pub fn stable_id(&self) -> *const () {
452 Rc::as_ptr(&self.state) as *const ()
453 }
454 pub fn to_mutable(&self) -> MutableInteractionSource {
458 MutableInteractionSource {
459 state: self.state.clone(),
460 }
461 }
462
463 pub fn reset(&self) {
465 self.to_mutable().reset();
466 }
467
468 pub fn reset_hover(&self) {
470 self.to_mutable().reset_hover();
471 }
472}
473
474#[derive(Clone)]
484pub struct MutableInteractionSource {
485 pub(crate) state: Rc<RefCell<InteractionState>>,
486}
487
488impl std::fmt::Debug for MutableInteractionSource {
489 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
490 f.debug_struct("MutableInteractionSource")
491 .finish_non_exhaustive()
492 }
493}
494
495impl MutableInteractionSource {
496 pub fn new() -> Self {
497 Self {
498 state: Rc::new(RefCell::new(InteractionState::default())),
499 }
500 }
501
502 pub fn emit(&self, interaction: Interaction) {
504 let changed = {
505 let mut s = self.state.borrow_mut();
506 match interaction {
507 Interaction::Press(id, pos) => {
508 let inserted = s.active_presses.insert(id);
509 s.last_press_id = Some(id);
510 s.last_press_position = Some(pos);
511 inserted
512 }
513 Interaction::Release(id) | Interaction::Cancel(id) => {
514 if s.active_presses.remove(&id) {
515 true
516 } else if id == 0 {
517 if let Some(any) = s.active_presses.iter().next().copied() {
518 s.active_presses.remove(&any);
519 true
520 } else {
521 false
522 }
523 } else {
524 false
525 }
526 }
527 Interaction::HoverEnter => {
528 let changed = !s.hovered;
529 s.hovered = true;
530 changed
531 }
532 Interaction::HoverLeave => {
533 let changed = s.hovered;
534 s.hovered = false;
535 if !s.active_presses.is_empty() {
537 s.active_presses.clear();
538 true
539 } else {
540 changed
541 }
542 }
543 Interaction::Focus => {
544 let changed = !s.focused;
545 s.focused = true;
546 changed
547 }
548 Interaction::Unfocus => {
549 let changed = s.focused;
550 s.focused = false;
551 changed
552 }
553 Interaction::DragStart => {
554 let changed = s.dragged == 0;
555 s.dragged = s.dragged.saturating_add(1);
556 changed
557 }
558 Interaction::DragStop | Interaction::DragCancel => {
559 let was = s.dragged;
560 s.dragged = s.dragged.saturating_sub(1);
561 was != s.dragged
562 }
563 }
564 };
565 if changed {
566 crate::frame_clock::request_frame();
568 }
569 }
570
571 pub fn source(&self) -> InteractionSource {
573 InteractionSource {
574 state: self.state.clone(),
575 }
576 }
577
578 pub fn reset(&self) {
580 let mut s = self.state.borrow_mut();
581 *s = InteractionState::default();
582 crate::frame_clock::request_frame();
583 }
584
585 pub fn reset_hover(&self) {
587 let mut s = self.state.borrow_mut();
588 if s.hovered {
589 s.hovered = false;
590 crate::frame_clock::request_frame();
591 }
592 }
593}
594
595impl Default for MutableInteractionSource {
596 fn default() -> Self {
597 Self::new()
598 }
599}
600
601#[derive(Clone, Default)]
602pub(crate) struct InteractionState {
603 active_presses: HashSet<PressId>,
605 hovered: bool,
606 focused: bool,
607 dragged: u32,
608 pub(crate) last_press_position: Option<Vec2>,
610 pub(crate) last_press_id: Option<PressId>,
612}
613
614#[derive(Clone, Default)]
615pub struct Modifier {
616 pub key: Option<u64>,
622
623 pub size: Option<Size>,
624 pub width: Option<f32>,
625 pub height: Option<f32>,
626 pub required_size: Option<Size>,
627 pub fill_max: Option<f32>,
628 pub fill_max_w: Option<f32>,
629 pub fill_max_h: Option<f32>,
630 pub padding: Option<f32>,
631 pub padding_values: Option<PaddingValues>,
632 pub min_width: Option<f32>,
633 pub min_height: Option<f32>,
634 pub max_width: Option<f32>,
635 pub max_height: Option<f32>,
636 pub required_min_width: Option<f32>,
638 pub required_max_width: Option<f32>,
640 pub required_min_height: Option<f32>,
642 pub required_max_height: Option<f32>,
644 pub default_min_width: Option<f32>,
647 pub default_min_height: Option<f32>,
648 pub background: Option<Brush>,
649 pub state_colors: Option<StateColors>,
650 pub state_elevation: Option<StateElevation>,
651
652 pub border: Option<Border>,
653 pub flex_grow: Option<f32>,
654 pub flex_shrink: Option<f32>,
655 pub flex_basis: Option<f32>,
656 pub flex_basis_content: bool,
659 pub flex_wrap: Option<FlexWrap>,
660 pub flex_line_count: Option<u16>,
663 pub flex_dir: Option<FlexDirection>,
664 pub gap: Option<f32>,
665 pub row_gap: Option<f32>,
666 pub column_gap: Option<f32>,
667 pub align_self: Option<AlignSelf>,
668 pub justify_content: Option<JustifyContent>,
669 pub align_items_container: Option<AlignItems>,
670 pub align_content: Option<AlignContent>,
671 pub clip_rounded: Option<[f32; 4]>,
672 pub clip_rect: Option<ClipRect>,
675 pub overflow: Option<Overflow>,
680 pub z_index: f32,
682 pub render_z_index: Option<f32>,
684 pub hit_passthrough: bool,
686 pub input_blocker: bool,
688 pub repaint_boundary: bool,
689 pub click: bool,
690 pub disabled: bool,
692 pub focusable: Option<bool>,
696 pub propagate_min: bool,
698 pub focus_group: bool,
701 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
702 pub scroll: Option<crate::scroll::ScrollBinding>,
708 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
717 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
718 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
719 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
720 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
721 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
722 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
723 pub on_click: Option<Rc<dyn Fn()>>,
725 pub on_double_click: Option<Rc<dyn Fn()>>,
727 pub on_long_click: Option<Rc<dyn Fn()>>,
729 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
732 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
735 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
738 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
741 pub blur: Option<BlurStyle>,
746 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (f32, f32)>>,
751 pub semantics: Option<crate::Semantics>,
752 pub alpha: Option<f32>,
753 pub graphics_layer: Option<f32>,
754 pub shadow: Option<ShadowSpec>,
755 pub transform: Option<Transform>,
756 pub grid: Option<GridConfig>,
757 pub grid_col_span: Option<u16>,
758 pub grid_row_span: Option<u16>,
759 pub position_type: Option<PositionType>,
760 pub offset_left: Option<f32>,
761 pub offset_right: Option<f32>,
762 pub offset_top: Option<f32>,
763 pub offset_bottom: Option<f32>,
764
765 pub margin_left: Option<f32>,
766 pub margin_right: Option<f32>,
767 pub margin_top: Option<f32>,
768 pub margin_bottom: Option<f32>,
769 pub aspect_ratio: Option<f32>,
770 pub intrinsic_width: Option<IntrinsicSize>,
773 pub intrinsic_height: Option<IntrinsicSize>,
776 pub fit_content_width: Option<f32>,
779 pub fit_content_height: Option<f32>,
782 pub baseline_align: Option<BaselineAlign>,
785 pub contain: Option<Contain>,
790 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
791 pub paint_callback: Option<crate::PaintCallbackPayload>,
792
793 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
795 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
796 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
797 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
798 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
799 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
800 pub drag_preview: Option<crate::dnd::DragPreview>,
802
803 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
804
805 pub cursor: Option<crate::CursorIcon>,
807
808 pub animate_content_size: Option<AnimationSpec>,
811
812 pub focus_requester: Option<crate::runtime::FocusRequester>,
816
817 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
820
821 pub interaction_source: Option<InteractionSource>,
828
829 pub text_input: Option<TextInputConfig>,
831
832 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
834}
835
836impl std::fmt::Debug for Modifier {
837 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
838 let mut s = f.debug_struct("Modifier");
839
840 macro_rules! opt_val {
841 ($($name:ident),+ $(,)?) => {
842 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
843 };
844 }
845 if self.indication.is_some() {
846 s.field("indication", &"…");
847 }
848
849 opt_val!(
850 key,
851 size,
852 width,
853 height,
854 required_size,
855 padding,
856 padding_values,
857 min_width,
858 min_height,
859 max_width,
860 max_height,
861 required_min_width,
862 required_max_width,
863 required_min_height,
864 required_max_height,
865 default_min_width,
866 default_min_height,
867 fill_max,
868 fill_max_w,
869 fill_max_h,
870 background,
871 state_colors,
872 state_elevation,
873 border,
874 flex_grow,
875 flex_shrink,
876 flex_basis,
877 flex_wrap,
878 flex_dir,
879 gap,
880 row_gap,
881 column_gap,
882 align_self,
883 justify_content,
884 align_items_container,
885 align_content,
886 clip_rounded,
887 clip_rect,
888 render_z_index,
889 semantics,
890 alpha,
891 transform,
892 grid,
893 grid_col_span,
894 grid_row_span,
895 position_type,
896 offset_left,
897 offset_right,
898 offset_top,
899 offset_bottom,
900 margin_left,
901 margin_right,
902 margin_top,
903 margin_bottom,
904 aspect_ratio,
905 intrinsic_width,
906 intrinsic_height,
907 cursor,
908 animate_content_size,
909 blur,
910 );
911
912 macro_rules! opt_cb {
913 ($($name:ident),+ $(,)?) => {
914 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
915 };
916 }
917 opt_cb!(
918 on_scroll,
919 scroll,
920 nested_scroll_connection,
921 on_pointer_down,
922 on_pointer_move,
923 on_pointer_up,
924 on_pointer_cancel,
925 on_pointer_enter,
926 on_pointer_leave,
927 on_click,
928 on_double_click,
929 on_long_click,
930 on_globally_positioned,
931 on_size_changed,
932 on_key_event,
933 on_preview_key_event,
934 painter,
935 paint_callback,
936 on_drag_start,
937 on_drag_end,
938 on_drag_enter,
939 on_drag_over,
940 on_drag_leave,
941 on_drop,
942 drag_preview,
943 on_action,
944 on_focus_changed,
945 interaction_source,
946 text_input,
947 layout,
948 );
949
950 macro_rules! flag {
951 ($($name:ident),+ $(,)?) => {
952 $( if self.$name { s.field(stringify!($name), &true); } )+
953 };
954 }
955 flag!(
956 hit_passthrough,
957 input_blocker,
958 repaint_boundary,
959 click,
960 disabled,
961 propagate_min,
962 focus_group,
963 );
964
965 if let Some(f) = self.focusable {
966 s.field("focusable", &f);
967 }
968 if self.z_index != 0.0 {
969 s.field("z_index", &self.z_index);
970 }
971
972 s.finish()
973 }
974}
975
976impl_option_fields!(Modifier);
977
978#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
982pub enum Alignment {
983 TopStart,
984 TopCenter,
985 TopEnd,
986 CenterStart,
987 #[default]
988 Center,
989 CenterEnd,
990 BottomStart,
991 BottomCenter,
992 BottomEnd,
993}
994
995impl Alignment {
996 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
998 use AlignItems as AI;
999 use JustifyContent as JC;
1000 match self {
1001 Self::TopStart => (AI::START, JC::START),
1002 Self::TopCenter => (AI::START, JC::CENTER),
1003 Self::TopEnd => (AI::START, JC::END),
1004 Self::CenterStart => (AI::CENTER, JC::START),
1005 Self::Center => (AI::CENTER, JC::CENTER),
1006 Self::CenterEnd => (AI::CENTER, JC::END),
1007 Self::BottomStart => (AI::END, JC::START),
1008 Self::BottomCenter => (AI::END, JC::CENTER),
1009 Self::BottomEnd => (AI::END, JC::END),
1010 }
1011 }
1012
1013 pub fn to_flex_safe(self) -> (AlignItems, JustifyContent) {
1018 use AlignItems as AI;
1019 use JustifyContent as JC;
1020 match self {
1021 Self::TopStart => (AI::SAFE_START, JC::SAFE_START),
1022 Self::TopCenter => (AI::SAFE_START, JC::SAFE_CENTER),
1023 Self::TopEnd => (AI::SAFE_START, JC::SAFE_END),
1024 Self::CenterStart => (AI::SAFE_CENTER, JC::SAFE_START),
1025 Self::Center => (AI::SAFE_CENTER, JC::SAFE_CENTER),
1026 Self::CenterEnd => (AI::SAFE_CENTER, JC::SAFE_END),
1027 Self::BottomStart => (AI::SAFE_END, JC::SAFE_START),
1028 Self::BottomCenter => (AI::SAFE_END, JC::SAFE_CENTER),
1029 Self::BottomEnd => (AI::SAFE_END, JC::SAFE_END),
1030 }
1031 }
1032}
1033
1034impl Modifier {
1035 pub fn new() -> Self {
1036 Self::default()
1037 }
1038
1039 pub fn key(mut self, key: u64) -> Self {
1042 self.key = Some(key);
1043 self
1044 }
1045
1046 pub fn size(mut self, w: f32, h: f32) -> Self {
1047 self.size = Some(Size {
1048 width: w,
1049 height: h,
1050 });
1051 self
1052 }
1053 pub fn width(mut self, w: f32) -> Self {
1054 self.width = Some(w);
1055 self
1056 }
1057 pub fn height(mut self, h: f32) -> Self {
1058 self.height = Some(h);
1059 self
1060 }
1061 pub fn required_size(mut self, w: f32, h: f32) -> Self {
1066 self.required_size = Some(Size {
1067 width: w,
1068 height: h,
1069 });
1070 self
1071 }
1072 pub fn required_width_in(mut self, min: f32, max: f32) -> Self {
1073 self.required_min_width = Some(min.max(0.0));
1074 self.required_max_width = Some(max.max(0.0));
1075 self
1076 }
1077 pub fn required_height_in(mut self, min: f32, max: f32) -> Self {
1078 self.required_min_height = Some(min.max(0.0));
1079 self.required_max_height = Some(max.max(0.0));
1080 self
1081 }
1082 pub fn required_min_width(mut self, w: f32) -> Self {
1083 self.required_min_width = Some(w.max(0.0));
1084 self
1085 }
1086 pub fn required_max_width(mut self, w: f32) -> Self {
1087 self.required_max_width = Some(w.max(0.0));
1088 self
1089 }
1090 pub fn required_min_height(mut self, h: f32) -> Self {
1091 self.required_min_height = Some(h.max(0.0));
1092 self
1093 }
1094 pub fn required_max_height(mut self, h: f32) -> Self {
1095 self.required_max_height = Some(h.max(0.0));
1096 self
1097 }
1098 pub fn default_min_size(mut self, w: f32, h: f32) -> Self {
1100 self.default_min_width = Some(w.max(0.0));
1101 self.default_min_height = Some(h.max(0.0));
1102 self
1103 }
1104 pub fn fill_max_size(mut self) -> Self {
1107 self.fill_max = Some(1.0);
1108 self
1109 }
1110 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
1111 self.fill_max = Some(fraction.clamp(0.0, 1.0));
1112 self
1113 }
1114 pub fn fill_max_width(mut self) -> Self {
1116 self.fill_max_w = Some(1.0);
1117 self
1118 }
1119 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
1120 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
1121 self
1122 }
1123 pub fn fill_max_height(mut self) -> Self {
1125 self.fill_max_h = Some(1.0);
1126 self
1127 }
1128 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
1129 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
1130 self
1131 }
1132 pub fn padding(mut self, v: f32) -> Self {
1133 self.padding = Some(v);
1134 self
1135 }
1136 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
1137 self.padding_values = Some(padding);
1138 self
1139 }
1140 pub fn ime_padding(mut self) -> Self {
1143 let insets = crate::locals::window_insets();
1144 let scale = crate::locals::effective_density_scale();
1145 let mut p = self.padding_values.unwrap_or_default();
1146 p.bottom += insets.ime_bottom / scale;
1147 self.padding_values = Some(p);
1148 self
1149 }
1150 pub fn system_bars_padding(mut self) -> Self {
1152 let insets = crate::locals::window_insets();
1153 let scale = crate::locals::effective_density_scale();
1154 let mut p = self.padding_values.unwrap_or_default();
1155 p.top += insets.top / scale;
1156 p.bottom += insets.bottom / scale;
1157 self.padding_values = Some(p);
1158 self
1159 }
1160 pub fn status_bars_padding(mut self) -> Self {
1162 let insets = crate::locals::window_insets();
1163 let scale = crate::locals::effective_density_scale();
1164 let mut p = self.padding_values.unwrap_or_default();
1165 p.top += insets.top / scale;
1166 self.padding_values = Some(p);
1167 self
1168 }
1169 pub fn navigation_bars_padding(mut self) -> Self {
1171 let insets = crate::locals::window_insets();
1172 let scale = crate::locals::effective_density_scale();
1173 let mut p = self.padding_values.unwrap_or_default();
1174 p.bottom += insets.bottom / scale;
1175 self.padding_values = Some(p);
1176 self
1177 }
1178 pub fn min_size(mut self, w: f32, h: f32) -> Self {
1179 self.min_width = Some(w);
1180 self.min_height = Some(h);
1181 self
1182 }
1183 pub fn max_size(mut self, w: f32, h: f32) -> Self {
1184 self.max_width = Some(w);
1185 self.max_height = Some(h);
1186 self
1187 }
1188 pub fn min_width(mut self, w: f32) -> Self {
1189 self.min_width = Some(w);
1190 self
1191 }
1192 pub fn min_height(mut self, h: f32) -> Self {
1193 self.min_height = Some(h);
1194 self
1195 }
1196 pub fn max_width(mut self, w: f32) -> Self {
1197 self.max_width = Some(w);
1198 self
1199 }
1200 pub fn max_height(mut self, h: f32) -> Self {
1201 self.max_height = Some(h);
1202 self
1203 }
1204 pub fn background(mut self, color: Color) -> Self {
1206 self.background = Some(Brush::Solid(color));
1207 self
1208 }
1209 pub fn background_brush(mut self, brush: Brush) -> Self {
1211 self.background = Some(brush);
1212 self
1213 }
1214 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
1215 self.border = Some(Border {
1216 width,
1217 color,
1218 radius: [radius; 4],
1219 });
1220 self
1221 }
1222 pub fn border_radii(mut self, width: f32, color: Color, radii: [f32; 4]) -> Self {
1223 self.border = Some(Border {
1224 width,
1225 color,
1226 radius: radii,
1227 });
1228 self
1229 }
1230 pub fn flex_grow(mut self, v: f32) -> Self {
1231 self.flex_grow = Some(v);
1232 self
1233 }
1234 pub fn flex_shrink(mut self, v: f32) -> Self {
1235 self.flex_shrink = Some(v);
1236 self
1237 }
1238 pub fn flex_basis(mut self, v: f32) -> Self {
1239 self.flex_basis = Some(v);
1240 self
1241 }
1242 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1243 self.flex_wrap = Some(w);
1244 self
1245 }
1246 pub fn flex_basis_content(mut self) -> Self {
1249 self.flex_basis_content = true;
1250 self
1251 }
1252 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1253 self.flex_dir = Some(d);
1254 self
1255 }
1256 pub fn gap(mut self, v: f32) -> Self {
1257 let v = v.max(0.0);
1258 self.gap = Some(v);
1259 self.row_gap = Some(v);
1260 self.column_gap = Some(v);
1261 self
1262 }
1263 pub fn row_gap(mut self, v: f32) -> Self {
1264 self.row_gap = Some(v.max(0.0));
1265 self
1266 }
1267 pub fn column_gap(mut self, v: f32) -> Self {
1268 self.column_gap = Some(v.max(0.0));
1269 self
1270 }
1271 pub fn align_self(mut self, a: AlignSelf) -> Self {
1272 self.align_self = Some(a);
1273 self
1274 }
1275 pub fn align_self_center(mut self) -> Self {
1276 self.align_self = Some(AlignSelf::CENTER);
1277 self
1278 }
1279 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1280 self.justify_content = Some(j);
1281 self
1282 }
1283 pub fn align_items(mut self, a: AlignItems) -> Self {
1284 self.align_items_container = Some(a);
1285 self
1286 }
1287 pub fn content_alignment(self, alignment: Alignment) -> Self {
1290 let (ai, jc) = alignment.to_flex();
1291 self.align_items(ai).justify_content(jc)
1292 }
1293 pub fn content_alignment_safe(self, alignment: Alignment) -> Self {
1298 let (ai, jc) = alignment.to_flex_safe();
1299 self.align_items(ai).justify_content(jc)
1300 }
1301 pub fn align_content(mut self, a: AlignContent) -> Self {
1302 self.align_content = Some(a);
1303 self
1304 }
1305 pub fn clip_rounded(mut self, radius: f32) -> Self {
1306 self.clip_rounded = Some([radius; 4]);
1307 self
1308 }
1309 pub fn clip_rounded_radii(mut self, radii: [f32; 4]) -> Self {
1310 self.clip_rounded = Some(radii);
1311 self
1312 }
1313 pub fn clip_rect(mut self, left: f32, top: f32, right: f32, bottom: f32, op: ClipOp) -> Self {
1316 self.clip_rect = Some(ClipRect {
1317 left,
1318 top,
1319 right,
1320 bottom,
1321 op,
1322 });
1323 self
1324 }
1325 pub fn overflow(mut self, overflow: Overflow) -> Self {
1326 self.overflow = Some(overflow);
1327 self
1328 }
1329 pub fn z_index(mut self, z: f32) -> Self {
1330 self.z_index = z;
1331 self
1332 }
1333
1334 pub fn render_z_index(mut self, z: f32) -> Self {
1337 self.render_z_index = Some(z);
1338 self
1339 }
1340
1341 pub fn input_blocker(mut self) -> Self {
1343 self.input_blocker = true;
1344 self
1345 }
1346
1347 pub fn hit_passthrough(mut self) -> Self {
1348 self.hit_passthrough = true;
1349 self
1350 }
1351 pub fn clickable(mut self) -> Self {
1352 self.click = true;
1353 if self.indication.is_none() {
1354 self.indication = crate::locals::local_indication();
1355 }
1356 self
1357 }
1358 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1361 self.click = true;
1362 self.interaction_source = Some(source.source());
1363 if self.indication.is_none() {
1364 self.indication = crate::locals::local_indication();
1365 }
1366 self
1367 }
1368 pub fn state_colors(mut self, colors: StateColors) -> Self {
1371 self.state_colors = Some(colors);
1372 self
1373 }
1374 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1376 self.state_elevation = Some(elev);
1377 self
1378 }
1379 pub fn disabled(mut self) -> Self {
1381 self.disabled = true;
1382 self
1383 }
1384 pub fn enabled(mut self, enabled: bool) -> Self {
1386 self.disabled = !enabled;
1387 self
1388 }
1389 pub fn focusable(mut self, focusable: bool) -> Self {
1394 self.focusable = Some(focusable);
1395 self
1396 }
1397 pub fn focus_group(mut self) -> Self {
1400 self.focus_group = true;
1401 self
1402 }
1403 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1414 self.interaction_source = Some(source.source());
1415 self
1416 }
1417 pub fn hoverable(
1420 mut self,
1421 on_enter: impl Fn() + 'static,
1422 on_leave: impl Fn() + 'static,
1423 ) -> Self {
1424 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1425 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1426 self
1427 }
1428 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1432 self.interaction_source = Some(source.source());
1433 self
1434 }
1435 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1438 self.propagate_min = propagate;
1439 self
1440 }
1441 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1442 self.on_scroll = Some(Rc::new(f));
1443 self
1444 }
1445 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1449 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1450 self
1451 }
1452 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1454 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1455 self
1456 }
1457 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1459 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1460 self
1461 }
1462 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1469 self.nested_scroll_connection = Some(conn);
1470 self
1471 }
1472 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1473 self.on_pointer_down = Some(Rc::new(f));
1474 self
1475 }
1476 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1477 self.on_pointer_move = Some(Rc::new(f));
1478 self
1479 }
1480 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1481 self.on_pointer_up = Some(Rc::new(f));
1482 self
1483 }
1484 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1485 self.on_pointer_cancel = Some(Rc::new(f));
1486 self
1487 }
1488
1489 pub fn draggable(self, on_drag: impl Fn(Vec2) + 'static) -> Self {
1490 let drag_pos = crate::state::remember_mutable(Vec2::default);
1491 let is_dragging = crate::state::remember_mutable(|| false);
1492 let on_drag = Rc::new(on_drag);
1493 self.on_pointer_down({
1494 let drag_pos = drag_pos.clone();
1495 let is_dragging = is_dragging.clone();
1496 move |ev| {
1497 is_dragging.set(true);
1498 drag_pos.set(ev.position);
1499 }
1500 })
1501 .on_pointer_up({
1502 let is_dragging = is_dragging.clone();
1503 move |_| is_dragging.set(false)
1504 })
1505 .on_pointer_cancel({
1506 let is_dragging = is_dragging.clone();
1507 move |_| is_dragging.set(false)
1508 })
1509 .on_pointer_move({
1510 let drag_pos = drag_pos.clone();
1511 let is_dragging = is_dragging.clone();
1512 let on_drag = on_drag.clone();
1513 move |ev| {
1514 if !*is_dragging.get() {
1515 return;
1516 }
1517 let prev = *drag_pos.get();
1518 let cur = ev.position;
1519 let delta = Vec2 {
1520 x: cur.x - prev.x,
1521 y: cur.y - prev.y,
1522 };
1523 drag_pos.set(cur);
1524 on_drag(delta);
1525 crate::frame_clock::request_frame();
1526 }
1527 })
1528 }
1529 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1530 self.on_pointer_enter = Some(Rc::new(f));
1531 self
1532 }
1533 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1534 self.on_pointer_leave = Some(Rc::new(f));
1535 self
1536 }
1537 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1538 self.on_click = Some(Rc::new(f));
1539 self.click = true;
1540 if self.semantics.is_none() {
1541 self.semantics = Some(crate::Semantics::new(crate::Role::Button));
1542 }
1543 self
1544 }
1545 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1546 self.on_double_click = Some(Rc::new(f));
1547 self.click = true;
1548 self
1549 }
1550 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1551 self.on_long_click = Some(Rc::new(f));
1552 self.click = true;
1553 self
1554 }
1555 pub fn clickable_ext(
1556 mut self,
1557 enabled: bool,
1558 on_click_label: Option<String>,
1559 role: Option<crate::semantics::Role>,
1560 on_click: impl Fn() + 'static,
1561 ) -> Self {
1562 if !enabled {
1563 let mut s = self.semantics.clone().unwrap_or_else(|| {
1564 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1565 });
1566 s.enabled = false;
1567 if let Some(r) = role {
1568 s.role = r;
1569 }
1570 if let Some(l) = on_click_label {
1571 s.label = Some(l);
1572 }
1573 return self
1574 .clickable()
1575 .enabled(false)
1576 .default_min_size(48.0, 48.0)
1577 .semantics(s);
1578 }
1579 self = self.clickable().on_click(on_click);
1580 if role.is_some() || on_click_label.is_some() {
1581 let mut s = self.semantics.clone().unwrap_or_else(|| {
1582 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1583 });
1584 s.enabled = true;
1585 if let Some(r) = role {
1586 s.role = r;
1587 }
1588 if let Some(l) = on_click_label {
1589 s.label = Some(l);
1590 }
1591 self = self.semantics(s);
1592 }
1593 self.default_min_size(48.0, 48.0)
1594 }
1595 pub fn combined_clickable(
1596 mut self,
1597 enabled: bool,
1598 on_click_label: Option<String>,
1599 role: Option<crate::semantics::Role>,
1600 on_long_click_label: Option<String>,
1601 on_click: impl Fn() + 'static,
1602 on_long_click: Option<impl Fn() + 'static>,
1603 on_double_click: Option<impl Fn() + 'static>,
1604 ) -> Self {
1605 let _ = on_long_click_label;
1606 if !enabled {
1607 return self.clickable_ext(false, on_click_label, role, || {});
1608 }
1609 self = self.clickable_ext(true, on_click_label, role, on_click);
1610 if let Some(f) = on_long_click {
1611 self = self.on_long_click(f);
1612 }
1613 if let Some(f) = on_double_click {
1614 self = self.on_double_click(f);
1615 }
1616 self.default_min_size(48.0, 48.0)
1617 }
1618 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1619 self.semantics = Some(s);
1620 self
1621 }
1622 pub fn alpha(mut self, a: f32) -> Self {
1623 self.alpha = Some(a);
1624 self
1625 }
1626 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1631 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1632 self
1633 }
1634 pub fn shadow(mut self, blur_radius: f32, offset_y: f32) -> Self {
1638 self.shadow = Some(ShadowSpec {
1639 blur_radius: blur_radius.max(0.0),
1640 offset_y,
1641 color: Color(0, 0, 0, 64),
1642 });
1643 self
1644 }
1645 pub fn shadow_with_color(mut self, blur_radius: f32, offset_y: f32, color: Color) -> Self {
1647 self.shadow = Some(ShadowSpec {
1648 blur_radius: blur_radius.max(0.0),
1649 offset_y,
1650 color,
1651 });
1652 self
1653 }
1654 pub fn elevation(mut self, level: f32) -> Self {
1658 if level <= 0.0 {
1659 self.shadow = None;
1660 return self;
1661 }
1662 self.shadow = Some(ShadowSpec {
1663 blur_radius: level * 2.0,
1664 offset_y: level * 0.5,
1665 color: Color(0, 0, 0, (level * 8.0).clamp(8.0, 80.0) as u8),
1666 });
1667 self
1668 }
1669 pub fn transform(mut self, t: Transform) -> Self {
1670 self.transform = Some(t);
1671 self
1672 }
1673 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
1674 self.grid = Some(GridConfig {
1675 columns,
1676 row_gap,
1677 column_gap,
1678 });
1679 self
1680 }
1681 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1682 self.grid_col_span = Some(col_span);
1683 self.grid_row_span = Some(row_span);
1684 self
1685 }
1686 pub fn absolute(mut self) -> Self {
1687 self.position_type = Some(PositionType::Absolute);
1688 self
1689 }
1690 pub fn offset(
1691 mut self,
1692 left: Option<f32>,
1693 top: Option<f32>,
1694 right: Option<f32>,
1695 bottom: Option<f32>,
1696 ) -> Self {
1697 self.offset_left = left;
1698 self.offset_top = top;
1699 self.offset_right = right;
1700 self.offset_bottom = bottom;
1701 self
1702 }
1703 pub fn offset_left(mut self, v: f32) -> Self {
1704 self.offset_left = Some(v);
1705 self
1706 }
1707 pub fn offset_right(mut self, v: f32) -> Self {
1708 self.offset_right = Some(v);
1709 self
1710 }
1711 pub fn offset_top(mut self, v: f32) -> Self {
1712 self.offset_top = Some(v);
1713 self
1714 }
1715 pub fn offset_bottom(mut self, v: f32) -> Self {
1716 self.offset_bottom = Some(v);
1717 self
1718 }
1719 pub fn margin(mut self, v: f32) -> Self {
1720 self.margin_left = Some(v);
1721 self.margin_right = Some(v);
1722 self.margin_top = Some(v);
1723 self.margin_bottom = Some(v);
1724 self
1725 }
1726
1727 pub fn margin_horizontal(mut self, v: f32) -> Self {
1728 self.margin_left = Some(v);
1729 self.margin_right = Some(v);
1730 self
1731 }
1732
1733 pub fn margin_vertical(mut self, v: f32) -> Self {
1734 self.margin_top = Some(v);
1735 self.margin_bottom = Some(v);
1736 self
1737 }
1738 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1739 self.aspect_ratio = Some(ratio);
1740 self
1741 }
1742 pub fn fit_content_width(mut self, limit_dp: f32) -> Self {
1744 self.fit_content_width = Some(limit_dp.max(0.0));
1745 self
1746 }
1747 pub fn fit_content_height(mut self, limit_dp: f32) -> Self {
1749 self.fit_content_height = Some(limit_dp.max(0.0));
1750 self
1751 }
1752 pub fn contain(mut self, c: Contain) -> Self {
1754 self.contain = Some(c);
1755 self
1756 }
1757 pub fn contain_layout(mut self) -> Self {
1759 self.contain = Some(Contain::LAYOUT);
1760 self
1761 }
1762 pub fn contain_paint(mut self) -> Self {
1764 self.contain = Some(Contain::PAINT);
1765 self
1766 }
1767 pub fn contain_content(mut self) -> Self {
1769 self.contain = Some(Contain::CONTENT);
1770 self
1771 }
1772 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1774 self.intrinsic_width = Some(mode);
1775 self
1776 }
1777 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1779 self.intrinsic_height = Some(mode);
1780 self
1781 }
1782 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1783 self.painter = Some(Rc::new(f));
1784 self
1785 }
1786 pub fn paint_callback(mut self, payload: crate::PaintCallbackPayload) -> Self {
1792 self.paint_callback = Some(payload);
1793 self
1794 }
1795 pub fn scale(self, s: f32) -> Self {
1796 self.scale2(s, s)
1797 }
1798 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1799 let mut t = self.transform.unwrap_or_else(Transform::identity);
1800 t.scale_x *= sx;
1801 t.scale_y *= sy;
1802 self.transform = Some(t);
1803 self
1804 }
1805 pub fn translate(mut self, x: f32, y: f32) -> Self {
1806 let t = self.transform.unwrap_or_else(Transform::identity);
1807 self.transform = Some(t.combine(&Transform::translate(x, y)));
1808 self
1809 }
1810 pub fn translate_vec2(self, v: Vec2) -> Self {
1811 self.translate(v.x, v.y)
1812 }
1813 pub fn rotate(mut self, radians: f32) -> Self {
1814 let mut t = self.transform.unwrap_or_else(Transform::identity);
1815 t.rotate += radians;
1816 self.transform = Some(t);
1817 self
1818 }
1819 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1820 let mut t = self.transform.unwrap_or_else(Transform::identity);
1821 t.origin_x = x;
1822 t.origin_y = y;
1823 self.transform = Some(t);
1824 self
1825 }
1826 pub fn weight(mut self, w: f32) -> Self {
1827 let w = w.max(0.0);
1828 self.flex_grow = Some(w);
1829 self.flex_shrink = Some(1.0);
1830 self.flex_basis = Some(0.0);
1832 self
1833 }
1834 pub fn repaint_boundary(mut self) -> Self {
1838 self.repaint_boundary = true;
1839 self
1840 }
1841 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1842 self.on_action = Some(Rc::new(f));
1843 self
1844 }
1845
1846 pub fn on_drag_start(
1848 mut self,
1849 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1850 ) -> Self {
1851 self.on_drag_start = Some(Rc::new(f));
1852 self
1853 }
1854
1855 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1857 self.on_drag_end = Some(Rc::new(f));
1858 self
1859 }
1860
1861 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1863 self.on_drag_enter = Some(Rc::new(f));
1864 self
1865 }
1866
1867 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1869 self.on_drag_over = Some(Rc::new(f));
1870 self
1871 }
1872
1873 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1875 self.on_drag_leave = Some(Rc::new(f));
1876 self
1877 }
1878
1879 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1882 self.on_drop = Some(Rc::new(f));
1883 self
1884 }
1885
1886 pub fn draw_drag_decoration(
1891 mut self,
1892 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
1893 ) -> Self {
1894 self.drag_preview = Some(Rc::new(f));
1895 self
1896 }
1897
1898 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
1900 self.drag_preview = Some(preview);
1901 self
1902 }
1903
1904 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
1906 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
1907 }
1908
1909 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
1911 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
1912 }
1913
1914 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1916 self.cursor = Some(c);
1917 self
1918 }
1919
1920 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1924 self.animate_content_size = Some(spec);
1925 self
1926 }
1927
1928 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1931 self.focus_requester = Some(fr);
1932 self
1933 }
1934
1935 pub fn focus_target(mut self) -> Self {
1938 self.focusable = Some(true);
1939 self
1940 }
1941
1942 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1945 self.on_focus_changed = Some(Rc::new(f));
1946 self
1947 }
1948
1949 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
1953 self.on_globally_positioned = Some(Rc::new(f));
1954 self
1955 }
1956
1957 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
1960 self.on_size_changed = Some(Rc::new(f));
1961 self
1962 }
1963
1964 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
1968 self.on_key_event = Some(Rc::new(f));
1969 self
1970 }
1971
1972 pub fn on_preview_key_event(
1976 mut self,
1977 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
1978 ) -> Self {
1979 self.on_preview_key_event = Some(Rc::new(f));
1980 self
1981 }
1982
1983 pub fn blur(mut self, radius_dp: f32) -> Self {
1990 self.blur = Some(BlurStyle {
1991 radius_x: radius_dp.max(0.0),
1992 radius_y: radius_dp.max(0.0),
1993 edge_treatment: BlurredEdgeTreatment::Rectangle,
1994 });
1995 self
1996 }
1997
1998 pub fn blur_with_edge(
2003 mut self,
2004 radius_x: f32,
2005 radius_y: f32,
2006 edge_treatment: BlurredEdgeTreatment,
2007 ) -> Self {
2008 self.blur = Some(BlurStyle {
2009 radius_x: radius_x.max(0.0),
2010 radius_y: radius_y.max(0.0),
2011 edge_treatment,
2012 });
2013 self
2014 }
2015
2016 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (f32, f32) + 'static) -> Self {
2024 self.layout = Some(Rc::new(f));
2025 self
2026 }
2027
2028 pub fn text_input(mut self, config: TextInputConfig) -> Self {
2030 self.text_input = Some(config);
2031 self
2032 }
2033
2034 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
2038 self.indication = Some(factory);
2039 self
2040 }
2041}