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 scrollbar_style,
109 nested_scroll_connection,
110 scroll,
111 on_pointer_down, on_pointer_move, on_pointer_up,
112 on_pointer_cancel,
113 on_pointer_enter, on_pointer_leave,
114 on_click, on_double_click, on_long_click,
115 on_globally_positioned, on_size_changed,
116 on_key_event, on_preview_key_event,
117 semantics, alpha, transform,
118 grid, grid_col_span, grid_row_span,
119 position_type,
120 offset_left, offset_right, offset_top, offset_bottom,
121 margin_left, margin_right, margin_top, margin_bottom,
122 aspect_ratio, intrinsic_width, intrinsic_height,
123 fit_content_width, fit_content_height,
124 contain,
125 painter,
126 paint_callback,
127 layout,
128 blur, graphics_layer, shadow,
129 on_drag_start, on_drag_end, on_drag_enter, on_drag_over, on_drag_leave, on_drop,
130 drag_preview,
131 on_action, cursor, animate_content_size, focus_requester, on_focus_changed,
132 interaction_source, text_input, text_selection,
133 );
134 merge_flags!(self, other;
135 hit_passthrough, input_blocker, repaint_boundary, click, disabled,
136 propagate_min, focus_group,
137 );
138
139 self.flex_basis_content |= other.flex_basis_content;
141
142 if let Some(f) = other.focusable {
143 self.focusable = Some(f);
144 }
145 if other.indication.is_some() {
146 self.indication = other.indication;
147 }
148 self.z_index = other.z_index;
150 self
151 }
152 }
153 };
154}
155
156#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
157pub enum ClipOp {
158 #[default]
160 Intersect,
161 Difference,
163}
164
165#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
171pub enum Overflow {
172 #[default]
173 Clip,
174 Visible,
175}
176
177#[derive(Clone, Copy, Debug)]
180pub struct ClipRect {
181 pub left: Dp,
182 pub top: Dp,
183 pub right: Dp,
184 pub bottom: Dp,
185 pub op: ClipOp,
186}
187
188#[derive(Clone, Debug)]
189pub struct Border {
190 pub width: Dp,
191 pub brush: Brush,
193 pub radius: [Dp; 4],
194}
195
196#[derive(Clone, Copy, Debug, Default)]
197pub struct PaddingValues {
198 pub left: Dp,
199 pub right: Dp,
200 pub top: Dp,
201 pub bottom: Dp,
202}
203
204#[derive(Clone, Debug)]
205pub struct GridConfig {
206 pub columns: usize,
207 pub row_gap: Dp,
208 pub column_gap: Dp,
209}
210
211#[derive(Clone, Copy, Debug, PartialEq)]
214pub enum BlurredEdgeTreatment {
215 Rectangle,
218 Unbounded,
221}
222
223#[derive(Clone, Copy, Debug)]
225pub struct BlurStyle {
226 pub radius_x: Dp,
228 pub radius_y: Dp,
230 pub edge_treatment: BlurredEdgeTreatment,
232}
233
234#[derive(Clone, Copy, Debug)]
240pub struct LayoutConstraints {
241 pub min_width: Dp,
242 pub max_width: Dp,
243 pub min_height: Dp,
244 pub max_height: Dp,
245}
246
247#[derive(Clone, Copy, Debug)]
254pub struct ShadowSpec {
255 pub blur_radius: Dp,
256 pub offset_y: Dp,
257 pub color: Color,
258}
259
260#[derive(Clone, Copy, Debug)]
261#[non_exhaustive]
262pub enum PositionType {
263 Relative,
264 Absolute,
265}
266
267#[derive(Clone)]
269pub struct TextInputConfig {
270 pub hint: String,
271 pub multiline: bool,
272 pub on_change: Option<Rc<dyn Fn(String)>>,
273 pub on_submit: Option<Rc<dyn Fn(String)>>,
274 pub focus_tracker: Option<Rc<Cell<bool>>>,
275 pub value: String,
276 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
277 pub keyboard_type: crate::text::KeyboardType,
278 pub capitalization: crate::text::KeyboardCapitalization,
279 pub ime_action: crate::text::ImeAction,
280 pub auto_correct_enabled: Option<bool>,
283 pub enabled: bool,
285 pub read_only: bool,
287 pub sensitive: bool,
288 pub max_lines: Option<usize>,
290 pub min_lines: usize,
292 pub cursor_color: Option<Color>,
294 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
297 pub text_style: Option<crate::text::TextStyle>,
300 pub keyboard_actions: Option<crate::text::KeyboardActions>,
303 pub interaction_source: Option<InteractionSource>,
305 pub line_limits: Option<crate::text::TextFieldLineLimits>,
307}
308
309impl Default for TextInputConfig {
310 fn default() -> Self {
311 Self {
312 hint: String::new(),
313 multiline: false,
314 on_change: None,
315 on_submit: None,
316 focus_tracker: None,
317 value: String::new(),
318 visual_transformation: None,
319 keyboard_type: crate::text::KeyboardType::default(),
320 capitalization: crate::text::KeyboardCapitalization::default(),
321 ime_action: crate::text::ImeAction::default(),
322 auto_correct_enabled: None,
323 enabled: true,
324 read_only: false,
325 sensitive: false,
326 max_lines: None,
327 min_lines: 1,
328 cursor_color: None,
329 on_text_layout: None,
330 text_style: None,
331 keyboard_actions: None,
332 interaction_source: None,
333 line_limits: None,
334 }
335 }
336}
337
338impl std::fmt::Debug for TextInputConfig {
339 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
340 let mut s = f.debug_struct("TextInputConfig");
341 s.field("hint", &self.hint);
342 s.field("multiline", &self.multiline);
343 if self.on_change.is_some() {
344 s.field("on_change", &"…");
345 }
346 if self.on_submit.is_some() {
347 s.field("on_submit", &"…");
348 }
349 if self.focus_tracker.is_some() {
350 s.field("focus_tracker", &"…");
351 }
352 s.field("value", &self.value);
353 if self.visual_transformation.is_some() {
354 s.field("visual_transformation", &"…");
355 }
356 s.field("keyboard_type", &self.keyboard_type);
357 s.field("capitalization", &self.capitalization);
358 s.field("ime_action", &self.ime_action);
359 s.field("auto_correct_enabled", &self.auto_correct_enabled);
360 s.field("enabled", &self.enabled);
361 s.field("read_only", &self.read_only);
362 s.field("sensitive", &self.sensitive);
363 s.field("max_lines", &self.max_lines);
364 s.field("min_lines", &self.min_lines);
365 s.field("cursor_color", &self.cursor_color);
366 if self.on_text_layout.is_some() {
367 s.field("on_text_layout", &"…");
368 }
369 s.finish()
370 }
371}
372
373#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
376pub enum IntrinsicSize {
377 Min,
378 Max,
379}
380
381#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
389pub enum BaselineAlign {
390 FirstBaseline,
391 LastBaseline,
392}
393
394static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
395
396thread_local! {
397 static INTERACTION_EPOCH: Cell<u64> = const { Cell::new(0) };
398}
399
400pub type PressId = u64;
402
403#[derive(Clone, Copy, Debug, PartialEq)]
411pub enum Interaction {
412 Press(PressId, Vec2),
415 Release(PressId),
417 Cancel(PressId),
420 HoverEnter,
421 HoverLeave,
422 Focus,
423 Unfocus,
424 DragStart,
425 DragStop,
426 DragCancel,
427}
428
429impl Interaction {
430 #[inline]
432 pub fn new_press(position: Vec2) -> Self {
433 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
434 }
435}
436
437#[derive(Clone)]
444pub struct InteractionSource {
445 pub(crate) state: Rc<RefCell<InteractionState>>,
446}
447
448impl InteractionSource {
449 pub fn collect_is_pressed(&self) -> bool {
450 !self.state.borrow().active_presses.is_empty()
451 }
452 pub fn collect_is_hovered(&self) -> bool {
453 self.state.borrow().hovered
454 }
455 pub fn collect_is_focused(&self) -> bool {
456 self.state.borrow().focused
457 }
458
459 pub fn collect_is_focus_visible(&self) -> bool {
461 crate::input::is_focus_visible(self.collect_is_focused())
462 }
463
464 pub fn collect_is_dragged(&self) -> bool {
465 self.state.borrow().dragged > 0
466 }
467 pub fn collect_last_press_position(&self) -> Option<Vec2> {
468 self.state.borrow().last_press_position
469 }
470 pub fn collect_last_press_id(&self) -> Option<PressId> {
471 self.state.borrow().last_press_id
472 }
473 pub fn stable_id(&self) -> *const () {
475 Rc::as_ptr(&self.state) as *const ()
476 }
477 pub fn to_mutable(&self) -> MutableInteractionSource {
481 MutableInteractionSource {
482 state: self.state.clone(),
483 }
484 }
485
486 pub fn reset(&self) {
488 self.to_mutable().reset();
489 }
490
491 pub fn reset_hover(&self) {
493 self.to_mutable().reset_hover();
494 }
495}
496
497pub fn interaction_epoch() -> u64 {
498 INTERACTION_EPOCH.with(Cell::get)
499}
500
501fn bump_interaction_epoch() {
502 INTERACTION_EPOCH.with(|epoch| epoch.set(epoch.get().wrapping_add(1)));
503}
504
505#[derive(Clone)]
515pub struct MutableInteractionSource {
516 pub(crate) state: Rc<RefCell<InteractionState>>,
517}
518
519impl std::fmt::Debug for MutableInteractionSource {
520 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
521 f.debug_struct("MutableInteractionSource")
522 .finish_non_exhaustive()
523 }
524}
525
526impl MutableInteractionSource {
527 pub fn new() -> Self {
528 Self {
529 state: Rc::new(RefCell::new(InteractionState::default())),
530 }
531 }
532
533 pub fn emit(&self, interaction: Interaction) {
535 let changed = {
536 let mut s = self.state.borrow_mut();
537 let changed = match interaction {
538 Interaction::Press(id, pos) => {
539 let inserted = s.active_presses.insert(id);
540 s.last_press_id = Some(id);
541 s.last_press_position = Some(pos);
542 inserted
543 }
544 Interaction::Release(id) | Interaction::Cancel(id) => {
545 if s.active_presses.remove(&id) {
546 true
547 } else if id == 0 {
548 if let Some(any) = s.active_presses.iter().next().copied() {
549 s.active_presses.remove(&any);
550 true
551 } else {
552 false
553 }
554 } else {
555 false
556 }
557 }
558 Interaction::HoverEnter => {
559 let changed = !s.hovered;
560 s.hovered = true;
561 changed
562 }
563 Interaction::HoverLeave => {
564 let changed = s.hovered;
565 s.hovered = false;
566 if !s.active_presses.is_empty() {
568 s.active_presses.clear();
569 true
570 } else {
571 changed
572 }
573 }
574 Interaction::Focus => {
575 let changed = !s.focused;
576 s.focused = true;
577 changed
578 }
579 Interaction::Unfocus => {
580 let changed = s.focused;
581 s.focused = false;
582 changed
583 }
584 Interaction::DragStart => {
585 let changed = s.dragged == 0;
586 s.dragged = s.dragged.saturating_add(1);
587 changed
588 }
589 Interaction::DragStop | Interaction::DragCancel => {
590 let was = s.dragged;
591 s.dragged = s.dragged.saturating_sub(1);
592 was != s.dragged
593 }
594 };
595 if changed {
596 bump_interaction_epoch();
597 }
598 changed
599 };
600 if changed {
601 crate::frame_clock::request_frame();
603 }
604 }
605
606 pub fn source(&self) -> InteractionSource {
608 InteractionSource {
609 state: self.state.clone(),
610 }
611 }
612
613 pub fn reset(&self) {
615 let mut s = self.state.borrow_mut();
616 *s = InteractionState::default();
617 drop(s);
618 bump_interaction_epoch();
619 crate::frame_clock::request_frame();
620 }
621
622 pub fn reset_hover(&self) {
624 let mut s = self.state.borrow_mut();
625 if s.hovered {
626 s.hovered = false;
627 drop(s);
628 bump_interaction_epoch();
629 crate::frame_clock::request_frame();
630 }
631 }
632}
633
634impl Default for MutableInteractionSource {
635 fn default() -> Self {
636 Self::new()
637 }
638}
639
640#[derive(Clone, Default)]
641pub(crate) struct InteractionState {
642 active_presses: HashSet<PressId>,
644 hovered: bool,
645 focused: bool,
646 dragged: u32,
647 pub(crate) last_press_position: Option<Vec2>,
649 pub(crate) last_press_id: Option<PressId>,
651}
652
653#[derive(Clone, Default)]
654pub struct Modifier {
655 pub key: Option<u64>,
661
662 pub size: Option<DpSize>,
663 pub width: Option<Dp>,
664 pub height: Option<Dp>,
665 pub required_size: Option<DpSize>,
666 pub fill_max: Option<f32>,
667 pub fill_max_w: Option<f32>,
668 pub fill_max_h: Option<f32>,
669 pub padding: Option<Dp>,
670 pub padding_values: Option<PaddingValues>,
671 pub min_width: Option<Dp>,
672 pub min_height: Option<Dp>,
673 pub max_width: Option<Dp>,
674 pub max_height: Option<Dp>,
675 pub required_min_width: Option<Dp>,
677 pub required_max_width: Option<Dp>,
679 pub required_min_height: Option<Dp>,
681 pub required_max_height: Option<Dp>,
683 pub default_min_width: Option<Dp>,
686 pub default_min_height: Option<Dp>,
687 pub background: Option<Brush>,
688 pub state_colors: Option<StateColors>,
689 pub state_elevation: Option<StateElevation>,
690
691 pub border: Option<Border>,
692 pub flex_grow: Option<f32>,
693 pub flex_shrink: Option<f32>,
694 pub flex_basis: Option<Dp>,
695 pub flex_basis_content: bool,
698 pub flex_wrap: Option<FlexWrap>,
699 pub flex_line_count: Option<u16>,
702 pub flex_dir: Option<FlexDirection>,
703 pub gap: Option<Dp>,
704 pub row_gap: Option<Dp>,
705 pub column_gap: Option<Dp>,
706 pub align_self: Option<AlignSelf>,
707 pub justify_content: Option<JustifyContent>,
708 pub align_items_container: Option<AlignItems>,
709 pub align_content: Option<AlignContent>,
710 pub clip_rounded: Option<[Dp; 4]>,
711 pub clip_rect: Option<ClipRect>,
714 pub overflow: Option<Overflow>,
719 pub z_index: f32,
721 pub render_z_index: Option<f32>,
723 pub hit_passthrough: bool,
725 pub input_blocker: bool,
727 pub repaint_boundary: bool,
728 pub click: bool,
729 pub disabled: bool,
731 pub focusable: Option<bool>,
735 pub propagate_min: bool,
737 pub focus_group: bool,
740 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
741 pub scroll: Option<crate::scroll::ScrollBinding>,
747 pub scrollbar_style: Option<crate::scroll::ScrollbarStyle>,
748 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
757 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
758 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
759 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
760 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
761 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
762 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
763 pub on_click: Option<Rc<dyn Fn()>>,
765 pub on_double_click: Option<Rc<dyn Fn()>>,
767 pub on_long_click: Option<Rc<dyn Fn()>>,
769 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
772 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
775 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
778 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
781 pub blur: Option<BlurStyle>,
786 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (Dp, Dp)>>,
791 pub semantics: Option<crate::Semantics>,
792 pub alpha: Option<f32>,
793 pub graphics_layer: Option<f32>,
794 pub shadow: Option<ShadowSpec>,
795 pub transform: Option<Transform>,
796 pub grid: Option<GridConfig>,
797 pub grid_col_span: Option<u16>,
798 pub grid_row_span: Option<u16>,
799 pub position_type: Option<PositionType>,
800 pub offset_left: Option<Dp>,
801 pub offset_right: Option<Dp>,
802 pub offset_top: Option<Dp>,
803 pub offset_bottom: Option<Dp>,
804
805 pub margin_left: Option<Dp>,
806 pub margin_right: Option<Dp>,
807 pub margin_top: Option<Dp>,
808 pub margin_bottom: Option<Dp>,
809 pub aspect_ratio: Option<f32>,
810 pub intrinsic_width: Option<IntrinsicSize>,
813 pub intrinsic_height: Option<IntrinsicSize>,
816 pub fit_content_width: Option<Dp>,
819 pub fit_content_height: Option<Dp>,
822 pub baseline_align: Option<BaselineAlign>,
825 pub contain: Option<Contain>,
830 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
831 pub paint_callback: Option<crate::PaintCallbackPayload>,
832
833 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
835 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
836 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
837 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
838 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
839 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
840 pub drag_preview: Option<crate::dnd::DragPreview>,
842
843 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
844
845 pub cursor: Option<crate::CursorIcon>,
847
848 pub animate_content_size: Option<AnimationSpec>,
851
852 pub focus_requester: Option<crate::runtime::FocusRequester>,
856
857 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
860
861 pub interaction_source: Option<InteractionSource>,
868
869 pub text_input: Option<TextInputConfig>,
871
872 pub text_selection: Option<crate::text::TextSelection>,
875
876 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
878}
879
880impl std::fmt::Debug for Modifier {
881 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
882 let mut s = f.debug_struct("Modifier");
883
884 macro_rules! opt_val {
885 ($($name:ident),+ $(,)?) => {
886 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
887 };
888 }
889 if self.indication.is_some() {
890 s.field("indication", &"…");
891 }
892 s.field("scrollbar_style", &self.scrollbar_style);
893
894 opt_val!(
895 key,
896 size,
897 width,
898 height,
899 required_size,
900 padding,
901 padding_values,
902 min_width,
903 min_height,
904 max_width,
905 max_height,
906 required_min_width,
907 required_max_width,
908 required_min_height,
909 required_max_height,
910 default_min_width,
911 default_min_height,
912 fill_max,
913 fill_max_w,
914 fill_max_h,
915 background,
916 state_colors,
917 state_elevation,
918 border,
919 flex_grow,
920 flex_shrink,
921 flex_basis,
922 flex_wrap,
923 flex_dir,
924 gap,
925 row_gap,
926 column_gap,
927 align_self,
928 justify_content,
929 align_items_container,
930 align_content,
931 clip_rounded,
932 clip_rect,
933 render_z_index,
934 semantics,
935 alpha,
936 transform,
937 grid,
938 grid_col_span,
939 grid_row_span,
940 position_type,
941 offset_left,
942 offset_right,
943 offset_top,
944 offset_bottom,
945 margin_left,
946 margin_right,
947 margin_top,
948 margin_bottom,
949 aspect_ratio,
950 intrinsic_width,
951 intrinsic_height,
952 cursor,
953 animate_content_size,
954 blur,
955 );
956
957 macro_rules! opt_cb {
958 ($($name:ident),+ $(,)?) => {
959 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
960 };
961 }
962 opt_cb!(
963 on_scroll,
964 scroll,
965 nested_scroll_connection,
966 on_pointer_down,
967 on_pointer_move,
968 on_pointer_up,
969 on_pointer_cancel,
970 on_pointer_enter,
971 on_pointer_leave,
972 on_click,
973 on_double_click,
974 on_long_click,
975 on_globally_positioned,
976 on_size_changed,
977 on_key_event,
978 on_preview_key_event,
979 painter,
980 paint_callback,
981 on_drag_start,
982 on_drag_end,
983 on_drag_enter,
984 on_drag_over,
985 on_drag_leave,
986 on_drop,
987 drag_preview,
988 on_action,
989 on_focus_changed,
990 interaction_source,
991 text_input,
992 text_selection,
993 layout,
994 );
995
996 macro_rules! flag {
997 ($($name:ident),+ $(,)?) => {
998 $( if self.$name { s.field(stringify!($name), &true); } )+
999 };
1000 }
1001 flag!(
1002 hit_passthrough,
1003 input_blocker,
1004 repaint_boundary,
1005 click,
1006 disabled,
1007 propagate_min,
1008 focus_group,
1009 );
1010
1011 if let Some(f) = self.focusable {
1012 s.field("focusable", &f);
1013 }
1014 if self.z_index != 0.0 {
1015 s.field("z_index", &self.z_index);
1016 }
1017
1018 s.finish()
1019 }
1020}
1021
1022impl_option_fields!(Modifier);
1023
1024#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1028pub enum Alignment {
1029 TopStart,
1030 TopCenter,
1031 TopEnd,
1032 CenterStart,
1033 #[default]
1034 Center,
1035 CenterEnd,
1036 BottomStart,
1037 BottomCenter,
1038 BottomEnd,
1039}
1040
1041impl Alignment {
1042 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
1044 use AlignItems as AI;
1045 use JustifyContent as JC;
1046 match self {
1047 Self::TopStart => (AI::START, JC::START),
1048 Self::TopCenter => (AI::START, JC::CENTER),
1049 Self::TopEnd => (AI::START, JC::END),
1050 Self::CenterStart => (AI::CENTER, JC::START),
1051 Self::Center => (AI::CENTER, JC::CENTER),
1052 Self::CenterEnd => (AI::CENTER, JC::END),
1053 Self::BottomStart => (AI::END, JC::START),
1054 Self::BottomCenter => (AI::END, JC::CENTER),
1055 Self::BottomEnd => (AI::END, JC::END),
1056 }
1057 }
1058
1059 pub fn to_flex_safe(self) -> (AlignItems, JustifyContent) {
1064 use AlignItems as AI;
1065 use JustifyContent as JC;
1066 match self {
1067 Self::TopStart => (AI::SAFE_START, JC::SAFE_START),
1068 Self::TopCenter => (AI::SAFE_START, JC::SAFE_CENTER),
1069 Self::TopEnd => (AI::SAFE_START, JC::SAFE_END),
1070 Self::CenterStart => (AI::SAFE_CENTER, JC::SAFE_START),
1071 Self::Center => (AI::SAFE_CENTER, JC::SAFE_CENTER),
1072 Self::CenterEnd => (AI::SAFE_CENTER, JC::SAFE_END),
1073 Self::BottomStart => (AI::SAFE_END, JC::SAFE_START),
1074 Self::BottomCenter => (AI::SAFE_END, JC::SAFE_CENTER),
1075 Self::BottomEnd => (AI::SAFE_END, JC::SAFE_END),
1076 }
1077 }
1078}
1079
1080impl Modifier {
1081 pub fn new() -> Self {
1082 Self::default()
1083 }
1084
1085 pub fn key(mut self, key: u64) -> Self {
1088 self.key = Some(key);
1089 self
1090 }
1091
1092 pub fn size(mut self, w: Dp, h: Dp) -> Self {
1093 self.size = Some(DpSize::new(w, h));
1094 self
1095 }
1096 pub fn width(mut self, w: Dp) -> Self {
1097 self.width = Some(w);
1098 self
1099 }
1100 pub fn height(mut self, h: Dp) -> Self {
1101 self.height = Some(h);
1102 self
1103 }
1104 pub fn required_size(mut self, w: Dp, h: Dp) -> Self {
1109 self.required_size = Some(DpSize::new(w, h));
1110 self
1111 }
1112 pub fn required_width_in(mut self, min: Dp, max: Dp) -> Self {
1113 self.required_min_width = Some(Dp(min.0.max(0.0)));
1114 self.required_max_width = Some(Dp(max.0.max(0.0)));
1115 self
1116 }
1117 pub fn required_height_in(mut self, min: Dp, max: Dp) -> Self {
1118 self.required_min_height = Some(Dp(min.0.max(0.0)));
1119 self.required_max_height = Some(Dp(max.0.max(0.0)));
1120 self
1121 }
1122 pub fn required_min_width(mut self, w: Dp) -> Self {
1123 self.required_min_width = Some(Dp(w.0.max(0.0)));
1124 self
1125 }
1126 pub fn required_max_width(mut self, w: Dp) -> Self {
1127 self.required_max_width = Some(Dp(w.0.max(0.0)));
1128 self
1129 }
1130 pub fn required_min_height(mut self, h: Dp) -> Self {
1131 self.required_min_height = Some(Dp(h.0.max(0.0)));
1132 self
1133 }
1134 pub fn required_max_height(mut self, h: Dp) -> Self {
1135 self.required_max_height = Some(Dp(h.0.max(0.0)));
1136 self
1137 }
1138 pub fn default_min_size(mut self, w: Dp, h: Dp) -> Self {
1140 self.default_min_width = Some(Dp(w.0.max(0.0)));
1141 self.default_min_height = Some(Dp(h.0.max(0.0)));
1142 self
1143 }
1144 pub fn fill_max_size(mut self) -> Self {
1147 self.fill_max = Some(1.0);
1148 self
1149 }
1150 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
1151 self.fill_max = Some(fraction.clamp(0.0, 1.0));
1152 self
1153 }
1154 pub fn fill_max_width(mut self) -> Self {
1156 self.fill_max_w = Some(1.0);
1157 self
1158 }
1159 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
1160 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
1161 self
1162 }
1163 pub fn fill_max_height(mut self) -> Self {
1165 self.fill_max_h = Some(1.0);
1166 self
1167 }
1168 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
1169 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
1170 self
1171 }
1172 pub fn padding(mut self, v: Dp) -> Self {
1173 self.padding = Some(v);
1174 self
1175 }
1176 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
1177 self.padding_values = Some(padding);
1178 self
1179 }
1180 pub fn ime_padding(mut self) -> Self {
1184 use crate::units::Px;
1185 let insets = crate::locals::window_insets();
1186 let mut p = self.padding_values.unwrap_or_default();
1187 p.bottom = p.bottom + Px(insets.ime_bottom).to_dp();
1188 self.padding_values = Some(p);
1189 self
1190 }
1191 pub fn system_bars_padding(mut self) -> Self {
1193 use crate::units::Px;
1194 let insets = crate::locals::window_insets();
1195 let mut p = self.padding_values.unwrap_or_default();
1196 p.top = p.top + Px(insets.top).to_dp();
1197 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1198 self.padding_values = Some(p);
1199 self
1200 }
1201 pub fn status_bars_padding(mut self) -> Self {
1203 use crate::units::Px;
1204 let insets = crate::locals::window_insets();
1205 let mut p = self.padding_values.unwrap_or_default();
1206 p.top = p.top + Px(insets.top).to_dp();
1207 self.padding_values = Some(p);
1208 self
1209 }
1210 pub fn navigation_bars_padding(mut self) -> Self {
1212 let insets = crate::locals::window_insets();
1213 use crate::units::Px;
1214 let mut p = self.padding_values.unwrap_or_default();
1215 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1216 self.padding_values = Some(p);
1217 self
1218 }
1219 pub fn min_size(mut self, w: Dp, h: Dp) -> Self {
1220 self.min_width = Some(w);
1221 self.min_height = Some(h);
1222 self
1223 }
1224 pub fn max_size(mut self, w: Dp, h: Dp) -> Self {
1225 self.max_width = Some(w);
1226 self.max_height = Some(h);
1227 self
1228 }
1229 pub fn min_width(mut self, w: Dp) -> Self {
1230 self.min_width = Some(w);
1231 self
1232 }
1233 pub fn min_height(mut self, h: Dp) -> Self {
1234 self.min_height = Some(h);
1235 self
1236 }
1237 pub fn max_width(mut self, w: Dp) -> Self {
1238 self.max_width = Some(w);
1239 self
1240 }
1241 pub fn max_height(mut self, h: Dp) -> Self {
1242 self.max_height = Some(h);
1243 self
1244 }
1245 pub fn background(mut self, color: Color) -> Self {
1247 self.background = Some(Brush::Solid(color));
1248 self
1249 }
1250 pub fn background_brush(mut self, brush: Brush) -> Self {
1252 self.background = Some(brush);
1253 self
1254 }
1255 pub fn border(mut self, width: Dp, color: Color, radius: Dp) -> Self {
1256 self.border = Some(Border {
1257 width,
1258 brush: Brush::Solid(color),
1259 radius: [radius; 4],
1260 });
1261 self
1262 }
1263 pub fn border_brush(mut self, width: Dp, brush: Brush, radius: Dp) -> Self {
1266 self.border = Some(Border {
1267 width,
1268 brush,
1269 radius: [radius; 4],
1270 });
1271 self
1272 }
1273 pub fn border_radii(mut self, width: Dp, color: Color, radii: [Dp; 4]) -> Self {
1274 self.border = Some(Border {
1275 width,
1276 brush: Brush::Solid(color),
1277 radius: radii,
1278 });
1279 self
1280 }
1281 pub fn border_brush_radii(mut self, width: Dp, brush: Brush, radii: [Dp; 4]) -> Self {
1283 self.border = Some(Border {
1284 width,
1285 brush,
1286 radius: radii,
1287 });
1288 self
1289 }
1290 pub fn flex_grow(mut self, v: f32) -> Self {
1291 self.flex_grow = Some(v);
1292 self
1293 }
1294 pub fn flex_shrink(mut self, v: f32) -> Self {
1295 self.flex_shrink = Some(v);
1296 self
1297 }
1298 pub fn flex_basis(mut self, v: Dp) -> Self {
1299 self.flex_basis = Some(v);
1300 self
1301 }
1302 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1303 self.flex_wrap = Some(w);
1304 self
1305 }
1306 pub fn flex_basis_content(mut self) -> Self {
1309 self.flex_basis_content = true;
1310 self
1311 }
1312 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1313 self.flex_dir = Some(d);
1314 self
1315 }
1316 pub fn gap(mut self, v: Dp) -> Self {
1317 let v = Dp(v.0.max(0.0));
1318 self.gap = Some(v);
1319 self.row_gap = Some(v);
1320 self.column_gap = Some(v);
1321 self
1322 }
1323 pub fn row_gap(mut self, v: Dp) -> Self {
1324 self.row_gap = Some(Dp(v.0.max(0.0)));
1325 self
1326 }
1327 pub fn column_gap(mut self, v: Dp) -> Self {
1328 self.column_gap = Some(Dp(v.0.max(0.0)));
1329 self
1330 }
1331 pub fn align_self(mut self, a: AlignSelf) -> Self {
1332 self.align_self = Some(a);
1333 self
1334 }
1335 pub fn align_self_center(mut self) -> Self {
1336 self.align_self = Some(AlignSelf::CENTER);
1337 self
1338 }
1339 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1340 self.justify_content = Some(j);
1341 self
1342 }
1343 pub fn align_items(mut self, a: AlignItems) -> Self {
1344 self.align_items_container = Some(a);
1345 self
1346 }
1347 pub fn content_alignment(self, alignment: Alignment) -> Self {
1350 let (ai, jc) = alignment.to_flex();
1351 self.align_items(ai).justify_content(jc)
1352 }
1353 pub fn content_alignment_safe(self, alignment: Alignment) -> Self {
1358 let (ai, jc) = alignment.to_flex_safe();
1359 self.align_items(ai).justify_content(jc)
1360 }
1361 pub fn align_content(mut self, a: AlignContent) -> Self {
1362 self.align_content = Some(a);
1363 self
1364 }
1365 pub fn clip_rounded(mut self, radius: Dp) -> Self {
1366 self.clip_rounded = Some([radius; 4]);
1367 self
1368 }
1369 pub fn clip_rounded_radii(mut self, radii: [Dp; 4]) -> Self {
1370 self.clip_rounded = Some(radii);
1371 self
1372 }
1373 pub fn clip_rect(mut self, left: Dp, top: Dp, right: Dp, bottom: Dp, op: ClipOp) -> Self {
1376 self.clip_rect = Some(ClipRect {
1377 left,
1378 top,
1379 right,
1380 bottom,
1381 op,
1382 });
1383 self
1384 }
1385 pub fn overflow(mut self, overflow: Overflow) -> Self {
1386 self.overflow = Some(overflow);
1387 self
1388 }
1389 pub fn z_index(mut self, z: f32) -> Self {
1390 self.z_index = z;
1391 self
1392 }
1393
1394 pub fn render_z_index(mut self, z: f32) -> Self {
1397 self.render_z_index = Some(z);
1398 self
1399 }
1400
1401 pub fn input_blocker(mut self) -> Self {
1403 self.input_blocker = true;
1404 self
1405 }
1406
1407 pub fn hit_passthrough(mut self) -> Self {
1408 self.hit_passthrough = true;
1409 self
1410 }
1411 pub fn clickable(mut self) -> Self {
1412 self.click = true;
1413 if self.indication.is_none() {
1414 self.indication = crate::locals::local_indication();
1415 }
1416 self
1417 }
1418 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1421 self.click = true;
1422 self.interaction_source = Some(source.source());
1423 if self.indication.is_none() {
1424 self.indication = crate::locals::local_indication();
1425 }
1426 self
1427 }
1428 pub fn state_colors(mut self, colors: StateColors) -> Self {
1431 self.state_colors = Some(colors);
1432 self
1433 }
1434 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1436 self.state_elevation = Some(elev);
1437 self
1438 }
1439 pub fn disabled(mut self) -> Self {
1441 self.disabled = true;
1442 self
1443 }
1444 pub fn enabled(mut self, enabled: bool) -> Self {
1446 self.disabled = !enabled;
1447 self
1448 }
1449 pub fn focusable(mut self, focusable: bool) -> Self {
1454 self.focusable = Some(focusable);
1455 self
1456 }
1457 pub fn focus_group(mut self) -> Self {
1460 self.focus_group = true;
1461 self
1462 }
1463 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1474 self.interaction_source = Some(source.source());
1475 self
1476 }
1477 pub fn hoverable(
1480 mut self,
1481 on_enter: impl Fn() + 'static,
1482 on_leave: impl Fn() + 'static,
1483 ) -> Self {
1484 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1485 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1486 self
1487 }
1488 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1492 self.interaction_source = Some(source.source());
1493 self
1494 }
1495 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1498 self.propagate_min = propagate;
1499 self
1500 }
1501 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1502 self.on_scroll = Some(Rc::new(f));
1503 self
1504 }
1505 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1509 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1510 self
1511 }
1512 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1514 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1515 self
1516 }
1517 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1519 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1520 self
1521 }
1522 pub fn scrollbar_style(mut self, style: crate::scroll::ScrollbarStyle) -> Self {
1523 self.scrollbar_style = Some(style);
1524 self
1525 }
1526 pub fn scrollbar_style_or_default(&self) -> crate::scroll::ScrollbarStyle {
1527 self.scrollbar_style.clone().unwrap_or_default()
1528 }
1529 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1536 self.nested_scroll_connection = Some(conn);
1537 self
1538 }
1539 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1540 self.on_pointer_down = Some(Rc::new(f));
1541 self
1542 }
1543 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1544 self.on_pointer_move = Some(Rc::new(f));
1545 self
1546 }
1547 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1548 self.on_pointer_up = Some(Rc::new(f));
1549 self
1550 }
1551 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1552 self.on_pointer_cancel = Some(Rc::new(f));
1553 self
1554 }
1555
1556 pub fn draggable(self, on_drag: impl Fn(Vec2) + 'static) -> Self {
1557 let drag_pos = crate::state::remember_mutable(Vec2::default);
1558 let is_dragging = crate::state::remember_mutable(|| false);
1559 let on_drag = Rc::new(on_drag);
1560 self.on_pointer_down({
1561 let drag_pos = drag_pos.clone();
1562 let is_dragging = is_dragging.clone();
1563 move |ev| {
1564 is_dragging.set(true);
1565 drag_pos.set(ev.position);
1566 }
1567 })
1568 .on_pointer_up({
1569 let is_dragging = is_dragging.clone();
1570 move |_| is_dragging.set(false)
1571 })
1572 .on_pointer_cancel({
1573 let is_dragging = is_dragging.clone();
1574 move |_| is_dragging.set(false)
1575 })
1576 .on_pointer_move({
1577 let drag_pos = drag_pos.clone();
1578 let is_dragging = is_dragging.clone();
1579 let on_drag = on_drag.clone();
1580 move |ev| {
1581 if !*is_dragging.get() {
1582 return;
1583 }
1584 let prev = *drag_pos.get();
1585 let cur = ev.position;
1586 let delta = Vec2 {
1587 x: cur.x - prev.x,
1588 y: cur.y - prev.y,
1589 };
1590 drag_pos.set(cur);
1591 on_drag(delta);
1592 crate::frame_clock::request_frame();
1593 }
1594 })
1595 }
1596 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1597 self.on_pointer_enter = Some(Rc::new(f));
1598 self
1599 }
1600 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1601 self.on_pointer_leave = Some(Rc::new(f));
1602 self
1603 }
1604 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1605 self.on_click = Some(Rc::new(f));
1606 self.click = true;
1607 if self.semantics.is_none() {
1608 self.semantics = Some(crate::Semantics::new(crate::Role::Button));
1609 }
1610 self
1611 }
1612 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1613 self.on_double_click = Some(Rc::new(f));
1614 self.click = true;
1615 self
1616 }
1617 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1618 self.on_long_click = Some(Rc::new(f));
1619 self.click = true;
1620 self
1621 }
1622 pub fn clickable_ext(
1623 mut self,
1624 enabled: bool,
1625 on_click_label: Option<String>,
1626 role: Option<crate::semantics::Role>,
1627 on_click: impl Fn() + 'static,
1628 ) -> Self {
1629 if !enabled {
1630 let mut s = self.semantics.clone().unwrap_or_else(|| {
1631 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1632 });
1633 s.enabled = false;
1634 if let Some(r) = role {
1635 s.role = r;
1636 }
1637 if let Some(l) = on_click_label {
1638 s.label = Some(l);
1639 }
1640 return self
1641 .clickable()
1642 .enabled(false)
1643 .default_min_size(Dp(48.0), Dp(48.0))
1644 .semantics(s);
1645 }
1646 self = self.clickable().on_click(on_click);
1647 if role.is_some() || on_click_label.is_some() {
1648 let mut s = self.semantics.clone().unwrap_or_else(|| {
1649 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1650 });
1651 s.enabled = true;
1652 if let Some(r) = role {
1653 s.role = r;
1654 }
1655 if let Some(l) = on_click_label {
1656 s.label = Some(l);
1657 }
1658 self = self.semantics(s);
1659 }
1660 self.default_min_size(Dp(48.0), Dp(48.0))
1661 }
1662 pub fn combined_clickable(
1663 mut self,
1664 enabled: bool,
1665 on_click_label: Option<String>,
1666 role: Option<crate::semantics::Role>,
1667 on_long_click_label: Option<String>,
1668 on_click: impl Fn() + 'static,
1669 on_long_click: Option<impl Fn() + 'static>,
1670 on_double_click: Option<impl Fn() + 'static>,
1671 ) -> Self {
1672 let _ = on_long_click_label;
1673 if !enabled {
1674 return self.clickable_ext(false, on_click_label, role, || {});
1675 }
1676 self = self.clickable_ext(true, on_click_label, role, on_click);
1677 if let Some(f) = on_long_click {
1678 self = self.on_long_click(f);
1679 }
1680 if let Some(f) = on_double_click {
1681 self = self.on_double_click(f);
1682 }
1683 self.default_min_size(Dp(48.0), Dp(48.0))
1684 }
1685 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1686 self.semantics = Some(s);
1687 self
1688 }
1689 pub fn alpha(mut self, a: f32) -> Self {
1690 self.alpha = Some(a);
1691 self
1692 }
1693 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1698 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1699 self
1700 }
1701 pub fn shadow(mut self, blur_radius: Dp, offset_y: Dp) -> Self {
1705 self.shadow = Some(ShadowSpec {
1706 blur_radius: Dp(blur_radius.0.max(0.0)),
1707 offset_y,
1708 color: Color(0, 0, 0, 64),
1709 });
1710 self
1711 }
1712 pub fn shadow_with_color(mut self, blur_radius: Dp, offset_y: Dp, color: Color) -> Self {
1714 self.shadow = Some(ShadowSpec {
1715 blur_radius: Dp(blur_radius.0.max(0.0)),
1716 offset_y,
1717 color,
1718 });
1719 self
1720 }
1721 pub fn elevation(mut self, level: Dp) -> Self {
1725 if level.0 <= 0.0 {
1726 self.shadow = None;
1727 return self;
1728 }
1729 self.shadow = Some(ShadowSpec {
1730 blur_radius: Dp(level.0 * 2.0),
1731 offset_y: Dp(level.0 * 0.5),
1732 color: Color(0, 0, 0, (level.0 * 8.0).clamp(8.0, 80.0) as u8),
1733 });
1734 self
1735 }
1736 pub fn transform(mut self, t: Transform) -> Self {
1737 self.transform = Some(t);
1738 self
1739 }
1740 pub fn grid(mut self, columns: usize, row_gap: Dp, column_gap: Dp) -> Self {
1741 self.grid = Some(GridConfig {
1742 columns,
1743 row_gap,
1744 column_gap,
1745 });
1746 self
1747 }
1748 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1749 self.grid_col_span = Some(col_span);
1750 self.grid_row_span = Some(row_span);
1751 self
1752 }
1753 pub fn absolute(mut self) -> Self {
1762 self.position_type = Some(PositionType::Absolute);
1763 self
1764 }
1765 pub fn offset(
1770 mut self,
1771 left: Option<Dp>,
1772 top: Option<Dp>,
1773 right: Option<Dp>,
1774 bottom: Option<Dp>,
1775 ) -> Self {
1776 self.offset_left = left;
1777 self.offset_top = top;
1778 self.offset_right = right;
1779 self.offset_bottom = bottom;
1780 self
1781 }
1782 pub fn offset_left(mut self, v: Dp) -> Self {
1783 self.offset_left = Some(v);
1784 self
1785 }
1786 pub fn offset_right(mut self, v: Dp) -> Self {
1787 self.offset_right = Some(v);
1788 self
1789 }
1790 pub fn offset_top(mut self, v: Dp) -> Self {
1791 self.offset_top = Some(v);
1792 self
1793 }
1794 pub fn offset_bottom(mut self, v: Dp) -> Self {
1795 self.offset_bottom = Some(v);
1796 self
1797 }
1798 pub fn margin(mut self, v: Dp) -> Self {
1799 self.margin_left = Some(v);
1800 self.margin_right = Some(v);
1801 self.margin_top = Some(v);
1802 self.margin_bottom = Some(v);
1803 self
1804 }
1805
1806 pub fn margin_horizontal(mut self, v: Dp) -> Self {
1807 self.margin_left = Some(v);
1808 self.margin_right = Some(v);
1809 self
1810 }
1811
1812 pub fn margin_vertical(mut self, v: Dp) -> Self {
1813 self.margin_top = Some(v);
1814 self.margin_bottom = Some(v);
1815 self
1816 }
1817 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1818 self.aspect_ratio = Some(ratio);
1819 self
1820 }
1821 pub fn fit_content_width(mut self, limit: Dp) -> Self {
1823 self.fit_content_width = Some(Dp(limit.0.max(0.0)));
1824 self
1825 }
1826 pub fn fit_content_height(mut self, limit: Dp) -> Self {
1828 self.fit_content_height = Some(Dp(limit.0.max(0.0)));
1829 self
1830 }
1831 pub fn contain(mut self, c: Contain) -> Self {
1833 self.contain = Some(c);
1834 self
1835 }
1836 pub fn contain_layout(mut self) -> Self {
1838 self.contain = Some(Contain::LAYOUT);
1839 self
1840 }
1841 pub fn contain_paint(mut self) -> Self {
1843 self.contain = Some(Contain::PAINT);
1844 self
1845 }
1846 pub fn contain_content(mut self) -> Self {
1848 self.contain = Some(Contain::CONTENT);
1849 self
1850 }
1851 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1853 self.intrinsic_width = Some(mode);
1854 self
1855 }
1856 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1858 self.intrinsic_height = Some(mode);
1859 self
1860 }
1861 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1862 self.painter = Some(Rc::new(f));
1863 self
1864 }
1865 pub fn paint_callback(mut self, payload: crate::PaintCallbackPayload) -> Self {
1871 self.paint_callback = Some(payload);
1872 self
1873 }
1874 pub fn scale(self, s: f32) -> Self {
1875 self.scale2(s, s)
1876 }
1877 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1878 let mut t = self.transform.unwrap_or_else(Transform::identity);
1879 t.scale_x *= sx;
1880 t.scale_y *= sy;
1881 self.transform = Some(t);
1882 self
1883 }
1884 pub fn translate(mut self, x: f32, y: f32) -> Self {
1885 let t = self.transform.unwrap_or_else(Transform::identity);
1886 self.transform = Some(t.combine(&Transform::translate(x, y)));
1887 self
1888 }
1889 pub fn translate_vec2(self, v: Vec2) -> Self {
1890 self.translate(v.x, v.y)
1891 }
1892 pub fn rotate(mut self, radians: f32) -> Self {
1893 let mut t = self.transform.unwrap_or_else(Transform::identity);
1894 t.rotate += radians;
1895 self.transform = Some(t);
1896 self
1897 }
1898 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1899 let mut t = self.transform.unwrap_or_else(Transform::identity);
1900 t.origin_x = x;
1901 t.origin_y = y;
1902 self.transform = Some(t);
1903 self
1904 }
1905 pub fn weight(mut self, w: f32) -> Self {
1906 let w = w.max(0.0);
1907 self.flex_grow = Some(w);
1908 self.flex_shrink = Some(1.0);
1909 self.flex_basis = Some(Dp::ZERO);
1910 self.flex_basis_content = false;
1911 self.min_width = Some(Dp::ZERO);
1915 self.min_height = Some(Dp::ZERO);
1916 self
1917 }
1918 pub fn repaint_boundary(mut self) -> Self {
1922 self.repaint_boundary = true;
1923 self
1924 }
1925 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1926 self.on_action = Some(Rc::new(f));
1927 self
1928 }
1929
1930 pub fn on_drag_start(
1932 mut self,
1933 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1934 ) -> Self {
1935 self.on_drag_start = Some(Rc::new(f));
1936 self
1937 }
1938
1939 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1941 self.on_drag_end = Some(Rc::new(f));
1942 self
1943 }
1944
1945 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1947 self.on_drag_enter = Some(Rc::new(f));
1948 self
1949 }
1950
1951 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1953 self.on_drag_over = Some(Rc::new(f));
1954 self
1955 }
1956
1957 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1959 self.on_drag_leave = Some(Rc::new(f));
1960 self
1961 }
1962
1963 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1966 self.on_drop = Some(Rc::new(f));
1967 self
1968 }
1969
1970 pub fn draw_drag_decoration(
1975 mut self,
1976 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
1977 ) -> Self {
1978 self.drag_preview = Some(Rc::new(f));
1979 self
1980 }
1981
1982 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
1984 self.drag_preview = Some(preview);
1985 self
1986 }
1987
1988 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
1990 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
1991 }
1992
1993 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
1995 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
1996 }
1997
1998 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
2000 self.cursor = Some(c);
2001 self
2002 }
2003
2004 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
2008 self.animate_content_size = Some(spec);
2009 self
2010 }
2011
2012 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
2015 self.focus_requester = Some(fr);
2016 self
2017 }
2018
2019 pub fn focus_target(mut self) -> Self {
2022 self.focusable = Some(true);
2023 self
2024 }
2025
2026 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
2029 self.on_focus_changed = Some(Rc::new(f));
2030 self
2031 }
2032
2033 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
2038 self.on_globally_positioned = Some(Rc::new(f));
2039 self
2040 }
2041
2042 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
2045 self.on_size_changed = Some(Rc::new(f));
2046 self
2047 }
2048
2049 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
2053 self.on_key_event = Some(Rc::new(f));
2054 self
2055 }
2056
2057 pub fn on_preview_key_event(
2061 mut self,
2062 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
2063 ) -> Self {
2064 self.on_preview_key_event = Some(Rc::new(f));
2065 self
2066 }
2067
2068 pub fn blur(mut self, radius: Dp) -> Self {
2075 self.blur = Some(BlurStyle {
2076 radius_x: Dp(radius.0.max(0.0)),
2077 radius_y: Dp(radius.0.max(0.0)),
2078 edge_treatment: BlurredEdgeTreatment::Rectangle,
2079 });
2080 self
2081 }
2082
2083 pub fn blur_with_edge(
2088 mut self,
2089 radius_x: Dp,
2090 radius_y: Dp,
2091 edge_treatment: BlurredEdgeTreatment,
2092 ) -> Self {
2093 self.blur = Some(BlurStyle {
2094 radius_x: Dp(radius_x.0.max(0.0)),
2095 radius_y: Dp(radius_y.0.max(0.0)),
2096 edge_treatment,
2097 });
2098 self
2099 }
2100
2101 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (Dp, Dp) + 'static) -> Self {
2109 self.layout = Some(Rc::new(f));
2110 self
2111 }
2112
2113 pub fn text_input(mut self, config: TextInputConfig) -> Self {
2115 self.text_input = Some(config);
2116 self
2117 }
2118
2119 pub fn text_selection(mut self, selection: crate::text::TextSelection) -> Self {
2122 self.text_selection = Some(selection);
2123 self
2124 }
2125
2126 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
2130 self.indication = Some(factory);
2131 self
2132 }
2133}