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, Default)]
109pub enum ClipOp {
110 #[default]
112 Intersect,
113 Difference,
115}
116
117#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
123pub enum Overflow {
124 #[default]
125 Clip,
126 Visible,
127}
128
129#[derive(Clone, Copy, Debug)]
132pub struct ClipRect {
133 pub left: f32,
134 pub top: f32,
135 pub right: f32,
136 pub bottom: f32,
137 pub op: ClipOp,
138}
139
140#[derive(Clone, Debug)]
141pub struct Border {
142 pub width: f32,
143 pub color: Color,
144 pub radius: [f32; 4],
145}
146
147#[derive(Clone, Copy, Debug, Default)]
148pub struct PaddingValues {
149 pub left: f32,
150 pub right: f32,
151 pub top: f32,
152 pub bottom: f32,
153}
154
155#[derive(Clone, Debug)]
156pub struct GridConfig {
157 pub columns: usize,
158 pub row_gap: f32,
159 pub column_gap: f32,
160}
161
162#[derive(Clone, Copy, Debug, PartialEq)]
165pub enum BlurredEdgeTreatment {
166 Rectangle,
169 Unbounded,
172}
173
174#[derive(Clone, Copy, Debug)]
176pub struct BlurStyle {
177 pub radius_x: f32,
179 pub radius_y: f32,
181 pub edge_treatment: BlurredEdgeTreatment,
183}
184
185#[derive(Clone, Copy, Debug)]
190pub struct LayoutConstraints {
191 pub min_width: f32,
192 pub max_width: f32,
193 pub min_height: f32,
194 pub max_height: f32,
195}
196
197#[derive(Clone, Copy, Debug)]
204pub struct ShadowSpec {
205 pub blur_radius: f32,
206 pub offset_y: f32,
207 pub color: Color,
208}
209
210#[derive(Clone, Copy, Debug)]
211#[non_exhaustive]
212pub enum PositionType {
213 Relative,
214 Absolute,
215}
216
217#[derive(Clone)]
219pub struct TextInputConfig {
220 pub hint: String,
221 pub multiline: bool,
222 pub on_change: Option<Rc<dyn Fn(String)>>,
223 pub on_submit: Option<Rc<dyn Fn(String)>>,
224 pub focus_tracker: Option<Rc<Cell<bool>>>,
225 pub value: String,
226 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
227 pub keyboard_type: crate::text::KeyboardType,
228 pub capitalization: crate::text::KeyboardCapitalization,
229 pub ime_action: crate::text::ImeAction,
230 pub auto_correct_enabled: Option<bool>,
233 pub enabled: bool,
235 pub read_only: bool,
237 pub max_lines: Option<usize>,
239 pub min_lines: usize,
241 pub cursor_color: Option<Color>,
243 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
246 pub text_style: Option<crate::text::TextStyle>,
249 pub keyboard_actions: Option<crate::text::KeyboardActions>,
252 pub interaction_source: Option<InteractionSource>,
254 pub line_limits: Option<crate::text::TextFieldLineLimits>,
256}
257
258impl std::fmt::Debug for TextInputConfig {
259 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
260 let mut s = f.debug_struct("TextInputConfig");
261 s.field("hint", &self.hint);
262 s.field("multiline", &self.multiline);
263 if self.on_change.is_some() {
264 s.field("on_change", &"…");
265 }
266 if self.on_submit.is_some() {
267 s.field("on_submit", &"…");
268 }
269 if self.focus_tracker.is_some() {
270 s.field("focus_tracker", &"…");
271 }
272 s.field("value", &self.value);
273 if self.visual_transformation.is_some() {
274 s.field("visual_transformation", &"…");
275 }
276 s.field("keyboard_type", &self.keyboard_type);
277 s.field("capitalization", &self.capitalization);
278 s.field("ime_action", &self.ime_action);
279 s.field("auto_correct_enabled", &self.auto_correct_enabled);
280 s.field("enabled", &self.enabled);
281 s.field("read_only", &self.read_only);
282 s.field("max_lines", &self.max_lines);
283 s.field("min_lines", &self.min_lines);
284 s.field("cursor_color", &self.cursor_color);
285 if self.on_text_layout.is_some() {
286 s.field("on_text_layout", &"…");
287 }
288 s.finish()
289 }
290}
291
292#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
295pub enum IntrinsicSize {
296 Min,
297 Max,
298}
299
300static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
301
302pub type PressId = u64;
304
305#[derive(Clone, Copy, Debug, PartialEq)]
313pub enum Interaction {
314 Press(PressId, Vec2),
317 Release(PressId),
319 Cancel(PressId),
322 HoverEnter,
323 HoverLeave,
324 Focus,
325 Unfocus,
326 DragStart,
327 DragStop,
328 DragCancel,
329}
330
331impl Interaction {
332 #[inline]
334 pub fn new_press(position: Vec2) -> Self {
335 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
336 }
337}
338
339#[derive(Clone)]
346pub struct InteractionSource {
347 pub(crate) state: Rc<RefCell<InteractionState>>,
348}
349
350impl InteractionSource {
351 pub fn collect_is_pressed(&self) -> bool {
352 self.state.borrow().pressed > 0
353 }
354 pub fn collect_is_hovered(&self) -> bool {
355 self.state.borrow().hovered
356 }
357 pub fn collect_is_focused(&self) -> bool {
358 self.state.borrow().focused
359 }
360 pub fn collect_is_dragged(&self) -> bool {
361 self.state.borrow().dragged > 0
362 }
363 pub fn collect_last_press_position(&self) -> Option<Vec2> {
364 self.state.borrow().last_press_position
365 }
366 pub fn collect_last_press_id(&self) -> Option<PressId> {
367 self.state.borrow().last_press_id
368 }
369 pub fn stable_id(&self) -> *const () {
371 Rc::as_ptr(&self.state) as *const ()
372 }
373 pub fn to_mutable(&self) -> MutableInteractionSource {
377 MutableInteractionSource {
378 state: self.state.clone(),
379 }
380 }
381}
382
383#[derive(Clone)]
393pub struct MutableInteractionSource {
394 pub(crate) state: Rc<RefCell<InteractionState>>,
395}
396
397impl std::fmt::Debug for MutableInteractionSource {
398 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
399 f.debug_struct("MutableInteractionSource")
400 .finish_non_exhaustive()
401 }
402}
403
404impl MutableInteractionSource {
405 pub fn new() -> Self {
406 Self {
407 state: Rc::new(RefCell::new(InteractionState::default())),
408 }
409 }
410
411 pub fn emit(&self, interaction: Interaction) {
413 let mut s = self.state.borrow_mut();
414 match interaction {
415 Interaction::Press(id, pos) => {
416 s.pressed = s.pressed.saturating_add(1);
417 s.last_press_id = Some(id);
418 s.last_press_position = Some(pos);
419 }
420 Interaction::Release(_) | Interaction::Cancel(_) => {
421 s.pressed = s.pressed.saturating_sub(1);
422 }
423 Interaction::HoverEnter => s.hovered = true,
424 Interaction::HoverLeave => s.hovered = false,
425 Interaction::Focus => s.focused = true,
426 Interaction::Unfocus => s.focused = false,
427 Interaction::DragStart => s.dragged = s.dragged.saturating_add(1),
428 Interaction::DragStop | Interaction::DragCancel => {
429 s.dragged = s.dragged.saturating_sub(1);
430 }
431 }
432 }
433
434 pub fn source(&self) -> InteractionSource {
436 InteractionSource {
437 state: self.state.clone(),
438 }
439 }
440}
441
442impl Default for MutableInteractionSource {
443 fn default() -> Self {
444 Self::new()
445 }
446}
447
448#[derive(Clone, Default)]
449pub(crate) struct InteractionState {
450 pressed: u32,
451 hovered: bool,
452 focused: bool,
453 dragged: u32,
454 pub(crate) last_press_position: Option<Vec2>,
456 pub(crate) last_press_id: Option<PressId>,
458}
459
460#[derive(Clone, Default)]
461pub struct Modifier {
462 pub key: Option<u64>,
468
469 pub size: Option<Size>,
470 pub width: Option<f32>,
471 pub height: Option<f32>,
472 pub required_size: Option<Size>,
473 pub fill_max: Option<f32>,
474 pub fill_max_w: Option<f32>,
475 pub fill_max_h: Option<f32>,
476 pub padding: Option<f32>,
477 pub padding_values: Option<PaddingValues>,
478 pub min_width: Option<f32>,
479 pub min_height: Option<f32>,
480 pub max_width: Option<f32>,
481 pub max_height: Option<f32>,
482 pub required_min_width: Option<f32>,
484 pub required_max_width: Option<f32>,
486 pub required_min_height: Option<f32>,
488 pub required_max_height: Option<f32>,
490 pub default_min_width: Option<f32>,
493 pub default_min_height: Option<f32>,
494 pub background: Option<Brush>,
495 pub state_colors: Option<StateColors>,
496 pub state_elevation: Option<StateElevation>,
497
498 pub border: Option<Border>,
499 pub flex_grow: Option<f32>,
500 pub flex_shrink: Option<f32>,
501 pub flex_basis: Option<f32>,
502 pub flex_wrap: Option<FlexWrap>,
503 pub flex_dir: Option<FlexDirection>,
504 pub gap: Option<f32>,
505 pub row_gap: Option<f32>,
506 pub column_gap: Option<f32>,
507 pub align_self: Option<AlignSelf>,
508 pub justify_content: Option<JustifyContent>,
509 pub align_items_container: Option<AlignItems>,
510 pub align_content: Option<AlignContent>,
511 pub clip_rounded: Option<[f32; 4]>,
512 pub clip_rect: Option<ClipRect>,
515 pub overflow: Option<Overflow>,
520 pub z_index: f32,
522 pub render_z_index: Option<f32>,
524 pub hit_passthrough: bool,
526 pub input_blocker: bool,
528 pub repaint_boundary: bool,
529 pub click: bool,
530 pub disabled: bool,
532 pub focusable: Option<bool>,
536 pub propagate_min: bool,
538 pub focus_group: bool,
541 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
542 pub scroll: Option<crate::scroll::ScrollBinding>,
548 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
557 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
558 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
559 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
560 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
561 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
562 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
563 pub on_click: Option<Rc<dyn Fn()>>,
565 pub on_double_click: Option<Rc<dyn Fn()>>,
567 pub on_long_click: Option<Rc<dyn Fn()>>,
569 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
572 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
575 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
578 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
581 pub blur: Option<BlurStyle>,
586 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (f32, f32)>>,
591 pub semantics: Option<crate::Semantics>,
592 pub alpha: Option<f32>,
593 pub graphics_layer: Option<f32>,
594 pub shadow: Option<ShadowSpec>,
595 pub transform: Option<Transform>,
596 pub grid: Option<GridConfig>,
597 pub grid_col_span: Option<u16>,
598 pub grid_row_span: Option<u16>,
599 pub position_type: Option<PositionType>,
600 pub offset_left: Option<f32>,
601 pub offset_right: Option<f32>,
602 pub offset_top: Option<f32>,
603 pub offset_bottom: Option<f32>,
604
605 pub margin_left: Option<f32>,
606 pub margin_right: Option<f32>,
607 pub margin_top: Option<f32>,
608 pub margin_bottom: Option<f32>,
609 pub aspect_ratio: Option<f32>,
610 pub intrinsic_width: Option<IntrinsicSize>,
612 pub intrinsic_height: Option<IntrinsicSize>,
614 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
615
616 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
618 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
619 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
620 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
621 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
622 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
623 pub drag_preview: Option<crate::dnd::DragPreview>,
625
626 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
627
628 pub cursor: Option<crate::CursorIcon>,
630
631 pub animate_content_size: Option<AnimationSpec>,
634
635 pub focus_requester: Option<crate::runtime::FocusRequester>,
639
640 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
643
644 pub interaction_source: Option<InteractionSource>,
651
652 pub text_input: Option<TextInputConfig>,
654
655 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
657}
658
659impl std::fmt::Debug for Modifier {
660 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
661 let mut s = f.debug_struct("Modifier");
662
663 macro_rules! opt_val {
664 ($($name:ident),+ $(,)?) => {
665 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
666 };
667 }
668 if self.indication.is_some() {
669 s.field("indication", &"…");
670 }
671
672 opt_val!(
673 key,
674 size,
675 width,
676 height,
677 required_size,
678 padding,
679 padding_values,
680 min_width,
681 min_height,
682 max_width,
683 max_height,
684 required_min_width,
685 required_max_width,
686 required_min_height,
687 required_max_height,
688 default_min_width,
689 default_min_height,
690 fill_max,
691 fill_max_w,
692 fill_max_h,
693 background,
694 state_colors,
695 state_elevation,
696 border,
697 flex_grow,
698 flex_shrink,
699 flex_basis,
700 flex_wrap,
701 flex_dir,
702 gap,
703 row_gap,
704 column_gap,
705 align_self,
706 justify_content,
707 align_items_container,
708 align_content,
709 clip_rounded,
710 clip_rect,
711 render_z_index,
712 semantics,
713 alpha,
714 transform,
715 grid,
716 grid_col_span,
717 grid_row_span,
718 position_type,
719 offset_left,
720 offset_right,
721 offset_top,
722 offset_bottom,
723 margin_left,
724 margin_right,
725 margin_top,
726 margin_bottom,
727 aspect_ratio,
728 intrinsic_width,
729 intrinsic_height,
730 cursor,
731 animate_content_size,
732 blur,
733 );
734
735 macro_rules! opt_cb {
736 ($($name:ident),+ $(,)?) => {
737 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
738 };
739 }
740 opt_cb!(
741 on_scroll,
742 scroll,
743 nested_scroll_connection,
744 on_pointer_down,
745 on_pointer_move,
746 on_pointer_up,
747 on_pointer_cancel,
748 on_pointer_enter,
749 on_pointer_leave,
750 on_click,
751 on_double_click,
752 on_long_click,
753 on_globally_positioned,
754 on_size_changed,
755 on_key_event,
756 on_preview_key_event,
757 painter,
758 on_drag_start,
759 on_drag_end,
760 on_drag_enter,
761 on_drag_over,
762 on_drag_leave,
763 on_drop,
764 drag_preview,
765 on_action,
766 on_focus_changed,
767 interaction_source,
768 text_input,
769 layout,
770 );
771
772 macro_rules! flag {
773 ($($name:ident),+ $(,)?) => {
774 $( if self.$name { s.field(stringify!($name), &true); } )+
775 };
776 }
777 flag!(
778 hit_passthrough,
779 input_blocker,
780 repaint_boundary,
781 click,
782 disabled,
783 propagate_min,
784 focus_group,
785 );
786
787 if let Some(f) = self.focusable {
788 s.field("focusable", &f);
789 }
790 if self.z_index != 0.0 {
791 s.field("z_index", &self.z_index);
792 }
793
794 s.finish()
795 }
796}
797
798impl_option_fields!(Modifier);
799
800#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
804pub enum Alignment {
805 TopStart,
806 TopCenter,
807 TopEnd,
808 CenterStart,
809 #[default]
810 Center,
811 CenterEnd,
812 BottomStart,
813 BottomCenter,
814 BottomEnd,
815}
816
817impl Alignment {
818 pub fn to_flex(self) -> (AlignItems, JustifyContent) {
820 use AlignItems as AI;
821 use JustifyContent as JC;
822 match self {
823 Self::TopStart => (AI::START, JC::START),
824 Self::TopCenter => (AI::START, JC::CENTER),
825 Self::TopEnd => (AI::START, JC::END),
826 Self::CenterStart => (AI::CENTER, JC::START),
827 Self::Center => (AI::CENTER, JC::CENTER),
828 Self::CenterEnd => (AI::CENTER, JC::END),
829 Self::BottomStart => (AI::END, JC::START),
830 Self::BottomCenter => (AI::END, JC::CENTER),
831 Self::BottomEnd => (AI::END, JC::END),
832 }
833 }
834}
835
836impl Modifier {
837 pub fn new() -> Self {
838 Self::default()
839 }
840
841 pub fn key(mut self, key: u64) -> Self {
844 self.key = Some(key);
845 self
846 }
847
848 pub fn size(mut self, w: f32, h: f32) -> Self {
849 self.size = Some(Size {
850 width: w,
851 height: h,
852 });
853 self
854 }
855 pub fn width(mut self, w: f32) -> Self {
856 self.width = Some(w);
857 self
858 }
859 pub fn height(mut self, h: f32) -> Self {
860 self.height = Some(h);
861 self
862 }
863 pub fn required_size(mut self, w: f32, h: f32) -> Self {
868 self.required_size = Some(Size {
869 width: w,
870 height: h,
871 });
872 self
873 }
874 pub fn required_width_in(mut self, min: f32, max: f32) -> Self {
875 self.required_min_width = Some(min.max(0.0));
876 self.required_max_width = Some(max.max(0.0));
877 self
878 }
879 pub fn required_height_in(mut self, min: f32, max: f32) -> Self {
880 self.required_min_height = Some(min.max(0.0));
881 self.required_max_height = Some(max.max(0.0));
882 self
883 }
884 pub fn required_min_width(mut self, w: f32) -> Self {
885 self.required_min_width = Some(w.max(0.0));
886 self
887 }
888 pub fn required_max_width(mut self, w: f32) -> Self {
889 self.required_max_width = Some(w.max(0.0));
890 self
891 }
892 pub fn required_min_height(mut self, h: f32) -> Self {
893 self.required_min_height = Some(h.max(0.0));
894 self
895 }
896 pub fn required_max_height(mut self, h: f32) -> Self {
897 self.required_max_height = Some(h.max(0.0));
898 self
899 }
900 pub fn default_min_size(mut self, w: f32, h: f32) -> Self {
902 self.default_min_width = Some(w.max(0.0));
903 self.default_min_height = Some(h.max(0.0));
904 self
905 }
906 pub fn fill_max_size(mut self) -> Self {
909 self.fill_max = Some(1.0);
910 self
911 }
912 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
913 self.fill_max = Some(fraction.clamp(0.0, 1.0));
914 self
915 }
916 pub fn fill_max_width(mut self) -> Self {
918 self.fill_max_w = Some(1.0);
919 self
920 }
921 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
922 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
923 self
924 }
925 pub fn fill_max_height(mut self) -> Self {
927 self.fill_max_h = Some(1.0);
928 self
929 }
930 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
931 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
932 self
933 }
934 pub fn padding(mut self, v: f32) -> Self {
935 self.padding = Some(v);
936 self
937 }
938 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
939 self.padding_values = Some(padding);
940 self
941 }
942 pub fn ime_padding(mut self) -> Self {
945 let insets = crate::locals::window_insets();
946 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
947 let mut p = self.padding_values.unwrap_or_default();
948 p.bottom += insets.ime_bottom / scale;
949 self.padding_values = Some(p);
950 self
951 }
952 pub fn system_bars_padding(mut self) -> Self {
954 let insets = crate::locals::window_insets();
955 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
956 let mut p = self.padding_values.unwrap_or_default();
957 p.top += insets.top / scale;
958 p.bottom += insets.bottom / scale;
959 self.padding_values = Some(p);
960 self
961 }
962 pub fn status_bars_padding(mut self) -> Self {
964 let insets = crate::locals::window_insets();
965 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
966 let mut p = self.padding_values.unwrap_or_default();
967 p.top += insets.top / scale;
968 self.padding_values = Some(p);
969 self
970 }
971 pub fn navigation_bars_padding(mut self) -> Self {
973 let insets = crate::locals::window_insets();
974 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
975 let mut p = self.padding_values.unwrap_or_default();
976 p.bottom += insets.bottom / scale;
977 self.padding_values = Some(p);
978 self
979 }
980 pub fn min_size(mut self, w: f32, h: f32) -> Self {
981 self.min_width = Some(w);
982 self.min_height = Some(h);
983 self
984 }
985 pub fn max_size(mut self, w: f32, h: f32) -> Self {
986 self.max_width = Some(w);
987 self.max_height = Some(h);
988 self
989 }
990 pub fn min_width(mut self, w: f32) -> Self {
991 self.min_width = Some(w);
992 self
993 }
994 pub fn min_height(mut self, h: f32) -> Self {
995 self.min_height = Some(h);
996 self
997 }
998 pub fn max_width(mut self, w: f32) -> Self {
999 self.max_width = Some(w);
1000 self
1001 }
1002 pub fn max_height(mut self, h: f32) -> Self {
1003 self.max_height = Some(h);
1004 self
1005 }
1006 pub fn background(mut self, color: Color) -> Self {
1008 self.background = Some(Brush::Solid(color));
1009 self
1010 }
1011 pub fn background_brush(mut self, brush: Brush) -> Self {
1013 self.background = Some(brush);
1014 self
1015 }
1016 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
1017 self.border = Some(Border {
1018 width,
1019 color,
1020 radius: [radius; 4],
1021 });
1022 self
1023 }
1024 pub fn border_radii(mut self, width: f32, color: Color, radii: [f32; 4]) -> Self {
1025 self.border = Some(Border {
1026 width,
1027 color,
1028 radius: radii,
1029 });
1030 self
1031 }
1032 pub fn flex_grow(mut self, v: f32) -> Self {
1033 self.flex_grow = Some(v);
1034 self
1035 }
1036 pub fn flex_shrink(mut self, v: f32) -> Self {
1037 self.flex_shrink = Some(v);
1038 self
1039 }
1040 pub fn flex_basis(mut self, v: f32) -> Self {
1041 self.flex_basis = Some(v);
1042 self
1043 }
1044 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1045 self.flex_wrap = Some(w);
1046 self
1047 }
1048 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1049 self.flex_dir = Some(d);
1050 self
1051 }
1052 pub fn gap(mut self, v: f32) -> Self {
1053 let v = v.max(0.0);
1054 self.gap = Some(v);
1055 self.row_gap = Some(v);
1056 self.column_gap = Some(v);
1057 self
1058 }
1059 pub fn row_gap(mut self, v: f32) -> Self {
1060 self.row_gap = Some(v.max(0.0));
1061 self
1062 }
1063 pub fn column_gap(mut self, v: f32) -> Self {
1064 self.column_gap = Some(v.max(0.0));
1065 self
1066 }
1067 pub fn align_self(mut self, a: AlignSelf) -> Self {
1068 self.align_self = Some(a);
1069 self
1070 }
1071 pub fn align_self_center(mut self) -> Self {
1072 self.align_self = Some(AlignSelf::CENTER);
1073 self
1074 }
1075 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1076 self.justify_content = Some(j);
1077 self
1078 }
1079 pub fn align_items(mut self, a: AlignItems) -> Self {
1080 self.align_items_container = Some(a);
1081 self
1082 }
1083 pub fn content_alignment(self, alignment: Alignment) -> Self {
1086 let (ai, jc) = alignment.to_flex();
1087 self.align_items(ai).justify_content(jc)
1088 }
1089 pub fn align_content(mut self, a: AlignContent) -> Self {
1090 self.align_content = Some(a);
1091 self
1092 }
1093 pub fn clip_rounded(mut self, radius: f32) -> Self {
1094 self.clip_rounded = Some([radius; 4]);
1095 self
1096 }
1097 pub fn clip_rounded_radii(mut self, radii: [f32; 4]) -> Self {
1098 self.clip_rounded = Some(radii);
1099 self
1100 }
1101 pub fn clip_rect(mut self, left: f32, top: f32, right: f32, bottom: f32, op: ClipOp) -> Self {
1104 self.clip_rect = Some(ClipRect {
1105 left,
1106 top,
1107 right,
1108 bottom,
1109 op,
1110 });
1111 self
1112 }
1113 pub fn overflow(mut self, overflow: Overflow) -> Self {
1114 self.overflow = Some(overflow);
1115 self
1116 }
1117 pub fn z_index(mut self, z: f32) -> Self {
1118 self.z_index = z;
1119 self
1120 }
1121
1122 pub fn render_z_index(mut self, z: f32) -> Self {
1125 self.render_z_index = Some(z);
1126 self
1127 }
1128
1129 pub fn input_blocker(mut self) -> Self {
1131 self.input_blocker = true;
1132 self
1133 }
1134
1135 pub fn hit_passthrough(mut self) -> Self {
1136 self.hit_passthrough = true;
1137 self
1138 }
1139 pub fn clickable(mut self) -> Self {
1140 self.click = true;
1141 self
1142 }
1143 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1146 self.click = true;
1147 self.interaction_source = Some(source.source());
1148 self
1149 }
1150 pub fn state_colors(mut self, colors: StateColors) -> Self {
1153 self.state_colors = Some(colors);
1154 self
1155 }
1156 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1158 self.state_elevation = Some(elev);
1159 self
1160 }
1161 pub fn disabled(mut self) -> Self {
1163 self.disabled = true;
1164 self
1165 }
1166 pub fn enabled(mut self, enabled: bool) -> Self {
1168 self.disabled = !enabled;
1169 self
1170 }
1171 pub fn focusable(mut self, focusable: bool) -> Self {
1176 self.focusable = Some(focusable);
1177 self
1178 }
1179 pub fn focus_group(mut self) -> Self {
1182 self.focus_group = true;
1183 self
1184 }
1185 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1194 self.interaction_source = Some(source.source());
1195 self
1196 }
1197 pub fn hoverable(
1200 mut self,
1201 on_enter: impl Fn() + 'static,
1202 on_leave: impl Fn() + 'static,
1203 ) -> Self {
1204 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1205 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1206 self
1207 }
1208 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1212 self.interaction_source = Some(source.source());
1213 self
1214 }
1215 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1218 self.propagate_min = propagate;
1219 self
1220 }
1221 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1222 self.on_scroll = Some(Rc::new(f));
1223 self
1224 }
1225 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1229 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1230 self
1231 }
1232 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1234 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1235 self
1236 }
1237 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1239 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1240 self
1241 }
1242 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1249 self.nested_scroll_connection = Some(conn);
1250 self
1251 }
1252 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1253 self.on_pointer_down = Some(Rc::new(f));
1254 self
1255 }
1256 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1257 self.on_pointer_move = Some(Rc::new(f));
1258 self
1259 }
1260 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1261 self.on_pointer_up = Some(Rc::new(f));
1262 self
1263 }
1264 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1265 self.on_pointer_cancel = Some(Rc::new(f));
1266 self
1267 }
1268 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1269 self.on_pointer_enter = Some(Rc::new(f));
1270 self
1271 }
1272 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1273 self.on_pointer_leave = Some(Rc::new(f));
1274 self
1275 }
1276 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1277 self.on_click = Some(Rc::new(f));
1278 self.click = true;
1279 self
1280 }
1281 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1282 self.on_double_click = Some(Rc::new(f));
1283 self
1284 }
1285 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1286 self.on_long_click = Some(Rc::new(f));
1287 self
1288 }
1289 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1290 self.semantics = Some(s);
1291 self
1292 }
1293 pub fn alpha(mut self, a: f32) -> Self {
1294 self.alpha = Some(a);
1295 self
1296 }
1297 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1302 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1303 self
1304 }
1305 pub fn shadow(mut self, blur_radius: f32, offset_y: f32) -> Self {
1309 self.shadow = Some(ShadowSpec {
1310 blur_radius: blur_radius.max(0.0),
1311 offset_y,
1312 color: Color(0, 0, 0, 64),
1313 });
1314 self
1315 }
1316 pub fn shadow_with_color(mut self, blur_radius: f32, offset_y: f32, color: Color) -> Self {
1318 self.shadow = Some(ShadowSpec {
1319 blur_radius: blur_radius.max(0.0),
1320 offset_y,
1321 color,
1322 });
1323 self
1324 }
1325 pub fn elevation(mut self, level: f32) -> Self {
1329 if level <= 0.0 {
1330 self.shadow = None;
1331 return self;
1332 }
1333 self.shadow = Some(ShadowSpec {
1334 blur_radius: level * 2.0,
1335 offset_y: level * 0.5,
1336 color: Color(0, 0, 0, (level * 8.0).clamp(8.0, 80.0) as u8),
1337 });
1338 self
1339 }
1340 pub fn transform(mut self, t: Transform) -> Self {
1341 self.transform = Some(t);
1342 self
1343 }
1344 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
1345 self.grid = Some(GridConfig {
1346 columns,
1347 row_gap,
1348 column_gap,
1349 });
1350 self
1351 }
1352 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1353 self.grid_col_span = Some(col_span);
1354 self.grid_row_span = Some(row_span);
1355 self
1356 }
1357 pub fn absolute(mut self) -> Self {
1358 self.position_type = Some(PositionType::Absolute);
1359 self
1360 }
1361 pub fn offset(
1362 mut self,
1363 left: Option<f32>,
1364 top: Option<f32>,
1365 right: Option<f32>,
1366 bottom: Option<f32>,
1367 ) -> Self {
1368 self.offset_left = left;
1369 self.offset_top = top;
1370 self.offset_right = right;
1371 self.offset_bottom = bottom;
1372 self
1373 }
1374 pub fn offset_left(mut self, v: f32) -> Self {
1375 self.offset_left = Some(v);
1376 self
1377 }
1378 pub fn offset_right(mut self, v: f32) -> Self {
1379 self.offset_right = Some(v);
1380 self
1381 }
1382 pub fn offset_top(mut self, v: f32) -> Self {
1383 self.offset_top = Some(v);
1384 self
1385 }
1386 pub fn offset_bottom(mut self, v: f32) -> Self {
1387 self.offset_bottom = Some(v);
1388 self
1389 }
1390 pub fn margin(mut self, v: f32) -> Self {
1391 self.margin_left = Some(v);
1392 self.margin_right = Some(v);
1393 self.margin_top = Some(v);
1394 self.margin_bottom = Some(v);
1395 self
1396 }
1397
1398 pub fn margin_horizontal(mut self, v: f32) -> Self {
1399 self.margin_left = Some(v);
1400 self.margin_right = Some(v);
1401 self
1402 }
1403
1404 pub fn margin_vertical(mut self, v: f32) -> Self {
1405 self.margin_top = Some(v);
1406 self.margin_bottom = Some(v);
1407 self
1408 }
1409 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1410 self.aspect_ratio = Some(ratio);
1411 self
1412 }
1413 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1415 self.intrinsic_width = Some(mode);
1416 self
1417 }
1418 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1420 self.intrinsic_height = Some(mode);
1421 self
1422 }
1423 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1424 self.painter = Some(Rc::new(f));
1425 self
1426 }
1427 pub fn scale(self, s: f32) -> Self {
1428 self.scale2(s, s)
1429 }
1430 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1431 let mut t = self.transform.unwrap_or_else(Transform::identity);
1432 t.scale_x *= sx;
1433 t.scale_y *= sy;
1434 self.transform = Some(t);
1435 self
1436 }
1437 pub fn translate(mut self, x: f32, y: f32) -> Self {
1438 let t = self.transform.unwrap_or_else(Transform::identity);
1439 self.transform = Some(t.combine(&Transform::translate(x, y)));
1440 self
1441 }
1442 pub fn translate_vec2(self, v: Vec2) -> Self {
1443 self.translate(v.x, v.y)
1444 }
1445 pub fn rotate(mut self, radians: f32) -> Self {
1446 let mut t = self.transform.unwrap_or_else(Transform::identity);
1447 t.rotate += radians;
1448 self.transform = Some(t);
1449 self
1450 }
1451 pub fn transform_origin(mut self, x: f32, y: f32) -> Self {
1452 let mut t = self.transform.unwrap_or_else(Transform::identity);
1453 t.origin_x = x;
1454 t.origin_y = y;
1455 self.transform = Some(t);
1456 self
1457 }
1458 pub fn weight(mut self, w: f32) -> Self {
1459 let w = w.max(0.0);
1460 self.flex_grow = Some(w);
1461 self.flex_shrink = Some(1.0);
1462 self.flex_basis = Some(0.0);
1464 self
1465 }
1466 pub fn repaint_boundary(mut self) -> Self {
1470 self.repaint_boundary = true;
1471 self
1472 }
1473 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1474 self.on_action = Some(Rc::new(f));
1475 self
1476 }
1477
1478 pub fn on_drag_start(
1480 mut self,
1481 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1482 ) -> Self {
1483 self.on_drag_start = Some(Rc::new(f));
1484 self
1485 }
1486
1487 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1489 self.on_drag_end = Some(Rc::new(f));
1490 self
1491 }
1492
1493 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1495 self.on_drag_enter = Some(Rc::new(f));
1496 self
1497 }
1498
1499 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1501 self.on_drag_over = Some(Rc::new(f));
1502 self
1503 }
1504
1505 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1507 self.on_drag_leave = Some(Rc::new(f));
1508 self
1509 }
1510
1511 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1514 self.on_drop = Some(Rc::new(f));
1515 self
1516 }
1517
1518 pub fn draw_drag_decoration(
1523 mut self,
1524 f: impl Fn(&mut crate::Scene, &crate::dnd::DragPreviewCtx) + 'static,
1525 ) -> Self {
1526 self.drag_preview = Some(Rc::new(f));
1527 self
1528 }
1529
1530 pub fn draw_drag_decoration_rc(mut self, preview: crate::dnd::DragPreview) -> Self {
1532 self.drag_preview = Some(preview);
1533 self
1534 }
1535
1536 pub fn drag_preview_label(self, label: impl Into<String>, accent: crate::Color) -> Self {
1538 self.draw_drag_decoration_rc(crate::dnd::drag_preview_label(label, accent))
1539 }
1540
1541 pub fn drag_preview_chip(self, label: impl Into<String>, accent: crate::Color) -> Self {
1543 self.draw_drag_decoration_rc(crate::dnd::drag_preview_chip(label, accent))
1544 }
1545
1546 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1548 self.cursor = Some(c);
1549 self
1550 }
1551
1552 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1556 self.animate_content_size = Some(spec);
1557 self
1558 }
1559
1560 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1563 self.focus_requester = Some(fr);
1564 self
1565 }
1566
1567 pub fn focus_target(mut self) -> Self {
1570 self.focusable = Some(true);
1571 self
1572 }
1573
1574 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1577 self.on_focus_changed = Some(Rc::new(f));
1578 self
1579 }
1580
1581 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
1585 self.on_globally_positioned = Some(Rc::new(f));
1586 self
1587 }
1588
1589 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
1592 self.on_size_changed = Some(Rc::new(f));
1593 self
1594 }
1595
1596 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
1600 self.on_key_event = Some(Rc::new(f));
1601 self
1602 }
1603
1604 pub fn on_preview_key_event(
1608 mut self,
1609 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
1610 ) -> Self {
1611 self.on_preview_key_event = Some(Rc::new(f));
1612 self
1613 }
1614
1615 pub fn blur(mut self, radius_dp: f32) -> Self {
1622 self.blur = Some(BlurStyle {
1623 radius_x: radius_dp.max(0.0),
1624 radius_y: radius_dp.max(0.0),
1625 edge_treatment: BlurredEdgeTreatment::Rectangle,
1626 });
1627 self
1628 }
1629
1630 pub fn blur_with_edge(
1635 mut self,
1636 radius_x: f32,
1637 radius_y: f32,
1638 edge_treatment: BlurredEdgeTreatment,
1639 ) -> Self {
1640 self.blur = Some(BlurStyle {
1641 radius_x: radius_x.max(0.0),
1642 radius_y: radius_y.max(0.0),
1643 edge_treatment,
1644 });
1645 self
1646 }
1647
1648 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (f32, f32) + 'static) -> Self {
1656 self.layout = Some(Rc::new(f));
1657 self
1658 }
1659
1660 pub fn text_input(mut self, config: TextInputConfig) -> Self {
1662 self.text_input = Some(config);
1663 self
1664 }
1665
1666 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
1670 self.indication = Some(factory);
1671 self
1672 }
1673}