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, 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 scroll: Option<crate::scroll::ScrollBinding>,
744 pub scrollbar_style: Option<crate::scroll::ScrollbarStyle>,
745 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
754 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
755 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
756 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
757 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
758 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
759 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
760 pub on_click: Option<Rc<dyn Fn()>>,
762 pub on_double_click: Option<Rc<dyn Fn()>>,
764 pub on_long_click: Option<Rc<dyn Fn()>>,
766 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
769 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
772 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
775 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
778 pub on_ime: Option<Rc<dyn Fn(crate::input::ImeEvent) -> bool>>,
781 pub blur: Option<BlurStyle>,
786 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (Dp, Dp)>>,
791 pub semantics: Option<crate::Semantics>,
792 pub alpha: Option<f32>,
793 pub graphics_layer: Option<f32>,
794 pub shadow: Option<ShadowSpec>,
795 pub shadow_shape: Option<[Dp; 4]>,
800 pub transform: Option<Transform>,
801 pub grid: Option<GridConfig>,
802 pub grid_col_span: Option<u16>,
803 pub grid_row_span: Option<u16>,
804 pub position_type: Option<PositionType>,
805 pub offset_left: Option<Dp>,
806 pub offset_right: Option<Dp>,
807 pub offset_top: Option<Dp>,
808 pub offset_bottom: Option<Dp>,
809
810 pub margin_left: Option<Dp>,
811 pub margin_right: Option<Dp>,
812 pub margin_top: Option<Dp>,
813 pub margin_bottom: Option<Dp>,
814 pub aspect_ratio: Option<f32>,
815 pub intrinsic_width: Option<IntrinsicSize>,
818 pub intrinsic_height: Option<IntrinsicSize>,
821 pub fit_content_width: Option<Dp>,
824 pub fit_content_height: Option<Dp>,
827 pub baseline_align: Option<BaselineAlign>,
830 pub contain: Option<Contain>,
835 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
836 pub paint_callback: Option<crate::PaintCallbackPayload>,
837
838 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
840 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
841 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
842 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
843 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
844 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
845 pub drag_preview: Option<crate::dnd::DragPreview>,
847
848 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
849
850 pub cursor: Option<crate::CursorIcon>,
852
853 pub animate_content_size: Option<AnimationSpec>,
856
857 pub focus_requester: Option<crate::runtime::FocusRequester>,
861
862 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
865
866 pub interaction_source: Option<InteractionSource>,
873
874 pub text_input: Option<TextInputConfig>,
876
877 pub text_selection: Option<crate::text::TextSelection>,
880
881 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
883}
884
885impl std::fmt::Debug for Modifier {
886 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
887 let mut s = f.debug_struct("Modifier");
888
889 macro_rules! opt_val {
890 ($($name:ident),+ $(,)?) => {
891 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
892 };
893 }
894 if self.indication.is_some() {
895 s.field("indication", &"…");
896 }
897 s.field("scrollbar_style", &self.scrollbar_style);
898
899 opt_val!(
900 key,
901 size,
902 width,
903 height,
904 required_size,
905 padding,
906 padding_values,
907 min_width,
908 min_height,
909 max_width,
910 max_height,
911 required_min_width,
912 required_max_width,
913 required_min_height,
914 required_max_height,
915 default_min_width,
916 default_min_height,
917 fill_max,
918 fill_max_w,
919 fill_max_h,
920 background,
921 state_colors,
922 state_elevation,
923 border,
924 flex_grow,
925 flex_shrink,
926 flex_basis,
927 flex_wrap,
928 flex_dir,
929 gap,
930 row_gap,
931 column_gap,
932 align_self,
933 justify_content,
934 align_items_container,
935 align_content,
936 clip_rounded,
937 clip_rect,
938 render_z_index,
939 semantics,
940 alpha,
941 transform,
942 grid,
943 grid_col_span,
944 grid_row_span,
945 position_type,
946 offset_left,
947 offset_right,
948 offset_top,
949 offset_bottom,
950 margin_left,
951 margin_right,
952 margin_top,
953 margin_bottom,
954 aspect_ratio,
955 intrinsic_width,
956 intrinsic_height,
957 cursor,
958 animate_content_size,
959 blur,
960 );
961
962 macro_rules! opt_cb {
963 ($($name:ident),+ $(,)?) => {
964 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
965 };
966 }
967 opt_cb!(
968 on_scroll,
969 scroll,
970 nested_scroll_connection,
971 on_pointer_down,
972 on_pointer_move,
973 on_pointer_up,
974 on_pointer_cancel,
975 on_pointer_enter,
976 on_pointer_leave,
977 on_click,
978 on_double_click,
979 on_long_click,
980 on_globally_positioned,
981 on_size_changed,
982 on_key_event,
983 on_preview_key_event,
984 on_ime,
985 painter,
986 paint_callback,
987 on_drag_start,
988 on_drag_end,
989 on_drag_enter,
990 on_drag_over,
991 on_drag_leave,
992 on_drop,
993 drag_preview,
994 on_action,
995 on_focus_changed,
996 interaction_source,
997 text_input,
998 text_selection,
999 layout,
1000 );
1001
1002 macro_rules! flag {
1003 ($($name:ident),+ $(,)?) => {
1004 $( if self.$name { s.field(stringify!($name), &true); } )+
1005 };
1006 }
1007 flag!(
1008 hit_passthrough,
1009 input_blocker,
1010 repaint_boundary,
1011 click,
1012 disabled,
1013 propagate_min,
1014 focus_group,
1015 );
1016
1017 if let Some(f) = self.focusable {
1018 s.field("focusable", &f);
1019 }
1020 if self.z_index != 0.0 {
1021 s.field("z_index", &self.z_index);
1022 }
1023
1024 s.finish()
1025 }
1026}
1027
1028impl_option_fields!(Modifier);
1029
1030#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1034pub enum Alignment {
1035 TopStart,
1036 TopCenter,
1037 TopEnd,
1038 CenterStart,
1039 #[default]
1040 Center,
1041 CenterEnd,
1042 BottomStart,
1043 BottomCenter,
1044 BottomEnd,
1045}
1046
1047impl Alignment {
1048 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
1050 use AlignItems as AI;
1051 use JustifyContent as JC;
1052 match self {
1053 Self::TopStart => (AI::START, JC::START),
1054 Self::TopCenter => (AI::START, JC::CENTER),
1055 Self::TopEnd => (AI::START, JC::END),
1056 Self::CenterStart => (AI::CENTER, JC::START),
1057 Self::Center => (AI::CENTER, JC::CENTER),
1058 Self::CenterEnd => (AI::CENTER, JC::END),
1059 Self::BottomStart => (AI::END, JC::START),
1060 Self::BottomCenter => (AI::END, JC::CENTER),
1061 Self::BottomEnd => (AI::END, JC::END),
1062 }
1063 }
1064
1065 pub fn to_flex_safe(self) -> (AlignItems, JustifyContent) {
1070 use AlignItems as AI;
1071 use JustifyContent as JC;
1072 match self {
1073 Self::TopStart => (AI::SAFE_START, JC::SAFE_START),
1074 Self::TopCenter => (AI::SAFE_START, JC::SAFE_CENTER),
1075 Self::TopEnd => (AI::SAFE_START, JC::SAFE_END),
1076 Self::CenterStart => (AI::SAFE_CENTER, JC::SAFE_START),
1077 Self::Center => (AI::SAFE_CENTER, JC::SAFE_CENTER),
1078 Self::CenterEnd => (AI::SAFE_CENTER, JC::SAFE_END),
1079 Self::BottomStart => (AI::SAFE_END, JC::SAFE_START),
1080 Self::BottomCenter => (AI::SAFE_END, JC::SAFE_CENTER),
1081 Self::BottomEnd => (AI::SAFE_END, JC::SAFE_END),
1082 }
1083 }
1084}
1085
1086impl Modifier {
1087 pub fn new() -> Self {
1088 Self::default()
1089 }
1090
1091 pub fn key(mut self, key: u64) -> Self {
1094 self.key = Some(key);
1095 self
1096 }
1097
1098 pub fn size(mut self, w: Dp, h: Dp) -> Self {
1099 self.size = Some(DpSize::new(w, h));
1100 self
1101 }
1102 pub fn width(mut self, w: Dp) -> Self {
1103 self.width = Some(w);
1104 self
1105 }
1106 pub fn height(mut self, h: Dp) -> Self {
1107 self.height = Some(h);
1108 self
1109 }
1110 pub fn required_size(mut self, w: Dp, h: Dp) -> Self {
1115 self.required_size = Some(DpSize::new(w, h));
1116 self
1117 }
1118 pub fn required_width_in(mut self, min: Dp, max: Dp) -> Self {
1119 self.required_min_width = Some(Dp(min.0.max(0.0)));
1120 self.required_max_width = Some(Dp(max.0.max(0.0)));
1121 self
1122 }
1123 pub fn required_height_in(mut self, min: Dp, max: Dp) -> Self {
1124 self.required_min_height = Some(Dp(min.0.max(0.0)));
1125 self.required_max_height = Some(Dp(max.0.max(0.0)));
1126 self
1127 }
1128 pub fn required_min_width(mut self, w: Dp) -> Self {
1129 self.required_min_width = Some(Dp(w.0.max(0.0)));
1130 self
1131 }
1132 pub fn required_max_width(mut self, w: Dp) -> Self {
1133 self.required_max_width = Some(Dp(w.0.max(0.0)));
1134 self
1135 }
1136 pub fn required_min_height(mut self, h: Dp) -> Self {
1137 self.required_min_height = Some(Dp(h.0.max(0.0)));
1138 self
1139 }
1140 pub fn required_max_height(mut self, h: Dp) -> Self {
1141 self.required_max_height = Some(Dp(h.0.max(0.0)));
1142 self
1143 }
1144 pub fn default_min_size(mut self, w: Dp, h: Dp) -> Self {
1146 self.default_min_width = Some(Dp(w.0.max(0.0)));
1147 self.default_min_height = Some(Dp(h.0.max(0.0)));
1148 self
1149 }
1150 pub fn fill_max_size(mut self) -> Self {
1153 self.fill_max = Some(1.0);
1154 self
1155 }
1156 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
1157 self.fill_max = Some(fraction.clamp(0.0, 1.0));
1158 self
1159 }
1160 pub fn fill_max_width(mut self) -> Self {
1162 self.fill_max_w = Some(1.0);
1163 self
1164 }
1165 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
1166 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
1167 self
1168 }
1169 pub fn fill_max_height(mut self) -> Self {
1171 self.fill_max_h = Some(1.0);
1172 self
1173 }
1174 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
1175 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
1176 self
1177 }
1178 pub fn padding(mut self, v: Dp) -> Self {
1179 self.padding = Some(v);
1180 self
1181 }
1182 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
1183 self.padding_values = Some(padding);
1184 self
1185 }
1186 pub fn ime_padding(mut self) -> Self {
1190 use crate::units::Px;
1191 let insets = crate::locals::window_insets();
1192 let mut p = self.padding_values.unwrap_or_default();
1193 p.bottom = p.bottom + Px(insets.ime_bottom).to_dp();
1194 self.padding_values = Some(p);
1195 self
1196 }
1197 pub fn system_bars_padding(mut self) -> Self {
1199 use crate::units::Px;
1200 let insets = crate::locals::window_insets();
1201 let mut p = self.padding_values.unwrap_or_default();
1202 p.top = p.top + Px(insets.top).to_dp();
1203 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1204 self.padding_values = Some(p);
1205 self
1206 }
1207 pub fn status_bars_padding(mut self) -> Self {
1209 use crate::units::Px;
1210 let insets = crate::locals::window_insets();
1211 let mut p = self.padding_values.unwrap_or_default();
1212 p.top = p.top + Px(insets.top).to_dp();
1213 self.padding_values = Some(p);
1214 self
1215 }
1216 pub fn navigation_bars_padding(mut self) -> Self {
1218 let insets = crate::locals::window_insets();
1219 use crate::units::Px;
1220 let mut p = self.padding_values.unwrap_or_default();
1221 p.bottom = p.bottom + Px(insets.bottom).to_dp();
1222 self.padding_values = Some(p);
1223 self
1224 }
1225 pub fn min_size(mut self, w: Dp, h: Dp) -> Self {
1226 self.min_width = Some(w);
1227 self.min_height = Some(h);
1228 self
1229 }
1230 pub fn max_size(mut self, w: Dp, h: Dp) -> Self {
1231 self.max_width = Some(w);
1232 self.max_height = Some(h);
1233 self
1234 }
1235 pub fn min_width(mut self, w: Dp) -> Self {
1236 self.min_width = Some(w);
1237 self
1238 }
1239 pub fn min_height(mut self, h: Dp) -> Self {
1240 self.min_height = Some(h);
1241 self
1242 }
1243 pub fn max_width(mut self, w: Dp) -> Self {
1244 self.max_width = Some(w);
1245 self
1246 }
1247 pub fn max_height(mut self, h: Dp) -> Self {
1248 self.max_height = Some(h);
1249 self
1250 }
1251 pub fn background(mut self, color: Color) -> Self {
1253 self.background = Some(Brush::Solid(color));
1254 self
1255 }
1256 pub fn background_brush(mut self, brush: Brush) -> Self {
1258 self.background = Some(brush);
1259 self
1260 }
1261 pub fn border(mut self, width: Dp, color: Color, radius: Dp) -> Self {
1262 self.border = Some(Border {
1263 width,
1264 brush: Brush::Solid(color),
1265 radius: [radius; 4],
1266 });
1267 self
1268 }
1269 pub fn border_brush(mut self, width: Dp, brush: Brush, radius: Dp) -> Self {
1272 self.border = Some(Border {
1273 width,
1274 brush,
1275 radius: [radius; 4],
1276 });
1277 self
1278 }
1279 pub fn border_radii(mut self, width: Dp, color: Color, radii: [Dp; 4]) -> Self {
1280 self.border = Some(Border {
1281 width,
1282 brush: Brush::Solid(color),
1283 radius: radii,
1284 });
1285 self
1286 }
1287 pub fn border_brush_radii(mut self, width: Dp, brush: Brush, radii: [Dp; 4]) -> Self {
1289 self.border = Some(Border {
1290 width,
1291 brush,
1292 radius: radii,
1293 });
1294 self
1295 }
1296 pub fn flex_grow(mut self, v: f32) -> Self {
1297 self.flex_grow = Some(v);
1298 self
1299 }
1300 pub fn flex_shrink(mut self, v: f32) -> Self {
1301 self.flex_shrink = Some(v);
1302 self
1303 }
1304 pub fn flex_basis(mut self, v: Dp) -> Self {
1305 self.flex_basis = Some(v);
1306 self
1307 }
1308 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1309 self.flex_wrap = Some(w);
1310 self
1311 }
1312 pub fn flex_basis_content(mut self) -> Self {
1315 self.flex_basis_content = true;
1316 self
1317 }
1318 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1319 self.flex_dir = Some(d);
1320 self
1321 }
1322 pub fn gap(mut self, v: Dp) -> Self {
1323 let v = Dp(v.0.max(0.0));
1324 self.gap = Some(v);
1325 self.row_gap = Some(v);
1326 self.column_gap = Some(v);
1327 self
1328 }
1329 pub fn row_gap(mut self, v: Dp) -> Self {
1330 self.row_gap = Some(Dp(v.0.max(0.0)));
1331 self
1332 }
1333 pub fn column_gap(mut self, v: Dp) -> Self {
1334 self.column_gap = Some(Dp(v.0.max(0.0)));
1335 self
1336 }
1337 pub fn align_self(mut self, a: AlignSelf) -> Self {
1338 self.align_self = Some(a);
1339 self
1340 }
1341 pub fn align_self_center(mut self) -> Self {
1342 self.align_self = Some(AlignSelf::CENTER);
1343 self
1344 }
1345 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1346 self.justify_content = Some(j);
1347 self
1348 }
1349 pub fn align_items(mut self, a: AlignItems) -> Self {
1350 self.align_items_container = Some(a);
1351 self
1352 }
1353 pub fn content_alignment(self, alignment: Alignment) -> Self {
1356 let (ai, jc) = alignment.to_flex();
1357 self.align_items(ai).justify_content(jc)
1358 }
1359 pub fn content_alignment_safe(self, alignment: Alignment) -> Self {
1364 let (ai, jc) = alignment.to_flex_safe();
1365 self.align_items(ai).justify_content(jc)
1366 }
1367 pub fn align_content(mut self, a: AlignContent) -> Self {
1368 self.align_content = Some(a);
1369 self
1370 }
1371 pub fn clip_rounded(mut self, radius: Dp) -> Self {
1372 self.clip_rounded = Some([radius; 4]);
1373 self
1374 }
1375 pub fn clip_rounded_radii(mut self, radii: [Dp; 4]) -> Self {
1376 self.clip_rounded = Some(radii);
1377 self
1378 }
1379 pub fn clip_rect(mut self, left: Dp, top: Dp, right: Dp, bottom: Dp, op: ClipOp) -> Self {
1382 self.clip_rect = Some(ClipRect {
1383 left,
1384 top,
1385 right,
1386 bottom,
1387 op,
1388 });
1389 self
1390 }
1391 pub fn overflow(mut self, overflow: Overflow) -> Self {
1392 self.overflow = Some(overflow);
1393 self
1394 }
1395 pub fn z_index(mut self, z: f32) -> Self {
1396 self.z_index = z;
1397 self
1398 }
1399
1400 pub fn render_z_index(mut self, z: f32) -> Self {
1403 self.render_z_index = Some(z);
1404 self
1405 }
1406
1407 pub fn input_blocker(mut self) -> Self {
1409 self.input_blocker = true;
1410 self
1411 }
1412
1413 pub fn hit_passthrough(mut self) -> Self {
1414 self.hit_passthrough = true;
1415 self
1416 }
1417 pub fn clickable(mut self) -> Self {
1418 self.click = true;
1419 if self.indication.is_none() {
1420 self.indication = crate::locals::local_indication();
1421 }
1422 self
1423 }
1424 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1427 self.click = true;
1428 self.interaction_source = Some(source.source());
1429 if self.indication.is_none() {
1430 self.indication = crate::locals::local_indication();
1431 }
1432 self
1433 }
1434 pub fn state_colors(mut self, colors: StateColors) -> Self {
1437 self.state_colors = Some(colors);
1438 self
1439 }
1440 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1442 self.state_elevation = Some(elev);
1443 self
1444 }
1445 pub fn disabled(mut self) -> Self {
1447 self.disabled = true;
1448 self
1449 }
1450 pub fn enabled(mut self, enabled: bool) -> Self {
1452 self.disabled = !enabled;
1453 self
1454 }
1455 pub fn focusable(mut self, focusable: bool) -> Self {
1460 self.focusable = Some(focusable);
1461 self
1462 }
1463 pub fn focus_group(mut self) -> Self {
1466 self.focus_group = true;
1467 self
1468 }
1469 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1480 self.interaction_source = Some(source.source());
1481 self
1482 }
1483 pub fn hoverable(
1486 mut self,
1487 on_enter: impl Fn() + 'static,
1488 on_leave: impl Fn() + 'static,
1489 ) -> Self {
1490 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1491 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1492 self
1493 }
1494 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1498 self.interaction_source = Some(source.source());
1499 self
1500 }
1501 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1504 self.propagate_min = propagate;
1505 self
1506 }
1507 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1508 self.on_scroll = Some(Rc::new(f));
1509 self
1510 }
1511 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1515 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1516 self
1517 }
1518 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1520 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1521 self
1522 }
1523 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1525 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1526 self
1527 }
1528 pub fn scrollbar_style(mut self, style: crate::scroll::ScrollbarStyle) -> Self {
1529 self.scrollbar_style = Some(style);
1530 self
1531 }
1532 pub fn scrollbar_style_or_default(&self) -> crate::scroll::ScrollbarStyle {
1533 self.scrollbar_style.clone().unwrap_or_default()
1534 }
1535 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1542 self.nested_scroll_connection = Some(conn);
1543 self
1544 }
1545 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1546 self.on_pointer_down = Some(Rc::new(f));
1547 self
1548 }
1549 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1550 self.on_pointer_move = Some(Rc::new(f));
1551 self
1552 }
1553 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1554 self.on_pointer_up = Some(Rc::new(f));
1555 self
1556 }
1557 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1558 self.on_pointer_cancel = Some(Rc::new(f));
1559 self
1560 }
1561
1562 pub fn draggable(self, on_drag: impl Fn(Vec2) + 'static) -> Self {
1563 self.draggable_with_end(on_drag, || {})
1564 }
1565
1566 pub fn draggable_with_end(
1569 self,
1570 on_drag: impl Fn(Vec2) + 'static,
1571 on_drag_end: impl Fn() + 'static,
1572 ) -> Self {
1573 let drag_pos = crate::state::remember_mutable(Vec2::default);
1574 let is_dragging = crate::state::remember_mutable(|| false);
1575 let on_drag = Rc::new(on_drag);
1576 let on_drag_end = Rc::new(on_drag_end);
1577 self.on_pointer_down({
1578 let drag_pos = drag_pos.clone();
1579 let is_dragging = is_dragging.clone();
1580 move |ev| {
1581 is_dragging.set(true);
1582 drag_pos.set(ev.position);
1583 }
1584 })
1585 .on_pointer_up({
1586 let is_dragging = is_dragging.clone();
1587 let on_drag_end = on_drag_end.clone();
1588 move |_| {
1589 if *is_dragging.get() {
1590 is_dragging.set(false);
1591 on_drag_end();
1592 }
1593 }
1594 })
1595 .on_pointer_cancel({
1596 let is_dragging = is_dragging.clone();
1597 let on_drag_end = on_drag_end.clone();
1598 move |_| {
1599 if *is_dragging.get() {
1600 is_dragging.set(false);
1601 on_drag_end();
1602 }
1603 }
1604 })
1605 .on_pointer_move({
1606 let drag_pos = drag_pos.clone();
1607 let is_dragging = is_dragging.clone();
1608 let on_drag = on_drag.clone();
1609 move |ev| {
1610 if !*is_dragging.get() {
1611 return;
1612 }
1613 let prev = *drag_pos.get();
1614 let cur = ev.position;
1615 let delta = Vec2 {
1616 x: cur.x - prev.x,
1617 y: cur.y - prev.y,
1618 };
1619 drag_pos.set(cur);
1620 on_drag(delta);
1621 crate::frame_clock::request_frame();
1622 }
1623 })
1624 }
1625 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1626 self.on_pointer_enter = Some(Rc::new(f));
1627 self
1628 }
1629 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1630 self.on_pointer_leave = Some(Rc::new(f));
1631 self
1632 }
1633 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1634 self.on_click = Some(Rc::new(f));
1635 self.click = true;
1636 if self.semantics.is_none() {
1637 self.semantics = Some(crate::Semantics::new(crate::Role::Button));
1638 }
1639 self
1640 }
1641 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1642 self.on_double_click = Some(Rc::new(f));
1643 self.click = true;
1644 self
1645 }
1646 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1647 self.on_long_click = Some(Rc::new(f));
1648 self.click = true;
1649 self
1650 }
1651 pub fn clickable_ext(
1652 mut self,
1653 enabled: bool,
1654 on_click_label: Option<String>,
1655 role: Option<crate::semantics::Role>,
1656 on_click: impl Fn() + 'static,
1657 ) -> Self {
1658 if !enabled {
1659 let mut s = self.semantics.clone().unwrap_or_else(|| {
1660 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1661 });
1662 s.enabled = false;
1663 if let Some(r) = role {
1664 s.role = r;
1665 }
1666 if let Some(l) = on_click_label {
1667 s.label = Some(l);
1668 }
1669 return self
1670 .clickable()
1671 .enabled(false)
1672 .default_min_size(Dp(48.0), Dp(48.0))
1673 .semantics(s);
1674 }
1675 self = self.clickable().on_click(on_click);
1676 if role.is_some() || on_click_label.is_some() {
1677 let mut s = self.semantics.clone().unwrap_or_else(|| {
1678 crate::semantics::Semantics::new(role.unwrap_or(crate::semantics::Role::Button))
1679 });
1680 s.enabled = true;
1681 if let Some(r) = role {
1682 s.role = r;
1683 }
1684 if let Some(l) = on_click_label {
1685 s.label = Some(l);
1686 }
1687 self = self.semantics(s);
1688 }
1689 self.default_min_size(Dp(48.0), Dp(48.0))
1690 }
1691 pub fn combined_clickable(
1692 mut self,
1693 enabled: bool,
1694 on_click_label: Option<String>,
1695 role: Option<crate::semantics::Role>,
1696 on_long_click_label: Option<String>,
1697 on_click: impl Fn() + 'static,
1698 on_long_click: Option<impl Fn() + 'static>,
1699 on_double_click: Option<impl Fn() + 'static>,
1700 ) -> Self {
1701 let _ = on_long_click_label;
1702 if !enabled {
1703 return self.clickable_ext(false, on_click_label, role, || {});
1704 }
1705 self = self.clickable_ext(true, on_click_label, role, on_click);
1706 if let Some(f) = on_long_click {
1707 self = self.on_long_click(f);
1708 }
1709 if let Some(f) = on_double_click {
1710 self = self.on_double_click(f);
1711 }
1712 self.default_min_size(Dp(48.0), Dp(48.0))
1713 }
1714 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1715 self.semantics = Some(s);
1716 self
1717 }
1718 pub fn alpha(mut self, a: f32) -> Self {
1719 self.alpha = Some(a);
1720 self
1721 }
1722 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1727 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1728 self
1729 }
1730 pub fn shadow(mut self, blur_radius: Dp, offset_y: Dp) -> Self {
1734 self.shadow = Some(ShadowSpec {
1735 blur_radius: Dp(blur_radius.0.max(0.0)),
1736 offset_y,
1737 color: Color(0, 0, 0, 64),
1738 });
1739 self
1740 }
1741 pub fn shadow_with_color(mut self, blur_radius: Dp, offset_y: Dp, color: Color) -> Self {
1743 self.shadow = Some(ShadowSpec {
1744 blur_radius: Dp(blur_radius.0.max(0.0)),
1745 offset_y,
1746 color,
1747 });
1748 self
1749 }
1750 pub fn elevation(mut self, level: Dp) -> Self {
1754 if level.0 <= 0.0 {
1755 self.shadow = None;
1756 return self;
1757 }
1758 self.shadow = Some(ShadowSpec {
1759 blur_radius: Dp(level.0 * 2.0),
1760 offset_y: Dp(level.0 * 0.5),
1761 color: Color(0, 0, 0, (level.0 * 8.0).clamp(8.0, 80.0) as u8),
1762 });
1763 self
1764 }
1765 pub fn elevation_with_color(mut self, level: Dp, color: Color) -> Self {
1768 if level.0 <= 0.0 {
1769 self.shadow = None;
1770 return self;
1771 }
1772 self.shadow = Some(ShadowSpec {
1773 blur_radius: Dp(level.0 * 2.0),
1774 offset_y: Dp(level.0 * 0.5),
1775 color,
1776 });
1777 self
1778 }
1779 pub fn shadow_rounded(mut self, radius: Dp) -> Self {
1784 self.shadow_shape = Some([radius; 4]);
1785 self
1786 }
1787 pub fn shadow_rounded_radii(mut self, radii: [Dp; 4]) -> Self {
1790 self.shadow_shape = Some(radii);
1791 self
1792 }
1793 pub fn transform(mut self, t: Transform) -> Self {
1794 self.transform = Some(t);
1795 self
1796 }
1797 pub fn grid(mut self, columns: usize, row_gap: Dp, column_gap: Dp) -> Self {
1798 self.grid = Some(GridConfig {
1799 columns,
1800 row_gap,
1801 column_gap,
1802 });
1803 self
1804 }
1805 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1806 self.grid_col_span = Some(col_span);
1807 self.grid_row_span = Some(row_span);
1808 self
1809 }
1810 pub fn absolute(mut self) -> Self {
1819 self.position_type = Some(PositionType::Absolute);
1820 self
1821 }
1822 pub fn offset(
1827 mut self,
1828 left: Option<Dp>,
1829 top: Option<Dp>,
1830 right: Option<Dp>,
1831 bottom: Option<Dp>,
1832 ) -> Self {
1833 self.offset_left = left;
1834 self.offset_top = top;
1835 self.offset_right = right;
1836 self.offset_bottom = bottom;
1837 self
1838 }
1839 pub fn offset_left(mut self, v: Dp) -> Self {
1840 self.offset_left = Some(v);
1841 self
1842 }
1843 pub fn offset_right(mut self, v: Dp) -> Self {
1844 self.offset_right = Some(v);
1845 self
1846 }
1847 pub fn offset_top(mut self, v: Dp) -> Self {
1848 self.offset_top = Some(v);
1849 self
1850 }
1851 pub fn offset_bottom(mut self, v: Dp) -> Self {
1852 self.offset_bottom = Some(v);
1853 self
1854 }
1855 pub fn margin(mut self, v: Dp) -> Self {
1856 self.margin_left = Some(v);
1857 self.margin_right = Some(v);
1858 self.margin_top = Some(v);
1859 self.margin_bottom = Some(v);
1860 self
1861 }
1862
1863 pub fn margin_horizontal(mut self, v: Dp) -> Self {
1864 self.margin_left = Some(v);
1865 self.margin_right = Some(v);
1866 self
1867 }
1868
1869 pub fn margin_vertical(mut self, v: Dp) -> Self {
1870 self.margin_top = Some(v);
1871 self.margin_bottom = Some(v);
1872 self
1873 }
1874 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1875 self.aspect_ratio = Some(ratio);
1876 self
1877 }
1878 pub fn fit_content_width(mut self, limit: Dp) -> Self {
1880 self.fit_content_width = Some(Dp(limit.0.max(0.0)));
1881 self
1882 }
1883 pub fn fit_content_height(mut self, limit: Dp) -> Self {
1885 self.fit_content_height = Some(Dp(limit.0.max(0.0)));
1886 self
1887 }
1888 pub fn contain(mut self, c: Contain) -> Self {
1890 self.contain = Some(c);
1891 self
1892 }
1893 pub fn contain_layout(mut self) -> Self {
1895 self.contain = Some(Contain::LAYOUT);
1896 self
1897 }
1898 pub fn contain_paint(mut self) -> Self {
1900 self.contain = Some(Contain::PAINT);
1901 self
1902 }
1903 pub fn contain_content(mut self) -> Self {
1905 self.contain = Some(Contain::CONTENT);
1906 self
1907 }
1908 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1910 self.intrinsic_width = Some(mode);
1911 self
1912 }
1913 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1915 self.intrinsic_height = Some(mode);
1916 self
1917 }
1918 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1919 self.painter = Some(Rc::new(f));
1920 self
1921 }
1922 pub fn paint_callback(mut self, payload: crate::PaintCallbackPayload) -> Self {
1928 self.paint_callback = Some(payload);
1929 self
1930 }
1931 pub fn scale(self, s: f32) -> Self {
1932 self.scale2(s, s)
1933 }
1934 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1935 let mut t = self.transform.unwrap_or_else(Transform::identity);
1936 t.scale_x *= sx;
1937 t.scale_y *= sy;
1938 self.transform = Some(t);
1939 self
1940 }
1941 pub fn translate(mut self, x: f32, y: f32) -> Self {
1942 let t = self.transform.unwrap_or_else(Transform::identity);
1943 self.transform = Some(t.combine(&Transform::translate(x, y)));
1944 self
1945 }
1946 pub fn translate_vec2(self, v: Vec2) -> Self {
1947 self.translate(v.x, v.y)
1948 }
1949 pub fn rotate(mut self, radians: f32) -> Self {
1950 let mut t = self.transform.unwrap_or_else(Transform::identity);
1951 t.rotate += radians;
1952 self.transform = Some(t);
1953 self
1954 }
1955 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1956 let mut t = self.transform.unwrap_or_else(Transform::identity);
1957 t.origin_x = x;
1958 t.origin_y = y;
1959 self.transform = Some(t);
1960 self
1961 }
1962 pub fn weight(mut self, w: f32) -> Self {
1963 let w = w.max(0.0);
1964 self.flex_grow = Some(w);
1965 self.flex_shrink = Some(1.0);
1966 self.flex_basis = Some(Dp::ZERO);
1967 self.flex_basis_content = false;
1968 self.min_width = Some(Dp::ZERO);
1972 self.min_height = Some(Dp::ZERO);
1973 self
1974 }
1975 pub fn repaint_boundary(mut self) -> Self {
1979 self.repaint_boundary = true;
1980 self
1981 }
1982 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1983 self.on_action = Some(Rc::new(f));
1984 self
1985 }
1986
1987 pub fn on_drag_start(
1989 mut self,
1990 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1991 ) -> Self {
1992 self.on_drag_start = Some(Rc::new(f));
1993 self
1994 }
1995
1996 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1998 self.on_drag_end = Some(Rc::new(f));
1999 self
2000 }
2001
2002 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
2004 self.on_drag_enter = Some(Rc::new(f));
2005 self
2006 }
2007
2008 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
2010 self.on_drag_over = Some(Rc::new(f));
2011 self
2012 }
2013
2014 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
2016 self.on_drag_leave = Some(Rc::new(f));
2017 self
2018 }
2019
2020 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
2023 self.on_drop = Some(Rc::new(f));
2024 self
2025 }
2026
2027 pub fn draw_drag_decoration(
2032 mut self,
2033 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
2034 ) -> Self {
2035 self.drag_preview = Some(Rc::new(f));
2036 self
2037 }
2038
2039 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
2041 self.drag_preview = Some(preview);
2042 self
2043 }
2044
2045 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
2047 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
2048 }
2049
2050 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
2052 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
2053 }
2054
2055 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
2057 self.cursor = Some(c);
2058 self
2059 }
2060
2061 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
2065 self.animate_content_size = Some(spec);
2066 self
2067 }
2068
2069 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
2072 self.focus_requester = Some(fr);
2073 self
2074 }
2075
2076 pub fn focus_target(mut self) -> Self {
2079 self.focusable = Some(true);
2080 self
2081 }
2082
2083 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
2086 self.on_focus_changed = Some(Rc::new(f));
2087 self
2088 }
2089
2090 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
2095 self.on_globally_positioned = Some(Rc::new(f));
2096 self
2097 }
2098
2099 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
2102 self.on_size_changed = Some(Rc::new(f));
2103 self
2104 }
2105
2106 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
2110 self.on_key_event = Some(Rc::new(f));
2111 self
2112 }
2113
2114 pub fn on_ime(mut self, f: impl Fn(crate::input::ImeEvent) -> bool + 'static) -> Self {
2117 self.on_ime = Some(Rc::new(f));
2118 self
2119 }
2120
2121 pub fn on_preview_key_event(
2125 mut self,
2126 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
2127 ) -> Self {
2128 self.on_preview_key_event = Some(Rc::new(f));
2129 self
2130 }
2131
2132 pub fn blur(mut self, radius: Dp) -> Self {
2139 self.blur = Some(BlurStyle {
2140 radius_x: Dp(radius.0.max(0.0)),
2141 radius_y: Dp(radius.0.max(0.0)),
2142 edge_treatment: BlurredEdgeTreatment::Rectangle,
2143 });
2144 self
2145 }
2146
2147 pub fn blur_with_edge(
2152 mut self,
2153 radius_x: Dp,
2154 radius_y: Dp,
2155 edge_treatment: BlurredEdgeTreatment,
2156 ) -> Self {
2157 self.blur = Some(BlurStyle {
2158 radius_x: Dp(radius_x.0.max(0.0)),
2159 radius_y: Dp(radius_y.0.max(0.0)),
2160 edge_treatment,
2161 });
2162 self
2163 }
2164
2165 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (Dp, Dp) + 'static) -> Self {
2173 self.layout = Some(Rc::new(f));
2174 self
2175 }
2176
2177 pub fn text_input(mut self, config: TextInputConfig) -> Self {
2179 self.text_input = Some(config);
2180 self
2181 }
2182
2183 pub fn text_selection(mut self, selection: crate::text::TextSelection) -> Self {
2186 self.text_selection = Some(selection);
2187 self
2188 }
2189
2190 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
2194 self.indication = Some(factory);
2195 self
2196 }
2197}