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 brush: Brush,
192 pub radius: [Dp; 4],
193}
194
195#[derive(Clone, Copy, Debug, Default)]
196pub struct PaddingValues {
197 pub left: Dp,
198 pub right: Dp,
199 pub top: Dp,
200 pub bottom: Dp,
201}
202
203#[derive(Clone, Debug)]
204pub struct GridConfig {
205 pub columns: usize,
206 pub row_gap: Dp,
207 pub column_gap: Dp,
208}
209
210#[derive(Clone, Copy, Debug, PartialEq)]
213pub enum BlurredEdgeTreatment {
214 Rectangle,
217 Unbounded,
220}
221
222#[derive(Clone, Copy, Debug)]
224pub struct BlurStyle {
225 pub radius_x: Dp,
227 pub radius_y: Dp,
229 pub edge_treatment: BlurredEdgeTreatment,
231}
232
233#[derive(Clone, Copy, Debug)]
239pub struct LayoutConstraints {
240 pub min_width: Dp,
241 pub max_width: Dp,
242 pub min_height: Dp,
243 pub max_height: Dp,
244}
245
246#[derive(Clone, Copy, Debug)]
253pub struct ShadowSpec {
254 pub blur_radius: Dp,
255 pub offset_y: Dp,
256 pub color: Color,
257}
258
259#[derive(Clone, Copy, Debug)]
260#[non_exhaustive]
261pub enum PositionType {
262 Relative,
263 Absolute,
264}
265
266#[derive(Clone)]
268pub struct TextInputConfig {
269 pub hint: String,
270 pub multiline: bool,
271 pub on_change: Option<Rc<dyn Fn(String)>>,
272 pub on_submit: Option<Rc<dyn Fn(String)>>,
273 pub focus_tracker: Option<Rc<Cell<bool>>>,
274 pub value: String,
275 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
276 pub keyboard_type: crate::text::KeyboardType,
277 pub capitalization: crate::text::KeyboardCapitalization,
278 pub ime_action: crate::text::ImeAction,
279 pub auto_correct_enabled: Option<bool>,
282 pub enabled: bool,
284 pub read_only: bool,
286 pub max_lines: Option<usize>,
288 pub min_lines: usize,
290 pub cursor_color: Option<Color>,
292 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
295 pub text_style: Option<crate::text::TextStyle>,
298 pub keyboard_actions: Option<crate::text::KeyboardActions>,
301 pub interaction_source: Option<InteractionSource>,
303 pub line_limits: Option<crate::text::TextFieldLineLimits>,
305}
306
307impl Default for TextInputConfig {
308 fn default() -> Self {
309 Self {
310 hint: String::new(),
311 multiline: false,
312 on_change: None,
313 on_submit: None,
314 focus_tracker: None,
315 value: String::new(),
316 visual_transformation: None,
317 keyboard_type: crate::text::KeyboardType::default(),
318 capitalization: crate::text::KeyboardCapitalization::default(),
319 ime_action: crate::text::ImeAction::default(),
320 auto_correct_enabled: None,
321 enabled: true,
322 read_only: false,
323 max_lines: None,
324 min_lines: 1,
325 cursor_color: None,
326 on_text_layout: None,
327 text_style: None,
328 keyboard_actions: None,
329 interaction_source: None,
330 line_limits: None,
331 }
332 }
333}
334
335impl std::fmt::Debug for TextInputConfig {
336 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
337 let mut s = f.debug_struct("TextInputConfig");
338 s.field("hint", &self.hint);
339 s.field("multiline", &self.multiline);
340 if self.on_change.is_some() {
341 s.field("on_change", &"…");
342 }
343 if self.on_submit.is_some() {
344 s.field("on_submit", &"…");
345 }
346 if self.focus_tracker.is_some() {
347 s.field("focus_tracker", &"…");
348 }
349 s.field("value", &self.value);
350 if self.visual_transformation.is_some() {
351 s.field("visual_transformation", &"…");
352 }
353 s.field("keyboard_type", &self.keyboard_type);
354 s.field("capitalization", &self.capitalization);
355 s.field("ime_action", &self.ime_action);
356 s.field("auto_correct_enabled", &self.auto_correct_enabled);
357 s.field("enabled", &self.enabled);
358 s.field("read_only", &self.read_only);
359 s.field("max_lines", &self.max_lines);
360 s.field("min_lines", &self.min_lines);
361 s.field("cursor_color", &self.cursor_color);
362 if self.on_text_layout.is_some() {
363 s.field("on_text_layout", &"…");
364 }
365 s.finish()
366 }
367}
368
369#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
372pub enum IntrinsicSize {
373 Min,
374 Max,
375}
376
377#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
385pub enum BaselineAlign {
386 FirstBaseline,
387 LastBaseline,
388}
389
390static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
391
392pub type PressId = u64;
394
395#[derive(Clone, Copy, Debug, PartialEq)]
403pub enum Interaction {
404 Press(PressId, Vec2),
407 Release(PressId),
409 Cancel(PressId),
412 HoverEnter,
413 HoverLeave,
414 Focus,
415 Unfocus,
416 DragStart,
417 DragStop,
418 DragCancel,
419}
420
421impl Interaction {
422 #[inline]
424 pub fn new_press(position: Vec2) -> Self {
425 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
426 }
427}
428
429#[derive(Clone)]
436pub struct InteractionSource {
437 pub(crate) state: Rc<RefCell<InteractionState>>,
438}
439
440impl InteractionSource {
441 pub fn collect_is_pressed(&self) -> bool {
442 !self.state.borrow().active_presses.is_empty()
443 }
444 pub fn collect_is_hovered(&self) -> bool {
445 self.state.borrow().hovered
446 }
447 pub fn collect_is_focused(&self) -> bool {
448 self.state.borrow().focused
449 }
450
451 pub fn collect_is_focus_visible(&self) -> bool {
453 crate::input::is_focus_visible(self.collect_is_focused())
454 }
455
456 pub fn collect_is_dragged(&self) -> bool {
457 self.state.borrow().dragged > 0
458 }
459 pub fn collect_last_press_position(&self) -> Option<Vec2> {
460 self.state.borrow().last_press_position
461 }
462 pub fn collect_last_press_id(&self) -> Option<PressId> {
463 self.state.borrow().last_press_id
464 }
465 pub fn stable_id(&self) -> *const () {
467 Rc::as_ptr(&self.state) as *const ()
468 }
469 pub fn to_mutable(&self) -> MutableInteractionSource {
473 MutableInteractionSource {
474 state: self.state.clone(),
475 }
476 }
477
478 pub fn reset(&self) {
480 self.to_mutable().reset();
481 }
482
483 pub fn reset_hover(&self) {
485 self.to_mutable().reset_hover();
486 }
487}
488
489#[derive(Clone)]
499pub struct MutableInteractionSource {
500 pub(crate) state: Rc<RefCell<InteractionState>>,
501}
502
503impl std::fmt::Debug for MutableInteractionSource {
504 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
505 f.debug_struct("MutableInteractionSource")
506 .finish_non_exhaustive()
507 }
508}
509
510impl MutableInteractionSource {
511 pub fn new() -> Self {
512 Self {
513 state: Rc::new(RefCell::new(InteractionState::default())),
514 }
515 }
516
517 pub fn emit(&self, interaction: Interaction) {
519 let changed = {
520 let mut s = self.state.borrow_mut();
521 match interaction {
522 Interaction::Press(id, pos) => {
523 let inserted = s.active_presses.insert(id);
524 s.last_press_id = Some(id);
525 s.last_press_position = Some(pos);
526 inserted
527 }
528 Interaction::Release(id) | Interaction::Cancel(id) => {
529 if s.active_presses.remove(&id) {
530 true
531 } else if id == 0 {
532 if let Some(any) = s.active_presses.iter().next().copied() {
533 s.active_presses.remove(&any);
534 true
535 } else {
536 false
537 }
538 } else {
539 false
540 }
541 }
542 Interaction::HoverEnter => {
543 let changed = !s.hovered;
544 s.hovered = true;
545 changed
546 }
547 Interaction::HoverLeave => {
548 let changed = s.hovered;
549 s.hovered = false;
550 if !s.active_presses.is_empty() {
552 s.active_presses.clear();
553 true
554 } else {
555 changed
556 }
557 }
558 Interaction::Focus => {
559 let changed = !s.focused;
560 s.focused = true;
561 changed
562 }
563 Interaction::Unfocus => {
564 let changed = s.focused;
565 s.focused = false;
566 changed
567 }
568 Interaction::DragStart => {
569 let changed = s.dragged == 0;
570 s.dragged = s.dragged.saturating_add(1);
571 changed
572 }
573 Interaction::DragStop | Interaction::DragCancel => {
574 let was = s.dragged;
575 s.dragged = s.dragged.saturating_sub(1);
576 was != s.dragged
577 }
578 }
579 };
580 if changed {
581 crate::frame_clock::request_frame();
583 }
584 }
585
586 pub fn source(&self) -> InteractionSource {
588 InteractionSource {
589 state: self.state.clone(),
590 }
591 }
592
593 pub fn reset(&self) {
595 let mut s = self.state.borrow_mut();
596 *s = InteractionState::default();
597 crate::frame_clock::request_frame();
598 }
599
600 pub fn reset_hover(&self) {
602 let mut s = self.state.borrow_mut();
603 if s.hovered {
604 s.hovered = false;
605 crate::frame_clock::request_frame();
606 }
607 }
608}
609
610impl Default for MutableInteractionSource {
611 fn default() -> Self {
612 Self::new()
613 }
614}
615
616#[derive(Clone, Default)]
617pub(crate) struct InteractionState {
618 active_presses: HashSet<PressId>,
620 hovered: bool,
621 focused: bool,
622 dragged: u32,
623 pub(crate) last_press_position: Option<Vec2>,
625 pub(crate) last_press_id: Option<PressId>,
627}
628
629#[derive(Clone, Default)]
630pub struct Modifier {
631 pub key: Option<u64>,
637
638 pub size: Option<DpSize>,
639 pub width: Option<Dp>,
640 pub height: Option<Dp>,
641 pub required_size: Option<DpSize>,
642 pub fill_max: Option<f32>,
643 pub fill_max_w: Option<f32>,
644 pub fill_max_h: Option<f32>,
645 pub padding: Option<Dp>,
646 pub padding_values: Option<PaddingValues>,
647 pub min_width: Option<Dp>,
648 pub min_height: Option<Dp>,
649 pub max_width: Option<Dp>,
650 pub max_height: Option<Dp>,
651 pub required_min_width: Option<Dp>,
653 pub required_max_width: Option<Dp>,
655 pub required_min_height: Option<Dp>,
657 pub required_max_height: Option<Dp>,
659 pub default_min_width: Option<Dp>,
662 pub default_min_height: Option<Dp>,
663 pub background: Option<Brush>,
664 pub state_colors: Option<StateColors>,
665 pub state_elevation: Option<StateElevation>,
666
667 pub border: Option<Border>,
668 pub flex_grow: Option<f32>,
669 pub flex_shrink: Option<f32>,
670 pub flex_basis: Option<Dp>,
671 pub flex_basis_content: bool,
674 pub flex_wrap: Option<FlexWrap>,
675 pub flex_line_count: Option<u16>,
678 pub flex_dir: Option<FlexDirection>,
679 pub gap: Option<Dp>,
680 pub row_gap: Option<Dp>,
681 pub column_gap: Option<Dp>,
682 pub align_self: Option<AlignSelf>,
683 pub justify_content: Option<JustifyContent>,
684 pub align_items_container: Option<AlignItems>,
685 pub align_content: Option<AlignContent>,
686 pub clip_rounded: Option<[Dp; 4]>,
687 pub clip_rect: Option<ClipRect>,
690 pub overflow: Option<Overflow>,
695 pub z_index: f32,
697 pub render_z_index: Option<f32>,
699 pub hit_passthrough: bool,
701 pub input_blocker: bool,
703 pub repaint_boundary: bool,
704 pub click: bool,
705 pub disabled: bool,
707 pub focusable: Option<bool>,
711 pub propagate_min: bool,
713 pub focus_group: bool,
716 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
717 pub scroll: Option<crate::scroll::ScrollBinding>,
723 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
732 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
733 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
734 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
735 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
736 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
737 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
738 pub on_click: Option<Rc<dyn Fn()>>,
740 pub on_double_click: Option<Rc<dyn Fn()>>,
742 pub on_long_click: Option<Rc<dyn Fn()>>,
744 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
747 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
750 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
753 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
756 pub blur: Option<BlurStyle>,
761 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (Dp, Dp)>>,
766 pub semantics: Option<crate::Semantics>,
767 pub alpha: Option<f32>,
768 pub graphics_layer: Option<f32>,
769 pub shadow: Option<ShadowSpec>,
770 pub transform: Option<Transform>,
771 pub grid: Option<GridConfig>,
772 pub grid_col_span: Option<u16>,
773 pub grid_row_span: Option<u16>,
774 pub position_type: Option<PositionType>,
775 pub offset_left: Option<Dp>,
776 pub offset_right: Option<Dp>,
777 pub offset_top: Option<Dp>,
778 pub offset_bottom: Option<Dp>,
779
780 pub margin_left: Option<Dp>,
781 pub margin_right: Option<Dp>,
782 pub margin_top: Option<Dp>,
783 pub margin_bottom: Option<Dp>,
784 pub aspect_ratio: Option<f32>,
785 pub intrinsic_width: Option<IntrinsicSize>,
788 pub intrinsic_height: Option<IntrinsicSize>,
791 pub fit_content_width: Option<Dp>,
794 pub fit_content_height: Option<Dp>,
797 pub baseline_align: Option<BaselineAlign>,
800 pub contain: Option<Contain>,
805 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
806 pub paint_callback: Option<crate::PaintCallbackPayload>,
807
808 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
810 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
811 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
812 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
813 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
814 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
815 pub drag_preview: Option<crate::dnd::DragPreview>,
817
818 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
819
820 pub cursor: Option<crate::CursorIcon>,
822
823 pub animate_content_size: Option<AnimationSpec>,
826
827 pub focus_requester: Option<crate::runtime::FocusRequester>,
831
832 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
835
836 pub interaction_source: Option<InteractionSource>,
843
844 pub text_input: Option<TextInputConfig>,
846
847 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
849}
850
851impl std::fmt::Debug for Modifier {
852 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
853 let mut s = f.debug_struct("Modifier");
854
855 macro_rules! opt_val {
856 ($($name:ident),+ $(,)?) => {
857 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
858 };
859 }
860 if self.indication.is_some() {
861 s.field("indication", &"…");
862 }
863
864 opt_val!(
865 key,
866 size,
867 width,
868 height,
869 required_size,
870 padding,
871 padding_values,
872 min_width,
873 min_height,
874 max_width,
875 max_height,
876 required_min_width,
877 required_max_width,
878 required_min_height,
879 required_max_height,
880 default_min_width,
881 default_min_height,
882 fill_max,
883 fill_max_w,
884 fill_max_h,
885 background,
886 state_colors,
887 state_elevation,
888 border,
889 flex_grow,
890 flex_shrink,
891 flex_basis,
892 flex_wrap,
893 flex_dir,
894 gap,
895 row_gap,
896 column_gap,
897 align_self,
898 justify_content,
899 align_items_container,
900 align_content,
901 clip_rounded,
902 clip_rect,
903 render_z_index,
904 semantics,
905 alpha,
906 transform,
907 grid,
908 grid_col_span,
909 grid_row_span,
910 position_type,
911 offset_left,
912 offset_right,
913 offset_top,
914 offset_bottom,
915 margin_left,
916 margin_right,
917 margin_top,
918 margin_bottom,
919 aspect_ratio,
920 intrinsic_width,
921 intrinsic_height,
922 cursor,
923 animate_content_size,
924 blur,
925 );
926
927 macro_rules! opt_cb {
928 ($($name:ident),+ $(,)?) => {
929 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
930 };
931 }
932 opt_cb!(
933 on_scroll,
934 scroll,
935 nested_scroll_connection,
936 on_pointer_down,
937 on_pointer_move,
938 on_pointer_up,
939 on_pointer_cancel,
940 on_pointer_enter,
941 on_pointer_leave,
942 on_click,
943 on_double_click,
944 on_long_click,
945 on_globally_positioned,
946 on_size_changed,
947 on_key_event,
948 on_preview_key_event,
949 painter,
950 paint_callback,
951 on_drag_start,
952 on_drag_end,
953 on_drag_enter,
954 on_drag_over,
955 on_drag_leave,
956 on_drop,
957 drag_preview,
958 on_action,
959 on_focus_changed,
960 interaction_source,
961 text_input,
962 layout,
963 );
964
965 macro_rules! flag {
966 ($($name:ident),+ $(,)?) => {
967 $( if self.$name { s.field(stringify!($name), &true); } )+
968 };
969 }
970 flag!(
971 hit_passthrough,
972 input_blocker,
973 repaint_boundary,
974 click,
975 disabled,
976 propagate_min,
977 focus_group,
978 );
979
980 if let Some(f) = self.focusable {
981 s.field("focusable", &f);
982 }
983 if self.z_index != 0.0 {
984 s.field("z_index", &self.z_index);
985 }
986
987 s.finish()
988 }
989}
990
991impl_option_fields!(Modifier);
992
993#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
997pub enum Alignment {
998 TopStart,
999 TopCenter,
1000 TopEnd,
1001 CenterStart,
1002 #[default]
1003 Center,
1004 CenterEnd,
1005 BottomStart,
1006 BottomCenter,
1007 BottomEnd,
1008}
1009
1010impl Alignment {
1011 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
1013 use AlignItems as AI;
1014 use JustifyContent as JC;
1015 match self {
1016 Self::TopStart => (AI::START, JC::START),
1017 Self::TopCenter => (AI::START, JC::CENTER),
1018 Self::TopEnd => (AI::START, JC::END),
1019 Self::CenterStart => (AI::CENTER, JC::START),
1020 Self::Center => (AI::CENTER, JC::CENTER),
1021 Self::CenterEnd => (AI::CENTER, JC::END),
1022 Self::BottomStart => (AI::END, JC::START),
1023 Self::BottomCenter => (AI::END, JC::CENTER),
1024 Self::BottomEnd => (AI::END, JC::END),
1025 }
1026 }
1027
1028 pub fn to_flex_safe(self) -> (AlignItems, JustifyContent) {
1033 use AlignItems as AI;
1034 use JustifyContent as JC;
1035 match self {
1036 Self::TopStart => (AI::SAFE_START, JC::SAFE_START),
1037 Self::TopCenter => (AI::SAFE_START, JC::SAFE_CENTER),
1038 Self::TopEnd => (AI::SAFE_START, JC::SAFE_END),
1039 Self::CenterStart => (AI::SAFE_CENTER, JC::SAFE_START),
1040 Self::Center => (AI::SAFE_CENTER, JC::SAFE_CENTER),
1041 Self::CenterEnd => (AI::SAFE_CENTER, JC::SAFE_END),
1042 Self::BottomStart => (AI::SAFE_END, JC::SAFE_START),
1043 Self::BottomCenter => (AI::SAFE_END, JC::SAFE_CENTER),
1044 Self::BottomEnd => (AI::SAFE_END, JC::SAFE_END),
1045 }
1046 }
1047}
1048
1049impl Modifier {
1050 pub fn new() -> Self {
1051 Self::default()
1052 }
1053
1054 pub fn key(mut self, key: u64) -> Self {
1057 self.key = Some(key);
1058 self
1059 }
1060
1061 pub fn size(mut self, w: Dp, h: Dp) -> Self {
1062 self.size = Some(DpSize::new(w, h));
1063 self
1064 }
1065 pub fn width(mut self, w: Dp) -> Self {
1066 self.width = Some(w);
1067 self
1068 }
1069 pub fn height(mut self, h: Dp) -> Self {
1070 self.height = Some(h);
1071 self
1072 }
1073 pub fn required_size(mut self, w: Dp, h: Dp) -> Self {
1078 self.required_size = Some(DpSize::new(w, h));
1079 self
1080 }
1081 pub fn required_width_in(mut self, min: Dp, max: Dp) -> Self {
1082 self.required_min_width = Some(Dp(min.0.max(0.0)));
1083 self.required_max_width = Some(Dp(max.0.max(0.0)));
1084 self
1085 }
1086 pub fn required_height_in(mut self, min: Dp, max: Dp) -> Self {
1087 self.required_min_height = Some(Dp(min.0.max(0.0)));
1088 self.required_max_height = Some(Dp(max.0.max(0.0)));
1089 self
1090 }
1091 pub fn required_min_width(mut self, w: Dp) -> Self {
1092 self.required_min_width = Some(Dp(w.0.max(0.0)));
1093 self
1094 }
1095 pub fn required_max_width(mut self, w: Dp) -> Self {
1096 self.required_max_width = Some(Dp(w.0.max(0.0)));
1097 self
1098 }
1099 pub fn required_min_height(mut self, h: Dp) -> Self {
1100 self.required_min_height = Some(Dp(h.0.max(0.0)));
1101 self
1102 }
1103 pub fn required_max_height(mut self, h: Dp) -> Self {
1104 self.required_max_height = Some(Dp(h.0.max(0.0)));
1105 self
1106 }
1107 pub fn default_min_size(mut self, w: Dp, h: Dp) -> Self {
1109 self.default_min_width = Some(Dp(w.0.max(0.0)));
1110 self.default_min_height = Some(Dp(h.0.max(0.0)));
1111 self
1112 }
1113 pub fn fill_max_size(mut self) -> Self {
1116 self.fill_max = Some(1.0);
1117 self
1118 }
1119 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
1120 self.fill_max = Some(fraction.clamp(0.0, 1.0));
1121 self
1122 }
1123 pub fn fill_max_width(mut self) -> Self {
1125 self.fill_max_w = Some(1.0);
1126 self
1127 }
1128 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
1129 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
1130 self
1131 }
1132 pub fn fill_max_height(mut self) -> Self {
1134 self.fill_max_h = Some(1.0);
1135 self
1136 }
1137 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
1138 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
1139 self
1140 }
1141 pub fn padding(mut self, v: Dp) -> Self {
1142 self.padding = Some(v);
1143 self
1144 }
1145 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
1146 self.padding_values = Some(padding);
1147 self
1148 }
1149 pub fn ime_padding(mut self) -> Self {
1153 use crate::units::Px;
1154 let insets = crate::locals::window_insets();
1155 let mut p = self.padding_values.unwrap_or_default();
1156 p.bottom = p.bottom + Px(insets.ime_bottom).to_dp();
1157 self.padding_values = Some(p);
1158 self
1159 }
1160 pub fn system_bars_padding(mut self) -> Self {
1162 use crate::units::Px;
1163 let insets = crate::locals::window_insets();
1164 let mut p = self.padding_values.unwrap_or_default();
1165 p.top = p.top + Px(insets.top).to_dp();
1166 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1167 self.padding_values = Some(p);
1168 self
1169 }
1170 pub fn status_bars_padding(mut self) -> Self {
1172 use crate::units::Px;
1173 let insets = crate::locals::window_insets();
1174 let mut p = self.padding_values.unwrap_or_default();
1175 p.top = p.top + Px(insets.top).to_dp();
1176 self.padding_values = Some(p);
1177 self
1178 }
1179 pub fn navigation_bars_padding(mut self) -> Self {
1181 let insets = crate::locals::window_insets();
1182 use crate::units::Px;
1183 let mut p = self.padding_values.unwrap_or_default();
1184 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1185 self.padding_values = Some(p);
1186 self
1187 }
1188 pub fn min_size(mut self, w: Dp, h: Dp) -> Self {
1189 self.min_width = Some(w);
1190 self.min_height = Some(h);
1191 self
1192 }
1193 pub fn max_size(mut self, w: Dp, h: Dp) -> Self {
1194 self.max_width = Some(w);
1195 self.max_height = Some(h);
1196 self
1197 }
1198 pub fn min_width(mut self, w: Dp) -> Self {
1199 self.min_width = Some(w);
1200 self
1201 }
1202 pub fn min_height(mut self, h: Dp) -> Self {
1203 self.min_height = Some(h);
1204 self
1205 }
1206 pub fn max_width(mut self, w: Dp) -> Self {
1207 self.max_width = Some(w);
1208 self
1209 }
1210 pub fn max_height(mut self, h: Dp) -> Self {
1211 self.max_height = Some(h);
1212 self
1213 }
1214 pub fn background(mut self, color: Color) -> Self {
1216 self.background = Some(Brush::Solid(color));
1217 self
1218 }
1219 pub fn background_brush(mut self, brush: Brush) -> Self {
1221 self.background = Some(brush);
1222 self
1223 }
1224 pub fn border(mut self, width: Dp, color: Color, radius: Dp) -> Self {
1225 self.border = Some(Border {
1226 width,
1227 brush: Brush::Solid(color),
1228 radius: [radius; 4],
1229 });
1230 self
1231 }
1232 pub fn border_brush(mut self, width: Dp, brush: Brush, radius: Dp) -> Self {
1235 self.border = Some(Border {
1236 width,
1237 brush,
1238 radius: [radius; 4],
1239 });
1240 self
1241 }
1242 pub fn border_radii(mut self, width: Dp, color: Color, radii: [Dp; 4]) -> Self {
1243 self.border = Some(Border {
1244 width,
1245 brush: Brush::Solid(color),
1246 radius: radii,
1247 });
1248 self
1249 }
1250 pub fn border_brush_radii(mut self, width: Dp, brush: Brush, radii: [Dp; 4]) -> Self {
1252 self.border = Some(Border {
1253 width,
1254 brush,
1255 radius: radii,
1256 });
1257 self
1258 }
1259 pub fn flex_grow(mut self, v: f32) -> Self {
1260 self.flex_grow = Some(v);
1261 self
1262 }
1263 pub fn flex_shrink(mut self, v: f32) -> Self {
1264 self.flex_shrink = Some(v);
1265 self
1266 }
1267 pub fn flex_basis(mut self, v: Dp) -> Self {
1268 self.flex_basis = Some(v);
1269 self
1270 }
1271 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1272 self.flex_wrap = Some(w);
1273 self
1274 }
1275 pub fn flex_basis_content(mut self) -> Self {
1278 self.flex_basis_content = true;
1279 self
1280 }
1281 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1282 self.flex_dir = Some(d);
1283 self
1284 }
1285 pub fn gap(mut self, v: Dp) -> Self {
1286 let v = Dp(v.0.max(0.0));
1287 self.gap = Some(v);
1288 self.row_gap = Some(v);
1289 self.column_gap = Some(v);
1290 self
1291 }
1292 pub fn row_gap(mut self, v: Dp) -> Self {
1293 self.row_gap = Some(Dp(v.0.max(0.0)));
1294 self
1295 }
1296 pub fn column_gap(mut self, v: Dp) -> Self {
1297 self.column_gap = Some(Dp(v.0.max(0.0)));
1298 self
1299 }
1300 pub fn align_self(mut self, a: AlignSelf) -> Self {
1301 self.align_self = Some(a);
1302 self
1303 }
1304 pub fn align_self_center(mut self) -> Self {
1305 self.align_self = Some(AlignSelf::CENTER);
1306 self
1307 }
1308 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1309 self.justify_content = Some(j);
1310 self
1311 }
1312 pub fn align_items(mut self, a: AlignItems) -> Self {
1313 self.align_items_container = Some(a);
1314 self
1315 }
1316 pub fn content_alignment(self, alignment: Alignment) -> Self {
1319 let (ai, jc) = alignment.to_flex();
1320 self.align_items(ai).justify_content(jc)
1321 }
1322 pub fn content_alignment_safe(self, alignment: Alignment) -> Self {
1327 let (ai, jc) = alignment.to_flex_safe();
1328 self.align_items(ai).justify_content(jc)
1329 }
1330 pub fn align_content(mut self, a: AlignContent) -> Self {
1331 self.align_content = Some(a);
1332 self
1333 }
1334 pub fn clip_rounded(mut self, radius: Dp) -> Self {
1335 self.clip_rounded = Some([radius; 4]);
1336 self
1337 }
1338 pub fn clip_rounded_radii(mut self, radii: [Dp; 4]) -> Self {
1339 self.clip_rounded = Some(radii);
1340 self
1341 }
1342 pub fn clip_rect(mut self, left: Dp, top: Dp, right: Dp, bottom: Dp, op: ClipOp) -> Self {
1345 self.clip_rect = Some(ClipRect {
1346 left,
1347 top,
1348 right,
1349 bottom,
1350 op,
1351 });
1352 self
1353 }
1354 pub fn overflow(mut self, overflow: Overflow) -> Self {
1355 self.overflow = Some(overflow);
1356 self
1357 }
1358 pub fn z_index(mut self, z: f32) -> Self {
1359 self.z_index = z;
1360 self
1361 }
1362
1363 pub fn render_z_index(mut self, z: f32) -> Self {
1366 self.render_z_index = Some(z);
1367 self
1368 }
1369
1370 pub fn input_blocker(mut self) -> Self {
1372 self.input_blocker = true;
1373 self
1374 }
1375
1376 pub fn hit_passthrough(mut self) -> Self {
1377 self.hit_passthrough = true;
1378 self
1379 }
1380 pub fn clickable(mut self) -> Self {
1381 self.click = true;
1382 if self.indication.is_none() {
1383 self.indication = crate::locals::local_indication();
1384 }
1385 self
1386 }
1387 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1390 self.click = true;
1391 self.interaction_source = Some(source.source());
1392 if self.indication.is_none() {
1393 self.indication = crate::locals::local_indication();
1394 }
1395 self
1396 }
1397 pub fn state_colors(mut self, colors: StateColors) -> Self {
1400 self.state_colors = Some(colors);
1401 self
1402 }
1403 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1405 self.state_elevation = Some(elev);
1406 self
1407 }
1408 pub fn disabled(mut self) -> Self {
1410 self.disabled = true;
1411 self
1412 }
1413 pub fn enabled(mut self, enabled: bool) -> Self {
1415 self.disabled = !enabled;
1416 self
1417 }
1418 pub fn focusable(mut self, focusable: bool) -> Self {
1423 self.focusable = Some(focusable);
1424 self
1425 }
1426 pub fn focus_group(mut self) -> Self {
1429 self.focus_group = true;
1430 self
1431 }
1432 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1443 self.interaction_source = Some(source.source());
1444 self
1445 }
1446 pub fn hoverable(
1449 mut self,
1450 on_enter: impl Fn() + 'static,
1451 on_leave: impl Fn() + 'static,
1452 ) -> Self {
1453 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1454 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1455 self
1456 }
1457 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1461 self.interaction_source = Some(source.source());
1462 self
1463 }
1464 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1467 self.propagate_min = propagate;
1468 self
1469 }
1470 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1471 self.on_scroll = Some(Rc::new(f));
1472 self
1473 }
1474 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1478 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1479 self
1480 }
1481 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1483 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1484 self
1485 }
1486 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1488 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1489 self
1490 }
1491 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1498 self.nested_scroll_connection = Some(conn);
1499 self
1500 }
1501 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1502 self.on_pointer_down = Some(Rc::new(f));
1503 self
1504 }
1505 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1506 self.on_pointer_move = Some(Rc::new(f));
1507 self
1508 }
1509 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1510 self.on_pointer_up = Some(Rc::new(f));
1511 self
1512 }
1513 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1514 self.on_pointer_cancel = Some(Rc::new(f));
1515 self
1516 }
1517
1518 pub fn draggable(self, on_drag: impl Fn(Vec2) + 'static) -> Self {
1519 let drag_pos = crate::state::remember_mutable(Vec2::default);
1520 let is_dragging = crate::state::remember_mutable(|| false);
1521 let on_drag = Rc::new(on_drag);
1522 self.on_pointer_down({
1523 let drag_pos = drag_pos.clone();
1524 let is_dragging = is_dragging.clone();
1525 move |ev| {
1526 is_dragging.set(true);
1527 drag_pos.set(ev.position);
1528 }
1529 })
1530 .on_pointer_up({
1531 let is_dragging = is_dragging.clone();
1532 move |_| is_dragging.set(false)
1533 })
1534 .on_pointer_cancel({
1535 let is_dragging = is_dragging.clone();
1536 move |_| is_dragging.set(false)
1537 })
1538 .on_pointer_move({
1539 let drag_pos = drag_pos.clone();
1540 let is_dragging = is_dragging.clone();
1541 let on_drag = on_drag.clone();
1542 move |ev| {
1543 if !*is_dragging.get() {
1544 return;
1545 }
1546 let prev = *drag_pos.get();
1547 let cur = ev.position;
1548 let delta = Vec2 {
1549 x: cur.x - prev.x,
1550 y: cur.y - prev.y,
1551 };
1552 drag_pos.set(cur);
1553 on_drag(delta);
1554 crate::frame_clock::request_frame();
1555 }
1556 })
1557 }
1558 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1559 self.on_pointer_enter = Some(Rc::new(f));
1560 self
1561 }
1562 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1563 self.on_pointer_leave = Some(Rc::new(f));
1564 self
1565 }
1566 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1567 self.on_click = Some(Rc::new(f));
1568 self.click = true;
1569 if self.semantics.is_none() {
1570 self.semantics = Some(crate::Semantics::new(crate::Role::Button));
1571 }
1572 self
1573 }
1574 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1575 self.on_double_click = Some(Rc::new(f));
1576 self.click = true;
1577 self
1578 }
1579 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1580 self.on_long_click = Some(Rc::new(f));
1581 self.click = true;
1582 self
1583 }
1584 pub fn clickable_ext(
1585 mut self,
1586 enabled: bool,
1587 on_click_label: Option<String>,
1588 role: Option<crate::semantics::Role>,
1589 on_click: impl Fn() + 'static,
1590 ) -> Self {
1591 if !enabled {
1592 let mut s = self.semantics.clone().unwrap_or_else(|| {
1593 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1594 });
1595 s.enabled = false;
1596 if let Some(r) = role {
1597 s.role = r;
1598 }
1599 if let Some(l) = on_click_label {
1600 s.label = Some(l);
1601 }
1602 return self
1603 .clickable()
1604 .enabled(false)
1605 .default_min_size(Dp(48.0), Dp(48.0))
1606 .semantics(s);
1607 }
1608 self = self.clickable().on_click(on_click);
1609 if role.is_some() || on_click_label.is_some() {
1610 let mut s = self.semantics.clone().unwrap_or_else(|| {
1611 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1612 });
1613 s.enabled = true;
1614 if let Some(r) = role {
1615 s.role = r;
1616 }
1617 if let Some(l) = on_click_label {
1618 s.label = Some(l);
1619 }
1620 self = self.semantics(s);
1621 }
1622 self.default_min_size(Dp(48.0), Dp(48.0))
1623 }
1624 pub fn combined_clickable(
1625 mut self,
1626 enabled: bool,
1627 on_click_label: Option<String>,
1628 role: Option<crate::semantics::Role>,
1629 on_long_click_label: Option<String>,
1630 on_click: impl Fn() + 'static,
1631 on_long_click: Option<impl Fn() + 'static>,
1632 on_double_click: Option<impl Fn() + 'static>,
1633 ) -> Self {
1634 let _ = on_long_click_label;
1635 if !enabled {
1636 return self.clickable_ext(false, on_click_label, role, || {});
1637 }
1638 self = self.clickable_ext(true, on_click_label, role, on_click);
1639 if let Some(f) = on_long_click {
1640 self = self.on_long_click(f);
1641 }
1642 if let Some(f) = on_double_click {
1643 self = self.on_double_click(f);
1644 }
1645 self.default_min_size(Dp(48.0), Dp(48.0))
1646 }
1647 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1648 self.semantics = Some(s);
1649 self
1650 }
1651 pub fn alpha(mut self, a: f32) -> Self {
1652 self.alpha = Some(a);
1653 self
1654 }
1655 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1660 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1661 self
1662 }
1663 pub fn shadow(mut self, blur_radius: Dp, offset_y: Dp) -> Self {
1667 self.shadow = Some(ShadowSpec {
1668 blur_radius: Dp(blur_radius.0.max(0.0)),
1669 offset_y,
1670 color: Color(0, 0, 0, 64),
1671 });
1672 self
1673 }
1674 pub fn shadow_with_color(mut self, blur_radius: Dp, offset_y: Dp, color: Color) -> Self {
1676 self.shadow = Some(ShadowSpec {
1677 blur_radius: Dp(blur_radius.0.max(0.0)),
1678 offset_y,
1679 color,
1680 });
1681 self
1682 }
1683 pub fn elevation(mut self, level: Dp) -> Self {
1687 if level.0 <= 0.0 {
1688 self.shadow = None;
1689 return self;
1690 }
1691 self.shadow = Some(ShadowSpec {
1692 blur_radius: Dp(level.0 * 2.0),
1693 offset_y: Dp(level.0 * 0.5),
1694 color: Color(0, 0, 0, (level.0 * 8.0).clamp(8.0, 80.0) as u8),
1695 });
1696 self
1697 }
1698 pub fn transform(mut self, t: Transform) -> Self {
1699 self.transform = Some(t);
1700 self
1701 }
1702 pub fn grid(mut self, columns: usize, row_gap: Dp, column_gap: Dp) -> Self {
1703 self.grid = Some(GridConfig {
1704 columns,
1705 row_gap,
1706 column_gap,
1707 });
1708 self
1709 }
1710 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1711 self.grid_col_span = Some(col_span);
1712 self.grid_row_span = Some(row_span);
1713 self
1714 }
1715 pub fn absolute(mut self) -> Self {
1724 self.position_type = Some(PositionType::Absolute);
1725 self
1726 }
1727 pub fn offset(
1732 mut self,
1733 left: Option<Dp>,
1734 top: Option<Dp>,
1735 right: Option<Dp>,
1736 bottom: Option<Dp>,
1737 ) -> Self {
1738 self.offset_left = left;
1739 self.offset_top = top;
1740 self.offset_right = right;
1741 self.offset_bottom = bottom;
1742 self
1743 }
1744 pub fn offset_left(mut self, v: Dp) -> Self {
1745 self.offset_left = Some(v);
1746 self
1747 }
1748 pub fn offset_right(mut self, v: Dp) -> Self {
1749 self.offset_right = Some(v);
1750 self
1751 }
1752 pub fn offset_top(mut self, v: Dp) -> Self {
1753 self.offset_top = Some(v);
1754 self
1755 }
1756 pub fn offset_bottom(mut self, v: Dp) -> Self {
1757 self.offset_bottom = Some(v);
1758 self
1759 }
1760 pub fn margin(mut self, v: Dp) -> Self {
1761 self.margin_left = Some(v);
1762 self.margin_right = Some(v);
1763 self.margin_top = Some(v);
1764 self.margin_bottom = Some(v);
1765 self
1766 }
1767
1768 pub fn margin_horizontal(mut self, v: Dp) -> Self {
1769 self.margin_left = Some(v);
1770 self.margin_right = Some(v);
1771 self
1772 }
1773
1774 pub fn margin_vertical(mut self, v: Dp) -> Self {
1775 self.margin_top = Some(v);
1776 self.margin_bottom = Some(v);
1777 self
1778 }
1779 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1780 self.aspect_ratio = Some(ratio);
1781 self
1782 }
1783 pub fn fit_content_width(mut self, limit: Dp) -> Self {
1785 self.fit_content_width = Some(Dp(limit.0.max(0.0)));
1786 self
1787 }
1788 pub fn fit_content_height(mut self, limit: Dp) -> Self {
1790 self.fit_content_height = Some(Dp(limit.0.max(0.0)));
1791 self
1792 }
1793 pub fn contain(mut self, c: Contain) -> Self {
1795 self.contain = Some(c);
1796 self
1797 }
1798 pub fn contain_layout(mut self) -> Self {
1800 self.contain = Some(Contain::LAYOUT);
1801 self
1802 }
1803 pub fn contain_paint(mut self) -> Self {
1805 self.contain = Some(Contain::PAINT);
1806 self
1807 }
1808 pub fn contain_content(mut self) -> Self {
1810 self.contain = Some(Contain::CONTENT);
1811 self
1812 }
1813 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1815 self.intrinsic_width = Some(mode);
1816 self
1817 }
1818 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1820 self.intrinsic_height = Some(mode);
1821 self
1822 }
1823 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1824 self.painter = Some(Rc::new(f));
1825 self
1826 }
1827 pub fn paint_callback(mut self, payload: crate::PaintCallbackPayload) -> Self {
1833 self.paint_callback = Some(payload);
1834 self
1835 }
1836 pub fn scale(self, s: f32) -> Self {
1837 self.scale2(s, s)
1838 }
1839 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1840 let mut t = self.transform.unwrap_or_else(Transform::identity);
1841 t.scale_x *= sx;
1842 t.scale_y *= sy;
1843 self.transform = Some(t);
1844 self
1845 }
1846 pub fn translate(mut self, x: f32, y: f32) -> Self {
1847 let t = self.transform.unwrap_or_else(Transform::identity);
1848 self.transform = Some(t.combine(&Transform::translate(x, y)));
1849 self
1850 }
1851 pub fn translate_vec2(self, v: Vec2) -> Self {
1852 self.translate(v.x, v.y)
1853 }
1854 pub fn rotate(mut self, radians: f32) -> Self {
1855 let mut t = self.transform.unwrap_or_else(Transform::identity);
1856 t.rotate += radians;
1857 self.transform = Some(t);
1858 self
1859 }
1860 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1861 let mut t = self.transform.unwrap_or_else(Transform::identity);
1862 t.origin_x = x;
1863 t.origin_y = y;
1864 self.transform = Some(t);
1865 self
1866 }
1867 pub fn weight(mut self, w: f32) -> Self {
1868 let w = w.max(0.0);
1869 self.flex_grow = Some(w);
1870 self.flex_shrink = Some(1.0);
1871 self.flex_basis = Some(Dp::ZERO);
1873 self
1874 }
1875 pub fn repaint_boundary(mut self) -> Self {
1879 self.repaint_boundary = true;
1880 self
1881 }
1882 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1883 self.on_action = Some(Rc::new(f));
1884 self
1885 }
1886
1887 pub fn on_drag_start(
1889 mut self,
1890 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1891 ) -> Self {
1892 self.on_drag_start = Some(Rc::new(f));
1893 self
1894 }
1895
1896 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1898 self.on_drag_end = Some(Rc::new(f));
1899 self
1900 }
1901
1902 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1904 self.on_drag_enter = Some(Rc::new(f));
1905 self
1906 }
1907
1908 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1910 self.on_drag_over = Some(Rc::new(f));
1911 self
1912 }
1913
1914 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1916 self.on_drag_leave = Some(Rc::new(f));
1917 self
1918 }
1919
1920 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1923 self.on_drop = Some(Rc::new(f));
1924 self
1925 }
1926
1927 pub fn draw_drag_decoration(
1932 mut self,
1933 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
1934 ) -> Self {
1935 self.drag_preview = Some(Rc::new(f));
1936 self
1937 }
1938
1939 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
1941 self.drag_preview = Some(preview);
1942 self
1943 }
1944
1945 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
1947 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
1948 }
1949
1950 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
1952 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
1953 }
1954
1955 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1957 self.cursor = Some(c);
1958 self
1959 }
1960
1961 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1965 self.animate_content_size = Some(spec);
1966 self
1967 }
1968
1969 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1972 self.focus_requester = Some(fr);
1973 self
1974 }
1975
1976 pub fn focus_target(mut self) -> Self {
1979 self.focusable = Some(true);
1980 self
1981 }
1982
1983 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1986 self.on_focus_changed = Some(Rc::new(f));
1987 self
1988 }
1989
1990 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
1995 self.on_globally_positioned = Some(Rc::new(f));
1996 self
1997 }
1998
1999 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
2002 self.on_size_changed = Some(Rc::new(f));
2003 self
2004 }
2005
2006 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
2010 self.on_key_event = Some(Rc::new(f));
2011 self
2012 }
2013
2014 pub fn on_preview_key_event(
2018 mut self,
2019 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
2020 ) -> Self {
2021 self.on_preview_key_event = Some(Rc::new(f));
2022 self
2023 }
2024
2025 pub fn blur(mut self, radius: Dp) -> Self {
2032 self.blur = Some(BlurStyle {
2033 radius_x: Dp(radius.0.max(0.0)),
2034 radius_y: Dp(radius.0.max(0.0)),
2035 edge_treatment: BlurredEdgeTreatment::Rectangle,
2036 });
2037 self
2038 }
2039
2040 pub fn blur_with_edge(
2045 mut self,
2046 radius_x: Dp,
2047 radius_y: Dp,
2048 edge_treatment: BlurredEdgeTreatment,
2049 ) -> Self {
2050 self.blur = Some(BlurStyle {
2051 radius_x: Dp(radius_x.0.max(0.0)),
2052 radius_y: Dp(radius_y.0.max(0.0)),
2053 edge_treatment,
2054 });
2055 self
2056 }
2057
2058 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (Dp, Dp) + 'static) -> Self {
2066 self.layout = Some(Rc::new(f));
2067 self
2068 }
2069
2070 pub fn text_input(mut self, config: TextInputConfig) -> Self {
2072 self.text_input = Some(config);
2073 self
2074 }
2075
2076 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
2080 self.indication = Some(factory);
2081 self
2082 }
2083}