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)]
15pub struct StateColors {
16 pub default: Color,
17 pub hovered: Color,
18 pub pressed: Color,
19 pub disabled: Color,
20 pub dragged: Color,
22}
23
24#[derive(Clone, Copy, Debug)]
26pub struct StateElevation {
27 pub default: f32,
28 pub hovered: f32,
29 pub pressed: f32,
30 pub disabled: f32,
31 pub dragged: f32,
33}
34
35macro_rules! merge_opts {
36 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
37 $( $dst.$f = $src.$f.or($dst.$f); )+
38 };
39}
40macro_rules! merge_flags {
41 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
42 $( $dst.$f |= $src.$f; )+
43 };
44}
45
46macro_rules! impl_option_fields {
47 ($ty:ty, $fn:ident) => {
48 impl $ty {
49 $fn!(replace);
50 }
51 };
52 ($ty:ident) => {
53 impl $ty {
54 pub fn then(mut self, other: Self) -> Self {
57 merge_opts!(self, other;
58 key, size, width, height, required_size,
59 padding, padding_values,
60 min_width, min_height, max_width, max_height,
61 required_min_width, required_max_width,
62 required_min_height, required_max_height,
63 default_min_width, default_min_height,
64 fill_max, fill_max_w, fill_max_h,
65 background, state_colors, state_elevation, border,
66 flex_grow, flex_shrink, flex_basis, flex_wrap, flex_dir,
67 gap, row_gap, column_gap,
68 align_self, justify_content, align_items_container, align_content,
69 clip_rounded, clip_rect, overflow, render_z_index,
70 on_scroll,
71 nested_scroll_connection,
72 scroll,
73 on_pointer_down, on_pointer_move, on_pointer_up,
74 on_pointer_enter, on_pointer_leave,
75 on_click, on_double_click, on_long_click,
76 semantics, alpha, transform,
77 grid, grid_col_span, grid_row_span,
78 position_type,
79 offset_left, offset_right, offset_top, offset_bottom,
80 margin_left, margin_right, margin_top, margin_bottom,
81 aspect_ratio, intrinsic_width, intrinsic_height,
82 painter,
83 on_drag_start, on_drag_end, on_drag_enter, on_drag_over, on_drag_leave, on_drop,
84 drag_preview,
85 on_action, cursor, animate_content_size, focus_requester, on_focus_changed,
86 interaction_source, text_input,
87 );
88 merge_flags!(self, other;
89 hit_passthrough, input_blocker, repaint_boundary, click, disabled,
90 propagate_min, focus_group,
91 );
92
93 if let Some(f) = other.focusable {
94 self.focusable = Some(f);
95 }
96 if other.indication.is_some() {
97 self.indication = other.indication;
98 }
99 if other.z_index != 0.0 {
100 self.z_index = other.z_index;
101 }
102 self
103 }
104 }
105 };
106}
107
108#[derive(Clone, Copy, Debug, PartialEq, Eq)]
109pub enum ClipOp {
110 Intersect,
112 Difference,
114}
115
116impl Default for ClipOp {
117 fn default() -> Self {
118 Self::Intersect
119 }
120}
121
122#[derive(Clone, Copy, Debug, PartialEq, Eq)]
128pub enum Overflow {
129 Clip,
130 Visible,
131}
132
133impl Default for Overflow {
134 fn default() -> Self {
135 Self::Clip
136 }
137}
138
139#[derive(Clone, Copy, Debug)]
142pub struct ClipRect {
143 pub left: f32,
144 pub top: f32,
145 pub right: f32,
146 pub bottom: f32,
147 pub op: ClipOp,
148}
149
150#[derive(Clone, Debug)]
151pub struct Border {
152 pub width: f32,
153 pub color: Color,
154 pub radius: [f32; 4],
155}
156
157#[derive(Clone, Copy, Debug, Default)]
158pub struct PaddingValues {
159 pub left: f32,
160 pub right: f32,
161 pub top: f32,
162 pub bottom: f32,
163}
164
165#[derive(Clone, Debug)]
166pub struct GridConfig {
167 pub columns: usize,
168 pub row_gap: f32,
169 pub column_gap: f32,
170}
171
172#[derive(Clone, Copy, Debug, PartialEq)]
175pub enum BlurredEdgeTreatment {
176 Rectangle,
179 Unbounded,
182}
183
184#[derive(Clone, Copy, Debug)]
186pub struct BlurStyle {
187 pub radius_x: f32,
189 pub radius_y: f32,
191 pub edge_treatment: BlurredEdgeTreatment,
193}
194
195#[derive(Clone, Copy, Debug)]
200pub struct LayoutConstraints {
201 pub min_width: f32,
202 pub max_width: f32,
203 pub min_height: f32,
204 pub max_height: f32,
205}
206
207#[derive(Clone, Copy, Debug)]
214pub struct ShadowSpec {
215 pub blur_radius: f32,
216 pub offset_y: f32,
217 pub color: Color,
218}
219
220#[derive(Clone, Copy, Debug)]
221#[non_exhaustive]
222pub enum PositionType {
223 Relative,
224 Absolute,
225}
226
227#[derive(Clone)]
229pub struct TextInputConfig {
230 pub hint: String,
231 pub multiline: bool,
232 pub on_change: Option<Rc<dyn Fn(String)>>,
233 pub on_submit: Option<Rc<dyn Fn(String)>>,
234 pub focus_tracker: Option<Rc<Cell<bool>>>,
235 pub value: String,
236 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
237 pub keyboard_type: crate::text::KeyboardType,
238 pub capitalization: crate::text::KeyboardCapitalization,
239 pub ime_action: crate::text::ImeAction,
240 pub enabled: bool,
242 pub read_only: bool,
244 pub max_lines: Option<usize>,
246 pub min_lines: usize,
248 pub cursor_color: Option<Color>,
250 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
253 pub text_style: Option<crate::text::TextStyle>,
256 pub keyboard_actions: Option<crate::text::KeyboardActions>,
259 pub interaction_source: Option<InteractionSource>,
261 pub line_limits: Option<crate::text::TextFieldLineLimits>,
263}
264
265impl std::fmt::Debug for TextInputConfig {
266 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267 let mut s = f.debug_struct("TextInputConfig");
268 s.field("hint", &self.hint);
269 s.field("multiline", &self.multiline);
270 if self.on_change.is_some() {
271 s.field("on_change", &"…");
272 }
273 if self.on_submit.is_some() {
274 s.field("on_submit", &"…");
275 }
276 if self.focus_tracker.is_some() {
277 s.field("focus_tracker", &"…");
278 }
279 s.field("value", &self.value);
280 if self.visual_transformation.is_some() {
281 s.field("visual_transformation", &"…");
282 }
283 s.field("keyboard_type", &self.keyboard_type);
284 s.field("capitalization", &self.capitalization);
285 s.field("ime_action", &self.ime_action);
286 s.field("enabled", &self.enabled);
287 s.field("read_only", &self.read_only);
288 s.field("max_lines", &self.max_lines);
289 s.field("min_lines", &self.min_lines);
290 s.field("cursor_color", &self.cursor_color);
291 if self.on_text_layout.is_some() {
292 s.field("on_text_layout", &"…");
293 }
294 s.finish()
295 }
296}
297
298#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
301pub enum IntrinsicSize {
302 Min,
303 Max,
304}
305
306static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
307
308pub type PressId = u64;
310
311#[derive(Clone, Copy, Debug, PartialEq)]
319pub enum Interaction {
320 Press(PressId, Vec2),
323 Release(PressId),
325 Cancel(PressId),
328 HoverEnter,
329 HoverLeave,
330 Focus,
331 Unfocus,
332 DragStart,
333 DragStop,
334 DragCancel,
335}
336
337impl Interaction {
338 #[inline]
340 pub fn new_press(position: Vec2) -> Self {
341 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
342 }
343}
344
345#[derive(Clone)]
352pub struct InteractionSource {
353 pub(crate) state: Rc<RefCell<InteractionState>>,
354}
355
356impl InteractionSource {
357 pub fn collect_is_pressed(&self) -> bool {
358 self.state.borrow().pressed > 0
359 }
360 pub fn collect_is_hovered(&self) -> bool {
361 self.state.borrow().hovered
362 }
363 pub fn collect_is_focused(&self) -> bool {
364 self.state.borrow().focused
365 }
366 pub fn collect_is_dragged(&self) -> bool {
367 self.state.borrow().dragged > 0
368 }
369 pub fn collect_last_press_position(&self) -> Option<Vec2> {
370 self.state.borrow().last_press_position
371 }
372 pub fn collect_last_press_id(&self) -> Option<PressId> {
373 self.state.borrow().last_press_id
374 }
375 pub fn stable_id(&self) -> *const () {
377 Rc::as_ptr(&self.state) as *const ()
378 }
379 pub fn to_mutable(&self) -> MutableInteractionSource {
383 MutableInteractionSource {
384 state: self.state.clone(),
385 }
386 }
387}
388
389#[derive(Clone)]
399pub struct MutableInteractionSource {
400 pub(crate) state: Rc<RefCell<InteractionState>>,
401}
402
403impl std::fmt::Debug for MutableInteractionSource {
404 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
405 f.debug_struct("MutableInteractionSource")
406 .finish_non_exhaustive()
407 }
408}
409
410impl MutableInteractionSource {
411 pub fn new() -> Self {
412 Self {
413 state: Rc::new(RefCell::new(InteractionState::default())),
414 }
415 }
416
417 pub fn emit(&self, interaction: Interaction) {
419 let mut s = self.state.borrow_mut();
420 match interaction {
421 Interaction::Press(id, pos) => {
422 s.pressed = s.pressed.saturating_add(1);
423 s.last_press_id = Some(id);
424 s.last_press_position = Some(pos);
425 }
426 Interaction::Release(_) | Interaction::Cancel(_) => {
427 s.pressed = s.pressed.saturating_sub(1);
428 }
429 Interaction::HoverEnter => s.hovered = true,
430 Interaction::HoverLeave => s.hovered = false,
431 Interaction::Focus => s.focused = true,
432 Interaction::Unfocus => s.focused = false,
433 Interaction::DragStart => s.dragged = s.dragged.saturating_add(1),
434 Interaction::DragStop | Interaction::DragCancel => {
435 s.dragged = s.dragged.saturating_sub(1);
436 }
437 }
438 }
439
440 pub fn source(&self) -> InteractionSource {
442 InteractionSource {
443 state: self.state.clone(),
444 }
445 }
446}
447
448impl Default for MutableInteractionSource {
449 fn default() -> Self {
450 Self::new()
451 }
452}
453
454#[derive(Clone, Default)]
455pub(crate) struct InteractionState {
456 pressed: u32,
457 hovered: bool,
458 focused: bool,
459 dragged: u32,
460 pub(crate) last_press_position: Option<Vec2>,
462 pub(crate) last_press_id: Option<PressId>,
464}
465
466#[derive(Clone, Default)]
467pub struct Modifier {
468 pub key: Option<u64>,
474
475 pub size: Option<Size>,
476 pub width: Option<f32>,
477 pub height: Option<f32>,
478 pub required_size: Option<Size>,
479 pub fill_max: Option<f32>,
480 pub fill_max_w: Option<f32>,
481 pub fill_max_h: Option<f32>,
482 pub padding: Option<f32>,
483 pub padding_values: Option<PaddingValues>,
484 pub min_width: Option<f32>,
485 pub min_height: Option<f32>,
486 pub max_width: Option<f32>,
487 pub max_height: Option<f32>,
488 pub required_min_width: Option<f32>,
490 pub required_max_width: Option<f32>,
492 pub required_min_height: Option<f32>,
494 pub required_max_height: Option<f32>,
496 pub default_min_width: Option<f32>,
499 pub default_min_height: Option<f32>,
500 pub background: Option<Brush>,
501 pub state_colors: Option<StateColors>,
502 pub state_elevation: Option<StateElevation>,
503
504 pub border: Option<Border>,
505 pub flex_grow: Option<f32>,
506 pub flex_shrink: Option<f32>,
507 pub flex_basis: Option<f32>,
508 pub flex_wrap: Option<FlexWrap>,
509 pub flex_dir: Option<FlexDirection>,
510 pub gap: Option<f32>,
511 pub row_gap: Option<f32>,
512 pub column_gap: Option<f32>,
513 pub align_self: Option<AlignSelf>,
514 pub justify_content: Option<JustifyContent>,
515 pub align_items_container: Option<AlignItems>,
516 pub align_content: Option<AlignContent>,
517 pub clip_rounded: Option<[f32; 4]>,
518 pub clip_rect: Option<ClipRect>,
521 pub overflow: Option<Overflow>,
526 pub z_index: f32,
528 pub render_z_index: Option<f32>,
530 pub hit_passthrough: bool,
532 pub input_blocker: bool,
534 pub repaint_boundary: bool,
535 pub click: bool,
536 pub disabled: bool,
538 pub focusable: Option<bool>,
542 pub propagate_min: bool,
544 pub focus_group: bool,
547 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
548 pub scroll: Option<crate::scroll::ScrollBinding>,
554 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
563 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
564 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
565 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
566 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
567 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
568 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
569 pub on_click: Option<Rc<dyn Fn()>>,
571 pub on_double_click: Option<Rc<dyn Fn()>>,
573 pub on_long_click: Option<Rc<dyn Fn()>>,
575 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
578 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
581 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
584 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
587 pub blur: Option<BlurStyle>,
592 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (f32, f32)>>,
597 pub semantics: Option<crate::Semantics>,
598 pub alpha: Option<f32>,
599 pub graphics_layer: Option<f32>,
600 pub shadow: Option<ShadowSpec>,
601 pub transform: Option<Transform>,
602 pub grid: Option<GridConfig>,
603 pub grid_col_span: Option<u16>,
604 pub grid_row_span: Option<u16>,
605 pub position_type: Option<PositionType>,
606 pub offset_left: Option<f32>,
607 pub offset_right: Option<f32>,
608 pub offset_top: Option<f32>,
609 pub offset_bottom: Option<f32>,
610
611 pub margin_left: Option<f32>,
612 pub margin_right: Option<f32>,
613 pub margin_top: Option<f32>,
614 pub margin_bottom: Option<f32>,
615 pub aspect_ratio: Option<f32>,
616 pub intrinsic_width: Option<IntrinsicSize>,
618 pub intrinsic_height: Option<IntrinsicSize>,
620 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
621
622 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
624 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
625 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
626 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
627 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
628 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
629 pub drag_preview: Option<crate::dnd::DragPreview>,
631
632 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
633
634 pub cursor: Option<crate::CursorIcon>,
636
637 pub animate_content_size: Option<AnimationSpec>,
640
641 pub focus_requester: Option<crate::runtime::FocusRequester>,
645
646 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
649
650 pub interaction_source: Option<InteractionSource>,
657
658 pub text_input: Option<TextInputConfig>,
660
661 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
663}
664
665impl std::fmt::Debug for Modifier {
666 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
667 let mut s = f.debug_struct("Modifier");
668
669 macro_rules! opt_val {
670 ($($name:ident),+ $(,)?) => {
671 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
672 };
673 }
674 if self.indication.is_some() {
675 s.field("indication", &"…");
676 }
677
678 opt_val!(
679 key,
680 size,
681 width,
682 height,
683 required_size,
684 padding,
685 padding_values,
686 min_width,
687 min_height,
688 max_width,
689 max_height,
690 required_min_width,
691 required_max_width,
692 required_min_height,
693 required_max_height,
694 default_min_width,
695 default_min_height,
696 fill_max,
697 fill_max_w,
698 fill_max_h,
699 background,
700 state_colors,
701 state_elevation,
702 border,
703 flex_grow,
704 flex_shrink,
705 flex_basis,
706 flex_wrap,
707 flex_dir,
708 gap,
709 row_gap,
710 column_gap,
711 align_self,
712 justify_content,
713 align_items_container,
714 align_content,
715 clip_rounded,
716 clip_rect,
717 render_z_index,
718 semantics,
719 alpha,
720 transform,
721 grid,
722 grid_col_span,
723 grid_row_span,
724 position_type,
725 offset_left,
726 offset_right,
727 offset_top,
728 offset_bottom,
729 margin_left,
730 margin_right,
731 margin_top,
732 margin_bottom,
733 aspect_ratio,
734 intrinsic_width,
735 intrinsic_height,
736 cursor,
737 animate_content_size,
738 blur,
739 );
740
741 macro_rules! opt_cb {
742 ($($name:ident),+ $(,)?) => {
743 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
744 };
745 }
746 opt_cb!(
747 on_scroll,
748 scroll,
749 nested_scroll_connection,
750 on_pointer_down,
751 on_pointer_move,
752 on_pointer_up,
753 on_pointer_cancel,
754 on_pointer_enter,
755 on_pointer_leave,
756 on_click,
757 on_double_click,
758 on_long_click,
759 on_globally_positioned,
760 on_size_changed,
761 on_key_event,
762 on_preview_key_event,
763 painter,
764 on_drag_start,
765 on_drag_end,
766 on_drag_enter,
767 on_drag_over,
768 on_drag_leave,
769 on_drop,
770 drag_preview,
771 on_action,
772 on_focus_changed,
773 interaction_source,
774 text_input,
775 layout,
776 );
777
778 macro_rules! flag {
779 ($($name:ident),+ $(,)?) => {
780 $( if self.$name { s.field(stringify!($name), &true); } )+
781 };
782 }
783 flag!(
784 hit_passthrough,
785 input_blocker,
786 repaint_boundary,
787 click,
788 disabled,
789 propagate_min,
790 focus_group,
791 );
792
793 if let Some(f) = self.focusable {
794 s.field("focusable", &f);
795 }
796 if self.z_index != 0.0 {
797 s.field("z_index", &self.z_index);
798 }
799
800 s.finish()
801 }
802}
803
804impl_option_fields!(Modifier);
805
806#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
810pub enum Alignment {
811 TopStart,
812 TopCenter,
813 TopEnd,
814 CenterStart,
815 #[default]
816 Center,
817 CenterEnd,
818 BottomStart,
819 BottomCenter,
820 BottomEnd,
821}
822
823impl Alignment {
824 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
826 use AlignItems as AI;
827 use JustifyContent as JC;
828 match self {
829 Self::TopStart => (AI::START, JC::START),
830 Self::TopCenter => (AI::START, JC::CENTER),
831 Self::TopEnd => (AI::START, JC::END),
832 Self::CenterStart => (AI::CENTER, JC::START),
833 Self::Center => (AI::CENTER, JC::CENTER),
834 Self::CenterEnd => (AI::CENTER, JC::END),
835 Self::BottomStart => (AI::END, JC::START),
836 Self::BottomCenter => (AI::END, JC::CENTER),
837 Self::BottomEnd => (AI::END, JC::END),
838 }
839 }
840}
841
842impl Modifier {
843 pub fn new() -> Self {
844 Self::default()
845 }
846
847 pub fn key(mut self, key: u64) -> Self {
850 self.key = Some(key);
851 self
852 }
853
854 pub fn size(mut self, w: f32, h: f32) -> Self {
855 self.size = Some(Size {
856 width: w,
857 height: h,
858 });
859 self
860 }
861 pub fn width(mut self, w: f32) -> Self {
862 self.width = Some(w);
863 self
864 }
865 pub fn height(mut self, h: f32) -> Self {
866 self.height = Some(h);
867 self
868 }
869 pub fn required_size(mut self, w: f32, h: f32) -> Self {
874 self.required_size = Some(Size {
875 width: w,
876 height: h,
877 });
878 self
879 }
880 pub fn required_width_in(mut self, min: f32, max: f32) -> Self {
881 self.required_min_width = Some(min.max(0.0));
882 self.required_max_width = Some(max.max(0.0));
883 self
884 }
885 pub fn required_height_in(mut self, min: f32, max: f32) -> Self {
886 self.required_min_height = Some(min.max(0.0));
887 self.required_max_height = Some(max.max(0.0));
888 self
889 }
890 pub fn required_min_width(mut self, w: f32) -> Self {
891 self.required_min_width = Some(w.max(0.0));
892 self
893 }
894 pub fn required_max_width(mut self, w: f32) -> Self {
895 self.required_max_width = Some(w.max(0.0));
896 self
897 }
898 pub fn required_min_height(mut self, h: f32) -> Self {
899 self.required_min_height = Some(h.max(0.0));
900 self
901 }
902 pub fn required_max_height(mut self, h: f32) -> Self {
903 self.required_max_height = Some(h.max(0.0));
904 self
905 }
906 pub fn default_min_size(mut self, w: f32, h: f32) -> Self {
908 self.default_min_width = Some(w.max(0.0));
909 self.default_min_height = Some(h.max(0.0));
910 self
911 }
912 pub fn fill_max_size(mut self) -> Self {
915 self.fill_max = Some(1.0);
916 self
917 }
918 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
919 self.fill_max = Some(fraction.clamp(0.0, 1.0));
920 self
921 }
922 pub fn fill_max_width(mut self) -> Self {
924 self.fill_max_w = Some(1.0);
925 self
926 }
927 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
928 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
929 self
930 }
931 pub fn fill_max_height(mut self) -> Self {
933 self.fill_max_h = Some(1.0);
934 self
935 }
936 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
937 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
938 self
939 }
940 pub fn padding(mut self, v: f32) -> Self {
941 self.padding = Some(v);
942 self
943 }
944 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
945 self.padding_values = Some(padding);
946 self
947 }
948 pub fn ime_padding(mut self) -> Self {
951 let insets = crate::locals::window_insets();
952 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
953 let mut p = self.padding_values.unwrap_or_default();
954 p.bottom += insets.ime_bottom / scale;
955 self.padding_values = Some(p);
956 self
957 }
958 pub fn system_bars_padding(mut self) -> Self {
960 let insets = crate::locals::window_insets();
961 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
962 let mut p = self.padding_values.unwrap_or_default();
963 p.top += insets.top / scale;
964 p.bottom += insets.bottom / scale;
965 self.padding_values = Some(p);
966 self
967 }
968 pub fn status_bars_padding(mut self) -> Self {
970 let insets = crate::locals::window_insets();
971 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
972 let mut p = self.padding_values.unwrap_or_default();
973 p.top += insets.top / scale;
974 self.padding_values = Some(p);
975 self
976 }
977 pub fn navigation_bars_padding(mut self) -> Self {
979 let insets = crate::locals::window_insets();
980 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
981 let mut p = self.padding_values.unwrap_or_default();
982 p.bottom += insets.bottom / scale;
983 self.padding_values = Some(p);
984 self
985 }
986 pub fn min_size(mut self, w: f32, h: f32) -> Self {
987 self.min_width = Some(w);
988 self.min_height = Some(h);
989 self
990 }
991 pub fn max_size(mut self, w: f32, h: f32) -> Self {
992 self.max_width = Some(w);
993 self.max_height = Some(h);
994 self
995 }
996 pub fn min_width(mut self, w: f32) -> Self {
997 self.min_width = Some(w);
998 self
999 }
1000 pub fn min_height(mut self, h: f32) -> Self {
1001 self.min_height = Some(h);
1002 self
1003 }
1004 pub fn max_width(mut self, w: f32) -> Self {
1005 self.max_width = Some(w);
1006 self
1007 }
1008 pub fn max_height(mut self, h: f32) -> Self {
1009 self.max_height = Some(h);
1010 self
1011 }
1012 pub fn background(mut self, color: Color) -> Self {
1014 self.background = Some(Brush::Solid(color));
1015 self
1016 }
1017 pub fn background_brush(mut self, brush: Brush) -> Self {
1019 self.background = Some(brush);
1020 self
1021 }
1022 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
1023 self.border = Some(Border {
1024 width,
1025 color,
1026 radius: [radius; 4],
1027 });
1028 self
1029 }
1030 pub fn border_radii(mut self, width: f32, color: Color, radii: [f32; 4]) -> Self {
1031 self.border = Some(Border {
1032 width,
1033 color,
1034 radius: radii,
1035 });
1036 self
1037 }
1038 pub fn flex_grow(mut self, v: f32) -> Self {
1039 self.flex_grow = Some(v);
1040 self
1041 }
1042 pub fn flex_shrink(mut self, v: f32) -> Self {
1043 self.flex_shrink = Some(v);
1044 self
1045 }
1046 pub fn flex_basis(mut self, v: f32) -> Self {
1047 self.flex_basis = Some(v);
1048 self
1049 }
1050 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1051 self.flex_wrap = Some(w);
1052 self
1053 }
1054 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1055 self.flex_dir = Some(d);
1056 self
1057 }
1058 pub fn gap(mut self, v: f32) -> Self {
1059 let v = v.max(0.0);
1060 self.gap = Some(v);
1061 self.row_gap = Some(v);
1062 self.column_gap = Some(v);
1063 self
1064 }
1065 pub fn row_gap(mut self, v: f32) -> Self {
1066 self.row_gap = Some(v.max(0.0));
1067 self
1068 }
1069 pub fn column_gap(mut self, v: f32) -> Self {
1070 self.column_gap = Some(v.max(0.0));
1071 self
1072 }
1073 pub fn align_self(mut self, a: AlignSelf) -> Self {
1074 self.align_self = Some(a);
1075 self
1076 }
1077 pub fn align_self_center(mut self) -> Self {
1078 self.align_self = Some(AlignSelf::CENTER);
1079 self
1080 }
1081 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1082 self.justify_content = Some(j);
1083 self
1084 }
1085 pub fn align_items(mut self, a: AlignItems) -> Self {
1086 self.align_items_container = Some(a);
1087 self
1088 }
1089 pub fn content_alignment(self, alignment: Alignment) -> Self {
1092 let (ai, jc) = alignment.to_flex();
1093 self.align_items(ai).justify_content(jc)
1094 }
1095 pub fn align_content(mut self, a: AlignContent) -> Self {
1096 self.align_content = Some(a);
1097 self
1098 }
1099 pub fn clip_rounded(mut self, radius: f32) -> Self {
1100 self.clip_rounded = Some([radius; 4]);
1101 self
1102 }
1103 pub fn clip_rounded_radii(mut self, radii: [f32; 4]) -> Self {
1104 self.clip_rounded = Some(radii);
1105 self
1106 }
1107 pub fn clip_rect(mut self, left: f32, top: f32, right: f32, bottom: f32, op: ClipOp) -> Self {
1110 self.clip_rect = Some(ClipRect {
1111 left,
1112 top,
1113 right,
1114 bottom,
1115 op,
1116 });
1117 self
1118 }
1119 pub fn overflow(mut self, overflow: Overflow) -> Self {
1120 self.overflow = Some(overflow);
1121 self
1122 }
1123 pub fn z_index(mut self, z: f32) -> Self {
1124 self.z_index = z;
1125 self
1126 }
1127
1128 pub fn render_z_index(mut self, z: f32) -> Self {
1131 self.render_z_index = Some(z);
1132 self
1133 }
1134
1135 pub fn input_blocker(mut self) -> Self {
1137 self.input_blocker = true;
1138 self
1139 }
1140
1141 pub fn hit_passthrough(mut self) -> Self {
1142 self.hit_passthrough = true;
1143 self
1144 }
1145 pub fn clickable(mut self) -> Self {
1146 self.click = true;
1147 self
1148 }
1149 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1152 self.click = true;
1153 self.interaction_source = Some(source.source());
1154 self
1155 }
1156 pub fn state_colors(mut self, colors: StateColors) -> Self {
1159 self.state_colors = Some(colors);
1160 self
1161 }
1162 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1164 self.state_elevation = Some(elev);
1165 self
1166 }
1167 pub fn disabled(mut self) -> Self {
1169 self.disabled = true;
1170 self
1171 }
1172 pub fn enabled(mut self, enabled: bool) -> Self {
1174 self.disabled = !enabled;
1175 self
1176 }
1177 pub fn focusable(mut self, focusable: bool) -> Self {
1182 self.focusable = Some(focusable);
1183 self
1184 }
1185 pub fn focus_group(mut self) -> Self {
1188 self.focus_group = true;
1189 self
1190 }
1191 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1200 self.interaction_source = Some(source.source());
1201 self
1202 }
1203 pub fn hoverable(
1206 mut self,
1207 on_enter: impl Fn() + 'static,
1208 on_leave: impl Fn() + 'static,
1209 ) -> Self {
1210 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1211 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1212 self
1213 }
1214 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1218 self.interaction_source = Some(source.source());
1219 self
1220 }
1221 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1224 self.propagate_min = propagate;
1225 self
1226 }
1227 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1228 self.on_scroll = Some(Rc::new(f));
1229 self
1230 }
1231 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1235 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1236 self
1237 }
1238 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1240 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1241 self
1242 }
1243 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1245 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1246 self
1247 }
1248 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1255 self.nested_scroll_connection = Some(conn);
1256 self
1257 }
1258 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1259 self.on_pointer_down = Some(Rc::new(f));
1260 self
1261 }
1262 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1263 self.on_pointer_move = Some(Rc::new(f));
1264 self
1265 }
1266 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1267 self.on_pointer_up = Some(Rc::new(f));
1268 self
1269 }
1270 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1271 self.on_pointer_cancel = Some(Rc::new(f));
1272 self
1273 }
1274 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1275 self.on_pointer_enter = Some(Rc::new(f));
1276 self
1277 }
1278 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1279 self.on_pointer_leave = Some(Rc::new(f));
1280 self
1281 }
1282 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1283 self.on_click = Some(Rc::new(f));
1284 self.click = true;
1285 self
1286 }
1287 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1288 self.on_double_click = Some(Rc::new(f));
1289 self
1290 }
1291 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1292 self.on_long_click = Some(Rc::new(f));
1293 self
1294 }
1295 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1296 self.semantics = Some(s);
1297 self
1298 }
1299 pub fn alpha(mut self, a: f32) -> Self {
1300 self.alpha = Some(a);
1301 self
1302 }
1303 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1308 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1309 self
1310 }
1311 pub fn shadow(mut self, blur_radius: f32, offset_y: f32) -> Self {
1315 self.shadow = Some(ShadowSpec {
1316 blur_radius: blur_radius.max(0.0),
1317 offset_y,
1318 color: Color(0, 0, 0, 64),
1319 });
1320 self
1321 }
1322 pub fn shadow_with_color(mut self, blur_radius: f32, offset_y: f32, color: Color) -> Self {
1324 self.shadow = Some(ShadowSpec {
1325 blur_radius: blur_radius.max(0.0),
1326 offset_y,
1327 color,
1328 });
1329 self
1330 }
1331 pub fn elevation(mut self, level: f32) -> Self {
1335 if level <= 0.0 {
1336 self.shadow = None;
1337 return self;
1338 }
1339 self.shadow = Some(ShadowSpec {
1340 blur_radius: level * 2.0,
1341 offset_y: level * 0.5,
1342 color: Color(0, 0, 0, (level * 8.0).clamp(8.0, 80.0) as u8),
1343 });
1344 self
1345 }
1346 pub fn transform(mut self, t: Transform) -> Self {
1347 self.transform = Some(t);
1348 self
1349 }
1350 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
1351 self.grid = Some(GridConfig {
1352 columns,
1353 row_gap,
1354 column_gap,
1355 });
1356 self
1357 }
1358 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1359 self.grid_col_span = Some(col_span);
1360 self.grid_row_span = Some(row_span);
1361 self
1362 }
1363 pub fn absolute(mut self) -> Self {
1364 self.position_type = Some(PositionType::Absolute);
1365 self
1366 }
1367 pub fn offset(
1368 mut self,
1369 left: Option<f32>,
1370 top: Option<f32>,
1371 right: Option<f32>,
1372 bottom: Option<f32>,
1373 ) -> Self {
1374 self.offset_left = left;
1375 self.offset_top = top;
1376 self.offset_right = right;
1377 self.offset_bottom = bottom;
1378 self
1379 }
1380 pub fn offset_left(mut self, v: f32) -> Self {
1381 self.offset_left = Some(v);
1382 self
1383 }
1384 pub fn offset_right(mut self, v: f32) -> Self {
1385 self.offset_right = Some(v);
1386 self
1387 }
1388 pub fn offset_top(mut self, v: f32) -> Self {
1389 self.offset_top = Some(v);
1390 self
1391 }
1392 pub fn offset_bottom(mut self, v: f32) -> Self {
1393 self.offset_bottom = Some(v);
1394 self
1395 }
1396 pub fn margin(mut self, v: f32) -> Self {
1397 self.margin_left = Some(v);
1398 self.margin_right = Some(v);
1399 self.margin_top = Some(v);
1400 self.margin_bottom = Some(v);
1401 self
1402 }
1403
1404 pub fn margin_horizontal(mut self, v: f32) -> Self {
1405 self.margin_left = Some(v);
1406 self.margin_right = Some(v);
1407 self
1408 }
1409
1410 pub fn margin_vertical(mut self, v: f32) -> Self {
1411 self.margin_top = Some(v);
1412 self.margin_bottom = Some(v);
1413 self
1414 }
1415 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1416 self.aspect_ratio = Some(ratio);
1417 self
1418 }
1419 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1421 self.intrinsic_width = Some(mode);
1422 self
1423 }
1424 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1426 self.intrinsic_height = Some(mode);
1427 self
1428 }
1429 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1430 self.painter = Some(Rc::new(f));
1431 self
1432 }
1433 pub fn scale(self, s: f32) -> Self {
1434 self.scale2(s, s)
1435 }
1436 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1437 let mut t = self.transform.unwrap_or_else(Transform::identity);
1438 t.scale_x *= sx;
1439 t.scale_y *= sy;
1440 self.transform = Some(t);
1441 self
1442 }
1443 pub fn translate(mut self, x: f32, y: f32) -> Self {
1444 let t = self.transform.unwrap_or_else(Transform::identity);
1445 self.transform = Some(t.combine(&Transform::translate(x, y)));
1446 self
1447 }
1448 pub fn translate_vec2(self, v: Vec2) -> Self {
1449 self.translate(v.x, v.y)
1450 }
1451 pub fn rotate(mut self, radians: f32) -> Self {
1452 let mut t = self.transform.unwrap_or_else(Transform::identity);
1453 t.rotate += radians;
1454 self.transform = Some(t);
1455 self
1456 }
1457 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1458 let mut t = self.transform.unwrap_or_else(Transform::identity);
1459 t.origin_x = x;
1460 t.origin_y = y;
1461 self.transform = Some(t);
1462 self
1463 }
1464 pub fn weight(mut self, w: f32) -> Self {
1465 let w = w.max(0.0);
1466 self.flex_grow = Some(w);
1467 self.flex_shrink = Some(1.0);
1468 self.flex_basis = Some(0.0);
1470 self
1471 }
1472 pub fn repaint_boundary(mut self) -> Self {
1476 self.repaint_boundary = true;
1477 self
1478 }
1479 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1480 self.on_action = Some(Rc::new(f));
1481 self
1482 }
1483
1484 pub fn on_drag_start(
1486 mut self,
1487 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1488 ) -> Self {
1489 self.on_drag_start = Some(Rc::new(f));
1490 self
1491 }
1492
1493 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1495 self.on_drag_end = Some(Rc::new(f));
1496 self
1497 }
1498
1499 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1501 self.on_drag_enter = Some(Rc::new(f));
1502 self
1503 }
1504
1505 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1507 self.on_drag_over = Some(Rc::new(f));
1508 self
1509 }
1510
1511 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1513 self.on_drag_leave = Some(Rc::new(f));
1514 self
1515 }
1516
1517 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1520 self.on_drop = Some(Rc::new(f));
1521 self
1522 }
1523
1524 pub fn draw_drag_decoration(
1529 mut self,
1530 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
1531 ) -> Self {
1532 self.drag_preview = Some(Rc::new(f));
1533 self
1534 }
1535
1536 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
1538 self.drag_preview = Some(preview);
1539 self
1540 }
1541
1542 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
1544 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
1545 }
1546
1547 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
1549 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
1550 }
1551
1552 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1554 self.cursor = Some(c);
1555 self
1556 }
1557
1558 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1562 self.animate_content_size = Some(spec);
1563 self
1564 }
1565
1566 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1569 self.focus_requester = Some(fr);
1570 self
1571 }
1572
1573 pub fn focus_target(mut self) -> Self {
1576 self.focusable = Some(true);
1577 self
1578 }
1579
1580 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1583 self.on_focus_changed = Some(Rc::new(f));
1584 self
1585 }
1586
1587 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
1591 self.on_globally_positioned = Some(Rc::new(f));
1592 self
1593 }
1594
1595 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
1598 self.on_size_changed = Some(Rc::new(f));
1599 self
1600 }
1601
1602 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
1606 self.on_key_event = Some(Rc::new(f));
1607 self
1608 }
1609
1610 pub fn on_preview_key_event(
1614 mut self,
1615 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
1616 ) -> Self {
1617 self.on_preview_key_event = Some(Rc::new(f));
1618 self
1619 }
1620
1621 pub fn blur(mut self, radius_dp: f32) -> Self {
1628 self.blur = Some(BlurStyle {
1629 radius_x: radius_dp.max(0.0),
1630 radius_y: radius_dp.max(0.0),
1631 edge_treatment: BlurredEdgeTreatment::Rectangle,
1632 });
1633 self
1634 }
1635
1636 pub fn blur_with_edge(
1641 mut self,
1642 radius_x: f32,
1643 radius_y: f32,
1644 edge_treatment: BlurredEdgeTreatment,
1645 ) -> Self {
1646 self.blur = Some(BlurStyle {
1647 radius_x: radius_x.max(0.0),
1648 radius_y: radius_y.max(0.0),
1649 edge_treatment,
1650 });
1651 self
1652 }
1653
1654 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (f32, f32) + 'static) -> Self {
1662 self.layout = Some(Rc::new(f));
1663 self
1664 }
1665
1666 pub fn text_input(mut self, config: TextInputConfig) -> Self {
1668 self.text_input = Some(config);
1669 self
1670 }
1671
1672 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
1676 self.indication = Some(factory);
1677 self
1678 }
1679}