1use std::cell::{Cell, RefCell};
2use std::rc::Rc;
3use std::sync::atomic::{AtomicU64, Ordering};
4
5use taffy::{AlignContent, AlignItems, AlignSelf, FlexDirection, FlexWrap, JustifyContent};
6
7use crate::animation::AnimationSpec;
8use crate::indication::IndicationNodeFactory;
9use crate::{Brush, Color, PointerEvent, Size, Transform, Vec2};
10
11#[derive(Clone, Copy, Debug)]
17pub struct StateColors {
18 pub default: Color,
19 pub hovered: Color,
20 pub focused: Color,
22 pub pressed: Color,
23 pub disabled: Color,
24 pub dragged: Color,
26}
27
28#[derive(Clone, Copy, Debug)]
31pub struct StateElevation {
32 pub default: f32,
33 pub hovered: f32,
34 pub focused: f32,
36 pub pressed: f32,
37 pub disabled: f32,
38 pub dragged: f32,
40}
41
42impl StateColors {
43 pub const fn transparent() -> Self {
45 Self {
46 default: Color::TRANSPARENT,
47 hovered: Color::TRANSPARENT,
48 focused: Color::TRANSPARENT,
49 pressed: Color::TRANSPARENT,
50 disabled: Color::TRANSPARENT,
51 dragged: Color::TRANSPARENT,
52 }
53 }
54}
55
56impl StateElevation {
57 pub const fn zero() -> Self {
59 Self {
60 default: 0.0,
61 hovered: 0.0,
62 focused: 0.0,
63 pressed: 0.0,
64 disabled: 0.0,
65 dragged: 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 gap, row_gap, column_gap,
103 align_self, justify_content, align_items_container, align_content,
104 clip_rounded, clip_rect, overflow, render_z_index,
105 on_scroll,
106 nested_scroll_connection,
107 scroll,
108 on_pointer_down, on_pointer_move, on_pointer_up,
109 on_pointer_enter, on_pointer_leave,
110 on_click, on_double_click, on_long_click,
111 semantics, alpha, transform,
112 grid, grid_col_span, grid_row_span,
113 position_type,
114 offset_left, offset_right, offset_top, offset_bottom,
115 margin_left, margin_right, margin_top, margin_bottom,
116 aspect_ratio, intrinsic_width, intrinsic_height,
117 painter,
118 on_drag_start, on_drag_end, on_drag_enter, on_drag_over, on_drag_leave, on_drop,
119 drag_preview,
120 on_action, cursor, animate_content_size, focus_requester, on_focus_changed,
121 interaction_source, text_input,
122 );
123 merge_flags!(self, other;
124 hit_passthrough, input_blocker, repaint_boundary, click, disabled,
125 propagate_min, focus_group,
126 );
127
128 if let Some(f) = other.focusable {
129 self.focusable = Some(f);
130 }
131 if other.indication.is_some() {
132 self.indication = other.indication;
133 }
134 if other.z_index != 0.0 {
135 self.z_index = other.z_index;
136 }
137 self
138 }
139 }
140 };
141}
142
143#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
144pub enum ClipOp {
145 #[default]
147 Intersect,
148 Difference,
150}
151
152#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
158pub enum Overflow {
159 #[default]
160 Clip,
161 Visible,
162}
163
164#[derive(Clone, Copy, Debug)]
167pub struct ClipRect {
168 pub left: f32,
169 pub top: f32,
170 pub right: f32,
171 pub bottom: f32,
172 pub op: ClipOp,
173}
174
175#[derive(Clone, Debug)]
176pub struct Border {
177 pub width: f32,
178 pub color: Color,
179 pub radius: [f32; 4],
180}
181
182#[derive(Clone, Copy, Debug, Default)]
183pub struct PaddingValues {
184 pub left: f32,
185 pub right: f32,
186 pub top: f32,
187 pub bottom: f32,
188}
189
190#[derive(Clone, Debug)]
191pub struct GridConfig {
192 pub columns: usize,
193 pub row_gap: f32,
194 pub column_gap: f32,
195}
196
197#[derive(Clone, Copy, Debug, PartialEq)]
200pub enum BlurredEdgeTreatment {
201 Rectangle,
204 Unbounded,
207}
208
209#[derive(Clone, Copy, Debug)]
211pub struct BlurStyle {
212 pub radius_x: f32,
214 pub radius_y: f32,
216 pub edge_treatment: BlurredEdgeTreatment,
218}
219
220#[derive(Clone, Copy, Debug)]
225pub struct LayoutConstraints {
226 pub min_width: f32,
227 pub max_width: f32,
228 pub min_height: f32,
229 pub max_height: f32,
230}
231
232#[derive(Clone, Copy, Debug)]
239pub struct ShadowSpec {
240 pub blur_radius: f32,
241 pub offset_y: f32,
242 pub color: Color,
243}
244
245#[derive(Clone, Copy, Debug)]
246#[non_exhaustive]
247pub enum PositionType {
248 Relative,
249 Absolute,
250}
251
252#[derive(Clone)]
254pub struct TextInputConfig {
255 pub hint: String,
256 pub multiline: bool,
257 pub on_change: Option<Rc<dyn Fn(String)>>,
258 pub on_submit: Option<Rc<dyn Fn(String)>>,
259 pub focus_tracker: Option<Rc<Cell<bool>>>,
260 pub value: String,
261 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
262 pub keyboard_type: crate::text::KeyboardType,
263 pub capitalization: crate::text::KeyboardCapitalization,
264 pub ime_action: crate::text::ImeAction,
265 pub auto_correct_enabled: Option<bool>,
268 pub enabled: bool,
270 pub read_only: bool,
272 pub max_lines: Option<usize>,
274 pub min_lines: usize,
276 pub cursor_color: Option<Color>,
278 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
281 pub text_style: Option<crate::text::TextStyle>,
284 pub keyboard_actions: Option<crate::text::KeyboardActions>,
287 pub interaction_source: Option<InteractionSource>,
289 pub line_limits: Option<crate::text::TextFieldLineLimits>,
291}
292
293impl std::fmt::Debug for TextInputConfig {
294 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
295 let mut s = f.debug_struct("TextInputConfig");
296 s.field("hint", &self.hint);
297 s.field("multiline", &self.multiline);
298 if self.on_change.is_some() {
299 s.field("on_change", &"…");
300 }
301 if self.on_submit.is_some() {
302 s.field("on_submit", &"…");
303 }
304 if self.focus_tracker.is_some() {
305 s.field("focus_tracker", &"…");
306 }
307 s.field("value", &self.value);
308 if self.visual_transformation.is_some() {
309 s.field("visual_transformation", &"…");
310 }
311 s.field("keyboard_type", &self.keyboard_type);
312 s.field("capitalization", &self.capitalization);
313 s.field("ime_action", &self.ime_action);
314 s.field("auto_correct_enabled", &self.auto_correct_enabled);
315 s.field("enabled", &self.enabled);
316 s.field("read_only", &self.read_only);
317 s.field("max_lines", &self.max_lines);
318 s.field("min_lines", &self.min_lines);
319 s.field("cursor_color", &self.cursor_color);
320 if self.on_text_layout.is_some() {
321 s.field("on_text_layout", &"…");
322 }
323 s.finish()
324 }
325}
326
327#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
330pub enum IntrinsicSize {
331 Min,
332 Max,
333}
334
335static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
336
337pub type PressId = u64;
339
340#[derive(Clone, Copy, Debug, PartialEq)]
348pub enum Interaction {
349 Press(PressId, Vec2),
352 Release(PressId),
354 Cancel(PressId),
357 HoverEnter,
358 HoverLeave,
359 Focus,
360 Unfocus,
361 DragStart,
362 DragStop,
363 DragCancel,
364}
365
366impl Interaction {
367 #[inline]
369 pub fn new_press(position: Vec2) -> Self {
370 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
371 }
372}
373
374#[derive(Clone)]
381pub struct InteractionSource {
382 pub(crate) state: Rc<RefCell<InteractionState>>,
383}
384
385impl InteractionSource {
386 pub fn collect_is_pressed(&self) -> bool {
387 self.state.borrow().pressed > 0
388 }
389 pub fn collect_is_hovered(&self) -> bool {
390 self.state.borrow().hovered
391 }
392 pub fn collect_is_focused(&self) -> bool {
393 self.state.borrow().focused
394 }
395 pub fn collect_is_dragged(&self) -> bool {
396 self.state.borrow().dragged > 0
397 }
398 pub fn collect_last_press_position(&self) -> Option<Vec2> {
399 self.state.borrow().last_press_position
400 }
401 pub fn collect_last_press_id(&self) -> Option<PressId> {
402 self.state.borrow().last_press_id
403 }
404 pub fn stable_id(&self) -> *const () {
406 Rc::as_ptr(&self.state) as *const ()
407 }
408 pub fn to_mutable(&self) -> MutableInteractionSource {
412 MutableInteractionSource {
413 state: self.state.clone(),
414 }
415 }
416}
417
418#[derive(Clone)]
428pub struct MutableInteractionSource {
429 pub(crate) state: Rc<RefCell<InteractionState>>,
430}
431
432impl std::fmt::Debug for MutableInteractionSource {
433 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
434 f.debug_struct("MutableInteractionSource")
435 .finish_non_exhaustive()
436 }
437}
438
439impl MutableInteractionSource {
440 pub fn new() -> Self {
441 Self {
442 state: Rc::new(RefCell::new(InteractionState::default())),
443 }
444 }
445
446 pub fn emit(&self, interaction: Interaction) {
448 let mut s = self.state.borrow_mut();
449 match interaction {
450 Interaction::Press(id, pos) => {
451 s.pressed = s.pressed.saturating_add(1);
452 s.last_press_id = Some(id);
453 s.last_press_position = Some(pos);
454 }
455 Interaction::Release(_) | Interaction::Cancel(_) => {
456 s.pressed = s.pressed.saturating_sub(1);
457 }
458 Interaction::HoverEnter => s.hovered = true,
459 Interaction::HoverLeave => {
460 s.hovered = false;
461 }
463 Interaction::Focus => s.focused = true,
464 Interaction::Unfocus => s.focused = false,
465 Interaction::DragStart => s.dragged = s.dragged.saturating_add(1),
466 Interaction::DragStop | Interaction::DragCancel => {
467 s.dragged = s.dragged.saturating_sub(1);
468 }
469 }
470 drop(s);
471 crate::frame_clock::request_frame();
473 }
474
475 pub fn source(&self) -> InteractionSource {
477 InteractionSource {
478 state: self.state.clone(),
479 }
480 }
481}
482
483impl Default for MutableInteractionSource {
484 fn default() -> Self {
485 Self::new()
486 }
487}
488
489#[derive(Clone, Default)]
490pub(crate) struct InteractionState {
491 pressed: u32,
492 hovered: bool,
493 focused: bool,
494 dragged: u32,
495 pub(crate) last_press_position: Option<Vec2>,
497 pub(crate) last_press_id: Option<PressId>,
499}
500
501#[derive(Clone, Default)]
502pub struct Modifier {
503 pub key: Option<u64>,
509
510 pub size: Option<Size>,
511 pub width: Option<f32>,
512 pub height: Option<f32>,
513 pub required_size: Option<Size>,
514 pub fill_max: Option<f32>,
515 pub fill_max_w: Option<f32>,
516 pub fill_max_h: Option<f32>,
517 pub padding: Option<f32>,
518 pub padding_values: Option<PaddingValues>,
519 pub min_width: Option<f32>,
520 pub min_height: Option<f32>,
521 pub max_width: Option<f32>,
522 pub max_height: Option<f32>,
523 pub required_min_width: Option<f32>,
525 pub required_max_width: Option<f32>,
527 pub required_min_height: Option<f32>,
529 pub required_max_height: Option<f32>,
531 pub default_min_width: Option<f32>,
534 pub default_min_height: Option<f32>,
535 pub background: Option<Brush>,
536 pub state_colors: Option<StateColors>,
537 pub state_elevation: Option<StateElevation>,
538
539 pub border: Option<Border>,
540 pub flex_grow: Option<f32>,
541 pub flex_shrink: Option<f32>,
542 pub flex_basis: Option<f32>,
543 pub flex_wrap: Option<FlexWrap>,
544 pub flex_dir: Option<FlexDirection>,
545 pub gap: Option<f32>,
546 pub row_gap: Option<f32>,
547 pub column_gap: Option<f32>,
548 pub align_self: Option<AlignSelf>,
549 pub justify_content: Option<JustifyContent>,
550 pub align_items_container: Option<AlignItems>,
551 pub align_content: Option<AlignContent>,
552 pub clip_rounded: Option<[f32; 4]>,
553 pub clip_rect: Option<ClipRect>,
556 pub overflow: Option<Overflow>,
561 pub z_index: f32,
563 pub render_z_index: Option<f32>,
565 pub hit_passthrough: bool,
567 pub input_blocker: bool,
569 pub repaint_boundary: bool,
570 pub click: bool,
571 pub disabled: bool,
573 pub focusable: Option<bool>,
577 pub propagate_min: bool,
579 pub focus_group: bool,
582 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
583 pub scroll: Option<crate::scroll::ScrollBinding>,
589 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
598 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
599 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
600 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
601 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
602 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
603 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
604 pub on_click: Option<Rc<dyn Fn()>>,
606 pub on_double_click: Option<Rc<dyn Fn()>>,
608 pub on_long_click: Option<Rc<dyn Fn()>>,
610 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
613 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
616 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
619 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
622 pub blur: Option<BlurStyle>,
627 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (f32, f32)>>,
632 pub semantics: Option<crate::Semantics>,
633 pub alpha: Option<f32>,
634 pub graphics_layer: Option<f32>,
635 pub shadow: Option<ShadowSpec>,
636 pub transform: Option<Transform>,
637 pub grid: Option<GridConfig>,
638 pub grid_col_span: Option<u16>,
639 pub grid_row_span: Option<u16>,
640 pub position_type: Option<PositionType>,
641 pub offset_left: Option<f32>,
642 pub offset_right: Option<f32>,
643 pub offset_top: Option<f32>,
644 pub offset_bottom: Option<f32>,
645
646 pub margin_left: Option<f32>,
647 pub margin_right: Option<f32>,
648 pub margin_top: Option<f32>,
649 pub margin_bottom: Option<f32>,
650 pub aspect_ratio: Option<f32>,
651 pub intrinsic_width: Option<IntrinsicSize>,
653 pub intrinsic_height: Option<IntrinsicSize>,
655 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
656
657 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
659 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
660 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
661 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
662 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
663 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
664 pub drag_preview: Option<crate::dnd::DragPreview>,
666
667 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
668
669 pub cursor: Option<crate::CursorIcon>,
671
672 pub animate_content_size: Option<AnimationSpec>,
675
676 pub focus_requester: Option<crate::runtime::FocusRequester>,
680
681 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
684
685 pub interaction_source: Option<InteractionSource>,
692
693 pub text_input: Option<TextInputConfig>,
695
696 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
698}
699
700impl std::fmt::Debug for Modifier {
701 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
702 let mut s = f.debug_struct("Modifier");
703
704 macro_rules! opt_val {
705 ($($name:ident),+ $(,)?) => {
706 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
707 };
708 }
709 if self.indication.is_some() {
710 s.field("indication", &"…");
711 }
712
713 opt_val!(
714 key,
715 size,
716 width,
717 height,
718 required_size,
719 padding,
720 padding_values,
721 min_width,
722 min_height,
723 max_width,
724 max_height,
725 required_min_width,
726 required_max_width,
727 required_min_height,
728 required_max_height,
729 default_min_width,
730 default_min_height,
731 fill_max,
732 fill_max_w,
733 fill_max_h,
734 background,
735 state_colors,
736 state_elevation,
737 border,
738 flex_grow,
739 flex_shrink,
740 flex_basis,
741 flex_wrap,
742 flex_dir,
743 gap,
744 row_gap,
745 column_gap,
746 align_self,
747 justify_content,
748 align_items_container,
749 align_content,
750 clip_rounded,
751 clip_rect,
752 render_z_index,
753 semantics,
754 alpha,
755 transform,
756 grid,
757 grid_col_span,
758 grid_row_span,
759 position_type,
760 offset_left,
761 offset_right,
762 offset_top,
763 offset_bottom,
764 margin_left,
765 margin_right,
766 margin_top,
767 margin_bottom,
768 aspect_ratio,
769 intrinsic_width,
770 intrinsic_height,
771 cursor,
772 animate_content_size,
773 blur,
774 );
775
776 macro_rules! opt_cb {
777 ($($name:ident),+ $(,)?) => {
778 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
779 };
780 }
781 opt_cb!(
782 on_scroll,
783 scroll,
784 nested_scroll_connection,
785 on_pointer_down,
786 on_pointer_move,
787 on_pointer_up,
788 on_pointer_cancel,
789 on_pointer_enter,
790 on_pointer_leave,
791 on_click,
792 on_double_click,
793 on_long_click,
794 on_globally_positioned,
795 on_size_changed,
796 on_key_event,
797 on_preview_key_event,
798 painter,
799 on_drag_start,
800 on_drag_end,
801 on_drag_enter,
802 on_drag_over,
803 on_drag_leave,
804 on_drop,
805 drag_preview,
806 on_action,
807 on_focus_changed,
808 interaction_source,
809 text_input,
810 layout,
811 );
812
813 macro_rules! flag {
814 ($($name:ident),+ $(,)?) => {
815 $( if self.$name { s.field(stringify!($name), &true); } )+
816 };
817 }
818 flag!(
819 hit_passthrough,
820 input_blocker,
821 repaint_boundary,
822 click,
823 disabled,
824 propagate_min,
825 focus_group,
826 );
827
828 if let Some(f) = self.focusable {
829 s.field("focusable", &f);
830 }
831 if self.z_index != 0.0 {
832 s.field("z_index", &self.z_index);
833 }
834
835 s.finish()
836 }
837}
838
839impl_option_fields!(Modifier);
840
841#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
845pub enum Alignment {
846 TopStart,
847 TopCenter,
848 TopEnd,
849 CenterStart,
850 #[default]
851 Center,
852 CenterEnd,
853 BottomStart,
854 BottomCenter,
855 BottomEnd,
856}
857
858impl Alignment {
859 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
861 use AlignItems as AI;
862 use JustifyContent as JC;
863 match self {
864 Self::TopStart => (AI::START, JC::START),
865 Self::TopCenter => (AI::START, JC::CENTER),
866 Self::TopEnd => (AI::START, JC::END),
867 Self::CenterStart => (AI::CENTER, JC::START),
868 Self::Center => (AI::CENTER, JC::CENTER),
869 Self::CenterEnd => (AI::CENTER, JC::END),
870 Self::BottomStart => (AI::END, JC::START),
871 Self::BottomCenter => (AI::END, JC::CENTER),
872 Self::BottomEnd => (AI::END, JC::END),
873 }
874 }
875}
876
877impl Modifier {
878 pub fn new() -> Self {
879 Self::default()
880 }
881
882 pub fn key(mut self, key: u64) -> Self {
885 self.key = Some(key);
886 self
887 }
888
889 pub fn size(mut self, w: f32, h: f32) -> Self {
890 self.size = Some(Size {
891 width: w,
892 height: h,
893 });
894 self
895 }
896 pub fn width(mut self, w: f32) -> Self {
897 self.width = Some(w);
898 self
899 }
900 pub fn height(mut self, h: f32) -> Self {
901 self.height = Some(h);
902 self
903 }
904 pub fn required_size(mut self, w: f32, h: f32) -> Self {
909 self.required_size = Some(Size {
910 width: w,
911 height: h,
912 });
913 self
914 }
915 pub fn required_width_in(mut self, min: f32, max: f32) -> Self {
916 self.required_min_width = Some(min.max(0.0));
917 self.required_max_width = Some(max.max(0.0));
918 self
919 }
920 pub fn required_height_in(mut self, min: f32, max: f32) -> Self {
921 self.required_min_height = Some(min.max(0.0));
922 self.required_max_height = Some(max.max(0.0));
923 self
924 }
925 pub fn required_min_width(mut self, w: f32) -> Self {
926 self.required_min_width = Some(w.max(0.0));
927 self
928 }
929 pub fn required_max_width(mut self, w: f32) -> Self {
930 self.required_max_width = Some(w.max(0.0));
931 self
932 }
933 pub fn required_min_height(mut self, h: f32) -> Self {
934 self.required_min_height = Some(h.max(0.0));
935 self
936 }
937 pub fn required_max_height(mut self, h: f32) -> Self {
938 self.required_max_height = Some(h.max(0.0));
939 self
940 }
941 pub fn default_min_size(mut self, w: f32, h: f32) -> Self {
943 self.default_min_width = Some(w.max(0.0));
944 self.default_min_height = Some(h.max(0.0));
945 self
946 }
947 pub fn fill_max_size(mut self) -> Self {
950 self.fill_max = Some(1.0);
951 self
952 }
953 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
954 self.fill_max = Some(fraction.clamp(0.0, 1.0));
955 self
956 }
957 pub fn fill_max_width(mut self) -> Self {
959 self.fill_max_w = Some(1.0);
960 self
961 }
962 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
963 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
964 self
965 }
966 pub fn fill_max_height(mut self) -> Self {
968 self.fill_max_h = Some(1.0);
969 self
970 }
971 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
972 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
973 self
974 }
975 pub fn padding(mut self, v: f32) -> Self {
976 self.padding = Some(v);
977 self
978 }
979 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
980 self.padding_values = Some(padding);
981 self
982 }
983 pub fn ime_padding(mut self) -> Self {
986 let insets = crate::locals::window_insets();
987 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
988 let mut p = self.padding_values.unwrap_or_default();
989 p.bottom += insets.ime_bottom / scale;
990 self.padding_values = Some(p);
991 self
992 }
993 pub fn system_bars_padding(mut self) -> Self {
995 let insets = crate::locals::window_insets();
996 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
997 let mut p = self.padding_values.unwrap_or_default();
998 p.top += insets.top / scale;
999 p.bottom += insets.bottom / scale;
1000 self.padding_values = Some(p);
1001 self
1002 }
1003 pub fn status_bars_padding(mut self) -> Self {
1005 let insets = crate::locals::window_insets();
1006 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
1007 let mut p = self.padding_values.unwrap_or_default();
1008 p.top += insets.top / scale;
1009 self.padding_values = Some(p);
1010 self
1011 }
1012 pub fn navigation_bars_padding(mut self) -> Self {
1014 let insets = crate::locals::window_insets();
1015 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
1016 let mut p = self.padding_values.unwrap_or_default();
1017 p.bottom += insets.bottom / scale;
1018 self.padding_values = Some(p);
1019 self
1020 }
1021 pub fn min_size(mut self, w: f32, h: f32) -> Self {
1022 self.min_width = Some(w);
1023 self.min_height = Some(h);
1024 self
1025 }
1026 pub fn max_size(mut self, w: f32, h: f32) -> Self {
1027 self.max_width = Some(w);
1028 self.max_height = Some(h);
1029 self
1030 }
1031 pub fn min_width(mut self, w: f32) -> Self {
1032 self.min_width = Some(w);
1033 self
1034 }
1035 pub fn min_height(mut self, h: f32) -> Self {
1036 self.min_height = Some(h);
1037 self
1038 }
1039 pub fn max_width(mut self, w: f32) -> Self {
1040 self.max_width = Some(w);
1041 self
1042 }
1043 pub fn max_height(mut self, h: f32) -> Self {
1044 self.max_height = Some(h);
1045 self
1046 }
1047 pub fn background(mut self, color: Color) -> Self {
1049 self.background = Some(Brush::Solid(color));
1050 self
1051 }
1052 pub fn background_brush(mut self, brush: Brush) -> Self {
1054 self.background = Some(brush);
1055 self
1056 }
1057 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
1058 self.border = Some(Border {
1059 width,
1060 color,
1061 radius: [radius; 4],
1062 });
1063 self
1064 }
1065 pub fn border_radii(mut self, width: f32, color: Color, radii: [f32; 4]) -> Self {
1066 self.border = Some(Border {
1067 width,
1068 color,
1069 radius: radii,
1070 });
1071 self
1072 }
1073 pub fn flex_grow(mut self, v: f32) -> Self {
1074 self.flex_grow = Some(v);
1075 self
1076 }
1077 pub fn flex_shrink(mut self, v: f32) -> Self {
1078 self.flex_shrink = Some(v);
1079 self
1080 }
1081 pub fn flex_basis(mut self, v: f32) -> Self {
1082 self.flex_basis = Some(v);
1083 self
1084 }
1085 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1086 self.flex_wrap = Some(w);
1087 self
1088 }
1089 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1090 self.flex_dir = Some(d);
1091 self
1092 }
1093 pub fn gap(mut self, v: f32) -> Self {
1094 let v = v.max(0.0);
1095 self.gap = Some(v);
1096 self.row_gap = Some(v);
1097 self.column_gap = Some(v);
1098 self
1099 }
1100 pub fn row_gap(mut self, v: f32) -> Self {
1101 self.row_gap = Some(v.max(0.0));
1102 self
1103 }
1104 pub fn column_gap(mut self, v: f32) -> Self {
1105 self.column_gap = Some(v.max(0.0));
1106 self
1107 }
1108 pub fn align_self(mut self, a: AlignSelf) -> Self {
1109 self.align_self = Some(a);
1110 self
1111 }
1112 pub fn align_self_center(mut self) -> Self {
1113 self.align_self = Some(AlignSelf::CENTER);
1114 self
1115 }
1116 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1117 self.justify_content = Some(j);
1118 self
1119 }
1120 pub fn align_items(mut self, a: AlignItems) -> Self {
1121 self.align_items_container = Some(a);
1122 self
1123 }
1124 pub fn content_alignment(self, alignment: Alignment) -> Self {
1127 let (ai, jc) = alignment.to_flex();
1128 self.align_items(ai).justify_content(jc)
1129 }
1130 pub fn align_content(mut self, a: AlignContent) -> Self {
1131 self.align_content = Some(a);
1132 self
1133 }
1134 pub fn clip_rounded(mut self, radius: f32) -> Self {
1135 self.clip_rounded = Some([radius; 4]);
1136 self
1137 }
1138 pub fn clip_rounded_radii(mut self, radii: [f32; 4]) -> Self {
1139 self.clip_rounded = Some(radii);
1140 self
1141 }
1142 pub fn clip_rect(mut self, left: f32, top: f32, right: f32, bottom: f32, op: ClipOp) -> Self {
1145 self.clip_rect = Some(ClipRect {
1146 left,
1147 top,
1148 right,
1149 bottom,
1150 op,
1151 });
1152 self
1153 }
1154 pub fn overflow(mut self, overflow: Overflow) -> Self {
1155 self.overflow = Some(overflow);
1156 self
1157 }
1158 pub fn z_index(mut self, z: f32) -> Self {
1159 self.z_index = z;
1160 self
1161 }
1162
1163 pub fn render_z_index(mut self, z: f32) -> Self {
1166 self.render_z_index = Some(z);
1167 self
1168 }
1169
1170 pub fn input_blocker(mut self) -> Self {
1172 self.input_blocker = true;
1173 self
1174 }
1175
1176 pub fn hit_passthrough(mut self) -> Self {
1177 self.hit_passthrough = true;
1178 self
1179 }
1180 pub fn clickable(mut self) -> Self {
1181 self.click = true;
1182 self
1183 }
1184 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1187 self.click = true;
1188 self.interaction_source = Some(source.source());
1189 self
1190 }
1191 pub fn state_colors(mut self, colors: StateColors) -> Self {
1194 self.state_colors = Some(colors);
1195 self
1196 }
1197 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1199 self.state_elevation = Some(elev);
1200 self
1201 }
1202 pub fn disabled(mut self) -> Self {
1204 self.disabled = true;
1205 self
1206 }
1207 pub fn enabled(mut self, enabled: bool) -> Self {
1209 self.disabled = !enabled;
1210 self
1211 }
1212 pub fn focusable(mut self, focusable: bool) -> Self {
1217 self.focusable = Some(focusable);
1218 self
1219 }
1220 pub fn focus_group(mut self) -> Self {
1223 self.focus_group = true;
1224 self
1225 }
1226 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1237 self.interaction_source = Some(source.source());
1238 self
1239 }
1240 pub fn hoverable(
1243 mut self,
1244 on_enter: impl Fn() + 'static,
1245 on_leave: impl Fn() + 'static,
1246 ) -> Self {
1247 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1248 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1249 self
1250 }
1251 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1255 self.interaction_source = Some(source.source());
1256 self
1257 }
1258 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1261 self.propagate_min = propagate;
1262 self
1263 }
1264 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1265 self.on_scroll = Some(Rc::new(f));
1266 self
1267 }
1268 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1272 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1273 self
1274 }
1275 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1277 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1278 self
1279 }
1280 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1282 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1283 self
1284 }
1285 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1292 self.nested_scroll_connection = Some(conn);
1293 self
1294 }
1295 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1296 self.on_pointer_down = Some(Rc::new(f));
1297 self
1298 }
1299 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1300 self.on_pointer_move = Some(Rc::new(f));
1301 self
1302 }
1303 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1304 self.on_pointer_up = Some(Rc::new(f));
1305 self
1306 }
1307 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1308 self.on_pointer_cancel = Some(Rc::new(f));
1309 self
1310 }
1311 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1312 self.on_pointer_enter = Some(Rc::new(f));
1313 self
1314 }
1315 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1316 self.on_pointer_leave = Some(Rc::new(f));
1317 self
1318 }
1319 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1320 self.on_click = Some(Rc::new(f));
1321 self.click = true;
1322 self
1323 }
1324 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1325 self.on_double_click = Some(Rc::new(f));
1326 self
1327 }
1328 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1329 self.on_long_click = Some(Rc::new(f));
1330 self
1331 }
1332 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1333 self.semantics = Some(s);
1334 self
1335 }
1336 pub fn alpha(mut self, a: f32) -> Self {
1337 self.alpha = Some(a);
1338 self
1339 }
1340 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1345 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1346 self
1347 }
1348 pub fn shadow(mut self, blur_radius: f32, offset_y: f32) -> Self {
1352 self.shadow = Some(ShadowSpec {
1353 blur_radius: blur_radius.max(0.0),
1354 offset_y,
1355 color: Color(0, 0, 0, 64),
1356 });
1357 self
1358 }
1359 pub fn shadow_with_color(mut self, blur_radius: f32, offset_y: f32, color: Color) -> Self {
1361 self.shadow = Some(ShadowSpec {
1362 blur_radius: blur_radius.max(0.0),
1363 offset_y,
1364 color,
1365 });
1366 self
1367 }
1368 pub fn elevation(mut self, level: f32) -> Self {
1372 if level <= 0.0 {
1373 self.shadow = None;
1374 return self;
1375 }
1376 self.shadow = Some(ShadowSpec {
1377 blur_radius: level * 2.0,
1378 offset_y: level * 0.5,
1379 color: Color(0, 0, 0, (level * 8.0).clamp(8.0, 80.0) as u8),
1380 });
1381 self
1382 }
1383 pub fn transform(mut self, t: Transform) -> Self {
1384 self.transform = Some(t);
1385 self
1386 }
1387 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
1388 self.grid = Some(GridConfig {
1389 columns,
1390 row_gap,
1391 column_gap,
1392 });
1393 self
1394 }
1395 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1396 self.grid_col_span = Some(col_span);
1397 self.grid_row_span = Some(row_span);
1398 self
1399 }
1400 pub fn absolute(mut self) -> Self {
1401 self.position_type = Some(PositionType::Absolute);
1402 self
1403 }
1404 pub fn offset(
1405 mut self,
1406 left: Option<f32>,
1407 top: Option<f32>,
1408 right: Option<f32>,
1409 bottom: Option<f32>,
1410 ) -> Self {
1411 self.offset_left = left;
1412 self.offset_top = top;
1413 self.offset_right = right;
1414 self.offset_bottom = bottom;
1415 self
1416 }
1417 pub fn offset_left(mut self, v: f32) -> Self {
1418 self.offset_left = Some(v);
1419 self
1420 }
1421 pub fn offset_right(mut self, v: f32) -> Self {
1422 self.offset_right = Some(v);
1423 self
1424 }
1425 pub fn offset_top(mut self, v: f32) -> Self {
1426 self.offset_top = Some(v);
1427 self
1428 }
1429 pub fn offset_bottom(mut self, v: f32) -> Self {
1430 self.offset_bottom = Some(v);
1431 self
1432 }
1433 pub fn margin(mut self, v: f32) -> Self {
1434 self.margin_left = Some(v);
1435 self.margin_right = Some(v);
1436 self.margin_top = Some(v);
1437 self.margin_bottom = Some(v);
1438 self
1439 }
1440
1441 pub fn margin_horizontal(mut self, v: f32) -> Self {
1442 self.margin_left = Some(v);
1443 self.margin_right = Some(v);
1444 self
1445 }
1446
1447 pub fn margin_vertical(mut self, v: f32) -> Self {
1448 self.margin_top = Some(v);
1449 self.margin_bottom = Some(v);
1450 self
1451 }
1452 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1453 self.aspect_ratio = Some(ratio);
1454 self
1455 }
1456 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1458 self.intrinsic_width = Some(mode);
1459 self
1460 }
1461 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1463 self.intrinsic_height = Some(mode);
1464 self
1465 }
1466 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1467 self.painter = Some(Rc::new(f));
1468 self
1469 }
1470 pub fn scale(self, s: f32) -> Self {
1471 self.scale2(s, s)
1472 }
1473 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1474 let mut t = self.transform.unwrap_or_else(Transform::identity);
1475 t.scale_x *= sx;
1476 t.scale_y *= sy;
1477 self.transform = Some(t);
1478 self
1479 }
1480 pub fn translate(mut self, x: f32, y: f32) -> Self {
1481 let t = self.transform.unwrap_or_else(Transform::identity);
1482 self.transform = Some(t.combine(&Transform::translate(x, y)));
1483 self
1484 }
1485 pub fn translate_vec2(self, v: Vec2) -> Self {
1486 self.translate(v.x, v.y)
1487 }
1488 pub fn rotate(mut self, radians: f32) -> Self {
1489 let mut t = self.transform.unwrap_or_else(Transform::identity);
1490 t.rotate += radians;
1491 self.transform = Some(t);
1492 self
1493 }
1494 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1495 let mut t = self.transform.unwrap_or_else(Transform::identity);
1496 t.origin_x = x;
1497 t.origin_y = y;
1498 self.transform = Some(t);
1499 self
1500 }
1501 pub fn weight(mut self, w: f32) -> Self {
1502 let w = w.max(0.0);
1503 self.flex_grow = Some(w);
1504 self.flex_shrink = Some(1.0);
1505 self.flex_basis = Some(0.0);
1507 self
1508 }
1509 pub fn repaint_boundary(mut self) -> Self {
1513 self.repaint_boundary = true;
1514 self
1515 }
1516 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1517 self.on_action = Some(Rc::new(f));
1518 self
1519 }
1520
1521 pub fn on_drag_start(
1523 mut self,
1524 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1525 ) -> Self {
1526 self.on_drag_start = Some(Rc::new(f));
1527 self
1528 }
1529
1530 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1532 self.on_drag_end = Some(Rc::new(f));
1533 self
1534 }
1535
1536 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1538 self.on_drag_enter = Some(Rc::new(f));
1539 self
1540 }
1541
1542 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1544 self.on_drag_over = Some(Rc::new(f));
1545 self
1546 }
1547
1548 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1550 self.on_drag_leave = Some(Rc::new(f));
1551 self
1552 }
1553
1554 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1557 self.on_drop = Some(Rc::new(f));
1558 self
1559 }
1560
1561 pub fn draw_drag_decoration(
1566 mut self,
1567 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
1568 ) -> Self {
1569 self.drag_preview = Some(Rc::new(f));
1570 self
1571 }
1572
1573 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
1575 self.drag_preview = Some(preview);
1576 self
1577 }
1578
1579 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
1581 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
1582 }
1583
1584 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
1586 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
1587 }
1588
1589 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1591 self.cursor = Some(c);
1592 self
1593 }
1594
1595 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1599 self.animate_content_size = Some(spec);
1600 self
1601 }
1602
1603 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1606 self.focus_requester = Some(fr);
1607 self
1608 }
1609
1610 pub fn focus_target(mut self) -> Self {
1613 self.focusable = Some(true);
1614 self
1615 }
1616
1617 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1620 self.on_focus_changed = Some(Rc::new(f));
1621 self
1622 }
1623
1624 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
1628 self.on_globally_positioned = Some(Rc::new(f));
1629 self
1630 }
1631
1632 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
1635 self.on_size_changed = Some(Rc::new(f));
1636 self
1637 }
1638
1639 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
1643 self.on_key_event = Some(Rc::new(f));
1644 self
1645 }
1646
1647 pub fn on_preview_key_event(
1651 mut self,
1652 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
1653 ) -> Self {
1654 self.on_preview_key_event = Some(Rc::new(f));
1655 self
1656 }
1657
1658 pub fn blur(mut self, radius_dp: f32) -> Self {
1665 self.blur = Some(BlurStyle {
1666 radius_x: radius_dp.max(0.0),
1667 radius_y: radius_dp.max(0.0),
1668 edge_treatment: BlurredEdgeTreatment::Rectangle,
1669 });
1670 self
1671 }
1672
1673 pub fn blur_with_edge(
1678 mut self,
1679 radius_x: f32,
1680 radius_y: f32,
1681 edge_treatment: BlurredEdgeTreatment,
1682 ) -> Self {
1683 self.blur = Some(BlurStyle {
1684 radius_x: radius_x.max(0.0),
1685 radius_y: radius_y.max(0.0),
1686 edge_treatment,
1687 });
1688 self
1689 }
1690
1691 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (f32, f32) + 'static) -> Self {
1699 self.layout = Some(Rc::new(f));
1700 self
1701 }
1702
1703 pub fn text_input(mut self, config: TextInputConfig) -> Self {
1705 self.text_input = Some(config);
1706 self
1707 }
1708
1709 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
1713 self.indication = Some(factory);
1714 self
1715 }
1716}