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 gap, row_gap, column_gap,
103 align_self, justify_content, align_items_container, align_content,
104 clip_rounded, clip_rect, overflow, render_z_index,
105 on_scroll,
106 nested_scroll_connection,
107 scroll,
108 on_pointer_down, on_pointer_move, on_pointer_up,
109 on_pointer_enter, on_pointer_leave,
110 on_click, on_double_click, on_long_click,
111 semantics, alpha, transform,
112 grid, grid_col_span, grid_row_span,
113 position_type,
114 offset_left, offset_right, offset_top, offset_bottom,
115 margin_left, margin_right, margin_top, margin_bottom,
116 aspect_ratio, intrinsic_width, intrinsic_height,
117 painter,
118 paint_callback,
119 on_drag_start, on_drag_end, on_drag_enter, on_drag_over, on_drag_leave, on_drop,
120 drag_preview,
121 on_action, cursor, animate_content_size, focus_requester, on_focus_changed,
122 interaction_source, text_input,
123 );
124 merge_flags!(self, other;
125 hit_passthrough, input_blocker, repaint_boundary, click, disabled,
126 propagate_min, focus_group,
127 );
128
129 if let Some(f) = other.focusable {
130 self.focusable = Some(f);
131 }
132 if other.indication.is_some() {
133 self.indication = other.indication;
134 }
135 if other.z_index != 0.0 {
136 self.z_index = other.z_index;
137 }
138 self
139 }
140 }
141 };
142}
143
144#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
145pub enum ClipOp {
146 #[default]
148 Intersect,
149 Difference,
151}
152
153#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
159pub enum Overflow {
160 #[default]
161 Clip,
162 Visible,
163}
164
165#[derive(Clone, Copy, Debug)]
168pub struct ClipRect {
169 pub left: Dp,
170 pub top: Dp,
171 pub right: Dp,
172 pub bottom: Dp,
173 pub op: ClipOp,
174}
175
176#[derive(Clone, Debug)]
177pub struct Border {
178 pub width: Dp,
179 pub color: Color,
180 pub radius: [Dp; 4],
181}
182
183#[derive(Clone, Copy, Debug, Default)]
184pub struct PaddingValues {
185 pub left: Dp,
186 pub right: Dp,
187 pub top: Dp,
188 pub bottom: Dp,
189}
190
191#[derive(Clone, Debug)]
192pub struct GridConfig {
193 pub columns: usize,
194 pub row_gap: Dp,
195 pub column_gap: Dp,
196}
197
198#[derive(Clone, Copy, Debug, PartialEq)]
201pub enum BlurredEdgeTreatment {
202 Rectangle,
205 Unbounded,
208}
209
210#[derive(Clone, Copy, Debug)]
212pub struct BlurStyle {
213 pub radius_x: Dp,
215 pub radius_y: Dp,
217 pub edge_treatment: BlurredEdgeTreatment,
219}
220
221#[derive(Clone, Copy, Debug)]
227pub struct LayoutConstraints {
228 pub min_width: Dp,
229 pub max_width: Dp,
230 pub min_height: Dp,
231 pub max_height: Dp,
232}
233
234#[derive(Clone, Copy, Debug)]
241pub struct ShadowSpec {
242 pub blur_radius: Dp,
243 pub offset_y: Dp,
244 pub color: Color,
245}
246
247#[derive(Clone, Copy, Debug)]
248#[non_exhaustive]
249pub enum PositionType {
250 Relative,
251 Absolute,
252}
253
254#[derive(Clone)]
256pub struct TextInputConfig {
257 pub hint: String,
258 pub multiline: bool,
259 pub on_change: Option<Rc<dyn Fn(String)>>,
260 pub on_submit: Option<Rc<dyn Fn(String)>>,
261 pub focus_tracker: Option<Rc<Cell<bool>>>,
262 pub value: String,
263 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
264 pub keyboard_type: crate::text::KeyboardType,
265 pub capitalization: crate::text::KeyboardCapitalization,
266 pub ime_action: crate::text::ImeAction,
267 pub auto_correct_enabled: Option<bool>,
270 pub enabled: bool,
272 pub read_only: bool,
274 pub max_lines: Option<usize>,
276 pub min_lines: usize,
278 pub cursor_color: Option<Color>,
280 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
283 pub text_style: Option<crate::text::TextStyle>,
286 pub keyboard_actions: Option<crate::text::KeyboardActions>,
289 pub interaction_source: Option<InteractionSource>,
291 pub line_limits: Option<crate::text::TextFieldLineLimits>,
293}
294
295impl Default for TextInputConfig {
296 fn default() -> Self {
297 Self {
298 hint: String::new(),
299 multiline: false,
300 on_change: None,
301 on_submit: None,
302 focus_tracker: None,
303 value: String::new(),
304 visual_transformation: None,
305 keyboard_type: crate::text::KeyboardType::default(),
306 capitalization: crate::text::KeyboardCapitalization::default(),
307 ime_action: crate::text::ImeAction::default(),
308 auto_correct_enabled: None,
309 enabled: true,
310 read_only: false,
311 max_lines: None,
312 min_lines: 1,
313 cursor_color: None,
314 on_text_layout: None,
315 text_style: None,
316 keyboard_actions: None,
317 interaction_source: None,
318 line_limits: None,
319 }
320 }
321}
322
323impl std::fmt::Debug for TextInputConfig {
324 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
325 let mut s = f.debug_struct("TextInputConfig");
326 s.field("hint", &self.hint);
327 s.field("multiline", &self.multiline);
328 if self.on_change.is_some() {
329 s.field("on_change", &"…");
330 }
331 if self.on_submit.is_some() {
332 s.field("on_submit", &"…");
333 }
334 if self.focus_tracker.is_some() {
335 s.field("focus_tracker", &"…");
336 }
337 s.field("value", &self.value);
338 if self.visual_transformation.is_some() {
339 s.field("visual_transformation", &"…");
340 }
341 s.field("keyboard_type", &self.keyboard_type);
342 s.field("capitalization", &self.capitalization);
343 s.field("ime_action", &self.ime_action);
344 s.field("auto_correct_enabled", &self.auto_correct_enabled);
345 s.field("enabled", &self.enabled);
346 s.field("read_only", &self.read_only);
347 s.field("max_lines", &self.max_lines);
348 s.field("min_lines", &self.min_lines);
349 s.field("cursor_color", &self.cursor_color);
350 if self.on_text_layout.is_some() {
351 s.field("on_text_layout", &"…");
352 }
353 s.finish()
354 }
355}
356
357#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
360pub enum IntrinsicSize {
361 Min,
362 Max,
363}
364
365#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
373pub enum BaselineAlign {
374 FirstBaseline,
375 LastBaseline,
376}
377
378static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
379
380pub type PressId = u64;
382
383#[derive(Clone, Copy, Debug, PartialEq)]
391pub enum Interaction {
392 Press(PressId, Vec2),
395 Release(PressId),
397 Cancel(PressId),
400 HoverEnter,
401 HoverLeave,
402 Focus,
403 Unfocus,
404 DragStart,
405 DragStop,
406 DragCancel,
407}
408
409impl Interaction {
410 #[inline]
412 pub fn new_press(position: Vec2) -> Self {
413 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
414 }
415}
416
417#[derive(Clone)]
424pub struct InteractionSource {
425 pub(crate) state: Rc<RefCell<InteractionState>>,
426}
427
428impl InteractionSource {
429 pub fn collect_is_pressed(&self) -> bool {
430 !self.state.borrow().active_presses.is_empty()
431 }
432 pub fn collect_is_hovered(&self) -> bool {
433 self.state.borrow().hovered
434 }
435 pub fn collect_is_focused(&self) -> bool {
436 self.state.borrow().focused
437 }
438
439 pub fn collect_is_focus_visible(&self) -> bool {
441 crate::input::is_focus_visible(self.collect_is_focused())
442 }
443
444 pub fn collect_is_dragged(&self) -> bool {
445 self.state.borrow().dragged > 0
446 }
447 pub fn collect_last_press_position(&self) -> Option<Vec2> {
448 self.state.borrow().last_press_position
449 }
450 pub fn collect_last_press_id(&self) -> Option<PressId> {
451 self.state.borrow().last_press_id
452 }
453 pub fn stable_id(&self) -> *const () {
455 Rc::as_ptr(&self.state) as *const ()
456 }
457 pub fn to_mutable(&self) -> MutableInteractionSource {
461 MutableInteractionSource {
462 state: self.state.clone(),
463 }
464 }
465
466 pub fn reset(&self) {
468 self.to_mutable().reset();
469 }
470
471 pub fn reset_hover(&self) {
473 self.to_mutable().reset_hover();
474 }
475}
476
477#[derive(Clone)]
487pub struct MutableInteractionSource {
488 pub(crate) state: Rc<RefCell<InteractionState>>,
489}
490
491impl std::fmt::Debug for MutableInteractionSource {
492 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
493 f.debug_struct("MutableInteractionSource")
494 .finish_non_exhaustive()
495 }
496}
497
498impl MutableInteractionSource {
499 pub fn new() -> Self {
500 Self {
501 state: Rc::new(RefCell::new(InteractionState::default())),
502 }
503 }
504
505 pub fn emit(&self, interaction: Interaction) {
507 let changed = {
508 let mut s = self.state.borrow_mut();
509 match interaction {
510 Interaction::Press(id, pos) => {
511 let inserted = s.active_presses.insert(id);
512 s.last_press_id = Some(id);
513 s.last_press_position = Some(pos);
514 inserted
515 }
516 Interaction::Release(id) | Interaction::Cancel(id) => {
517 if s.active_presses.remove(&id) {
518 true
519 } else if id == 0 {
520 if let Some(any) = s.active_presses.iter().next().copied() {
521 s.active_presses.remove(&any);
522 true
523 } else {
524 false
525 }
526 } else {
527 false
528 }
529 }
530 Interaction::HoverEnter => {
531 let changed = !s.hovered;
532 s.hovered = true;
533 changed
534 }
535 Interaction::HoverLeave => {
536 let changed = s.hovered;
537 s.hovered = false;
538 if !s.active_presses.is_empty() {
540 s.active_presses.clear();
541 true
542 } else {
543 changed
544 }
545 }
546 Interaction::Focus => {
547 let changed = !s.focused;
548 s.focused = true;
549 changed
550 }
551 Interaction::Unfocus => {
552 let changed = s.focused;
553 s.focused = false;
554 changed
555 }
556 Interaction::DragStart => {
557 let changed = s.dragged == 0;
558 s.dragged = s.dragged.saturating_add(1);
559 changed
560 }
561 Interaction::DragStop | Interaction::DragCancel => {
562 let was = s.dragged;
563 s.dragged = s.dragged.saturating_sub(1);
564 was != s.dragged
565 }
566 }
567 };
568 if changed {
569 crate::frame_clock::request_frame();
571 }
572 }
573
574 pub fn source(&self) -> InteractionSource {
576 InteractionSource {
577 state: self.state.clone(),
578 }
579 }
580
581 pub fn reset(&self) {
583 let mut s = self.state.borrow_mut();
584 *s = InteractionState::default();
585 crate::frame_clock::request_frame();
586 }
587
588 pub fn reset_hover(&self) {
590 let mut s = self.state.borrow_mut();
591 if s.hovered {
592 s.hovered = false;
593 crate::frame_clock::request_frame();
594 }
595 }
596}
597
598impl Default for MutableInteractionSource {
599 fn default() -> Self {
600 Self::new()
601 }
602}
603
604#[derive(Clone, Default)]
605pub(crate) struct InteractionState {
606 active_presses: HashSet<PressId>,
608 hovered: bool,
609 focused: bool,
610 dragged: u32,
611 pub(crate) last_press_position: Option<Vec2>,
613 pub(crate) last_press_id: Option<PressId>,
615}
616
617#[derive(Clone, Default)]
618pub struct Modifier {
619 pub key: Option<u64>,
625
626 pub size: Option<DpSize>,
627 pub width: Option<Dp>,
628 pub height: Option<Dp>,
629 pub required_size: Option<DpSize>,
630 pub fill_max: Option<f32>,
631 pub fill_max_w: Option<f32>,
632 pub fill_max_h: Option<f32>,
633 pub padding: Option<Dp>,
634 pub padding_values: Option<PaddingValues>,
635 pub min_width: Option<Dp>,
636 pub min_height: Option<Dp>,
637 pub max_width: Option<Dp>,
638 pub max_height: Option<Dp>,
639 pub required_min_width: Option<Dp>,
641 pub required_max_width: Option<Dp>,
643 pub required_min_height: Option<Dp>,
645 pub required_max_height: Option<Dp>,
647 pub default_min_width: Option<Dp>,
650 pub default_min_height: Option<Dp>,
651 pub background: Option<Brush>,
652 pub state_colors: Option<StateColors>,
653 pub state_elevation: Option<StateElevation>,
654
655 pub border: Option<Border>,
656 pub flex_grow: Option<f32>,
657 pub flex_shrink: Option<f32>,
658 pub flex_basis: Option<Dp>,
659 pub flex_basis_content: bool,
662 pub flex_wrap: Option<FlexWrap>,
663 pub flex_line_count: Option<u16>,
666 pub flex_dir: Option<FlexDirection>,
667 pub gap: Option<Dp>,
668 pub row_gap: Option<Dp>,
669 pub column_gap: Option<Dp>,
670 pub align_self: Option<AlignSelf>,
671 pub justify_content: Option<JustifyContent>,
672 pub align_items_container: Option<AlignItems>,
673 pub align_content: Option<AlignContent>,
674 pub clip_rounded: Option<[Dp; 4]>,
675 pub clip_rect: Option<ClipRect>,
678 pub overflow: Option<Overflow>,
683 pub z_index: f32,
685 pub render_z_index: Option<f32>,
687 pub hit_passthrough: bool,
689 pub input_blocker: bool,
691 pub repaint_boundary: bool,
692 pub click: bool,
693 pub disabled: bool,
695 pub focusable: Option<bool>,
699 pub propagate_min: bool,
701 pub focus_group: bool,
704 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
705 pub scroll: Option<crate::scroll::ScrollBinding>,
711 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
720 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
721 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
722 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
723 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
724 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
725 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
726 pub on_click: Option<Rc<dyn Fn()>>,
728 pub on_double_click: Option<Rc<dyn Fn()>>,
730 pub on_long_click: Option<Rc<dyn Fn()>>,
732 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
735 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
738 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
741 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
744 pub blur: Option<BlurStyle>,
749 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (Dp, Dp)>>,
754 pub semantics: Option<crate::Semantics>,
755 pub alpha: Option<f32>,
756 pub graphics_layer: Option<f32>,
757 pub shadow: Option<ShadowSpec>,
758 pub transform: Option<Transform>,
759 pub grid: Option<GridConfig>,
760 pub grid_col_span: Option<u16>,
761 pub grid_row_span: Option<u16>,
762 pub position_type: Option<PositionType>,
763 pub offset_left: Option<Dp>,
764 pub offset_right: Option<Dp>,
765 pub offset_top: Option<Dp>,
766 pub offset_bottom: Option<Dp>,
767
768 pub margin_left: Option<Dp>,
769 pub margin_right: Option<Dp>,
770 pub margin_top: Option<Dp>,
771 pub margin_bottom: Option<Dp>,
772 pub aspect_ratio: Option<f32>,
773 pub intrinsic_width: Option<IntrinsicSize>,
776 pub intrinsic_height: Option<IntrinsicSize>,
779 pub fit_content_width: Option<Dp>,
782 pub fit_content_height: Option<Dp>,
785 pub baseline_align: Option<BaselineAlign>,
788 pub contain: Option<Contain>,
793 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
794 pub paint_callback: Option<crate::PaintCallbackPayload>,
795
796 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
798 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
799 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
800 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
801 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
802 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
803 pub drag_preview: Option<crate::dnd::DragPreview>,
805
806 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
807
808 pub cursor: Option<crate::CursorIcon>,
810
811 pub animate_content_size: Option<AnimationSpec>,
814
815 pub focus_requester: Option<crate::runtime::FocusRequester>,
819
820 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
823
824 pub interaction_source: Option<InteractionSource>,
831
832 pub text_input: Option<TextInputConfig>,
834
835 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
837}
838
839impl std::fmt::Debug for Modifier {
840 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
841 let mut s = f.debug_struct("Modifier");
842
843 macro_rules! opt_val {
844 ($($name:ident),+ $(,)?) => {
845 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
846 };
847 }
848 if self.indication.is_some() {
849 s.field("indication", &"…");
850 }
851
852 opt_val!(
853 key,
854 size,
855 width,
856 height,
857 required_size,
858 padding,
859 padding_values,
860 min_width,
861 min_height,
862 max_width,
863 max_height,
864 required_min_width,
865 required_max_width,
866 required_min_height,
867 required_max_height,
868 default_min_width,
869 default_min_height,
870 fill_max,
871 fill_max_w,
872 fill_max_h,
873 background,
874 state_colors,
875 state_elevation,
876 border,
877 flex_grow,
878 flex_shrink,
879 flex_basis,
880 flex_wrap,
881 flex_dir,
882 gap,
883 row_gap,
884 column_gap,
885 align_self,
886 justify_content,
887 align_items_container,
888 align_content,
889 clip_rounded,
890 clip_rect,
891 render_z_index,
892 semantics,
893 alpha,
894 transform,
895 grid,
896 grid_col_span,
897 grid_row_span,
898 position_type,
899 offset_left,
900 offset_right,
901 offset_top,
902 offset_bottom,
903 margin_left,
904 margin_right,
905 margin_top,
906 margin_bottom,
907 aspect_ratio,
908 intrinsic_width,
909 intrinsic_height,
910 cursor,
911 animate_content_size,
912 blur,
913 );
914
915 macro_rules! opt_cb {
916 ($($name:ident),+ $(,)?) => {
917 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
918 };
919 }
920 opt_cb!(
921 on_scroll,
922 scroll,
923 nested_scroll_connection,
924 on_pointer_down,
925 on_pointer_move,
926 on_pointer_up,
927 on_pointer_cancel,
928 on_pointer_enter,
929 on_pointer_leave,
930 on_click,
931 on_double_click,
932 on_long_click,
933 on_globally_positioned,
934 on_size_changed,
935 on_key_event,
936 on_preview_key_event,
937 painter,
938 paint_callback,
939 on_drag_start,
940 on_drag_end,
941 on_drag_enter,
942 on_drag_over,
943 on_drag_leave,
944 on_drop,
945 drag_preview,
946 on_action,
947 on_focus_changed,
948 interaction_source,
949 text_input,
950 layout,
951 );
952
953 macro_rules! flag {
954 ($($name:ident),+ $(,)?) => {
955 $( if self.$name { s.field(stringify!($name), &true); } )+
956 };
957 }
958 flag!(
959 hit_passthrough,
960 input_blocker,
961 repaint_boundary,
962 click,
963 disabled,
964 propagate_min,
965 focus_group,
966 );
967
968 if let Some(f) = self.focusable {
969 s.field("focusable", &f);
970 }
971 if self.z_index != 0.0 {
972 s.field("z_index", &self.z_index);
973 }
974
975 s.finish()
976 }
977}
978
979impl_option_fields!(Modifier);
980
981#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
985pub enum Alignment {
986 TopStart,
987 TopCenter,
988 TopEnd,
989 CenterStart,
990 #[default]
991 Center,
992 CenterEnd,
993 BottomStart,
994 BottomCenter,
995 BottomEnd,
996}
997
998impl Alignment {
999 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
1001 use AlignItems as AI;
1002 use JustifyContent as JC;
1003 match self {
1004 Self::TopStart => (AI::START, JC::START),
1005 Self::TopCenter => (AI::START, JC::CENTER),
1006 Self::TopEnd => (AI::START, JC::END),
1007 Self::CenterStart => (AI::CENTER, JC::START),
1008 Self::Center => (AI::CENTER, JC::CENTER),
1009 Self::CenterEnd => (AI::CENTER, JC::END),
1010 Self::BottomStart => (AI::END, JC::START),
1011 Self::BottomCenter => (AI::END, JC::CENTER),
1012 Self::BottomEnd => (AI::END, JC::END),
1013 }
1014 }
1015
1016 pub fn to_flex_safe(self) -> (AlignItems, JustifyContent) {
1021 use AlignItems as AI;
1022 use JustifyContent as JC;
1023 match self {
1024 Self::TopStart => (AI::SAFE_START, JC::SAFE_START),
1025 Self::TopCenter => (AI::SAFE_START, JC::SAFE_CENTER),
1026 Self::TopEnd => (AI::SAFE_START, JC::SAFE_END),
1027 Self::CenterStart => (AI::SAFE_CENTER, JC::SAFE_START),
1028 Self::Center => (AI::SAFE_CENTER, JC::SAFE_CENTER),
1029 Self::CenterEnd => (AI::SAFE_CENTER, JC::SAFE_END),
1030 Self::BottomStart => (AI::SAFE_END, JC::SAFE_START),
1031 Self::BottomCenter => (AI::SAFE_END, JC::SAFE_CENTER),
1032 Self::BottomEnd => (AI::SAFE_END, JC::SAFE_END),
1033 }
1034 }
1035}
1036
1037impl Modifier {
1038 pub fn new() -> Self {
1039 Self::default()
1040 }
1041
1042 pub fn key(mut self, key: u64) -> Self {
1045 self.key = Some(key);
1046 self
1047 }
1048
1049 pub fn size(mut self, w: Dp, h: Dp) -> Self {
1050 self.size = Some(DpSize::new(w, h));
1051 self
1052 }
1053 pub fn width(mut self, w: Dp) -> Self {
1054 self.width = Some(w);
1055 self
1056 }
1057 pub fn height(mut self, h: Dp) -> Self {
1058 self.height = Some(h);
1059 self
1060 }
1061 pub fn required_size(mut self, w: Dp, h: Dp) -> Self {
1066 self.required_size = Some(DpSize::new(w, h));
1067 self
1068 }
1069 pub fn required_width_in(mut self, min: Dp, max: Dp) -> Self {
1070 self.required_min_width = Some(Dp(min.0.max(0.0)));
1071 self.required_max_width = Some(Dp(max.0.max(0.0)));
1072 self
1073 }
1074 pub fn required_height_in(mut self, min: Dp, max: Dp) -> Self {
1075 self.required_min_height = Some(Dp(min.0.max(0.0)));
1076 self.required_max_height = Some(Dp(max.0.max(0.0)));
1077 self
1078 }
1079 pub fn required_min_width(mut self, w: Dp) -> Self {
1080 self.required_min_width = Some(Dp(w.0.max(0.0)));
1081 self
1082 }
1083 pub fn required_max_width(mut self, w: Dp) -> Self {
1084 self.required_max_width = Some(Dp(w.0.max(0.0)));
1085 self
1086 }
1087 pub fn required_min_height(mut self, h: Dp) -> Self {
1088 self.required_min_height = Some(Dp(h.0.max(0.0)));
1089 self
1090 }
1091 pub fn required_max_height(mut self, h: Dp) -> Self {
1092 self.required_max_height = Some(Dp(h.0.max(0.0)));
1093 self
1094 }
1095 pub fn default_min_size(mut self, w: Dp, h: Dp) -> Self {
1097 self.default_min_width = Some(Dp(w.0.max(0.0)));
1098 self.default_min_height = Some(Dp(h.0.max(0.0)));
1099 self
1100 }
1101 pub fn fill_max_size(mut self) -> Self {
1104 self.fill_max = Some(1.0);
1105 self
1106 }
1107 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
1108 self.fill_max = Some(fraction.clamp(0.0, 1.0));
1109 self
1110 }
1111 pub fn fill_max_width(mut self) -> Self {
1113 self.fill_max_w = Some(1.0);
1114 self
1115 }
1116 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
1117 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
1118 self
1119 }
1120 pub fn fill_max_height(mut self) -> Self {
1122 self.fill_max_h = Some(1.0);
1123 self
1124 }
1125 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
1126 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
1127 self
1128 }
1129 pub fn padding(mut self, v: Dp) -> Self {
1130 self.padding = Some(v);
1131 self
1132 }
1133 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
1134 self.padding_values = Some(padding);
1135 self
1136 }
1137 pub fn ime_padding(mut self) -> Self {
1141 use crate::units::Px;
1142 let insets = crate::locals::window_insets();
1143 let mut p = self.padding_values.unwrap_or_default();
1144 p.bottom = p.bottom + Px(insets.ime_bottom).to_dp();
1145 self.padding_values = Some(p);
1146 self
1147 }
1148 pub fn system_bars_padding(mut self) -> Self {
1150 use crate::units::Px;
1151 let insets = crate::locals::window_insets();
1152 let mut p = self.padding_values.unwrap_or_default();
1153 p.top = p.top + Px(insets.top).to_dp();
1154 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1155 self.padding_values = Some(p);
1156 self
1157 }
1158 pub fn status_bars_padding(mut self) -> Self {
1160 use crate::units::Px;
1161 let insets = crate::locals::window_insets();
1162 let mut p = self.padding_values.unwrap_or_default();
1163 p.top = p.top + Px(insets.top).to_dp();
1164 self.padding_values = Some(p);
1165 self
1166 }
1167 pub fn navigation_bars_padding(mut self) -> Self {
1169 let insets = crate::locals::window_insets();
1170 use crate::units::Px;
1171 let mut p = self.padding_values.unwrap_or_default();
1172 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1173 self.padding_values = Some(p);
1174 self
1175 }
1176 pub fn min_size(mut self, w: Dp, h: Dp) -> Self {
1177 self.min_width = Some(w);
1178 self.min_height = Some(h);
1179 self
1180 }
1181 pub fn max_size(mut self, w: Dp, h: Dp) -> Self {
1182 self.max_width = Some(w);
1183 self.max_height = Some(h);
1184 self
1185 }
1186 pub fn min_width(mut self, w: Dp) -> Self {
1187 self.min_width = Some(w);
1188 self
1189 }
1190 pub fn min_height(mut self, h: Dp) -> Self {
1191 self.min_height = Some(h);
1192 self
1193 }
1194 pub fn max_width(mut self, w: Dp) -> Self {
1195 self.max_width = Some(w);
1196 self
1197 }
1198 pub fn max_height(mut self, h: Dp) -> Self {
1199 self.max_height = Some(h);
1200 self
1201 }
1202 pub fn background(mut self, color: Color) -> Self {
1204 self.background = Some(Brush::Solid(color));
1205 self
1206 }
1207 pub fn background_brush(mut self, brush: Brush) -> Self {
1209 self.background = Some(brush);
1210 self
1211 }
1212 pub fn border(mut self, width: Dp, color: Color, radius: Dp) -> Self {
1213 self.border = Some(Border {
1214 width,
1215 color,
1216 radius: [radius; 4],
1217 });
1218 self
1219 }
1220 pub fn border_radii(mut self, width: Dp, color: Color, radii: [Dp; 4]) -> Self {
1221 self.border = Some(Border {
1222 width,
1223 color,
1224 radius: radii,
1225 });
1226 self
1227 }
1228 pub fn flex_grow(mut self, v: f32) -> Self {
1229 self.flex_grow = Some(v);
1230 self
1231 }
1232 pub fn flex_shrink(mut self, v: f32) -> Self {
1233 self.flex_shrink = Some(v);
1234 self
1235 }
1236 pub fn flex_basis(mut self, v: Dp) -> Self {
1237 self.flex_basis = Some(v);
1238 self
1239 }
1240 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1241 self.flex_wrap = Some(w);
1242 self
1243 }
1244 pub fn flex_basis_content(mut self) -> Self {
1247 self.flex_basis_content = true;
1248 self
1249 }
1250 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1251 self.flex_dir = Some(d);
1252 self
1253 }
1254 pub fn gap(mut self, v: Dp) -> Self {
1255 let v = Dp(v.0.max(0.0));
1256 self.gap = Some(v);
1257 self.row_gap = Some(v);
1258 self.column_gap = Some(v);
1259 self
1260 }
1261 pub fn row_gap(mut self, v: Dp) -> Self {
1262 self.row_gap = Some(Dp(v.0.max(0.0)));
1263 self
1264 }
1265 pub fn column_gap(mut self, v: Dp) -> Self {
1266 self.column_gap = Some(Dp(v.0.max(0.0)));
1267 self
1268 }
1269 pub fn align_self(mut self, a: AlignSelf) -> Self {
1270 self.align_self = Some(a);
1271 self
1272 }
1273 pub fn align_self_center(mut self) -> Self {
1274 self.align_self = Some(AlignSelf::CENTER);
1275 self
1276 }
1277 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1278 self.justify_content = Some(j);
1279 self
1280 }
1281 pub fn align_items(mut self, a: AlignItems) -> Self {
1282 self.align_items_container = Some(a);
1283 self
1284 }
1285 pub fn content_alignment(self, alignment: Alignment) -> Self {
1288 let (ai, jc) = alignment.to_flex();
1289 self.align_items(ai).justify_content(jc)
1290 }
1291 pub fn content_alignment_safe(self, alignment: Alignment) -> Self {
1296 let (ai, jc) = alignment.to_flex_safe();
1297 self.align_items(ai).justify_content(jc)
1298 }
1299 pub fn align_content(mut self, a: AlignContent) -> Self {
1300 self.align_content = Some(a);
1301 self
1302 }
1303 pub fn clip_rounded(mut self, radius: Dp) -> Self {
1304 self.clip_rounded = Some([radius; 4]);
1305 self
1306 }
1307 pub fn clip_rounded_radii(mut self, radii: [Dp; 4]) -> Self {
1308 self.clip_rounded = Some(radii);
1309 self
1310 }
1311 pub fn clip_rect(mut self, left: Dp, top: Dp, right: Dp, bottom: Dp, op: ClipOp) -> Self {
1314 self.clip_rect = Some(ClipRect {
1315 left,
1316 top,
1317 right,
1318 bottom,
1319 op,
1320 });
1321 self
1322 }
1323 pub fn overflow(mut self, overflow: Overflow) -> Self {
1324 self.overflow = Some(overflow);
1325 self
1326 }
1327 pub fn z_index(mut self, z: f32) -> Self {
1328 self.z_index = z;
1329 self
1330 }
1331
1332 pub fn render_z_index(mut self, z: f32) -> Self {
1335 self.render_z_index = Some(z);
1336 self
1337 }
1338
1339 pub fn input_blocker(mut self) -> Self {
1341 self.input_blocker = true;
1342 self
1343 }
1344
1345 pub fn hit_passthrough(mut self) -> Self {
1346 self.hit_passthrough = true;
1347 self
1348 }
1349 pub fn clickable(mut self) -> Self {
1350 self.click = true;
1351 if self.indication.is_none() {
1352 self.indication = crate::locals::local_indication();
1353 }
1354 self
1355 }
1356 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1359 self.click = true;
1360 self.interaction_source = Some(source.source());
1361 if self.indication.is_none() {
1362 self.indication = crate::locals::local_indication();
1363 }
1364 self
1365 }
1366 pub fn state_colors(mut self, colors: StateColors) -> Self {
1369 self.state_colors = Some(colors);
1370 self
1371 }
1372 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1374 self.state_elevation = Some(elev);
1375 self
1376 }
1377 pub fn disabled(mut self) -> Self {
1379 self.disabled = true;
1380 self
1381 }
1382 pub fn enabled(mut self, enabled: bool) -> Self {
1384 self.disabled = !enabled;
1385 self
1386 }
1387 pub fn focusable(mut self, focusable: bool) -> Self {
1392 self.focusable = Some(focusable);
1393 self
1394 }
1395 pub fn focus_group(mut self) -> Self {
1398 self.focus_group = true;
1399 self
1400 }
1401 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1412 self.interaction_source = Some(source.source());
1413 self
1414 }
1415 pub fn hoverable(
1418 mut self,
1419 on_enter: impl Fn() + 'static,
1420 on_leave: impl Fn() + 'static,
1421 ) -> Self {
1422 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1423 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1424 self
1425 }
1426 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1430 self.interaction_source = Some(source.source());
1431 self
1432 }
1433 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1436 self.propagate_min = propagate;
1437 self
1438 }
1439 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1440 self.on_scroll = Some(Rc::new(f));
1441 self
1442 }
1443 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1447 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1448 self
1449 }
1450 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1452 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1453 self
1454 }
1455 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1457 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1458 self
1459 }
1460 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1467 self.nested_scroll_connection = Some(conn);
1468 self
1469 }
1470 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1471 self.on_pointer_down = Some(Rc::new(f));
1472 self
1473 }
1474 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1475 self.on_pointer_move = Some(Rc::new(f));
1476 self
1477 }
1478 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1479 self.on_pointer_up = Some(Rc::new(f));
1480 self
1481 }
1482 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1483 self.on_pointer_cancel = Some(Rc::new(f));
1484 self
1485 }
1486
1487 pub fn draggable(self, on_drag: impl Fn(Vec2) + 'static) -> Self {
1488 let drag_pos = crate::state::remember_mutable(Vec2::default);
1489 let is_dragging = crate::state::remember_mutable(|| false);
1490 let on_drag = Rc::new(on_drag);
1491 self.on_pointer_down({
1492 let drag_pos = drag_pos.clone();
1493 let is_dragging = is_dragging.clone();
1494 move |ev| {
1495 is_dragging.set(true);
1496 drag_pos.set(ev.position);
1497 }
1498 })
1499 .on_pointer_up({
1500 let is_dragging = is_dragging.clone();
1501 move |_| is_dragging.set(false)
1502 })
1503 .on_pointer_cancel({
1504 let is_dragging = is_dragging.clone();
1505 move |_| is_dragging.set(false)
1506 })
1507 .on_pointer_move({
1508 let drag_pos = drag_pos.clone();
1509 let is_dragging = is_dragging.clone();
1510 let on_drag = on_drag.clone();
1511 move |ev| {
1512 if !*is_dragging.get() {
1513 return;
1514 }
1515 let prev = *drag_pos.get();
1516 let cur = ev.position;
1517 let delta = Vec2 {
1518 x: cur.x - prev.x,
1519 y: cur.y - prev.y,
1520 };
1521 drag_pos.set(cur);
1522 on_drag(delta);
1523 crate::frame_clock::request_frame();
1524 }
1525 })
1526 }
1527 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1528 self.on_pointer_enter = Some(Rc::new(f));
1529 self
1530 }
1531 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1532 self.on_pointer_leave = Some(Rc::new(f));
1533 self
1534 }
1535 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1536 self.on_click = Some(Rc::new(f));
1537 self.click = true;
1538 if self.semantics.is_none() {
1539 self.semantics = Some(crate::Semantics::new(crate::Role::Button));
1540 }
1541 self
1542 }
1543 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1544 self.on_double_click = Some(Rc::new(f));
1545 self.click = true;
1546 self
1547 }
1548 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1549 self.on_long_click = Some(Rc::new(f));
1550 self.click = true;
1551 self
1552 }
1553 pub fn clickable_ext(
1554 mut self,
1555 enabled: bool,
1556 on_click_label: Option<String>,
1557 role: Option<crate::semantics::Role>,
1558 on_click: impl Fn() + 'static,
1559 ) -> Self {
1560 if !enabled {
1561 let mut s = self.semantics.clone().unwrap_or_else(|| {
1562 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1563 });
1564 s.enabled = false;
1565 if let Some(r) = role {
1566 s.role = r;
1567 }
1568 if let Some(l) = on_click_label {
1569 s.label = Some(l);
1570 }
1571 return self
1572 .clickable()
1573 .enabled(false)
1574 .default_min_size(Dp(48.0), Dp(48.0))
1575 .semantics(s);
1576 }
1577 self = self.clickable().on_click(on_click);
1578 if role.is_some() || on_click_label.is_some() {
1579 let mut s = self.semantics.clone().unwrap_or_else(|| {
1580 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1581 });
1582 s.enabled = true;
1583 if let Some(r) = role {
1584 s.role = r;
1585 }
1586 if let Some(l) = on_click_label {
1587 s.label = Some(l);
1588 }
1589 self = self.semantics(s);
1590 }
1591 self.default_min_size(Dp(48.0), Dp(48.0))
1592 }
1593 pub fn combined_clickable(
1594 mut self,
1595 enabled: bool,
1596 on_click_label: Option<String>,
1597 role: Option<crate::semantics::Role>,
1598 on_long_click_label: Option<String>,
1599 on_click: impl Fn() + 'static,
1600 on_long_click: Option<impl Fn() + 'static>,
1601 on_double_click: Option<impl Fn() + 'static>,
1602 ) -> Self {
1603 let _ = on_long_click_label;
1604 if !enabled {
1605 return self.clickable_ext(false, on_click_label, role, || {});
1606 }
1607 self = self.clickable_ext(true, on_click_label, role, on_click);
1608 if let Some(f) = on_long_click {
1609 self = self.on_long_click(f);
1610 }
1611 if let Some(f) = on_double_click {
1612 self = self.on_double_click(f);
1613 }
1614 self.default_min_size(Dp(48.0), Dp(48.0))
1615 }
1616 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1617 self.semantics = Some(s);
1618 self
1619 }
1620 pub fn alpha(mut self, a: f32) -> Self {
1621 self.alpha = Some(a);
1622 self
1623 }
1624 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1629 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1630 self
1631 }
1632 pub fn shadow(mut self, blur_radius: Dp, offset_y: Dp) -> Self {
1636 self.shadow = Some(ShadowSpec {
1637 blur_radius: Dp(blur_radius.0.max(0.0)),
1638 offset_y,
1639 color: Color(0, 0, 0, 64),
1640 });
1641 self
1642 }
1643 pub fn shadow_with_color(mut self, blur_radius: Dp, offset_y: Dp, color: Color) -> Self {
1645 self.shadow = Some(ShadowSpec {
1646 blur_radius: Dp(blur_radius.0.max(0.0)),
1647 offset_y,
1648 color,
1649 });
1650 self
1651 }
1652 pub fn elevation(mut self, level: Dp) -> Self {
1656 if level.0 <= 0.0 {
1657 self.shadow = None;
1658 return self;
1659 }
1660 self.shadow = Some(ShadowSpec {
1661 blur_radius: Dp(level.0 * 2.0),
1662 offset_y: Dp(level.0 * 0.5),
1663 color: Color(0, 0, 0, (level.0 * 8.0).clamp(8.0, 80.0) as u8),
1664 });
1665 self
1666 }
1667 pub fn transform(mut self, t: Transform) -> Self {
1668 self.transform = Some(t);
1669 self
1670 }
1671 pub fn grid(mut self, columns: usize, row_gap: Dp, column_gap: Dp) -> Self {
1672 self.grid = Some(GridConfig {
1673 columns,
1674 row_gap,
1675 column_gap,
1676 });
1677 self
1678 }
1679 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1680 self.grid_col_span = Some(col_span);
1681 self.grid_row_span = Some(row_span);
1682 self
1683 }
1684 pub fn absolute(mut self) -> Self {
1685 self.position_type = Some(PositionType::Absolute);
1686 self
1687 }
1688 pub fn offset(
1689 mut self,
1690 left: Option<Dp>,
1691 top: Option<Dp>,
1692 right: Option<Dp>,
1693 bottom: Option<Dp>,
1694 ) -> Self {
1695 self.offset_left = left;
1696 self.offset_top = top;
1697 self.offset_right = right;
1698 self.offset_bottom = bottom;
1699 self
1700 }
1701 pub fn offset_left(mut self, v: Dp) -> Self {
1702 self.offset_left = Some(v);
1703 self
1704 }
1705 pub fn offset_right(mut self, v: Dp) -> Self {
1706 self.offset_right = Some(v);
1707 self
1708 }
1709 pub fn offset_top(mut self, v: Dp) -> Self {
1710 self.offset_top = Some(v);
1711 self
1712 }
1713 pub fn offset_bottom(mut self, v: Dp) -> Self {
1714 self.offset_bottom = Some(v);
1715 self
1716 }
1717 pub fn margin(mut self, v: Dp) -> Self {
1718 self.margin_left = Some(v);
1719 self.margin_right = Some(v);
1720 self.margin_top = Some(v);
1721 self.margin_bottom = Some(v);
1722 self
1723 }
1724
1725 pub fn margin_horizontal(mut self, v: Dp) -> Self {
1726 self.margin_left = Some(v);
1727 self.margin_right = Some(v);
1728 self
1729 }
1730
1731 pub fn margin_vertical(mut self, v: Dp) -> Self {
1732 self.margin_top = Some(v);
1733 self.margin_bottom = Some(v);
1734 self
1735 }
1736 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1737 self.aspect_ratio = Some(ratio);
1738 self
1739 }
1740 pub fn fit_content_width(mut self, limit: Dp) -> Self {
1742 self.fit_content_width = Some(Dp(limit.0.max(0.0)));
1743 self
1744 }
1745 pub fn fit_content_height(mut self, limit: Dp) -> Self {
1747 self.fit_content_height = Some(Dp(limit.0.max(0.0)));
1748 self
1749 }
1750 pub fn contain(mut self, c: Contain) -> Self {
1752 self.contain = Some(c);
1753 self
1754 }
1755 pub fn contain_layout(mut self) -> Self {
1757 self.contain = Some(Contain::LAYOUT);
1758 self
1759 }
1760 pub fn contain_paint(mut self) -> Self {
1762 self.contain = Some(Contain::PAINT);
1763 self
1764 }
1765 pub fn contain_content(mut self) -> Self {
1767 self.contain = Some(Contain::CONTENT);
1768 self
1769 }
1770 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1772 self.intrinsic_width = Some(mode);
1773 self
1774 }
1775 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1777 self.intrinsic_height = Some(mode);
1778 self
1779 }
1780 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1781 self.painter = Some(Rc::new(f));
1782 self
1783 }
1784 pub fn paint_callback(mut self, payload: crate::PaintCallbackPayload) -> Self {
1790 self.paint_callback = Some(payload);
1791 self
1792 }
1793 pub fn scale(self, s: f32) -> Self {
1794 self.scale2(s, s)
1795 }
1796 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1797 let mut t = self.transform.unwrap_or_else(Transform::identity);
1798 t.scale_x *= sx;
1799 t.scale_y *= sy;
1800 self.transform = Some(t);
1801 self
1802 }
1803 pub fn translate(mut self, x: f32, y: f32) -> Self {
1804 let t = self.transform.unwrap_or_else(Transform::identity);
1805 self.transform = Some(t.combine(&Transform::translate(x, y)));
1806 self
1807 }
1808 pub fn translate_vec2(self, v: Vec2) -> Self {
1809 self.translate(v.x, v.y)
1810 }
1811 pub fn rotate(mut self, radians: f32) -> Self {
1812 let mut t = self.transform.unwrap_or_else(Transform::identity);
1813 t.rotate += radians;
1814 self.transform = Some(t);
1815 self
1816 }
1817 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1818 let mut t = self.transform.unwrap_or_else(Transform::identity);
1819 t.origin_x = x;
1820 t.origin_y = y;
1821 self.transform = Some(t);
1822 self
1823 }
1824 pub fn weight(mut self, w: f32) -> Self {
1825 let w = w.max(0.0);
1826 self.flex_grow = Some(w);
1827 self.flex_shrink = Some(1.0);
1828 self.flex_basis = Some(Dp::ZERO);
1830 self
1831 }
1832 pub fn repaint_boundary(mut self) -> Self {
1836 self.repaint_boundary = true;
1837 self
1838 }
1839 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1840 self.on_action = Some(Rc::new(f));
1841 self
1842 }
1843
1844 pub fn on_drag_start(
1846 mut self,
1847 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1848 ) -> Self {
1849 self.on_drag_start = Some(Rc::new(f));
1850 self
1851 }
1852
1853 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1855 self.on_drag_end = Some(Rc::new(f));
1856 self
1857 }
1858
1859 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1861 self.on_drag_enter = Some(Rc::new(f));
1862 self
1863 }
1864
1865 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1867 self.on_drag_over = Some(Rc::new(f));
1868 self
1869 }
1870
1871 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1873 self.on_drag_leave = Some(Rc::new(f));
1874 self
1875 }
1876
1877 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1880 self.on_drop = Some(Rc::new(f));
1881 self
1882 }
1883
1884 pub fn draw_drag_decoration(
1889 mut self,
1890 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
1891 ) -> Self {
1892 self.drag_preview = Some(Rc::new(f));
1893 self
1894 }
1895
1896 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
1898 self.drag_preview = Some(preview);
1899 self
1900 }
1901
1902 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
1904 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
1905 }
1906
1907 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
1909 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
1910 }
1911
1912 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1914 self.cursor = Some(c);
1915 self
1916 }
1917
1918 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1922 self.animate_content_size = Some(spec);
1923 self
1924 }
1925
1926 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1929 self.focus_requester = Some(fr);
1930 self
1931 }
1932
1933 pub fn focus_target(mut self) -> Self {
1936 self.focusable = Some(true);
1937 self
1938 }
1939
1940 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1943 self.on_focus_changed = Some(Rc::new(f));
1944 self
1945 }
1946
1947 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
1952 self.on_globally_positioned = Some(Rc::new(f));
1953 self
1954 }
1955
1956 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
1959 self.on_size_changed = Some(Rc::new(f));
1960 self
1961 }
1962
1963 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
1967 self.on_key_event = Some(Rc::new(f));
1968 self
1969 }
1970
1971 pub fn on_preview_key_event(
1975 mut self,
1976 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
1977 ) -> Self {
1978 self.on_preview_key_event = Some(Rc::new(f));
1979 self
1980 }
1981
1982 pub fn blur(mut self, radius: Dp) -> Self {
1989 self.blur = Some(BlurStyle {
1990 radius_x: Dp(radius.0.max(0.0)),
1991 radius_y: Dp(radius.0.max(0.0)),
1992 edge_treatment: BlurredEdgeTreatment::Rectangle,
1993 });
1994 self
1995 }
1996
1997 pub fn blur_with_edge(
2002 mut self,
2003 radius_x: Dp,
2004 radius_y: Dp,
2005 edge_treatment: BlurredEdgeTreatment,
2006 ) -> Self {
2007 self.blur = Some(BlurStyle {
2008 radius_x: Dp(radius_x.0.max(0.0)),
2009 radius_y: Dp(radius_y.0.max(0.0)),
2010 edge_treatment,
2011 });
2012 self
2013 }
2014
2015 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (Dp, Dp) + 'static) -> Self {
2023 self.layout = Some(Rc::new(f));
2024 self
2025 }
2026
2027 pub fn text_input(mut self, config: TextInputConfig) -> Self {
2029 self.text_input = Some(config);
2030 self
2031 }
2032
2033 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
2037 self.indication = Some(factory);
2038 self
2039 }
2040}