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, on_scroll_with_source,
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, on_ime,
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, shadow_shape,
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;
568 s.hovered = false;
569 changed
570 }
571 Interaction::Focus => {
572 let changed = !s.focused;
573 s.focused = true;
574 changed
575 }
576 Interaction::Unfocus => {
577 let changed = s.focused;
578 s.focused = false;
579 changed
580 }
581 Interaction::DragStart => {
582 let changed = s.dragged == 0;
583 s.dragged = s.dragged.saturating_add(1);
584 changed
585 }
586 Interaction::DragStop | Interaction::DragCancel => {
587 let was = s.dragged;
588 s.dragged = s.dragged.saturating_sub(1);
589 was != s.dragged
590 }
591 };
592 if changed {
593 bump_interaction_epoch();
594 }
595 changed
596 };
597 if changed {
598 crate::frame_clock::request_frame();
600 }
601 }
602
603 pub fn source(&self) -> InteractionSource {
605 InteractionSource {
606 state: self.state.clone(),
607 }
608 }
609
610 pub fn reset(&self) {
612 let mut s = self.state.borrow_mut();
613 *s = InteractionState::default();
614 drop(s);
615 bump_interaction_epoch();
616 crate::frame_clock::request_frame();
617 }
618
619 pub fn reset_hover(&self) {
621 let mut s = self.state.borrow_mut();
622 if s.hovered {
623 s.hovered = false;
624 drop(s);
625 bump_interaction_epoch();
626 crate::frame_clock::request_frame();
627 }
628 }
629}
630
631impl Default for MutableInteractionSource {
632 fn default() -> Self {
633 Self::new()
634 }
635}
636
637#[derive(Clone, Default)]
638pub(crate) struct InteractionState {
639 active_presses: HashSet<PressId>,
641 hovered: bool,
642 focused: bool,
643 dragged: u32,
644 pub(crate) last_press_position: Option<Vec2>,
646 pub(crate) last_press_id: Option<PressId>,
648}
649
650#[derive(Clone, Default)]
651pub struct Modifier {
652 pub key: Option<u64>,
658
659 pub size: Option<DpSize>,
660 pub width: Option<Dp>,
661 pub height: Option<Dp>,
662 pub required_size: Option<DpSize>,
663 pub fill_max: Option<f32>,
664 pub fill_max_w: Option<f32>,
665 pub fill_max_h: Option<f32>,
666 pub padding: Option<Dp>,
667 pub padding_values: Option<PaddingValues>,
668 pub min_width: Option<Dp>,
669 pub min_height: Option<Dp>,
670 pub max_width: Option<Dp>,
671 pub max_height: Option<Dp>,
672 pub required_min_width: Option<Dp>,
674 pub required_max_width: Option<Dp>,
676 pub required_min_height: Option<Dp>,
678 pub required_max_height: Option<Dp>,
680 pub default_min_width: Option<Dp>,
683 pub default_min_height: Option<Dp>,
684 pub background: Option<Brush>,
685 pub state_colors: Option<StateColors>,
686 pub state_elevation: Option<StateElevation>,
687
688 pub border: Option<Border>,
689 pub flex_grow: Option<f32>,
690 pub flex_shrink: Option<f32>,
691 pub flex_basis: Option<Dp>,
692 pub flex_basis_content: bool,
695 pub flex_wrap: Option<FlexWrap>,
696 pub flex_line_count: Option<u16>,
699 pub flex_dir: Option<FlexDirection>,
700 pub gap: Option<Dp>,
701 pub row_gap: Option<Dp>,
702 pub column_gap: Option<Dp>,
703 pub align_self: Option<AlignSelf>,
704 pub justify_content: Option<JustifyContent>,
705 pub align_items_container: Option<AlignItems>,
706 pub align_content: Option<AlignContent>,
707 pub clip_rounded: Option<[Dp; 4]>,
708 pub clip_rect: Option<ClipRect>,
711 pub overflow: Option<Overflow>,
716 pub z_index: f32,
718 pub render_z_index: Option<f32>,
720 pub hit_passthrough: bool,
722 pub input_blocker: bool,
724 pub repaint_boundary: bool,
725 pub click: bool,
726 pub disabled: bool,
728 pub focusable: Option<bool>,
732 pub propagate_min: bool,
734 pub focus_group: bool,
737 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
738 pub on_scroll_with_source: Option<Rc<dyn Fn(Vec2, crate::input::ScrollSource) -> 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 on_ime: Option<Rc<dyn Fn(crate::input::ImeEvent) -> bool>>,
784 pub blur: Option<BlurStyle>,
789 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (Dp, Dp)>>,
794 pub semantics: Option<crate::Semantics>,
795 pub alpha: Option<f32>,
796 pub graphics_layer: Option<f32>,
797 pub shadow: Option<ShadowSpec>,
798 pub shadow_shape: Option<[Dp; 4]>,
803 pub transform: Option<Transform>,
804 pub grid: Option<GridConfig>,
805 pub grid_col_span: Option<u16>,
806 pub grid_row_span: Option<u16>,
807 pub position_type: Option<PositionType>,
808 pub offset_left: Option<Dp>,
809 pub offset_right: Option<Dp>,
810 pub offset_top: Option<Dp>,
811 pub offset_bottom: Option<Dp>,
812
813 pub margin_left: Option<Dp>,
814 pub margin_right: Option<Dp>,
815 pub margin_top: Option<Dp>,
816 pub margin_bottom: Option<Dp>,
817 pub aspect_ratio: Option<f32>,
818 pub intrinsic_width: Option<IntrinsicSize>,
821 pub intrinsic_height: Option<IntrinsicSize>,
824 pub fit_content_width: Option<Dp>,
827 pub fit_content_height: Option<Dp>,
830 pub baseline_align: Option<BaselineAlign>,
833 pub contain: Option<Contain>,
838 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
839 pub paint_callback: Option<crate::PaintCallbackPayload>,
840
841 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
843 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
844 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
845 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
846 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
847 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
848 pub drag_preview: Option<crate::dnd::DragPreview>,
850
851 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
852
853 pub cursor: Option<crate::CursorIcon>,
855
856 pub animate_content_size: Option<AnimationSpec>,
859
860 pub focus_requester: Option<crate::runtime::FocusRequester>,
864
865 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
868
869 pub interaction_source: Option<InteractionSource>,
876
877 pub text_input: Option<TextInputConfig>,
879
880 pub text_selection: Option<crate::text::TextSelection>,
883
884 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
886}
887
888impl std::fmt::Debug for Modifier {
889 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
890 let mut s = f.debug_struct("Modifier");
891
892 macro_rules! opt_val {
893 ($($name:ident),+ $(,)?) => {
894 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
895 };
896 }
897 if self.indication.is_some() {
898 s.field("indication", &"…");
899 }
900 s.field("scrollbar_style", &self.scrollbar_style);
901
902 opt_val!(
903 key,
904 size,
905 width,
906 height,
907 required_size,
908 padding,
909 padding_values,
910 min_width,
911 min_height,
912 max_width,
913 max_height,
914 required_min_width,
915 required_max_width,
916 required_min_height,
917 required_max_height,
918 default_min_width,
919 default_min_height,
920 fill_max,
921 fill_max_w,
922 fill_max_h,
923 background,
924 state_colors,
925 state_elevation,
926 border,
927 flex_grow,
928 flex_shrink,
929 flex_basis,
930 flex_wrap,
931 flex_dir,
932 gap,
933 row_gap,
934 column_gap,
935 align_self,
936 justify_content,
937 align_items_container,
938 align_content,
939 clip_rounded,
940 clip_rect,
941 render_z_index,
942 semantics,
943 alpha,
944 transform,
945 grid,
946 grid_col_span,
947 grid_row_span,
948 position_type,
949 offset_left,
950 offset_right,
951 offset_top,
952 offset_bottom,
953 margin_left,
954 margin_right,
955 margin_top,
956 margin_bottom,
957 aspect_ratio,
958 intrinsic_width,
959 intrinsic_height,
960 cursor,
961 animate_content_size,
962 blur,
963 );
964
965 macro_rules! opt_cb {
966 ($($name:ident),+ $(,)?) => {
967 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
968 };
969 }
970 opt_cb!(
971 on_scroll,
972 scroll,
973 nested_scroll_connection,
974 on_pointer_down,
975 on_pointer_move,
976 on_pointer_up,
977 on_pointer_cancel,
978 on_pointer_enter,
979 on_pointer_leave,
980 on_click,
981 on_double_click,
982 on_long_click,
983 on_globally_positioned,
984 on_size_changed,
985 on_key_event,
986 on_preview_key_event,
987 on_ime,
988 painter,
989 paint_callback,
990 on_drag_start,
991 on_drag_end,
992 on_drag_enter,
993 on_drag_over,
994 on_drag_leave,
995 on_drop,
996 drag_preview,
997 on_action,
998 on_focus_changed,
999 interaction_source,
1000 text_input,
1001 text_selection,
1002 layout,
1003 );
1004
1005 macro_rules! flag {
1006 ($($name:ident),+ $(,)?) => {
1007 $( if self.$name { s.field(stringify!($name), &true); } )+
1008 };
1009 }
1010 flag!(
1011 hit_passthrough,
1012 input_blocker,
1013 repaint_boundary,
1014 click,
1015 disabled,
1016 propagate_min,
1017 focus_group,
1018 );
1019
1020 if let Some(f) = self.focusable {
1021 s.field("focusable", &f);
1022 }
1023 if self.z_index != 0.0 {
1024 s.field("z_index", &self.z_index);
1025 }
1026
1027 s.finish()
1028 }
1029}
1030
1031impl_option_fields!(Modifier);
1032
1033#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1037pub enum Alignment {
1038 TopStart,
1039 TopCenter,
1040 TopEnd,
1041 CenterStart,
1042 #[default]
1043 Center,
1044 CenterEnd,
1045 BottomStart,
1046 BottomCenter,
1047 BottomEnd,
1048}
1049
1050impl Alignment {
1051 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
1053 use AlignItems as AI;
1054 use JustifyContent as JC;
1055 match self {
1056 Self::TopStart => (AI::START, JC::START),
1057 Self::TopCenter => (AI::START, JC::CENTER),
1058 Self::TopEnd => (AI::START, JC::END),
1059 Self::CenterStart => (AI::CENTER, JC::START),
1060 Self::Center => (AI::CENTER, JC::CENTER),
1061 Self::CenterEnd => (AI::CENTER, JC::END),
1062 Self::BottomStart => (AI::END, JC::START),
1063 Self::BottomCenter => (AI::END, JC::CENTER),
1064 Self::BottomEnd => (AI::END, JC::END),
1065 }
1066 }
1067
1068 pub fn to_flex_safe(self) -> (AlignItems, JustifyContent) {
1073 use AlignItems as AI;
1074 use JustifyContent as JC;
1075 match self {
1076 Self::TopStart => (AI::SAFE_START, JC::SAFE_START),
1077 Self::TopCenter => (AI::SAFE_START, JC::SAFE_CENTER),
1078 Self::TopEnd => (AI::SAFE_START, JC::SAFE_END),
1079 Self::CenterStart => (AI::SAFE_CENTER, JC::SAFE_START),
1080 Self::Center => (AI::SAFE_CENTER, JC::SAFE_CENTER),
1081 Self::CenterEnd => (AI::SAFE_CENTER, JC::SAFE_END),
1082 Self::BottomStart => (AI::SAFE_END, JC::SAFE_START),
1083 Self::BottomCenter => (AI::SAFE_END, JC::SAFE_CENTER),
1084 Self::BottomEnd => (AI::SAFE_END, JC::SAFE_END),
1085 }
1086 }
1087}
1088
1089impl Modifier {
1090 pub fn new() -> Self {
1091 Self::default()
1092 }
1093
1094 pub fn key(mut self, key: u64) -> Self {
1097 self.key = Some(key);
1098 self
1099 }
1100
1101 pub fn size(mut self, w: Dp, h: Dp) -> Self {
1102 self.size = Some(DpSize::new(w, h));
1103 self
1104 }
1105 pub fn width(mut self, w: Dp) -> Self {
1106 self.width = Some(w);
1107 self
1108 }
1109 pub fn height(mut self, h: Dp) -> Self {
1110 self.height = Some(h);
1111 self
1112 }
1113 pub fn required_size(mut self, w: Dp, h: Dp) -> Self {
1118 self.required_size = Some(DpSize::new(w, h));
1119 self
1120 }
1121 pub fn required_width_in(mut self, min: Dp, max: Dp) -> Self {
1122 self.required_min_width = Some(Dp(min.0.max(0.0)));
1123 self.required_max_width = Some(Dp(max.0.max(0.0)));
1124 self
1125 }
1126 pub fn required_height_in(mut self, min: Dp, max: Dp) -> Self {
1127 self.required_min_height = Some(Dp(min.0.max(0.0)));
1128 self.required_max_height = Some(Dp(max.0.max(0.0)));
1129 self
1130 }
1131 pub fn required_min_width(mut self, w: Dp) -> Self {
1132 self.required_min_width = Some(Dp(w.0.max(0.0)));
1133 self
1134 }
1135 pub fn required_max_width(mut self, w: Dp) -> Self {
1136 self.required_max_width = Some(Dp(w.0.max(0.0)));
1137 self
1138 }
1139 pub fn required_min_height(mut self, h: Dp) -> Self {
1140 self.required_min_height = Some(Dp(h.0.max(0.0)));
1141 self
1142 }
1143 pub fn required_max_height(mut self, h: Dp) -> Self {
1144 self.required_max_height = Some(Dp(h.0.max(0.0)));
1145 self
1146 }
1147 pub fn default_min_size(mut self, w: Dp, h: Dp) -> Self {
1149 self.default_min_width = Some(Dp(w.0.max(0.0)));
1150 self.default_min_height = Some(Dp(h.0.max(0.0)));
1151 self
1152 }
1153 pub fn fill_max_size(mut self) -> Self {
1156 self.fill_max = Some(1.0);
1157 self
1158 }
1159 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
1160 self.fill_max = Some(fraction.clamp(0.0, 1.0));
1161 self
1162 }
1163 pub fn fill_max_width(mut self) -> Self {
1165 self.fill_max_w = Some(1.0);
1166 self
1167 }
1168 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
1169 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
1170 self
1171 }
1172 pub fn fill_max_height(mut self) -> Self {
1174 self.fill_max_h = Some(1.0);
1175 self
1176 }
1177 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
1178 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
1179 self
1180 }
1181 pub fn padding(mut self, v: Dp) -> Self {
1182 self.padding = Some(v);
1183 self
1184 }
1185 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
1186 self.padding_values = Some(padding);
1187 self
1188 }
1189 pub fn ime_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.bottom = p.bottom + Px(insets.ime_bottom).to_dp();
1197 self.padding_values = Some(p);
1198 self
1199 }
1200 pub fn system_bars_padding(mut self) -> Self {
1202 use crate::units::Px;
1203 let insets = crate::locals::window_insets();
1204 let mut p = self.padding_values.unwrap_or_default();
1205 p.top = p.top + Px(insets.top).to_dp();
1206 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1207 self.padding_values = Some(p);
1208 self
1209 }
1210 pub fn status_bars_padding(mut self) -> Self {
1212 use crate::units::Px;
1213 let insets = crate::locals::window_insets();
1214 let mut p = self.padding_values.unwrap_or_default();
1215 p.top = p.top + Px(insets.top).to_dp();
1216 self.padding_values = Some(p);
1217 self
1218 }
1219 pub fn navigation_bars_padding(mut self) -> Self {
1221 let insets = crate::locals::window_insets();
1222 use crate::units::Px;
1223 let mut p = self.padding_values.unwrap_or_default();
1224 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1225 self.padding_values = Some(p);
1226 self
1227 }
1228 pub fn min_size(mut self, w: Dp, h: Dp) -> Self {
1229 self.min_width = Some(w);
1230 self.min_height = Some(h);
1231 self
1232 }
1233 pub fn max_size(mut self, w: Dp, h: Dp) -> Self {
1234 self.max_width = Some(w);
1235 self.max_height = Some(h);
1236 self
1237 }
1238 pub fn min_width(mut self, w: Dp) -> Self {
1239 self.min_width = Some(w);
1240 self
1241 }
1242 pub fn min_height(mut self, h: Dp) -> Self {
1243 self.min_height = Some(h);
1244 self
1245 }
1246 pub fn max_width(mut self, w: Dp) -> Self {
1247 self.max_width = Some(w);
1248 self
1249 }
1250 pub fn max_height(mut self, h: Dp) -> Self {
1251 self.max_height = Some(h);
1252 self
1253 }
1254 pub fn background(mut self, color: Color) -> Self {
1256 self.background = Some(Brush::Solid(color));
1257 self
1258 }
1259 pub fn background_brush(mut self, brush: Brush) -> Self {
1261 self.background = Some(brush);
1262 self
1263 }
1264 pub fn border(mut self, width: Dp, color: Color, radius: Dp) -> Self {
1265 self.border = Some(Border {
1266 width,
1267 brush: Brush::Solid(color),
1268 radius: [radius; 4],
1269 });
1270 self
1271 }
1272 pub fn border_brush(mut self, width: Dp, brush: Brush, radius: Dp) -> Self {
1275 self.border = Some(Border {
1276 width,
1277 brush,
1278 radius: [radius; 4],
1279 });
1280 self
1281 }
1282 pub fn border_radii(mut self, width: Dp, color: Color, radii: [Dp; 4]) -> Self {
1283 self.border = Some(Border {
1284 width,
1285 brush: Brush::Solid(color),
1286 radius: radii,
1287 });
1288 self
1289 }
1290 pub fn border_brush_radii(mut self, width: Dp, brush: Brush, radii: [Dp; 4]) -> Self {
1292 self.border = Some(Border {
1293 width,
1294 brush,
1295 radius: radii,
1296 });
1297 self
1298 }
1299 pub fn flex_grow(mut self, v: f32) -> Self {
1300 self.flex_grow = Some(v);
1301 self
1302 }
1303 pub fn flex_shrink(mut self, v: f32) -> Self {
1304 self.flex_shrink = Some(v);
1305 self
1306 }
1307 pub fn flex_basis(mut self, v: Dp) -> Self {
1308 self.flex_basis = Some(v);
1309 self
1310 }
1311 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1312 self.flex_wrap = Some(w);
1313 self
1314 }
1315 pub fn flex_basis_content(mut self) -> Self {
1318 self.flex_basis_content = true;
1319 self
1320 }
1321 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1322 self.flex_dir = Some(d);
1323 self
1324 }
1325 pub fn gap(mut self, v: Dp) -> Self {
1326 let v = Dp(v.0.max(0.0));
1327 self.gap = Some(v);
1328 self.row_gap = Some(v);
1329 self.column_gap = Some(v);
1330 self
1331 }
1332 pub fn row_gap(mut self, v: Dp) -> Self {
1333 self.row_gap = Some(Dp(v.0.max(0.0)));
1334 self
1335 }
1336 pub fn column_gap(mut self, v: Dp) -> Self {
1337 self.column_gap = Some(Dp(v.0.max(0.0)));
1338 self
1339 }
1340 pub fn align_self(mut self, a: AlignSelf) -> Self {
1341 self.align_self = Some(a);
1342 self
1343 }
1344 pub fn align_self_center(mut self) -> Self {
1345 self.align_self = Some(AlignSelf::CENTER);
1346 self
1347 }
1348 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1349 self.justify_content = Some(j);
1350 self
1351 }
1352 pub fn align_items(mut self, a: AlignItems) -> Self {
1353 self.align_items_container = Some(a);
1354 self
1355 }
1356 pub fn content_alignment(self, alignment: Alignment) -> Self {
1359 let (ai, jc) = alignment.to_flex();
1360 self.align_items(ai).justify_content(jc)
1361 }
1362 pub fn content_alignment_safe(self, alignment: Alignment) -> Self {
1367 let (ai, jc) = alignment.to_flex_safe();
1368 self.align_items(ai).justify_content(jc)
1369 }
1370 pub fn align_content(mut self, a: AlignContent) -> Self {
1371 self.align_content = Some(a);
1372 self
1373 }
1374 pub fn clip_rounded(mut self, radius: Dp) -> Self {
1375 self.clip_rounded = Some([radius; 4]);
1376 self
1377 }
1378 pub fn clip_rounded_radii(mut self, radii: [Dp; 4]) -> Self {
1379 self.clip_rounded = Some(radii);
1380 self
1381 }
1382 pub fn clip_rect(mut self, left: Dp, top: Dp, right: Dp, bottom: Dp, op: ClipOp) -> Self {
1385 self.clip_rect = Some(ClipRect {
1386 left,
1387 top,
1388 right,
1389 bottom,
1390 op,
1391 });
1392 self
1393 }
1394 pub fn overflow(mut self, overflow: Overflow) -> Self {
1395 self.overflow = Some(overflow);
1396 self
1397 }
1398 pub fn z_index(mut self, z: f32) -> Self {
1399 self.z_index = z;
1400 self
1401 }
1402
1403 pub fn render_z_index(mut self, z: f32) -> Self {
1406 self.render_z_index = Some(z);
1407 self
1408 }
1409
1410 pub fn input_blocker(mut self) -> Self {
1412 self.input_blocker = true;
1413 self
1414 }
1415
1416 pub fn hit_passthrough(mut self) -> Self {
1417 self.hit_passthrough = true;
1418 self
1419 }
1420 pub fn clickable(mut self) -> Self {
1421 self.click = true;
1422 if self.indication.is_none() {
1423 self.indication = crate::locals::local_indication();
1424 }
1425 self
1426 }
1427 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1430 self.click = true;
1431 self.interaction_source = Some(source.source());
1432 if self.indication.is_none() {
1433 self.indication = crate::locals::local_indication();
1434 }
1435 self
1436 }
1437 pub fn state_colors(mut self, colors: StateColors) -> Self {
1440 self.state_colors = Some(colors);
1441 self
1442 }
1443 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1445 self.state_elevation = Some(elev);
1446 self
1447 }
1448 pub fn disabled(mut self) -> Self {
1450 self.disabled = true;
1451 self
1452 }
1453 pub fn enabled(mut self, enabled: bool) -> Self {
1455 self.disabled = !enabled;
1456 self
1457 }
1458 pub fn focusable(mut self, focusable: bool) -> Self {
1463 self.focusable = Some(focusable);
1464 self
1465 }
1466 pub fn focus_group(mut self) -> Self {
1469 self.focus_group = true;
1470 self
1471 }
1472 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1483 self.interaction_source = Some(source.source());
1484 self
1485 }
1486 pub fn hoverable(
1489 mut self,
1490 on_enter: impl Fn() + 'static,
1491 on_leave: impl Fn() + 'static,
1492 ) -> Self {
1493 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1494 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1495 self
1496 }
1497 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1501 self.interaction_source = Some(source.source());
1502 self
1503 }
1504 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1507 self.propagate_min = propagate;
1508 self
1509 }
1510 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1511 self.on_scroll = Some(Rc::new(f));
1512 self
1513 }
1514 pub fn on_scroll_with_source(
1521 mut self,
1522 f: impl Fn(Vec2, crate::input::ScrollSource) -> Vec2 + 'static,
1523 ) -> Self {
1524 self.on_scroll_with_source = Some(Rc::new(f));
1525 self
1526 }
1527 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1531 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1532 self
1533 }
1534 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1536 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1537 self
1538 }
1539 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1541 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1542 self
1543 }
1544 pub fn scrollbar_style(mut self, style: crate::scroll::ScrollbarStyle) -> Self {
1545 self.scrollbar_style = Some(style);
1546 self
1547 }
1548 pub fn scrollbar_style_or_default(&self) -> crate::scroll::ScrollbarStyle {
1549 self.scrollbar_style.clone().unwrap_or_default()
1550 }
1551 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1558 self.nested_scroll_connection = Some(conn);
1559 self
1560 }
1561 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1562 self.on_pointer_down = Some(Rc::new(f));
1563 self
1564 }
1565 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1566 self.on_pointer_move = Some(Rc::new(f));
1567 self
1568 }
1569 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1570 self.on_pointer_up = Some(Rc::new(f));
1571 self
1572 }
1573 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1574 self.on_pointer_cancel = Some(Rc::new(f));
1575 self
1576 }
1577
1578 pub fn draggable(self, on_drag: impl Fn(Vec2) + 'static) -> Self {
1579 self.draggable_with_end(on_drag, || {})
1580 }
1581
1582 pub fn draggable_with_end(
1585 self,
1586 on_drag: impl Fn(Vec2) + 'static,
1587 on_drag_end: impl Fn() + 'static,
1588 ) -> Self {
1589 let drag_pos = crate::state::remember_mutable(Vec2::default);
1590 let is_dragging = crate::state::remember_mutable(|| false);
1591 let on_drag = Rc::new(on_drag);
1592 let on_drag_end = Rc::new(on_drag_end);
1593 self.on_pointer_down({
1594 let drag_pos = drag_pos.clone();
1595 let is_dragging = is_dragging.clone();
1596 move |ev| {
1597 is_dragging.set(true);
1598 drag_pos.set(ev.position);
1599 }
1600 })
1601 .on_pointer_up({
1602 let is_dragging = is_dragging.clone();
1603 let on_drag_end = on_drag_end.clone();
1604 move |_| {
1605 if *is_dragging.get() {
1606 is_dragging.set(false);
1607 on_drag_end();
1608 }
1609 }
1610 })
1611 .on_pointer_cancel({
1612 let is_dragging = is_dragging.clone();
1613 let on_drag_end = on_drag_end.clone();
1614 move |_| {
1615 if *is_dragging.get() {
1616 is_dragging.set(false);
1617 on_drag_end();
1618 }
1619 }
1620 })
1621 .on_pointer_move({
1622 let drag_pos = drag_pos.clone();
1623 let is_dragging = is_dragging.clone();
1624 let on_drag = on_drag.clone();
1625 move |ev| {
1626 if !*is_dragging.get() {
1627 return;
1628 }
1629 let prev = *drag_pos.get();
1630 let cur = ev.position;
1631 let delta = Vec2 {
1632 x: cur.x - prev.x,
1633 y: cur.y - prev.y,
1634 };
1635 drag_pos.set(cur);
1636 on_drag(delta);
1637 crate::frame_clock::request_frame();
1638 }
1639 })
1640 }
1641 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1642 self.on_pointer_enter = Some(Rc::new(f));
1643 self
1644 }
1645 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1646 self.on_pointer_leave = Some(Rc::new(f));
1647 self
1648 }
1649 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1650 self.on_click = Some(Rc::new(f));
1651 self.click = true;
1652 if self.semantics.is_none() {
1653 self.semantics = Some(crate::Semantics::new(crate::Role::Button));
1654 }
1655 self
1656 }
1657 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1658 self.on_double_click = Some(Rc::new(f));
1659 self.click = true;
1660 self
1661 }
1662 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1663 self.on_long_click = Some(Rc::new(f));
1664 self.click = true;
1665 self
1666 }
1667 pub fn clickable_ext(
1668 mut self,
1669 enabled: bool,
1670 on_click_label: Option<String>,
1671 role: Option<crate::semantics::Role>,
1672 on_click: impl Fn() + 'static,
1673 ) -> Self {
1674 if !enabled {
1675 let mut s = self.semantics.clone().unwrap_or_else(|| {
1676 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1677 });
1678 s.enabled = false;
1679 if let Some(r) = role {
1680 s.role = r;
1681 }
1682 if let Some(l) = on_click_label {
1683 s.label = Some(l);
1684 }
1685 return self
1686 .clickable()
1687 .enabled(false)
1688 .default_min_size(Dp(48.0), Dp(48.0))
1689 .semantics(s);
1690 }
1691 self = self.clickable().on_click(on_click);
1692 if role.is_some() || on_click_label.is_some() {
1693 let mut s = self.semantics.clone().unwrap_or_else(|| {
1694 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1695 });
1696 s.enabled = true;
1697 if let Some(r) = role {
1698 s.role = r;
1699 }
1700 if let Some(l) = on_click_label {
1701 s.label = Some(l);
1702 }
1703 self = self.semantics(s);
1704 }
1705 self.default_min_size(Dp(48.0), Dp(48.0))
1706 }
1707 pub fn combined_clickable(
1708 mut self,
1709 enabled: bool,
1710 on_click_label: Option<String>,
1711 role: Option<crate::semantics::Role>,
1712 on_long_click_label: Option<String>,
1713 on_click: impl Fn() + 'static,
1714 on_long_click: Option<impl Fn() + 'static>,
1715 on_double_click: Option<impl Fn() + 'static>,
1716 ) -> Self {
1717 let _ = on_long_click_label;
1718 if !enabled {
1719 return self.clickable_ext(false, on_click_label, role, || {});
1720 }
1721 self = self.clickable_ext(true, on_click_label, role, on_click);
1722 if let Some(f) = on_long_click {
1723 self = self.on_long_click(f);
1724 }
1725 if let Some(f) = on_double_click {
1726 self = self.on_double_click(f);
1727 }
1728 self.default_min_size(Dp(48.0), Dp(48.0))
1729 }
1730 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1731 self.semantics = Some(s);
1732 self
1733 }
1734 pub fn alpha(mut self, a: f32) -> Self {
1735 self.alpha = Some(a);
1736 self
1737 }
1738 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1743 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1744 self
1745 }
1746 pub fn shadow(mut self, blur_radius: Dp, offset_y: Dp) -> Self {
1750 self.shadow = Some(ShadowSpec {
1751 blur_radius: Dp(blur_radius.0.max(0.0)),
1752 offset_y,
1753 color: Color(0, 0, 0, 64),
1754 });
1755 self
1756 }
1757 pub fn shadow_with_color(mut self, blur_radius: Dp, offset_y: Dp, color: Color) -> Self {
1759 self.shadow = Some(ShadowSpec {
1760 blur_radius: Dp(blur_radius.0.max(0.0)),
1761 offset_y,
1762 color,
1763 });
1764 self
1765 }
1766 pub fn elevation(mut self, level: Dp) -> Self {
1770 if level.0 <= 0.0 {
1771 self.shadow = None;
1772 return self;
1773 }
1774 self.shadow = Some(ShadowSpec {
1775 blur_radius: Dp(level.0 * 2.0),
1776 offset_y: Dp(level.0 * 0.5),
1777 color: Color(0, 0, 0, (level.0 * 8.0).clamp(8.0, 80.0) as u8),
1778 });
1779 self
1780 }
1781 pub fn elevation_with_color(mut self, level: Dp, color: Color) -> Self {
1784 if level.0 <= 0.0 {
1785 self.shadow = None;
1786 return self;
1787 }
1788 self.shadow = Some(ShadowSpec {
1789 blur_radius: Dp(level.0 * 2.0),
1790 offset_y: Dp(level.0 * 0.5),
1791 color,
1792 });
1793 self
1794 }
1795 pub fn shadow_rounded(mut self, radius: Dp) -> Self {
1800 self.shadow_shape = Some([radius; 4]);
1801 self
1802 }
1803 pub fn shadow_rounded_radii(mut self, radii: [Dp; 4]) -> Self {
1806 self.shadow_shape = Some(radii);
1807 self
1808 }
1809 pub fn transform(mut self, t: Transform) -> Self {
1810 self.transform = Some(t);
1811 self
1812 }
1813 pub fn grid(mut self, columns: usize, row_gap: Dp, column_gap: Dp) -> Self {
1814 self.grid = Some(GridConfig {
1815 columns,
1816 row_gap,
1817 column_gap,
1818 });
1819 self
1820 }
1821 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1822 self.grid_col_span = Some(col_span);
1823 self.grid_row_span = Some(row_span);
1824 self
1825 }
1826 pub fn absolute(mut self) -> Self {
1835 self.position_type = Some(PositionType::Absolute);
1836 self
1837 }
1838 pub fn offset(
1843 mut self,
1844 left: Option<Dp>,
1845 top: Option<Dp>,
1846 right: Option<Dp>,
1847 bottom: Option<Dp>,
1848 ) -> Self {
1849 self.offset_left = left;
1850 self.offset_top = top;
1851 self.offset_right = right;
1852 self.offset_bottom = bottom;
1853 self
1854 }
1855 pub fn offset_left(mut self, v: Dp) -> Self {
1856 self.offset_left = Some(v);
1857 self
1858 }
1859 pub fn offset_right(mut self, v: Dp) -> Self {
1860 self.offset_right = Some(v);
1861 self
1862 }
1863 pub fn offset_top(mut self, v: Dp) -> Self {
1864 self.offset_top = Some(v);
1865 self
1866 }
1867 pub fn offset_bottom(mut self, v: Dp) -> Self {
1868 self.offset_bottom = Some(v);
1869 self
1870 }
1871 pub fn margin(mut self, v: Dp) -> Self {
1872 self.margin_left = Some(v);
1873 self.margin_right = Some(v);
1874 self.margin_top = Some(v);
1875 self.margin_bottom = Some(v);
1876 self
1877 }
1878
1879 pub fn margin_horizontal(mut self, v: Dp) -> Self {
1880 self.margin_left = Some(v);
1881 self.margin_right = Some(v);
1882 self
1883 }
1884
1885 pub fn margin_vertical(mut self, v: Dp) -> Self {
1886 self.margin_top = Some(v);
1887 self.margin_bottom = Some(v);
1888 self
1889 }
1890 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1891 self.aspect_ratio = Some(ratio);
1892 self
1893 }
1894 pub fn fit_content_width(mut self, limit: Dp) -> Self {
1896 self.fit_content_width = Some(Dp(limit.0.max(0.0)));
1897 self
1898 }
1899 pub fn fit_content_height(mut self, limit: Dp) -> Self {
1901 self.fit_content_height = Some(Dp(limit.0.max(0.0)));
1902 self
1903 }
1904 pub fn contain(mut self, c: Contain) -> Self {
1906 self.contain = Some(c);
1907 self
1908 }
1909 pub fn contain_layout(mut self) -> Self {
1911 self.contain = Some(Contain::LAYOUT);
1912 self
1913 }
1914 pub fn contain_paint(mut self) -> Self {
1916 self.contain = Some(Contain::PAINT);
1917 self
1918 }
1919 pub fn contain_content(mut self) -> Self {
1921 self.contain = Some(Contain::CONTENT);
1922 self
1923 }
1924 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1926 self.intrinsic_width = Some(mode);
1927 self
1928 }
1929 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1931 self.intrinsic_height = Some(mode);
1932 self
1933 }
1934 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1935 self.painter = Some(Rc::new(f));
1936 self
1937 }
1938 pub fn paint_callback(mut self, payload: crate::PaintCallbackPayload) -> Self {
1944 self.paint_callback = Some(payload);
1945 self
1946 }
1947 pub fn scale(self, s: f32) -> Self {
1948 self.scale2(s, s)
1949 }
1950 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1951 let mut t = self.transform.unwrap_or_else(Transform::identity);
1952 t.scale_x *= sx;
1953 t.scale_y *= sy;
1954 self.transform = Some(t);
1955 self
1956 }
1957 pub fn translate(mut self, x: f32, y: f32) -> Self {
1958 let t = self.transform.unwrap_or_else(Transform::identity);
1959 self.transform = Some(t.combine(&Transform::translate(x, y)));
1960 self
1961 }
1962 pub fn translate_vec2(self, v: Vec2) -> Self {
1963 self.translate(v.x, v.y)
1964 }
1965 pub fn rotate(mut self, radians: f32) -> Self {
1966 let mut t = self.transform.unwrap_or_else(Transform::identity);
1967 t.rotate += radians;
1968 self.transform = Some(t);
1969 self
1970 }
1971 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1972 let mut t = self.transform.unwrap_or_else(Transform::identity);
1973 t.origin_x = x;
1974 t.origin_y = y;
1975 self.transform = Some(t);
1976 self
1977 }
1978 pub fn weight(mut self, w: f32) -> Self {
1979 let w = w.max(0.0);
1980 self.flex_grow = Some(w);
1981 self.flex_shrink = Some(1.0);
1982 self.flex_basis = Some(Dp::ZERO);
1983 self.flex_basis_content = false;
1984 self.min_width = Some(Dp::ZERO);
1988 self.min_height = Some(Dp::ZERO);
1989 self
1990 }
1991 pub fn repaint_boundary(mut self) -> Self {
1995 self.repaint_boundary = true;
1996 self
1997 }
1998 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1999 self.on_action = Some(Rc::new(f));
2000 self
2001 }
2002
2003 pub fn on_drag_start(
2005 mut self,
2006 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
2007 ) -> Self {
2008 self.on_drag_start = Some(Rc::new(f));
2009 self
2010 }
2011
2012 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
2014 self.on_drag_end = Some(Rc::new(f));
2015 self
2016 }
2017
2018 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
2020 self.on_drag_enter = Some(Rc::new(f));
2021 self
2022 }
2023
2024 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
2026 self.on_drag_over = Some(Rc::new(f));
2027 self
2028 }
2029
2030 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
2032 self.on_drag_leave = Some(Rc::new(f));
2033 self
2034 }
2035
2036 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
2039 self.on_drop = Some(Rc::new(f));
2040 self
2041 }
2042
2043 pub fn draw_drag_decoration(
2048 mut self,
2049 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
2050 ) -> Self {
2051 self.drag_preview = Some(Rc::new(f));
2052 self
2053 }
2054
2055 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
2057 self.drag_preview = Some(preview);
2058 self
2059 }
2060
2061 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
2063 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
2064 }
2065
2066 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
2068 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
2069 }
2070
2071 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
2073 self.cursor = Some(c);
2074 self
2075 }
2076
2077 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
2081 self.animate_content_size = Some(spec);
2082 self
2083 }
2084
2085 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
2088 self.focus_requester = Some(fr);
2089 self
2090 }
2091
2092 pub fn focus_target(mut self) -> Self {
2095 self.focusable = Some(true);
2096 self
2097 }
2098
2099 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
2102 self.on_focus_changed = Some(Rc::new(f));
2103 self
2104 }
2105
2106 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
2111 self.on_globally_positioned = Some(Rc::new(f));
2112 self
2113 }
2114
2115 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
2118 self.on_size_changed = Some(Rc::new(f));
2119 self
2120 }
2121
2122 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
2126 self.on_key_event = Some(Rc::new(f));
2127 self
2128 }
2129
2130 pub fn on_ime(mut self, f: impl Fn(crate::input::ImeEvent) -> bool + 'static) -> Self {
2133 self.on_ime = Some(Rc::new(f));
2134 self
2135 }
2136
2137 pub fn on_preview_key_event(
2141 mut self,
2142 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
2143 ) -> Self {
2144 self.on_preview_key_event = Some(Rc::new(f));
2145 self
2146 }
2147
2148 pub fn blur(mut self, radius: Dp) -> Self {
2155 self.blur = Some(BlurStyle {
2156 radius_x: Dp(radius.0.max(0.0)),
2157 radius_y: Dp(radius.0.max(0.0)),
2158 edge_treatment: BlurredEdgeTreatment::Rectangle,
2159 });
2160 self
2161 }
2162
2163 pub fn blur_with_edge(
2168 mut self,
2169 radius_x: Dp,
2170 radius_y: Dp,
2171 edge_treatment: BlurredEdgeTreatment,
2172 ) -> Self {
2173 self.blur = Some(BlurStyle {
2174 radius_x: Dp(radius_x.0.max(0.0)),
2175 radius_y: Dp(radius_y.0.max(0.0)),
2176 edge_treatment,
2177 });
2178 self
2179 }
2180
2181 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (Dp, Dp) + 'static) -> Self {
2189 self.layout = Some(Rc::new(f));
2190 self
2191 }
2192
2193 pub fn text_input(mut self, config: TextInputConfig) -> Self {
2195 self.text_input = Some(config);
2196 self
2197 }
2198
2199 pub fn text_selection(mut self, selection: crate::text::TextSelection) -> Self {
2202 self.text_selection = Some(selection);
2203 self
2204 }
2205
2206 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
2210 self.indication = Some(factory);
2211 self
2212 }
2213}