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, 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,
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 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 transform: Option<Transform>,
799 pub grid: Option<GridConfig>,
800 pub grid_col_span: Option<u16>,
801 pub grid_row_span: Option<u16>,
802 pub position_type: Option<PositionType>,
803 pub offset_left: Option<Dp>,
804 pub offset_right: Option<Dp>,
805 pub offset_top: Option<Dp>,
806 pub offset_bottom: Option<Dp>,
807
808 pub margin_left: Option<Dp>,
809 pub margin_right: Option<Dp>,
810 pub margin_top: Option<Dp>,
811 pub margin_bottom: Option<Dp>,
812 pub aspect_ratio: Option<f32>,
813 pub intrinsic_width: Option<IntrinsicSize>,
816 pub intrinsic_height: Option<IntrinsicSize>,
819 pub fit_content_width: Option<Dp>,
822 pub fit_content_height: Option<Dp>,
825 pub baseline_align: Option<BaselineAlign>,
828 pub contain: Option<Contain>,
833 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
834 pub paint_callback: Option<crate::PaintCallbackPayload>,
835
836 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
838 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
839 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
840 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
841 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
842 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
843 pub drag_preview: Option<crate::dnd::DragPreview>,
845
846 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
847
848 pub cursor: Option<crate::CursorIcon>,
850
851 pub animate_content_size: Option<AnimationSpec>,
854
855 pub focus_requester: Option<crate::runtime::FocusRequester>,
859
860 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
863
864 pub interaction_source: Option<InteractionSource>,
871
872 pub text_input: Option<TextInputConfig>,
874
875 pub text_selection: Option<crate::text::TextSelection>,
878
879 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
881}
882
883impl std::fmt::Debug for Modifier {
884 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
885 let mut s = f.debug_struct("Modifier");
886
887 macro_rules! opt_val {
888 ($($name:ident),+ $(,)?) => {
889 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
890 };
891 }
892 if self.indication.is_some() {
893 s.field("indication", &"…");
894 }
895 s.field("scrollbar_style", &self.scrollbar_style);
896
897 opt_val!(
898 key,
899 size,
900 width,
901 height,
902 required_size,
903 padding,
904 padding_values,
905 min_width,
906 min_height,
907 max_width,
908 max_height,
909 required_min_width,
910 required_max_width,
911 required_min_height,
912 required_max_height,
913 default_min_width,
914 default_min_height,
915 fill_max,
916 fill_max_w,
917 fill_max_h,
918 background,
919 state_colors,
920 state_elevation,
921 border,
922 flex_grow,
923 flex_shrink,
924 flex_basis,
925 flex_wrap,
926 flex_dir,
927 gap,
928 row_gap,
929 column_gap,
930 align_self,
931 justify_content,
932 align_items_container,
933 align_content,
934 clip_rounded,
935 clip_rect,
936 render_z_index,
937 semantics,
938 alpha,
939 transform,
940 grid,
941 grid_col_span,
942 grid_row_span,
943 position_type,
944 offset_left,
945 offset_right,
946 offset_top,
947 offset_bottom,
948 margin_left,
949 margin_right,
950 margin_top,
951 margin_bottom,
952 aspect_ratio,
953 intrinsic_width,
954 intrinsic_height,
955 cursor,
956 animate_content_size,
957 blur,
958 );
959
960 macro_rules! opt_cb {
961 ($($name:ident),+ $(,)?) => {
962 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
963 };
964 }
965 opt_cb!(
966 on_scroll,
967 scroll,
968 nested_scroll_connection,
969 on_pointer_down,
970 on_pointer_move,
971 on_pointer_up,
972 on_pointer_cancel,
973 on_pointer_enter,
974 on_pointer_leave,
975 on_click,
976 on_double_click,
977 on_long_click,
978 on_globally_positioned,
979 on_size_changed,
980 on_key_event,
981 on_preview_key_event,
982 on_ime,
983 painter,
984 paint_callback,
985 on_drag_start,
986 on_drag_end,
987 on_drag_enter,
988 on_drag_over,
989 on_drag_leave,
990 on_drop,
991 drag_preview,
992 on_action,
993 on_focus_changed,
994 interaction_source,
995 text_input,
996 text_selection,
997 layout,
998 );
999
1000 macro_rules! flag {
1001 ($($name:ident),+ $(,)?) => {
1002 $( if self.$name { s.field(stringify!($name), &true); } )+
1003 };
1004 }
1005 flag!(
1006 hit_passthrough,
1007 input_blocker,
1008 repaint_boundary,
1009 click,
1010 disabled,
1011 propagate_min,
1012 focus_group,
1013 );
1014
1015 if let Some(f) = self.focusable {
1016 s.field("focusable", &f);
1017 }
1018 if self.z_index != 0.0 {
1019 s.field("z_index", &self.z_index);
1020 }
1021
1022 s.finish()
1023 }
1024}
1025
1026impl_option_fields!(Modifier);
1027
1028#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1032pub enum Alignment {
1033 TopStart,
1034 TopCenter,
1035 TopEnd,
1036 CenterStart,
1037 #[default]
1038 Center,
1039 CenterEnd,
1040 BottomStart,
1041 BottomCenter,
1042 BottomEnd,
1043}
1044
1045impl Alignment {
1046 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
1048 use AlignItems as AI;
1049 use JustifyContent as JC;
1050 match self {
1051 Self::TopStart => (AI::START, JC::START),
1052 Self::TopCenter => (AI::START, JC::CENTER),
1053 Self::TopEnd => (AI::START, JC::END),
1054 Self::CenterStart => (AI::CENTER, JC::START),
1055 Self::Center => (AI::CENTER, JC::CENTER),
1056 Self::CenterEnd => (AI::CENTER, JC::END),
1057 Self::BottomStart => (AI::END, JC::START),
1058 Self::BottomCenter => (AI::END, JC::CENTER),
1059 Self::BottomEnd => (AI::END, JC::END),
1060 }
1061 }
1062
1063 pub fn to_flex_safe(self) -> (AlignItems, JustifyContent) {
1068 use AlignItems as AI;
1069 use JustifyContent as JC;
1070 match self {
1071 Self::TopStart => (AI::SAFE_START, JC::SAFE_START),
1072 Self::TopCenter => (AI::SAFE_START, JC::SAFE_CENTER),
1073 Self::TopEnd => (AI::SAFE_START, JC::SAFE_END),
1074 Self::CenterStart => (AI::SAFE_CENTER, JC::SAFE_START),
1075 Self::Center => (AI::SAFE_CENTER, JC::SAFE_CENTER),
1076 Self::CenterEnd => (AI::SAFE_CENTER, JC::SAFE_END),
1077 Self::BottomStart => (AI::SAFE_END, JC::SAFE_START),
1078 Self::BottomCenter => (AI::SAFE_END, JC::SAFE_CENTER),
1079 Self::BottomEnd => (AI::SAFE_END, JC::SAFE_END),
1080 }
1081 }
1082}
1083
1084impl Modifier {
1085 pub fn new() -> Self {
1086 Self::default()
1087 }
1088
1089 pub fn key(mut self, key: u64) -> Self {
1092 self.key = Some(key);
1093 self
1094 }
1095
1096 pub fn size(mut self, w: Dp, h: Dp) -> Self {
1097 self.size = Some(DpSize::new(w, h));
1098 self
1099 }
1100 pub fn width(mut self, w: Dp) -> Self {
1101 self.width = Some(w);
1102 self
1103 }
1104 pub fn height(mut self, h: Dp) -> Self {
1105 self.height = Some(h);
1106 self
1107 }
1108 pub fn required_size(mut self, w: Dp, h: Dp) -> Self {
1113 self.required_size = Some(DpSize::new(w, h));
1114 self
1115 }
1116 pub fn required_width_in(mut self, min: Dp, max: Dp) -> Self {
1117 self.required_min_width = Some(Dp(min.0.max(0.0)));
1118 self.required_max_width = Some(Dp(max.0.max(0.0)));
1119 self
1120 }
1121 pub fn required_height_in(mut self, min: Dp, max: Dp) -> Self {
1122 self.required_min_height = Some(Dp(min.0.max(0.0)));
1123 self.required_max_height = Some(Dp(max.0.max(0.0)));
1124 self
1125 }
1126 pub fn required_min_width(mut self, w: Dp) -> Self {
1127 self.required_min_width = Some(Dp(w.0.max(0.0)));
1128 self
1129 }
1130 pub fn required_max_width(mut self, w: Dp) -> Self {
1131 self.required_max_width = Some(Dp(w.0.max(0.0)));
1132 self
1133 }
1134 pub fn required_min_height(mut self, h: Dp) -> Self {
1135 self.required_min_height = Some(Dp(h.0.max(0.0)));
1136 self
1137 }
1138 pub fn required_max_height(mut self, h: Dp) -> Self {
1139 self.required_max_height = Some(Dp(h.0.max(0.0)));
1140 self
1141 }
1142 pub fn default_min_size(mut self, w: Dp, h: Dp) -> Self {
1144 self.default_min_width = Some(Dp(w.0.max(0.0)));
1145 self.default_min_height = Some(Dp(h.0.max(0.0)));
1146 self
1147 }
1148 pub fn fill_max_size(mut self) -> Self {
1151 self.fill_max = Some(1.0);
1152 self
1153 }
1154 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
1155 self.fill_max = Some(fraction.clamp(0.0, 1.0));
1156 self
1157 }
1158 pub fn fill_max_width(mut self) -> Self {
1160 self.fill_max_w = Some(1.0);
1161 self
1162 }
1163 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
1164 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
1165 self
1166 }
1167 pub fn fill_max_height(mut self) -> Self {
1169 self.fill_max_h = Some(1.0);
1170 self
1171 }
1172 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
1173 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
1174 self
1175 }
1176 pub fn padding(mut self, v: Dp) -> Self {
1177 self.padding = Some(v);
1178 self
1179 }
1180 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
1181 self.padding_values = Some(padding);
1182 self
1183 }
1184 pub fn ime_padding(mut self) -> Self {
1188 use crate::units::Px;
1189 let insets = crate::locals::window_insets();
1190 let mut p = self.padding_values.unwrap_or_default();
1191 p.bottom = p.bottom + Px(insets.ime_bottom).to_dp();
1192 self.padding_values = Some(p);
1193 self
1194 }
1195 pub fn system_bars_padding(mut self) -> Self {
1197 use crate::units::Px;
1198 let insets = crate::locals::window_insets();
1199 let mut p = self.padding_values.unwrap_or_default();
1200 p.top = p.top + Px(insets.top).to_dp();
1201 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1202 self.padding_values = Some(p);
1203 self
1204 }
1205 pub fn status_bars_padding(mut self) -> Self {
1207 use crate::units::Px;
1208 let insets = crate::locals::window_insets();
1209 let mut p = self.padding_values.unwrap_or_default();
1210 p.top = p.top + Px(insets.top).to_dp();
1211 self.padding_values = Some(p);
1212 self
1213 }
1214 pub fn navigation_bars_padding(mut self) -> Self {
1216 let insets = crate::locals::window_insets();
1217 use crate::units::Px;
1218 let mut p = self.padding_values.unwrap_or_default();
1219 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1220 self.padding_values = Some(p);
1221 self
1222 }
1223 pub fn min_size(mut self, w: Dp, h: Dp) -> Self {
1224 self.min_width = Some(w);
1225 self.min_height = Some(h);
1226 self
1227 }
1228 pub fn max_size(mut self, w: Dp, h: Dp) -> Self {
1229 self.max_width = Some(w);
1230 self.max_height = Some(h);
1231 self
1232 }
1233 pub fn min_width(mut self, w: Dp) -> Self {
1234 self.min_width = Some(w);
1235 self
1236 }
1237 pub fn min_height(mut self, h: Dp) -> Self {
1238 self.min_height = Some(h);
1239 self
1240 }
1241 pub fn max_width(mut self, w: Dp) -> Self {
1242 self.max_width = Some(w);
1243 self
1244 }
1245 pub fn max_height(mut self, h: Dp) -> Self {
1246 self.max_height = Some(h);
1247 self
1248 }
1249 pub fn background(mut self, color: Color) -> Self {
1251 self.background = Some(Brush::Solid(color));
1252 self
1253 }
1254 pub fn background_brush(mut self, brush: Brush) -> Self {
1256 self.background = Some(brush);
1257 self
1258 }
1259 pub fn border(mut self, width: Dp, color: Color, radius: Dp) -> Self {
1260 self.border = Some(Border {
1261 width,
1262 brush: Brush::Solid(color),
1263 radius: [radius; 4],
1264 });
1265 self
1266 }
1267 pub fn border_brush(mut self, width: Dp, brush: Brush, radius: Dp) -> Self {
1270 self.border = Some(Border {
1271 width,
1272 brush,
1273 radius: [radius; 4],
1274 });
1275 self
1276 }
1277 pub fn border_radii(mut self, width: Dp, color: Color, radii: [Dp; 4]) -> Self {
1278 self.border = Some(Border {
1279 width,
1280 brush: Brush::Solid(color),
1281 radius: radii,
1282 });
1283 self
1284 }
1285 pub fn border_brush_radii(mut self, width: Dp, brush: Brush, radii: [Dp; 4]) -> Self {
1287 self.border = Some(Border {
1288 width,
1289 brush,
1290 radius: radii,
1291 });
1292 self
1293 }
1294 pub fn flex_grow(mut self, v: f32) -> Self {
1295 self.flex_grow = Some(v);
1296 self
1297 }
1298 pub fn flex_shrink(mut self, v: f32) -> Self {
1299 self.flex_shrink = Some(v);
1300 self
1301 }
1302 pub fn flex_basis(mut self, v: Dp) -> Self {
1303 self.flex_basis = Some(v);
1304 self
1305 }
1306 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1307 self.flex_wrap = Some(w);
1308 self
1309 }
1310 pub fn flex_basis_content(mut self) -> Self {
1313 self.flex_basis_content = true;
1314 self
1315 }
1316 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1317 self.flex_dir = Some(d);
1318 self
1319 }
1320 pub fn gap(mut self, v: Dp) -> Self {
1321 let v = Dp(v.0.max(0.0));
1322 self.gap = Some(v);
1323 self.row_gap = Some(v);
1324 self.column_gap = Some(v);
1325 self
1326 }
1327 pub fn row_gap(mut self, v: Dp) -> Self {
1328 self.row_gap = Some(Dp(v.0.max(0.0)));
1329 self
1330 }
1331 pub fn column_gap(mut self, v: Dp) -> Self {
1332 self.column_gap = Some(Dp(v.0.max(0.0)));
1333 self
1334 }
1335 pub fn align_self(mut self, a: AlignSelf) -> Self {
1336 self.align_self = Some(a);
1337 self
1338 }
1339 pub fn align_self_center(mut self) -> Self {
1340 self.align_self = Some(AlignSelf::CENTER);
1341 self
1342 }
1343 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1344 self.justify_content = Some(j);
1345 self
1346 }
1347 pub fn align_items(mut self, a: AlignItems) -> Self {
1348 self.align_items_container = Some(a);
1349 self
1350 }
1351 pub fn content_alignment(self, alignment: Alignment) -> Self {
1354 let (ai, jc) = alignment.to_flex();
1355 self.align_items(ai).justify_content(jc)
1356 }
1357 pub fn content_alignment_safe(self, alignment: Alignment) -> Self {
1362 let (ai, jc) = alignment.to_flex_safe();
1363 self.align_items(ai).justify_content(jc)
1364 }
1365 pub fn align_content(mut self, a: AlignContent) -> Self {
1366 self.align_content = Some(a);
1367 self
1368 }
1369 pub fn clip_rounded(mut self, radius: Dp) -> Self {
1370 self.clip_rounded = Some([radius; 4]);
1371 self
1372 }
1373 pub fn clip_rounded_radii(mut self, radii: [Dp; 4]) -> Self {
1374 self.clip_rounded = Some(radii);
1375 self
1376 }
1377 pub fn clip_rect(mut self, left: Dp, top: Dp, right: Dp, bottom: Dp, op: ClipOp) -> Self {
1380 self.clip_rect = Some(ClipRect {
1381 left,
1382 top,
1383 right,
1384 bottom,
1385 op,
1386 });
1387 self
1388 }
1389 pub fn overflow(mut self, overflow: Overflow) -> Self {
1390 self.overflow = Some(overflow);
1391 self
1392 }
1393 pub fn z_index(mut self, z: f32) -> Self {
1394 self.z_index = z;
1395 self
1396 }
1397
1398 pub fn render_z_index(mut self, z: f32) -> Self {
1401 self.render_z_index = Some(z);
1402 self
1403 }
1404
1405 pub fn input_blocker(mut self) -> Self {
1407 self.input_blocker = true;
1408 self
1409 }
1410
1411 pub fn hit_passthrough(mut self) -> Self {
1412 self.hit_passthrough = true;
1413 self
1414 }
1415 pub fn clickable(mut self) -> Self {
1416 self.click = true;
1417 if self.indication.is_none() {
1418 self.indication = crate::locals::local_indication();
1419 }
1420 self
1421 }
1422 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1425 self.click = true;
1426 self.interaction_source = Some(source.source());
1427 if self.indication.is_none() {
1428 self.indication = crate::locals::local_indication();
1429 }
1430 self
1431 }
1432 pub fn state_colors(mut self, colors: StateColors) -> Self {
1435 self.state_colors = Some(colors);
1436 self
1437 }
1438 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1440 self.state_elevation = Some(elev);
1441 self
1442 }
1443 pub fn disabled(mut self) -> Self {
1445 self.disabled = true;
1446 self
1447 }
1448 pub fn enabled(mut self, enabled: bool) -> Self {
1450 self.disabled = !enabled;
1451 self
1452 }
1453 pub fn focusable(mut self, focusable: bool) -> Self {
1458 self.focusable = Some(focusable);
1459 self
1460 }
1461 pub fn focus_group(mut self) -> Self {
1464 self.focus_group = true;
1465 self
1466 }
1467 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1478 self.interaction_source = Some(source.source());
1479 self
1480 }
1481 pub fn hoverable(
1484 mut self,
1485 on_enter: impl Fn() + 'static,
1486 on_leave: impl Fn() + 'static,
1487 ) -> Self {
1488 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1489 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1490 self
1491 }
1492 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1496 self.interaction_source = Some(source.source());
1497 self
1498 }
1499 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1502 self.propagate_min = propagate;
1503 self
1504 }
1505 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1506 self.on_scroll = Some(Rc::new(f));
1507 self
1508 }
1509 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1513 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1514 self
1515 }
1516 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1518 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1519 self
1520 }
1521 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1523 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1524 self
1525 }
1526 pub fn scrollbar_style(mut self, style: crate::scroll::ScrollbarStyle) -> Self {
1527 self.scrollbar_style = Some(style);
1528 self
1529 }
1530 pub fn scrollbar_style_or_default(&self) -> crate::scroll::ScrollbarStyle {
1531 self.scrollbar_style.clone().unwrap_or_default()
1532 }
1533 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1540 self.nested_scroll_connection = Some(conn);
1541 self
1542 }
1543 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1544 self.on_pointer_down = Some(Rc::new(f));
1545 self
1546 }
1547 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1548 self.on_pointer_move = Some(Rc::new(f));
1549 self
1550 }
1551 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1552 self.on_pointer_up = Some(Rc::new(f));
1553 self
1554 }
1555 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1556 self.on_pointer_cancel = Some(Rc::new(f));
1557 self
1558 }
1559
1560 pub fn draggable(self, on_drag: impl Fn(Vec2) + 'static) -> Self {
1561 self.draggable_with_end(on_drag, || {})
1562 }
1563
1564 pub fn draggable_with_end(
1567 self,
1568 on_drag: impl Fn(Vec2) + 'static,
1569 on_drag_end: impl Fn() + 'static,
1570 ) -> Self {
1571 let drag_pos = crate::state::remember_mutable(Vec2::default);
1572 let is_dragging = crate::state::remember_mutable(|| false);
1573 let on_drag = Rc::new(on_drag);
1574 let on_drag_end = Rc::new(on_drag_end);
1575 self.on_pointer_down({
1576 let drag_pos = drag_pos.clone();
1577 let is_dragging = is_dragging.clone();
1578 move |ev| {
1579 is_dragging.set(true);
1580 drag_pos.set(ev.position);
1581 }
1582 })
1583 .on_pointer_up({
1584 let is_dragging = is_dragging.clone();
1585 let on_drag_end = on_drag_end.clone();
1586 move |_| {
1587 if *is_dragging.get() {
1588 is_dragging.set(false);
1589 on_drag_end();
1590 }
1591 }
1592 })
1593 .on_pointer_cancel({
1594 let is_dragging = is_dragging.clone();
1595 let on_drag_end = on_drag_end.clone();
1596 move |_| {
1597 if *is_dragging.get() {
1598 is_dragging.set(false);
1599 on_drag_end();
1600 }
1601 }
1602 })
1603 .on_pointer_move({
1604 let drag_pos = drag_pos.clone();
1605 let is_dragging = is_dragging.clone();
1606 let on_drag = on_drag.clone();
1607 move |ev| {
1608 if !*is_dragging.get() {
1609 return;
1610 }
1611 let prev = *drag_pos.get();
1612 let cur = ev.position;
1613 let delta = Vec2 {
1614 x: cur.x - prev.x,
1615 y: cur.y - prev.y,
1616 };
1617 drag_pos.set(cur);
1618 on_drag(delta);
1619 crate::frame_clock::request_frame();
1620 }
1621 })
1622 }
1623 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1624 self.on_pointer_enter = Some(Rc::new(f));
1625 self
1626 }
1627 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1628 self.on_pointer_leave = Some(Rc::new(f));
1629 self
1630 }
1631 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1632 self.on_click = Some(Rc::new(f));
1633 self.click = true;
1634 if self.semantics.is_none() {
1635 self.semantics = Some(crate::Semantics::new(crate::Role::Button));
1636 }
1637 self
1638 }
1639 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1640 self.on_double_click = Some(Rc::new(f));
1641 self.click = true;
1642 self
1643 }
1644 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1645 self.on_long_click = Some(Rc::new(f));
1646 self.click = true;
1647 self
1648 }
1649 pub fn clickable_ext(
1650 mut self,
1651 enabled: bool,
1652 on_click_label: Option<String>,
1653 role: Option<crate::semantics::Role>,
1654 on_click: impl Fn() + 'static,
1655 ) -> Self {
1656 if !enabled {
1657 let mut s = self.semantics.clone().unwrap_or_else(|| {
1658 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1659 });
1660 s.enabled = false;
1661 if let Some(r) = role {
1662 s.role = r;
1663 }
1664 if let Some(l) = on_click_label {
1665 s.label = Some(l);
1666 }
1667 return self
1668 .clickable()
1669 .enabled(false)
1670 .default_min_size(Dp(48.0), Dp(48.0))
1671 .semantics(s);
1672 }
1673 self = self.clickable().on_click(on_click);
1674 if role.is_some() || on_click_label.is_some() {
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 = true;
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 self = self.semantics(s);
1686 }
1687 self.default_min_size(Dp(48.0), Dp(48.0))
1688 }
1689 pub fn combined_clickable(
1690 mut self,
1691 enabled: bool,
1692 on_click_label: Option<String>,
1693 role: Option<crate::semantics::Role>,
1694 on_long_click_label: Option<String>,
1695 on_click: impl Fn() + 'static,
1696 on_long_click: Option<impl Fn() + 'static>,
1697 on_double_click: Option<impl Fn() + 'static>,
1698 ) -> Self {
1699 let _ = on_long_click_label;
1700 if !enabled {
1701 return self.clickable_ext(false, on_click_label, role, || {});
1702 }
1703 self = self.clickable_ext(true, on_click_label, role, on_click);
1704 if let Some(f) = on_long_click {
1705 self = self.on_long_click(f);
1706 }
1707 if let Some(f) = on_double_click {
1708 self = self.on_double_click(f);
1709 }
1710 self.default_min_size(Dp(48.0), Dp(48.0))
1711 }
1712 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1713 self.semantics = Some(s);
1714 self
1715 }
1716 pub fn alpha(mut self, a: f32) -> Self {
1717 self.alpha = Some(a);
1718 self
1719 }
1720 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1725 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1726 self
1727 }
1728 pub fn shadow(mut self, blur_radius: Dp, offset_y: Dp) -> Self {
1732 self.shadow = Some(ShadowSpec {
1733 blur_radius: Dp(blur_radius.0.max(0.0)),
1734 offset_y,
1735 color: Color(0, 0, 0, 64),
1736 });
1737 self
1738 }
1739 pub fn shadow_with_color(mut self, blur_radius: Dp, offset_y: Dp, color: Color) -> Self {
1741 self.shadow = Some(ShadowSpec {
1742 blur_radius: Dp(blur_radius.0.max(0.0)),
1743 offset_y,
1744 color,
1745 });
1746 self
1747 }
1748 pub fn elevation(mut self, level: Dp) -> Self {
1752 if level.0 <= 0.0 {
1753 self.shadow = None;
1754 return self;
1755 }
1756 self.shadow = Some(ShadowSpec {
1757 blur_radius: Dp(level.0 * 2.0),
1758 offset_y: Dp(level.0 * 0.5),
1759 color: Color(0, 0, 0, (level.0 * 8.0).clamp(8.0, 80.0) as u8),
1760 });
1761 self
1762 }
1763 pub fn transform(mut self, t: Transform) -> Self {
1764 self.transform = Some(t);
1765 self
1766 }
1767 pub fn grid(mut self, columns: usize, row_gap: Dp, column_gap: Dp) -> Self {
1768 self.grid = Some(GridConfig {
1769 columns,
1770 row_gap,
1771 column_gap,
1772 });
1773 self
1774 }
1775 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1776 self.grid_col_span = Some(col_span);
1777 self.grid_row_span = Some(row_span);
1778 self
1779 }
1780 pub fn absolute(mut self) -> Self {
1789 self.position_type = Some(PositionType::Absolute);
1790 self
1791 }
1792 pub fn offset(
1797 mut self,
1798 left: Option<Dp>,
1799 top: Option<Dp>,
1800 right: Option<Dp>,
1801 bottom: Option<Dp>,
1802 ) -> Self {
1803 self.offset_left = left;
1804 self.offset_top = top;
1805 self.offset_right = right;
1806 self.offset_bottom = bottom;
1807 self
1808 }
1809 pub fn offset_left(mut self, v: Dp) -> Self {
1810 self.offset_left = Some(v);
1811 self
1812 }
1813 pub fn offset_right(mut self, v: Dp) -> Self {
1814 self.offset_right = Some(v);
1815 self
1816 }
1817 pub fn offset_top(mut self, v: Dp) -> Self {
1818 self.offset_top = Some(v);
1819 self
1820 }
1821 pub fn offset_bottom(mut self, v: Dp) -> Self {
1822 self.offset_bottom = Some(v);
1823 self
1824 }
1825 pub fn margin(mut self, v: Dp) -> Self {
1826 self.margin_left = Some(v);
1827 self.margin_right = Some(v);
1828 self.margin_top = Some(v);
1829 self.margin_bottom = Some(v);
1830 self
1831 }
1832
1833 pub fn margin_horizontal(mut self, v: Dp) -> Self {
1834 self.margin_left = Some(v);
1835 self.margin_right = Some(v);
1836 self
1837 }
1838
1839 pub fn margin_vertical(mut self, v: Dp) -> Self {
1840 self.margin_top = Some(v);
1841 self.margin_bottom = Some(v);
1842 self
1843 }
1844 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1845 self.aspect_ratio = Some(ratio);
1846 self
1847 }
1848 pub fn fit_content_width(mut self, limit: Dp) -> Self {
1850 self.fit_content_width = Some(Dp(limit.0.max(0.0)));
1851 self
1852 }
1853 pub fn fit_content_height(mut self, limit: Dp) -> Self {
1855 self.fit_content_height = Some(Dp(limit.0.max(0.0)));
1856 self
1857 }
1858 pub fn contain(mut self, c: Contain) -> Self {
1860 self.contain = Some(c);
1861 self
1862 }
1863 pub fn contain_layout(mut self) -> Self {
1865 self.contain = Some(Contain::LAYOUT);
1866 self
1867 }
1868 pub fn contain_paint(mut self) -> Self {
1870 self.contain = Some(Contain::PAINT);
1871 self
1872 }
1873 pub fn contain_content(mut self) -> Self {
1875 self.contain = Some(Contain::CONTENT);
1876 self
1877 }
1878 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1880 self.intrinsic_width = Some(mode);
1881 self
1882 }
1883 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1885 self.intrinsic_height = Some(mode);
1886 self
1887 }
1888 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1889 self.painter = Some(Rc::new(f));
1890 self
1891 }
1892 pub fn paint_callback(mut self, payload: crate::PaintCallbackPayload) -> Self {
1898 self.paint_callback = Some(payload);
1899 self
1900 }
1901 pub fn scale(self, s: f32) -> Self {
1902 self.scale2(s, s)
1903 }
1904 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1905 let mut t = self.transform.unwrap_or_else(Transform::identity);
1906 t.scale_x *= sx;
1907 t.scale_y *= sy;
1908 self.transform = Some(t);
1909 self
1910 }
1911 pub fn translate(mut self, x: f32, y: f32) -> Self {
1912 let t = self.transform.unwrap_or_else(Transform::identity);
1913 self.transform = Some(t.combine(&Transform::translate(x, y)));
1914 self
1915 }
1916 pub fn translate_vec2(self, v: Vec2) -> Self {
1917 self.translate(v.x, v.y)
1918 }
1919 pub fn rotate(mut self, radians: f32) -> Self {
1920 let mut t = self.transform.unwrap_or_else(Transform::identity);
1921 t.rotate += radians;
1922 self.transform = Some(t);
1923 self
1924 }
1925 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1926 let mut t = self.transform.unwrap_or_else(Transform::identity);
1927 t.origin_x = x;
1928 t.origin_y = y;
1929 self.transform = Some(t);
1930 self
1931 }
1932 pub fn weight(mut self, w: f32) -> Self {
1933 let w = w.max(0.0);
1934 self.flex_grow = Some(w);
1935 self.flex_shrink = Some(1.0);
1936 self.flex_basis = Some(Dp::ZERO);
1937 self.flex_basis_content = false;
1938 self.min_width = Some(Dp::ZERO);
1942 self.min_height = Some(Dp::ZERO);
1943 self
1944 }
1945 pub fn repaint_boundary(mut self) -> Self {
1949 self.repaint_boundary = true;
1950 self
1951 }
1952 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1953 self.on_action = Some(Rc::new(f));
1954 self
1955 }
1956
1957 pub fn on_drag_start(
1959 mut self,
1960 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1961 ) -> Self {
1962 self.on_drag_start = Some(Rc::new(f));
1963 self
1964 }
1965
1966 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1968 self.on_drag_end = Some(Rc::new(f));
1969 self
1970 }
1971
1972 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1974 self.on_drag_enter = Some(Rc::new(f));
1975 self
1976 }
1977
1978 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1980 self.on_drag_over = Some(Rc::new(f));
1981 self
1982 }
1983
1984 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1986 self.on_drag_leave = Some(Rc::new(f));
1987 self
1988 }
1989
1990 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1993 self.on_drop = Some(Rc::new(f));
1994 self
1995 }
1996
1997 pub fn draw_drag_decoration(
2002 mut self,
2003 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
2004 ) -> Self {
2005 self.drag_preview = Some(Rc::new(f));
2006 self
2007 }
2008
2009 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
2011 self.drag_preview = Some(preview);
2012 self
2013 }
2014
2015 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
2017 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
2018 }
2019
2020 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
2022 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
2023 }
2024
2025 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
2027 self.cursor = Some(c);
2028 self
2029 }
2030
2031 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
2035 self.animate_content_size = Some(spec);
2036 self
2037 }
2038
2039 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
2042 self.focus_requester = Some(fr);
2043 self
2044 }
2045
2046 pub fn focus_target(mut self) -> Self {
2049 self.focusable = Some(true);
2050 self
2051 }
2052
2053 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
2056 self.on_focus_changed = Some(Rc::new(f));
2057 self
2058 }
2059
2060 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
2065 self.on_globally_positioned = Some(Rc::new(f));
2066 self
2067 }
2068
2069 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
2072 self.on_size_changed = Some(Rc::new(f));
2073 self
2074 }
2075
2076 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
2080 self.on_key_event = Some(Rc::new(f));
2081 self
2082 }
2083
2084 pub fn on_ime(mut self, f: impl Fn(crate::input::ImeEvent) -> bool + 'static) -> Self {
2087 self.on_ime = Some(Rc::new(f));
2088 self
2089 }
2090
2091 pub fn on_preview_key_event(
2095 mut self,
2096 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
2097 ) -> Self {
2098 self.on_preview_key_event = Some(Rc::new(f));
2099 self
2100 }
2101
2102 pub fn blur(mut self, radius: Dp) -> Self {
2109 self.blur = Some(BlurStyle {
2110 radius_x: Dp(radius.0.max(0.0)),
2111 radius_y: Dp(radius.0.max(0.0)),
2112 edge_treatment: BlurredEdgeTreatment::Rectangle,
2113 });
2114 self
2115 }
2116
2117 pub fn blur_with_edge(
2122 mut self,
2123 radius_x: Dp,
2124 radius_y: Dp,
2125 edge_treatment: BlurredEdgeTreatment,
2126 ) -> Self {
2127 self.blur = Some(BlurStyle {
2128 radius_x: Dp(radius_x.0.max(0.0)),
2129 radius_y: Dp(radius_y.0.max(0.0)),
2130 edge_treatment,
2131 });
2132 self
2133 }
2134
2135 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (Dp, Dp) + 'static) -> Self {
2143 self.layout = Some(Rc::new(f));
2144 self
2145 }
2146
2147 pub fn text_input(mut self, config: TextInputConfig) -> Self {
2149 self.text_input = Some(config);
2150 self
2151 }
2152
2153 pub fn text_selection(mut self, selection: crate::text::TextSelection) -> Self {
2156 self.text_selection = Some(selection);
2157 self
2158 }
2159
2160 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
2164 self.indication = Some(factory);
2165 self
2166 }
2167}