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::units::{Dp, DpSize};
13use crate::{Brush, Color, PointerEvent, Transform, Vec2};
14
15#[derive(Clone, Copy, Debug)]
19pub struct StateColors {
20 pub default: Color,
21 pub hovered: Color,
22 pub focused: Color,
24 pub pressed: Color,
25 pub disabled: Color,
26 pub dragged: Color,
28}
29
30#[derive(Clone, Copy, Debug)]
33pub struct StateElevation {
34 pub default: Dp,
35 pub hovered: Dp,
36 pub focused: Dp,
38 pub pressed: Dp,
39 pub disabled: Dp,
40 pub dragged: Dp,
42}
43
44impl StateColors {
45 pub const fn transparent() -> Self {
46 Self {
47 default: Color::TRANSPARENT,
48 hovered: Color::TRANSPARENT,
49 focused: Color::TRANSPARENT,
50 pressed: Color::TRANSPARENT,
51 disabled: Color::TRANSPARENT,
52 dragged: Color::TRANSPARENT,
53 }
54 }
55}
56
57impl StateElevation {
58 pub const fn zero() -> Self {
59 Self {
60 default: Dp(0.0),
61 hovered: Dp(0.0),
62 focused: Dp(0.0),
63 pressed: Dp(0.0),
64 disabled: Dp(0.0),
65 dragged: Dp(0.0),
66 }
67 }
68}
69
70macro_rules! merge_opts {
71 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
72 $( $dst.$f = $src.$f.or($dst.$f); )+
73 };
74}
75macro_rules! merge_flags {
76 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
77 $( $dst.$f |= $src.$f; )+
78 };
79}
80
81macro_rules! impl_option_fields {
82 ($ty:ty, $fn:ident) => {
83 impl $ty {
84 $fn!(replace);
85 }
86 };
87 ($ty:ident) => {
88 impl $ty {
89 pub fn then(mut self, other: Self) -> Self {
92 merge_opts!(self, other;
93 key, size, width, height, required_size,
94 padding, padding_values,
95 min_width, min_height, max_width, max_height,
96 required_min_width, required_max_width,
97 required_min_height, required_max_height,
98 default_min_width, default_min_height,
99 fill_max, fill_max_w, fill_max_h,
100 background, state_colors, state_elevation, border,
101 flex_grow, flex_shrink, flex_basis, flex_wrap, flex_dir,
102 flex_line_count,
103 gap, row_gap, column_gap,
104 align_self, justify_content, align_items_container, align_content,
105 baseline_align,
106 clip_rounded, clip_rect, overflow, render_z_index,
107 on_scroll,
108 nested_scroll_connection,
109 scroll,
110 on_pointer_down, on_pointer_move, on_pointer_up,
111 on_pointer_cancel,
112 on_pointer_enter, on_pointer_leave,
113 on_click, on_double_click, on_long_click,
114 on_globally_positioned, on_size_changed,
115 on_key_event, on_preview_key_event,
116 semantics, alpha, transform,
117 grid, grid_col_span, grid_row_span,
118 position_type,
119 offset_left, offset_right, offset_top, offset_bottom,
120 margin_left, margin_right, margin_top, margin_bottom,
121 aspect_ratio, intrinsic_width, intrinsic_height,
122 fit_content_width, fit_content_height,
123 contain,
124 painter,
125 paint_callback,
126 layout,
127 blur, graphics_layer, shadow,
128 on_drag_start, on_drag_end, on_drag_enter, on_drag_over, on_drag_leave, on_drop,
129 drag_preview,
130 on_action, cursor, animate_content_size, focus_requester, on_focus_changed,
131 interaction_source, text_input,
132 );
133 merge_flags!(self, other;
134 hit_passthrough, input_blocker, repaint_boundary, click, disabled,
135 propagate_min, focus_group,
136 );
137
138 self.flex_basis_content |= other.flex_basis_content;
140
141 if let Some(f) = other.focusable {
142 self.focusable = Some(f);
143 }
144 if other.indication.is_some() {
145 self.indication = other.indication;
146 }
147 self.z_index = other.z_index;
149 self
150 }
151 }
152 };
153}
154
155#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
156pub enum ClipOp {
157 #[default]
159 Intersect,
160 Difference,
162}
163
164#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
170pub enum Overflow {
171 #[default]
172 Clip,
173 Visible,
174}
175
176#[derive(Clone, Copy, Debug)]
179pub struct ClipRect {
180 pub left: Dp,
181 pub top: Dp,
182 pub right: Dp,
183 pub bottom: Dp,
184 pub op: ClipOp,
185}
186
187#[derive(Clone, Debug)]
188pub struct Border {
189 pub width: Dp,
190 pub color: Color,
191 pub radius: [Dp; 4],
192}
193
194#[derive(Clone, Copy, Debug, Default)]
195pub struct PaddingValues {
196 pub left: Dp,
197 pub right: Dp,
198 pub top: Dp,
199 pub bottom: Dp,
200}
201
202#[derive(Clone, Debug)]
203pub struct GridConfig {
204 pub columns: usize,
205 pub row_gap: Dp,
206 pub column_gap: Dp,
207}
208
209#[derive(Clone, Copy, Debug, PartialEq)]
212pub enum BlurredEdgeTreatment {
213 Rectangle,
216 Unbounded,
219}
220
221#[derive(Clone, Copy, Debug)]
223pub struct BlurStyle {
224 pub radius_x: Dp,
226 pub radius_y: Dp,
228 pub edge_treatment: BlurredEdgeTreatment,
230}
231
232#[derive(Clone, Copy, Debug)]
238pub struct LayoutConstraints {
239 pub min_width: Dp,
240 pub max_width: Dp,
241 pub min_height: Dp,
242 pub max_height: Dp,
243}
244
245#[derive(Clone, Copy, Debug)]
252pub struct ShadowSpec {
253 pub blur_radius: Dp,
254 pub offset_y: Dp,
255 pub color: Color,
256}
257
258#[derive(Clone, Copy, Debug)]
259#[non_exhaustive]
260pub enum PositionType {
261 Relative,
262 Absolute,
263}
264
265#[derive(Clone)]
267pub struct TextInputConfig {
268 pub hint: String,
269 pub multiline: bool,
270 pub on_change: Option<Rc<dyn Fn(String)>>,
271 pub on_submit: Option<Rc<dyn Fn(String)>>,
272 pub focus_tracker: Option<Rc<Cell<bool>>>,
273 pub value: String,
274 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
275 pub keyboard_type: crate::text::KeyboardType,
276 pub capitalization: crate::text::KeyboardCapitalization,
277 pub ime_action: crate::text::ImeAction,
278 pub auto_correct_enabled: Option<bool>,
281 pub enabled: bool,
283 pub read_only: bool,
285 pub max_lines: Option<usize>,
287 pub min_lines: usize,
289 pub cursor_color: Option<Color>,
291 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
294 pub text_style: Option<crate::text::TextStyle>,
297 pub keyboard_actions: Option<crate::text::KeyboardActions>,
300 pub interaction_source: Option<InteractionSource>,
302 pub line_limits: Option<crate::text::TextFieldLineLimits>,
304}
305
306impl Default for TextInputConfig {
307 fn default() -> Self {
308 Self {
309 hint: String::new(),
310 multiline: false,
311 on_change: None,
312 on_submit: None,
313 focus_tracker: None,
314 value: String::new(),
315 visual_transformation: None,
316 keyboard_type: crate::text::KeyboardType::default(),
317 capitalization: crate::text::KeyboardCapitalization::default(),
318 ime_action: crate::text::ImeAction::default(),
319 auto_correct_enabled: None,
320 enabled: true,
321 read_only: false,
322 max_lines: None,
323 min_lines: 1,
324 cursor_color: None,
325 on_text_layout: None,
326 text_style: None,
327 keyboard_actions: None,
328 interaction_source: None,
329 line_limits: None,
330 }
331 }
332}
333
334impl std::fmt::Debug for TextInputConfig {
335 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
336 let mut s = f.debug_struct("TextInputConfig");
337 s.field("hint", &self.hint);
338 s.field("multiline", &self.multiline);
339 if self.on_change.is_some() {
340 s.field("on_change", &"…");
341 }
342 if self.on_submit.is_some() {
343 s.field("on_submit", &"…");
344 }
345 if self.focus_tracker.is_some() {
346 s.field("focus_tracker", &"…");
347 }
348 s.field("value", &self.value);
349 if self.visual_transformation.is_some() {
350 s.field("visual_transformation", &"…");
351 }
352 s.field("keyboard_type", &self.keyboard_type);
353 s.field("capitalization", &self.capitalization);
354 s.field("ime_action", &self.ime_action);
355 s.field("auto_correct_enabled", &self.auto_correct_enabled);
356 s.field("enabled", &self.enabled);
357 s.field("read_only", &self.read_only);
358 s.field("max_lines", &self.max_lines);
359 s.field("min_lines", &self.min_lines);
360 s.field("cursor_color", &self.cursor_color);
361 if self.on_text_layout.is_some() {
362 s.field("on_text_layout", &"…");
363 }
364 s.finish()
365 }
366}
367
368#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
371pub enum IntrinsicSize {
372 Min,
373 Max,
374}
375
376#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
384pub enum BaselineAlign {
385 FirstBaseline,
386 LastBaseline,
387}
388
389static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
390
391pub type PressId = u64;
393
394#[derive(Clone, Copy, Debug, PartialEq)]
402pub enum Interaction {
403 Press(PressId, Vec2),
406 Release(PressId),
408 Cancel(PressId),
411 HoverEnter,
412 HoverLeave,
413 Focus,
414 Unfocus,
415 DragStart,
416 DragStop,
417 DragCancel,
418}
419
420impl Interaction {
421 #[inline]
423 pub fn new_press(position: Vec2) -> Self {
424 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
425 }
426}
427
428#[derive(Clone)]
435pub struct InteractionSource {
436 pub(crate) state: Rc<RefCell<InteractionState>>,
437}
438
439impl InteractionSource {
440 pub fn collect_is_pressed(&self) -> bool {
441 !self.state.borrow().active_presses.is_empty()
442 }
443 pub fn collect_is_hovered(&self) -> bool {
444 self.state.borrow().hovered
445 }
446 pub fn collect_is_focused(&self) -> bool {
447 self.state.borrow().focused
448 }
449
450 pub fn collect_is_focus_visible(&self) -> bool {
452 crate::input::is_focus_visible(self.collect_is_focused())
453 }
454
455 pub fn collect_is_dragged(&self) -> bool {
456 self.state.borrow().dragged > 0
457 }
458 pub fn collect_last_press_position(&self) -> Option<Vec2> {
459 self.state.borrow().last_press_position
460 }
461 pub fn collect_last_press_id(&self) -> Option<PressId> {
462 self.state.borrow().last_press_id
463 }
464 pub fn stable_id(&self) -> *const () {
466 Rc::as_ptr(&self.state) as *const ()
467 }
468 pub fn to_mutable(&self) -> MutableInteractionSource {
472 MutableInteractionSource {
473 state: self.state.clone(),
474 }
475 }
476
477 pub fn reset(&self) {
479 self.to_mutable().reset();
480 }
481
482 pub fn reset_hover(&self) {
484 self.to_mutable().reset_hover();
485 }
486}
487
488#[derive(Clone)]
498pub struct MutableInteractionSource {
499 pub(crate) state: Rc<RefCell<InteractionState>>,
500}
501
502impl std::fmt::Debug for MutableInteractionSource {
503 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
504 f.debug_struct("MutableInteractionSource")
505 .finish_non_exhaustive()
506 }
507}
508
509impl MutableInteractionSource {
510 pub fn new() -> Self {
511 Self {
512 state: Rc::new(RefCell::new(InteractionState::default())),
513 }
514 }
515
516 pub fn emit(&self, interaction: Interaction) {
518 let changed = {
519 let mut s = self.state.borrow_mut();
520 match interaction {
521 Interaction::Press(id, pos) => {
522 let inserted = s.active_presses.insert(id);
523 s.last_press_id = Some(id);
524 s.last_press_position = Some(pos);
525 inserted
526 }
527 Interaction::Release(id) | Interaction::Cancel(id) => {
528 if s.active_presses.remove(&id) {
529 true
530 } else if id == 0 {
531 if let Some(any) = s.active_presses.iter().next().copied() {
532 s.active_presses.remove(&any);
533 true
534 } else {
535 false
536 }
537 } else {
538 false
539 }
540 }
541 Interaction::HoverEnter => {
542 let changed = !s.hovered;
543 s.hovered = true;
544 changed
545 }
546 Interaction::HoverLeave => {
547 let changed = s.hovered;
548 s.hovered = false;
549 if !s.active_presses.is_empty() {
551 s.active_presses.clear();
552 true
553 } else {
554 changed
555 }
556 }
557 Interaction::Focus => {
558 let changed = !s.focused;
559 s.focused = true;
560 changed
561 }
562 Interaction::Unfocus => {
563 let changed = s.focused;
564 s.focused = false;
565 changed
566 }
567 Interaction::DragStart => {
568 let changed = s.dragged == 0;
569 s.dragged = s.dragged.saturating_add(1);
570 changed
571 }
572 Interaction::DragStop | Interaction::DragCancel => {
573 let was = s.dragged;
574 s.dragged = s.dragged.saturating_sub(1);
575 was != s.dragged
576 }
577 }
578 };
579 if changed {
580 crate::frame_clock::request_frame();
582 }
583 }
584
585 pub fn source(&self) -> InteractionSource {
587 InteractionSource {
588 state: self.state.clone(),
589 }
590 }
591
592 pub fn reset(&self) {
594 let mut s = self.state.borrow_mut();
595 *s = InteractionState::default();
596 crate::frame_clock::request_frame();
597 }
598
599 pub fn reset_hover(&self) {
601 let mut s = self.state.borrow_mut();
602 if s.hovered {
603 s.hovered = false;
604 crate::frame_clock::request_frame();
605 }
606 }
607}
608
609impl Default for MutableInteractionSource {
610 fn default() -> Self {
611 Self::new()
612 }
613}
614
615#[derive(Clone, Default)]
616pub(crate) struct InteractionState {
617 active_presses: HashSet<PressId>,
619 hovered: bool,
620 focused: bool,
621 dragged: u32,
622 pub(crate) last_press_position: Option<Vec2>,
624 pub(crate) last_press_id: Option<PressId>,
626}
627
628#[derive(Clone, Default)]
629pub struct Modifier {
630 pub key: Option<u64>,
636
637 pub size: Option<DpSize>,
638 pub width: Option<Dp>,
639 pub height: Option<Dp>,
640 pub required_size: Option<DpSize>,
641 pub fill_max: Option<f32>,
642 pub fill_max_w: Option<f32>,
643 pub fill_max_h: Option<f32>,
644 pub padding: Option<Dp>,
645 pub padding_values: Option<PaddingValues>,
646 pub min_width: Option<Dp>,
647 pub min_height: Option<Dp>,
648 pub max_width: Option<Dp>,
649 pub max_height: Option<Dp>,
650 pub required_min_width: Option<Dp>,
652 pub required_max_width: Option<Dp>,
654 pub required_min_height: Option<Dp>,
656 pub required_max_height: Option<Dp>,
658 pub default_min_width: Option<Dp>,
661 pub default_min_height: Option<Dp>,
662 pub background: Option<Brush>,
663 pub state_colors: Option<StateColors>,
664 pub state_elevation: Option<StateElevation>,
665
666 pub border: Option<Border>,
667 pub flex_grow: Option<f32>,
668 pub flex_shrink: Option<f32>,
669 pub flex_basis: Option<Dp>,
670 pub flex_basis_content: bool,
673 pub flex_wrap: Option<FlexWrap>,
674 pub flex_line_count: Option<u16>,
677 pub flex_dir: Option<FlexDirection>,
678 pub gap: Option<Dp>,
679 pub row_gap: Option<Dp>,
680 pub column_gap: Option<Dp>,
681 pub align_self: Option<AlignSelf>,
682 pub justify_content: Option<JustifyContent>,
683 pub align_items_container: Option<AlignItems>,
684 pub align_content: Option<AlignContent>,
685 pub clip_rounded: Option<[Dp; 4]>,
686 pub clip_rect: Option<ClipRect>,
689 pub overflow: Option<Overflow>,
694 pub z_index: f32,
696 pub render_z_index: Option<f32>,
698 pub hit_passthrough: bool,
700 pub input_blocker: bool,
702 pub repaint_boundary: bool,
703 pub click: bool,
704 pub disabled: bool,
706 pub focusable: Option<bool>,
710 pub propagate_min: bool,
712 pub focus_group: bool,
715 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
716 pub scroll: Option<crate::scroll::ScrollBinding>,
722 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
731 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
732 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
733 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
734 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
735 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
736 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
737 pub on_click: Option<Rc<dyn Fn()>>,
739 pub on_double_click: Option<Rc<dyn Fn()>>,
741 pub on_long_click: Option<Rc<dyn Fn()>>,
743 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
746 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
749 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
752 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
755 pub blur: Option<BlurStyle>,
760 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (Dp, Dp)>>,
765 pub semantics: Option<crate::Semantics>,
766 pub alpha: Option<f32>,
767 pub graphics_layer: Option<f32>,
768 pub shadow: Option<ShadowSpec>,
769 pub transform: Option<Transform>,
770 pub grid: Option<GridConfig>,
771 pub grid_col_span: Option<u16>,
772 pub grid_row_span: Option<u16>,
773 pub position_type: Option<PositionType>,
774 pub offset_left: Option<Dp>,
775 pub offset_right: Option<Dp>,
776 pub offset_top: Option<Dp>,
777 pub offset_bottom: Option<Dp>,
778
779 pub margin_left: Option<Dp>,
780 pub margin_right: Option<Dp>,
781 pub margin_top: Option<Dp>,
782 pub margin_bottom: Option<Dp>,
783 pub aspect_ratio: Option<f32>,
784 pub intrinsic_width: Option<IntrinsicSize>,
787 pub intrinsic_height: Option<IntrinsicSize>,
790 pub fit_content_width: Option<Dp>,
793 pub fit_content_height: Option<Dp>,
796 pub baseline_align: Option<BaselineAlign>,
799 pub contain: Option<Contain>,
804 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
805 pub paint_callback: Option<crate::PaintCallbackPayload>,
806
807 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
809 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
810 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
811 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
812 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
813 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
814 pub drag_preview: Option<crate::dnd::DragPreview>,
816
817 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
818
819 pub cursor: Option<crate::CursorIcon>,
821
822 pub animate_content_size: Option<AnimationSpec>,
825
826 pub focus_requester: Option<crate::runtime::FocusRequester>,
830
831 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
834
835 pub interaction_source: Option<InteractionSource>,
842
843 pub text_input: Option<TextInputConfig>,
845
846 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
848}
849
850impl std::fmt::Debug for Modifier {
851 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
852 let mut s = f.debug_struct("Modifier");
853
854 macro_rules! opt_val {
855 ($($name:ident),+ $(,)?) => {
856 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
857 };
858 }
859 if self.indication.is_some() {
860 s.field("indication", &"…");
861 }
862
863 opt_val!(
864 key,
865 size,
866 width,
867 height,
868 required_size,
869 padding,
870 padding_values,
871 min_width,
872 min_height,
873 max_width,
874 max_height,
875 required_min_width,
876 required_max_width,
877 required_min_height,
878 required_max_height,
879 default_min_width,
880 default_min_height,
881 fill_max,
882 fill_max_w,
883 fill_max_h,
884 background,
885 state_colors,
886 state_elevation,
887 border,
888 flex_grow,
889 flex_shrink,
890 flex_basis,
891 flex_wrap,
892 flex_dir,
893 gap,
894 row_gap,
895 column_gap,
896 align_self,
897 justify_content,
898 align_items_container,
899 align_content,
900 clip_rounded,
901 clip_rect,
902 render_z_index,
903 semantics,
904 alpha,
905 transform,
906 grid,
907 grid_col_span,
908 grid_row_span,
909 position_type,
910 offset_left,
911 offset_right,
912 offset_top,
913 offset_bottom,
914 margin_left,
915 margin_right,
916 margin_top,
917 margin_bottom,
918 aspect_ratio,
919 intrinsic_width,
920 intrinsic_height,
921 cursor,
922 animate_content_size,
923 blur,
924 );
925
926 macro_rules! opt_cb {
927 ($($name:ident),+ $(,)?) => {
928 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
929 };
930 }
931 opt_cb!(
932 on_scroll,
933 scroll,
934 nested_scroll_connection,
935 on_pointer_down,
936 on_pointer_move,
937 on_pointer_up,
938 on_pointer_cancel,
939 on_pointer_enter,
940 on_pointer_leave,
941 on_click,
942 on_double_click,
943 on_long_click,
944 on_globally_positioned,
945 on_size_changed,
946 on_key_event,
947 on_preview_key_event,
948 painter,
949 paint_callback,
950 on_drag_start,
951 on_drag_end,
952 on_drag_enter,
953 on_drag_over,
954 on_drag_leave,
955 on_drop,
956 drag_preview,
957 on_action,
958 on_focus_changed,
959 interaction_source,
960 text_input,
961 layout,
962 );
963
964 macro_rules! flag {
965 ($($name:ident),+ $(,)?) => {
966 $( if self.$name { s.field(stringify!($name), &true); } )+
967 };
968 }
969 flag!(
970 hit_passthrough,
971 input_blocker,
972 repaint_boundary,
973 click,
974 disabled,
975 propagate_min,
976 focus_group,
977 );
978
979 if let Some(f) = self.focusable {
980 s.field("focusable", &f);
981 }
982 if self.z_index != 0.0 {
983 s.field("z_index", &self.z_index);
984 }
985
986 s.finish()
987 }
988}
989
990impl_option_fields!(Modifier);
991
992#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
996pub enum Alignment {
997 TopStart,
998 TopCenter,
999 TopEnd,
1000 CenterStart,
1001 #[default]
1002 Center,
1003 CenterEnd,
1004 BottomStart,
1005 BottomCenter,
1006 BottomEnd,
1007}
1008
1009impl Alignment {
1010 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
1012 use AlignItems as AI;
1013 use JustifyContent as JC;
1014 match self {
1015 Self::TopStart => (AI::START, JC::START),
1016 Self::TopCenter => (AI::START, JC::CENTER),
1017 Self::TopEnd => (AI::START, JC::END),
1018 Self::CenterStart => (AI::CENTER, JC::START),
1019 Self::Center => (AI::CENTER, JC::CENTER),
1020 Self::CenterEnd => (AI::CENTER, JC::END),
1021 Self::BottomStart => (AI::END, JC::START),
1022 Self::BottomCenter => (AI::END, JC::CENTER),
1023 Self::BottomEnd => (AI::END, JC::END),
1024 }
1025 }
1026
1027 pub fn to_flex_safe(self) -> (AlignItems, JustifyContent) {
1032 use AlignItems as AI;
1033 use JustifyContent as JC;
1034 match self {
1035 Self::TopStart => (AI::SAFE_START, JC::SAFE_START),
1036 Self::TopCenter => (AI::SAFE_START, JC::SAFE_CENTER),
1037 Self::TopEnd => (AI::SAFE_START, JC::SAFE_END),
1038 Self::CenterStart => (AI::SAFE_CENTER, JC::SAFE_START),
1039 Self::Center => (AI::SAFE_CENTER, JC::SAFE_CENTER),
1040 Self::CenterEnd => (AI::SAFE_CENTER, JC::SAFE_END),
1041 Self::BottomStart => (AI::SAFE_END, JC::SAFE_START),
1042 Self::BottomCenter => (AI::SAFE_END, JC::SAFE_CENTER),
1043 Self::BottomEnd => (AI::SAFE_END, JC::SAFE_END),
1044 }
1045 }
1046}
1047
1048impl Modifier {
1049 pub fn new() -> Self {
1050 Self::default()
1051 }
1052
1053 pub fn key(mut self, key: u64) -> Self {
1056 self.key = Some(key);
1057 self
1058 }
1059
1060 pub fn size(mut self, w: Dp, h: Dp) -> Self {
1061 self.size = Some(DpSize::new(w, h));
1062 self
1063 }
1064 pub fn width(mut self, w: Dp) -> Self {
1065 self.width = Some(w);
1066 self
1067 }
1068 pub fn height(mut self, h: Dp) -> Self {
1069 self.height = Some(h);
1070 self
1071 }
1072 pub fn required_size(mut self, w: Dp, h: Dp) -> Self {
1077 self.required_size = Some(DpSize::new(w, h));
1078 self
1079 }
1080 pub fn required_width_in(mut self, min: Dp, max: Dp) -> Self {
1081 self.required_min_width = Some(Dp(min.0.max(0.0)));
1082 self.required_max_width = Some(Dp(max.0.max(0.0)));
1083 self
1084 }
1085 pub fn required_height_in(mut self, min: Dp, max: Dp) -> Self {
1086 self.required_min_height = Some(Dp(min.0.max(0.0)));
1087 self.required_max_height = Some(Dp(max.0.max(0.0)));
1088 self
1089 }
1090 pub fn required_min_width(mut self, w: Dp) -> Self {
1091 self.required_min_width = Some(Dp(w.0.max(0.0)));
1092 self
1093 }
1094 pub fn required_max_width(mut self, w: Dp) -> Self {
1095 self.required_max_width = Some(Dp(w.0.max(0.0)));
1096 self
1097 }
1098 pub fn required_min_height(mut self, h: Dp) -> Self {
1099 self.required_min_height = Some(Dp(h.0.max(0.0)));
1100 self
1101 }
1102 pub fn required_max_height(mut self, h: Dp) -> Self {
1103 self.required_max_height = Some(Dp(h.0.max(0.0)));
1104 self
1105 }
1106 pub fn default_min_size(mut self, w: Dp, h: Dp) -> Self {
1108 self.default_min_width = Some(Dp(w.0.max(0.0)));
1109 self.default_min_height = Some(Dp(h.0.max(0.0)));
1110 self
1111 }
1112 pub fn fill_max_size(mut self) -> Self {
1115 self.fill_max = Some(1.0);
1116 self
1117 }
1118 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
1119 self.fill_max = Some(fraction.clamp(0.0, 1.0));
1120 self
1121 }
1122 pub fn fill_max_width(mut self) -> Self {
1124 self.fill_max_w = Some(1.0);
1125 self
1126 }
1127 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
1128 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
1129 self
1130 }
1131 pub fn fill_max_height(mut self) -> Self {
1133 self.fill_max_h = Some(1.0);
1134 self
1135 }
1136 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
1137 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
1138 self
1139 }
1140 pub fn padding(mut self, v: Dp) -> Self {
1141 self.padding = Some(v);
1142 self
1143 }
1144 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
1145 self.padding_values = Some(padding);
1146 self
1147 }
1148 pub fn ime_padding(mut self) -> Self {
1152 use crate::units::Px;
1153 let insets = crate::locals::window_insets();
1154 let mut p = self.padding_values.unwrap_or_default();
1155 p.bottom = p.bottom + Px(insets.ime_bottom).to_dp();
1156 self.padding_values = Some(p);
1157 self
1158 }
1159 pub fn system_bars_padding(mut self) -> Self {
1161 use crate::units::Px;
1162 let insets = crate::locals::window_insets();
1163 let mut p = self.padding_values.unwrap_or_default();
1164 p.top = p.top + Px(insets.top).to_dp();
1165 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1166 self.padding_values = Some(p);
1167 self
1168 }
1169 pub fn status_bars_padding(mut self) -> Self {
1171 use crate::units::Px;
1172 let insets = crate::locals::window_insets();
1173 let mut p = self.padding_values.unwrap_or_default();
1174 p.top = p.top + Px(insets.top).to_dp();
1175 self.padding_values = Some(p);
1176 self
1177 }
1178 pub fn navigation_bars_padding(mut self) -> Self {
1180 let insets = crate::locals::window_insets();
1181 use crate::units::Px;
1182 let mut p = self.padding_values.unwrap_or_default();
1183 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1184 self.padding_values = Some(p);
1185 self
1186 }
1187 pub fn min_size(mut self, w: Dp, h: Dp) -> Self {
1188 self.min_width = Some(w);
1189 self.min_height = Some(h);
1190 self
1191 }
1192 pub fn max_size(mut self, w: Dp, h: Dp) -> Self {
1193 self.max_width = Some(w);
1194 self.max_height = Some(h);
1195 self
1196 }
1197 pub fn min_width(mut self, w: Dp) -> Self {
1198 self.min_width = Some(w);
1199 self
1200 }
1201 pub fn min_height(mut self, h: Dp) -> Self {
1202 self.min_height = Some(h);
1203 self
1204 }
1205 pub fn max_width(mut self, w: Dp) -> Self {
1206 self.max_width = Some(w);
1207 self
1208 }
1209 pub fn max_height(mut self, h: Dp) -> Self {
1210 self.max_height = Some(h);
1211 self
1212 }
1213 pub fn background(mut self, color: Color) -> Self {
1215 self.background = Some(Brush::Solid(color));
1216 self
1217 }
1218 pub fn background_brush(mut self, brush: Brush) -> Self {
1220 self.background = Some(brush);
1221 self
1222 }
1223 pub fn border(mut self, width: Dp, color: Color, radius: Dp) -> Self {
1224 self.border = Some(Border {
1225 width,
1226 color,
1227 radius: [radius; 4],
1228 });
1229 self
1230 }
1231 pub fn border_radii(mut self, width: Dp, color: Color, radii: [Dp; 4]) -> Self {
1232 self.border = Some(Border {
1233 width,
1234 color,
1235 radius: radii,
1236 });
1237 self
1238 }
1239 pub fn flex_grow(mut self, v: f32) -> Self {
1240 self.flex_grow = Some(v);
1241 self
1242 }
1243 pub fn flex_shrink(mut self, v: f32) -> Self {
1244 self.flex_shrink = Some(v);
1245 self
1246 }
1247 pub fn flex_basis(mut self, v: Dp) -> Self {
1248 self.flex_basis = Some(v);
1249 self
1250 }
1251 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1252 self.flex_wrap = Some(w);
1253 self
1254 }
1255 pub fn flex_basis_content(mut self) -> Self {
1258 self.flex_basis_content = true;
1259 self
1260 }
1261 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1262 self.flex_dir = Some(d);
1263 self
1264 }
1265 pub fn gap(mut self, v: Dp) -> Self {
1266 let v = Dp(v.0.max(0.0));
1267 self.gap = Some(v);
1268 self.row_gap = Some(v);
1269 self.column_gap = Some(v);
1270 self
1271 }
1272 pub fn row_gap(mut self, v: Dp) -> Self {
1273 self.row_gap = Some(Dp(v.0.max(0.0)));
1274 self
1275 }
1276 pub fn column_gap(mut self, v: Dp) -> Self {
1277 self.column_gap = Some(Dp(v.0.max(0.0)));
1278 self
1279 }
1280 pub fn align_self(mut self, a: AlignSelf) -> Self {
1281 self.align_self = Some(a);
1282 self
1283 }
1284 pub fn align_self_center(mut self) -> Self {
1285 self.align_self = Some(AlignSelf::CENTER);
1286 self
1287 }
1288 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1289 self.justify_content = Some(j);
1290 self
1291 }
1292 pub fn align_items(mut self, a: AlignItems) -> Self {
1293 self.align_items_container = Some(a);
1294 self
1295 }
1296 pub fn content_alignment(self, alignment: Alignment) -> Self {
1299 let (ai, jc) = alignment.to_flex();
1300 self.align_items(ai).justify_content(jc)
1301 }
1302 pub fn content_alignment_safe(self, alignment: Alignment) -> Self {
1307 let (ai, jc) = alignment.to_flex_safe();
1308 self.align_items(ai).justify_content(jc)
1309 }
1310 pub fn align_content(mut self, a: AlignContent) -> Self {
1311 self.align_content = Some(a);
1312 self
1313 }
1314 pub fn clip_rounded(mut self, radius: Dp) -> Self {
1315 self.clip_rounded = Some([radius; 4]);
1316 self
1317 }
1318 pub fn clip_rounded_radii(mut self, radii: [Dp; 4]) -> Self {
1319 self.clip_rounded = Some(radii);
1320 self
1321 }
1322 pub fn clip_rect(mut self, left: Dp, top: Dp, right: Dp, bottom: Dp, op: ClipOp) -> Self {
1325 self.clip_rect = Some(ClipRect {
1326 left,
1327 top,
1328 right,
1329 bottom,
1330 op,
1331 });
1332 self
1333 }
1334 pub fn overflow(mut self, overflow: Overflow) -> Self {
1335 self.overflow = Some(overflow);
1336 self
1337 }
1338 pub fn z_index(mut self, z: f32) -> Self {
1339 self.z_index = z;
1340 self
1341 }
1342
1343 pub fn render_z_index(mut self, z: f32) -> Self {
1346 self.render_z_index = Some(z);
1347 self
1348 }
1349
1350 pub fn input_blocker(mut self) -> Self {
1352 self.input_blocker = true;
1353 self
1354 }
1355
1356 pub fn hit_passthrough(mut self) -> Self {
1357 self.hit_passthrough = true;
1358 self
1359 }
1360 pub fn clickable(mut self) -> Self {
1361 self.click = true;
1362 if self.indication.is_none() {
1363 self.indication = crate::locals::local_indication();
1364 }
1365 self
1366 }
1367 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1370 self.click = true;
1371 self.interaction_source = Some(source.source());
1372 if self.indication.is_none() {
1373 self.indication = crate::locals::local_indication();
1374 }
1375 self
1376 }
1377 pub fn state_colors(mut self, colors: StateColors) -> Self {
1380 self.state_colors = Some(colors);
1381 self
1382 }
1383 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1385 self.state_elevation = Some(elev);
1386 self
1387 }
1388 pub fn disabled(mut self) -> Self {
1390 self.disabled = true;
1391 self
1392 }
1393 pub fn enabled(mut self, enabled: bool) -> Self {
1395 self.disabled = !enabled;
1396 self
1397 }
1398 pub fn focusable(mut self, focusable: bool) -> Self {
1403 self.focusable = Some(focusable);
1404 self
1405 }
1406 pub fn focus_group(mut self) -> Self {
1409 self.focus_group = true;
1410 self
1411 }
1412 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1423 self.interaction_source = Some(source.source());
1424 self
1425 }
1426 pub fn hoverable(
1429 mut self,
1430 on_enter: impl Fn() + 'static,
1431 on_leave: impl Fn() + 'static,
1432 ) -> Self {
1433 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1434 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1435 self
1436 }
1437 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1441 self.interaction_source = Some(source.source());
1442 self
1443 }
1444 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1447 self.propagate_min = propagate;
1448 self
1449 }
1450 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1451 self.on_scroll = Some(Rc::new(f));
1452 self
1453 }
1454 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1458 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1459 self
1460 }
1461 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1463 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1464 self
1465 }
1466 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1468 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1469 self
1470 }
1471 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1478 self.nested_scroll_connection = Some(conn);
1479 self
1480 }
1481 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1482 self.on_pointer_down = Some(Rc::new(f));
1483 self
1484 }
1485 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1486 self.on_pointer_move = Some(Rc::new(f));
1487 self
1488 }
1489 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1490 self.on_pointer_up = Some(Rc::new(f));
1491 self
1492 }
1493 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1494 self.on_pointer_cancel = Some(Rc::new(f));
1495 self
1496 }
1497
1498 pub fn draggable(self, on_drag: impl Fn(Vec2) + 'static) -> Self {
1499 let drag_pos = crate::state::remember_mutable(Vec2::default);
1500 let is_dragging = crate::state::remember_mutable(|| false);
1501 let on_drag = Rc::new(on_drag);
1502 self.on_pointer_down({
1503 let drag_pos = drag_pos.clone();
1504 let is_dragging = is_dragging.clone();
1505 move |ev| {
1506 is_dragging.set(true);
1507 drag_pos.set(ev.position);
1508 }
1509 })
1510 .on_pointer_up({
1511 let is_dragging = is_dragging.clone();
1512 move |_| is_dragging.set(false)
1513 })
1514 .on_pointer_cancel({
1515 let is_dragging = is_dragging.clone();
1516 move |_| is_dragging.set(false)
1517 })
1518 .on_pointer_move({
1519 let drag_pos = drag_pos.clone();
1520 let is_dragging = is_dragging.clone();
1521 let on_drag = on_drag.clone();
1522 move |ev| {
1523 if !*is_dragging.get() {
1524 return;
1525 }
1526 let prev = *drag_pos.get();
1527 let cur = ev.position;
1528 let delta = Vec2 {
1529 x: cur.x - prev.x,
1530 y: cur.y - prev.y,
1531 };
1532 drag_pos.set(cur);
1533 on_drag(delta);
1534 crate::frame_clock::request_frame();
1535 }
1536 })
1537 }
1538 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1539 self.on_pointer_enter = Some(Rc::new(f));
1540 self
1541 }
1542 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1543 self.on_pointer_leave = Some(Rc::new(f));
1544 self
1545 }
1546 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1547 self.on_click = Some(Rc::new(f));
1548 self.click = true;
1549 if self.semantics.is_none() {
1550 self.semantics = Some(crate::Semantics::new(crate::Role::Button));
1551 }
1552 self
1553 }
1554 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1555 self.on_double_click = Some(Rc::new(f));
1556 self.click = true;
1557 self
1558 }
1559 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1560 self.on_long_click = Some(Rc::new(f));
1561 self.click = true;
1562 self
1563 }
1564 pub fn clickable_ext(
1565 mut self,
1566 enabled: bool,
1567 on_click_label: Option<String>,
1568 role: Option<crate::semantics::Role>,
1569 on_click: impl Fn() + 'static,
1570 ) -> Self {
1571 if !enabled {
1572 let mut s = self.semantics.clone().unwrap_or_else(|| {
1573 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1574 });
1575 s.enabled = false;
1576 if let Some(r) = role {
1577 s.role = r;
1578 }
1579 if let Some(l) = on_click_label {
1580 s.label = Some(l);
1581 }
1582 return self
1583 .clickable()
1584 .enabled(false)
1585 .default_min_size(Dp(48.0), Dp(48.0))
1586 .semantics(s);
1587 }
1588 self = self.clickable().on_click(on_click);
1589 if role.is_some() || on_click_label.is_some() {
1590 let mut s = self.semantics.clone().unwrap_or_else(|| {
1591 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1592 });
1593 s.enabled = true;
1594 if let Some(r) = role {
1595 s.role = r;
1596 }
1597 if let Some(l) = on_click_label {
1598 s.label = Some(l);
1599 }
1600 self = self.semantics(s);
1601 }
1602 self.default_min_size(Dp(48.0), Dp(48.0))
1603 }
1604 pub fn combined_clickable(
1605 mut self,
1606 enabled: bool,
1607 on_click_label: Option<String>,
1608 role: Option<crate::semantics::Role>,
1609 on_long_click_label: Option<String>,
1610 on_click: impl Fn() + 'static,
1611 on_long_click: Option<impl Fn() + 'static>,
1612 on_double_click: Option<impl Fn() + 'static>,
1613 ) -> Self {
1614 let _ = on_long_click_label;
1615 if !enabled {
1616 return self.clickable_ext(false, on_click_label, role, || {});
1617 }
1618 self = self.clickable_ext(true, on_click_label, role, on_click);
1619 if let Some(f) = on_long_click {
1620 self = self.on_long_click(f);
1621 }
1622 if let Some(f) = on_double_click {
1623 self = self.on_double_click(f);
1624 }
1625 self.default_min_size(Dp(48.0), Dp(48.0))
1626 }
1627 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1628 self.semantics = Some(s);
1629 self
1630 }
1631 pub fn alpha(mut self, a: f32) -> Self {
1632 self.alpha = Some(a);
1633 self
1634 }
1635 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1640 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1641 self
1642 }
1643 pub fn shadow(mut self, blur_radius: Dp, offset_y: Dp) -> Self {
1647 self.shadow = Some(ShadowSpec {
1648 blur_radius: Dp(blur_radius.0.max(0.0)),
1649 offset_y,
1650 color: Color(0, 0, 0, 64),
1651 });
1652 self
1653 }
1654 pub fn shadow_with_color(mut self, blur_radius: Dp, offset_y: Dp, color: Color) -> Self {
1656 self.shadow = Some(ShadowSpec {
1657 blur_radius: Dp(blur_radius.0.max(0.0)),
1658 offset_y,
1659 color,
1660 });
1661 self
1662 }
1663 pub fn elevation(mut self, level: Dp) -> Self {
1667 if level.0 <= 0.0 {
1668 self.shadow = None;
1669 return self;
1670 }
1671 self.shadow = Some(ShadowSpec {
1672 blur_radius: Dp(level.0 * 2.0),
1673 offset_y: Dp(level.0 * 0.5),
1674 color: Color(0, 0, 0, (level.0 * 8.0).clamp(8.0, 80.0) as u8),
1675 });
1676 self
1677 }
1678 pub fn transform(mut self, t: Transform) -> Self {
1679 self.transform = Some(t);
1680 self
1681 }
1682 pub fn grid(mut self, columns: usize, row_gap: Dp, column_gap: Dp) -> Self {
1683 self.grid = Some(GridConfig {
1684 columns,
1685 row_gap,
1686 column_gap,
1687 });
1688 self
1689 }
1690 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1691 self.grid_col_span = Some(col_span);
1692 self.grid_row_span = Some(row_span);
1693 self
1694 }
1695 pub fn absolute(mut self) -> Self {
1704 self.position_type = Some(PositionType::Absolute);
1705 self
1706 }
1707 pub fn offset(
1712 mut self,
1713 left: Option<Dp>,
1714 top: Option<Dp>,
1715 right: Option<Dp>,
1716 bottom: Option<Dp>,
1717 ) -> Self {
1718 self.offset_left = left;
1719 self.offset_top = top;
1720 self.offset_right = right;
1721 self.offset_bottom = bottom;
1722 self
1723 }
1724 pub fn offset_left(mut self, v: Dp) -> Self {
1725 self.offset_left = Some(v);
1726 self
1727 }
1728 pub fn offset_right(mut self, v: Dp) -> Self {
1729 self.offset_right = Some(v);
1730 self
1731 }
1732 pub fn offset_top(mut self, v: Dp) -> Self {
1733 self.offset_top = Some(v);
1734 self
1735 }
1736 pub fn offset_bottom(mut self, v: Dp) -> Self {
1737 self.offset_bottom = Some(v);
1738 self
1739 }
1740 pub fn margin(mut self, v: Dp) -> Self {
1741 self.margin_left = Some(v);
1742 self.margin_right = Some(v);
1743 self.margin_top = Some(v);
1744 self.margin_bottom = Some(v);
1745 self
1746 }
1747
1748 pub fn margin_horizontal(mut self, v: Dp) -> Self {
1749 self.margin_left = Some(v);
1750 self.margin_right = Some(v);
1751 self
1752 }
1753
1754 pub fn margin_vertical(mut self, v: Dp) -> Self {
1755 self.margin_top = Some(v);
1756 self.margin_bottom = Some(v);
1757 self
1758 }
1759 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1760 self.aspect_ratio = Some(ratio);
1761 self
1762 }
1763 pub fn fit_content_width(mut self, limit: Dp) -> Self {
1765 self.fit_content_width = Some(Dp(limit.0.max(0.0)));
1766 self
1767 }
1768 pub fn fit_content_height(mut self, limit: Dp) -> Self {
1770 self.fit_content_height = Some(Dp(limit.0.max(0.0)));
1771 self
1772 }
1773 pub fn contain(mut self, c: Contain) -> Self {
1775 self.contain = Some(c);
1776 self
1777 }
1778 pub fn contain_layout(mut self) -> Self {
1780 self.contain = Some(Contain::LAYOUT);
1781 self
1782 }
1783 pub fn contain_paint(mut self) -> Self {
1785 self.contain = Some(Contain::PAINT);
1786 self
1787 }
1788 pub fn contain_content(mut self) -> Self {
1790 self.contain = Some(Contain::CONTENT);
1791 self
1792 }
1793 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1795 self.intrinsic_width = Some(mode);
1796 self
1797 }
1798 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1800 self.intrinsic_height = Some(mode);
1801 self
1802 }
1803 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1804 self.painter = Some(Rc::new(f));
1805 self
1806 }
1807 pub fn paint_callback(mut self, payload: crate::PaintCallbackPayload) -> Self {
1813 self.paint_callback = Some(payload);
1814 self
1815 }
1816 pub fn scale(self, s: f32) -> Self {
1817 self.scale2(s, s)
1818 }
1819 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1820 let mut t = self.transform.unwrap_or_else(Transform::identity);
1821 t.scale_x *= sx;
1822 t.scale_y *= sy;
1823 self.transform = Some(t);
1824 self
1825 }
1826 pub fn translate(mut self, x: f32, y: f32) -> Self {
1827 let t = self.transform.unwrap_or_else(Transform::identity);
1828 self.transform = Some(t.combine(&Transform::translate(x, y)));
1829 self
1830 }
1831 pub fn translate_vec2(self, v: Vec2) -> Self {
1832 self.translate(v.x, v.y)
1833 }
1834 pub fn rotate(mut self, radians: f32) -> Self {
1835 let mut t = self.transform.unwrap_or_else(Transform::identity);
1836 t.rotate += radians;
1837 self.transform = Some(t);
1838 self
1839 }
1840 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1841 let mut t = self.transform.unwrap_or_else(Transform::identity);
1842 t.origin_x = x;
1843 t.origin_y = y;
1844 self.transform = Some(t);
1845 self
1846 }
1847 pub fn weight(mut self, w: f32) -> Self {
1848 let w = w.max(0.0);
1849 self.flex_grow = Some(w);
1850 self.flex_shrink = Some(1.0);
1851 self.flex_basis = Some(Dp::ZERO);
1853 self
1854 }
1855 pub fn repaint_boundary(mut self) -> Self {
1859 self.repaint_boundary = true;
1860 self
1861 }
1862 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1863 self.on_action = Some(Rc::new(f));
1864 self
1865 }
1866
1867 pub fn on_drag_start(
1869 mut self,
1870 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1871 ) -> Self {
1872 self.on_drag_start = Some(Rc::new(f));
1873 self
1874 }
1875
1876 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1878 self.on_drag_end = Some(Rc::new(f));
1879 self
1880 }
1881
1882 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1884 self.on_drag_enter = Some(Rc::new(f));
1885 self
1886 }
1887
1888 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1890 self.on_drag_over = Some(Rc::new(f));
1891 self
1892 }
1893
1894 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1896 self.on_drag_leave = Some(Rc::new(f));
1897 self
1898 }
1899
1900 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1903 self.on_drop = Some(Rc::new(f));
1904 self
1905 }
1906
1907 pub fn draw_drag_decoration(
1912 mut self,
1913 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
1914 ) -> Self {
1915 self.drag_preview = Some(Rc::new(f));
1916 self
1917 }
1918
1919 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
1921 self.drag_preview = Some(preview);
1922 self
1923 }
1924
1925 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
1927 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
1928 }
1929
1930 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
1932 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
1933 }
1934
1935 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1937 self.cursor = Some(c);
1938 self
1939 }
1940
1941 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1945 self.animate_content_size = Some(spec);
1946 self
1947 }
1948
1949 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1952 self.focus_requester = Some(fr);
1953 self
1954 }
1955
1956 pub fn focus_target(mut self) -> Self {
1959 self.focusable = Some(true);
1960 self
1961 }
1962
1963 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1966 self.on_focus_changed = Some(Rc::new(f));
1967 self
1968 }
1969
1970 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
1975 self.on_globally_positioned = Some(Rc::new(f));
1976 self
1977 }
1978
1979 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
1982 self.on_size_changed = Some(Rc::new(f));
1983 self
1984 }
1985
1986 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
1990 self.on_key_event = Some(Rc::new(f));
1991 self
1992 }
1993
1994 pub fn on_preview_key_event(
1998 mut self,
1999 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
2000 ) -> Self {
2001 self.on_preview_key_event = Some(Rc::new(f));
2002 self
2003 }
2004
2005 pub fn blur(mut self, radius: Dp) -> Self {
2012 self.blur = Some(BlurStyle {
2013 radius_x: Dp(radius.0.max(0.0)),
2014 radius_y: Dp(radius.0.max(0.0)),
2015 edge_treatment: BlurredEdgeTreatment::Rectangle,
2016 });
2017 self
2018 }
2019
2020 pub fn blur_with_edge(
2025 mut self,
2026 radius_x: Dp,
2027 radius_y: Dp,
2028 edge_treatment: BlurredEdgeTreatment,
2029 ) -> Self {
2030 self.blur = Some(BlurStyle {
2031 radius_x: Dp(radius_x.0.max(0.0)),
2032 radius_y: Dp(radius_y.0.max(0.0)),
2033 edge_treatment,
2034 });
2035 self
2036 }
2037
2038 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (Dp, Dp) + 'static) -> Self {
2046 self.layout = Some(Rc::new(f));
2047 self
2048 }
2049
2050 pub fn text_input(mut self, config: TextInputConfig) -> Self {
2052 self.text_input = Some(config);
2053 self
2054 }
2055
2056 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
2060 self.indication = Some(factory);
2061 self
2062 }
2063}