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}
21
22#[derive(Clone, Copy, Debug)]
24pub struct StateElevation {
25 pub default: f32,
26 pub hovered: f32,
27 pub pressed: f32,
28 pub disabled: f32,
29}
30
31macro_rules! merge_opts {
32 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
33 $( $dst.$f = $src.$f.or($dst.$f); )+
34 };
35}
36macro_rules! merge_flags {
37 ($dst:ident, $src:ident; $($f:ident),+ $(,)?) => {
38 $( $dst.$f |= $src.$f; )+
39 };
40}
41
42macro_rules! impl_option_fields {
43 ($ty:ty, $fn:ident) => {
44 impl $ty {
45 $fn!(replace);
46 }
47 };
48 ($ty:ident) => {
49 impl $ty {
50 pub fn then(mut self, other: Self) -> Self {
53 merge_opts!(self, other;
54 key, size, width, height, required_size,
55 padding, padding_values,
56 min_width, min_height, max_width, max_height,
57 required_min_width, required_max_width,
58 required_min_height, required_max_height,
59 default_min_width, default_min_height,
60 fill_max, fill_max_w, fill_max_h,
61 background, state_colors, state_elevation, border,
62 flex_grow, flex_shrink, flex_basis, flex_wrap, flex_dir,
63 gap, row_gap, column_gap,
64 align_self, justify_content, align_items_container, align_content,
65 clip_rounded, clip_rect, overflow, render_z_index,
66 on_scroll,
67 nested_scroll_connection,
68 scroll,
69 on_pointer_down, on_pointer_move, on_pointer_up,
70 on_pointer_enter, on_pointer_leave,
71 on_click, on_double_click, on_long_click,
72 semantics, alpha, transform,
73 grid, grid_col_span, grid_row_span,
74 position_type,
75 offset_left, offset_right, offset_top, offset_bottom,
76 margin_left, margin_right, margin_top, margin_bottom,
77 aspect_ratio, intrinsic_width, intrinsic_height,
78 painter,
79 on_drag_start, on_drag_end, on_drag_enter, on_drag_over, on_drag_leave, on_drop,
80 on_action, cursor, animate_content_size, focus_requester, on_focus_changed,
81 interaction_source, text_input,
82 );
83 merge_flags!(self, other;
84 hit_passthrough, input_blocker, repaint_boundary, click, disabled,
85 propagate_min, focus_group,
86 );
87
88 if let Some(f) = other.focusable {
89 self.focusable = Some(f);
90 }
91 if other.indication.is_some() {
92 self.indication = other.indication;
93 }
94 if other.z_index != 0.0 {
95 self.z_index = other.z_index;
96 }
97 self
98 }
99 }
100 };
101}
102
103#[derive(Clone, Copy, Debug, PartialEq, Eq)]
104pub enum ClipOp {
105 Intersect,
107 Difference,
109}
110
111impl Default for ClipOp {
112 fn default() -> Self {
113 Self::Intersect
114 }
115}
116
117#[derive(Clone, Copy, Debug, PartialEq, Eq)]
123pub enum Overflow {
124 Clip,
125 Visible,
126}
127
128impl Default for Overflow {
129 fn default() -> Self {
130 Self::Clip
131 }
132}
133
134#[derive(Clone, Copy, Debug)]
137pub struct ClipRect {
138 pub left: f32,
139 pub top: f32,
140 pub right: f32,
141 pub bottom: f32,
142 pub op: ClipOp,
143}
144
145#[derive(Clone, Debug)]
146pub struct Border {
147 pub width: f32,
148 pub color: Color,
149 pub radius: [f32; 4],
150}
151
152#[derive(Clone, Copy, Debug, Default)]
153pub struct PaddingValues {
154 pub left: f32,
155 pub right: f32,
156 pub top: f32,
157 pub bottom: f32,
158}
159
160#[derive(Clone, Debug)]
161pub struct GridConfig {
162 pub columns: usize,
163 pub row_gap: f32,
164 pub column_gap: f32,
165}
166
167#[derive(Clone, Copy, Debug, PartialEq)]
170pub enum BlurredEdgeTreatment {
171 Rectangle,
174 Unbounded,
177}
178
179#[derive(Clone, Copy, Debug)]
181pub struct BlurStyle {
182 pub radius_x: f32,
184 pub radius_y: f32,
186 pub edge_treatment: BlurredEdgeTreatment,
188}
189
190#[derive(Clone, Copy, Debug)]
195pub struct LayoutConstraints {
196 pub min_width: f32,
197 pub max_width: f32,
198 pub min_height: f32,
199 pub max_height: f32,
200}
201
202#[derive(Clone, Copy, Debug)]
209pub struct ShadowSpec {
210 pub blur_radius: f32,
211 pub offset_y: f32,
212 pub color: Color,
213}
214
215#[derive(Clone, Copy, Debug)]
216#[non_exhaustive]
217pub enum PositionType {
218 Relative,
219 Absolute,
220}
221
222#[derive(Clone)]
224pub struct TextInputConfig {
225 pub hint: String,
226 pub multiline: bool,
227 pub on_change: Option<Rc<dyn Fn(String)>>,
228 pub on_submit: Option<Rc<dyn Fn(String)>>,
229 pub focus_tracker: Option<Rc<Cell<bool>>>,
230 pub value: String,
231 pub visual_transformation: Option<Rc<dyn crate::text::VisualTransformation>>,
232 pub keyboard_type: crate::text::KeyboardType,
233 pub capitalization: crate::text::KeyboardCapitalization,
234 pub ime_action: crate::text::ImeAction,
235 pub enabled: bool,
237 pub read_only: bool,
239 pub max_lines: Option<usize>,
241 pub min_lines: usize,
243 pub cursor_color: Option<Color>,
245 pub on_text_layout: Option<Rc<dyn Fn(&crate::text::TextLayoutResult)>>,
248 pub text_style: Option<crate::text::TextStyle>,
251 pub keyboard_actions: Option<crate::text::KeyboardActions>,
254 pub interaction_source: Option<InteractionSource>,
256 pub line_limits: Option<crate::text::TextFieldLineLimits>,
258}
259
260impl std::fmt::Debug for TextInputConfig {
261 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
262 let mut s = f.debug_struct("TextInputConfig");
263 s.field("hint", &self.hint);
264 s.field("multiline", &self.multiline);
265 if self.on_change.is_some() {
266 s.field("on_change", &"…");
267 }
268 if self.on_submit.is_some() {
269 s.field("on_submit", &"…");
270 }
271 if self.focus_tracker.is_some() {
272 s.field("focus_tracker", &"…");
273 }
274 s.field("value", &self.value);
275 if self.visual_transformation.is_some() {
276 s.field("visual_transformation", &"…");
277 }
278 s.field("keyboard_type", &self.keyboard_type);
279 s.field("capitalization", &self.capitalization);
280 s.field("ime_action", &self.ime_action);
281 s.field("enabled", &self.enabled);
282 s.field("read_only", &self.read_only);
283 s.field("max_lines", &self.max_lines);
284 s.field("min_lines", &self.min_lines);
285 s.field("cursor_color", &self.cursor_color);
286 if self.on_text_layout.is_some() {
287 s.field("on_text_layout", &"…");
288 }
289 s.finish()
290 }
291}
292
293#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
296pub enum IntrinsicSize {
297 Min,
298 Max,
299}
300
301static PRESS_COUNTER: AtomicU64 = AtomicU64::new(1);
302
303pub type PressId = u64;
305
306#[derive(Clone, Copy, Debug, PartialEq)]
314pub enum Interaction {
315 Press(PressId, Vec2),
318 Release(PressId),
320 Cancel(PressId),
323 HoverEnter,
324 HoverLeave,
325 Focus,
326 Unfocus,
327 DragStart,
328 DragStop,
329 DragCancel,
330}
331
332impl Interaction {
333 #[inline]
335 pub fn new_press(position: Vec2) -> Self {
336 Interaction::Press(PRESS_COUNTER.fetch_add(1, Ordering::Relaxed), position)
337 }
338}
339
340#[derive(Clone)]
347pub struct InteractionSource {
348 pub(crate) state: Rc<RefCell<InteractionState>>,
349}
350
351impl InteractionSource {
352 pub fn collect_is_pressed(&self) -> bool {
353 self.state.borrow().pressed > 0
354 }
355 pub fn collect_is_hovered(&self) -> bool {
356 self.state.borrow().hovered
357 }
358 pub fn collect_is_focused(&self) -> bool {
359 self.state.borrow().focused
360 }
361 pub fn collect_is_dragged(&self) -> bool {
362 self.state.borrow().dragged > 0
363 }
364 pub fn collect_last_press_position(&self) -> Option<Vec2> {
365 self.state.borrow().last_press_position
366 }
367 pub fn collect_last_press_id(&self) -> Option<PressId> {
368 self.state.borrow().last_press_id
369 }
370 pub fn stable_id(&self) -> *const () {
372 Rc::as_ptr(&self.state) as *const ()
373 }
374 pub fn to_mutable(&self) -> MutableInteractionSource {
378 MutableInteractionSource {
379 state: self.state.clone(),
380 }
381 }
382}
383
384#[derive(Clone)]
394pub struct MutableInteractionSource {
395 pub(crate) state: Rc<RefCell<InteractionState>>,
396}
397
398impl std::fmt::Debug for MutableInteractionSource {
399 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
400 f.debug_struct("MutableInteractionSource")
401 .finish_non_exhaustive()
402 }
403}
404
405impl MutableInteractionSource {
406 pub fn new() -> Self {
407 Self {
408 state: Rc::new(RefCell::new(InteractionState::default())),
409 }
410 }
411
412 pub fn emit(&self, interaction: Interaction) {
414 let mut s = self.state.borrow_mut();
415 match interaction {
416 Interaction::Press(id, pos) => {
417 s.pressed = s.pressed.saturating_add(1);
418 s.last_press_id = Some(id);
419 s.last_press_position = Some(pos);
420 }
421 Interaction::Release(_) | Interaction::Cancel(_) => {
422 s.pressed = s.pressed.saturating_sub(1);
423 }
424 Interaction::HoverEnter => s.hovered = true,
425 Interaction::HoverLeave => s.hovered = false,
426 Interaction::Focus => s.focused = true,
427 Interaction::Unfocus => s.focused = false,
428 Interaction::DragStart => s.dragged = s.dragged.saturating_add(1),
429 Interaction::DragStop | Interaction::DragCancel => {
430 s.dragged = s.dragged.saturating_sub(1);
431 }
432 }
433 }
434
435 pub fn source(&self) -> InteractionSource {
437 InteractionSource {
438 state: self.state.clone(),
439 }
440 }
441}
442
443impl Default for MutableInteractionSource {
444 fn default() -> Self {
445 Self::new()
446 }
447}
448
449#[derive(Clone, Default)]
450pub(crate) struct InteractionState {
451 pressed: u32,
452 hovered: bool,
453 focused: bool,
454 dragged: u32,
455 pub(crate) last_press_position: Option<Vec2>,
457 pub(crate) last_press_id: Option<PressId>,
459}
460
461#[derive(Clone, Default)]
462pub struct Modifier {
463 pub key: Option<u64>,
469
470 pub size: Option<Size>,
471 pub width: Option<f32>,
472 pub height: Option<f32>,
473 pub required_size: Option<Size>,
474 pub fill_max: Option<f32>,
475 pub fill_max_w: Option<f32>,
476 pub fill_max_h: Option<f32>,
477 pub padding: Option<f32>,
478 pub padding_values: Option<PaddingValues>,
479 pub min_width: Option<f32>,
480 pub min_height: Option<f32>,
481 pub max_width: Option<f32>,
482 pub max_height: Option<f32>,
483 pub required_min_width: Option<f32>,
485 pub required_max_width: Option<f32>,
487 pub required_min_height: Option<f32>,
489 pub required_max_height: Option<f32>,
491 pub default_min_width: Option<f32>,
494 pub default_min_height: Option<f32>,
495 pub background: Option<Brush>,
496 pub state_colors: Option<StateColors>,
497 pub state_elevation: Option<StateElevation>,
498
499 pub border: Option<Border>,
500 pub flex_grow: Option<f32>,
501 pub flex_shrink: Option<f32>,
502 pub flex_basis: Option<f32>,
503 pub flex_wrap: Option<FlexWrap>,
504 pub flex_dir: Option<FlexDirection>,
505 pub gap: Option<f32>,
506 pub row_gap: Option<f32>,
507 pub column_gap: Option<f32>,
508 pub align_self: Option<AlignSelf>,
509 pub justify_content: Option<JustifyContent>,
510 pub align_items_container: Option<AlignItems>,
511 pub align_content: Option<AlignContent>,
512 pub clip_rounded: Option<[f32; 4]>,
513 pub clip_rect: Option<ClipRect>,
516 pub overflow: Option<Overflow>,
521 pub z_index: f32,
523 pub render_z_index: Option<f32>,
525 pub hit_passthrough: bool,
527 pub input_blocker: bool,
529 pub repaint_boundary: bool,
530 pub click: bool,
531 pub disabled: bool,
533 pub focusable: Option<bool>,
537 pub propagate_min: bool,
539 pub focus_group: bool,
542 pub on_scroll: Option<Rc<dyn Fn(Vec2) -> Vec2>>,
543 pub scroll: Option<crate::scroll::ScrollBinding>,
549 pub nested_scroll_connection: Option<crate::nested_scroll::NestedScrollConnection>,
558 pub on_pointer_down: Option<Rc<dyn Fn(PointerEvent)>>,
559 pub on_pointer_move: Option<Rc<dyn Fn(PointerEvent)>>,
560 pub on_pointer_up: Option<Rc<dyn Fn(PointerEvent)>>,
561 pub on_pointer_cancel: Option<Rc<dyn Fn(PointerEvent)>>,
562 pub on_pointer_enter: Option<Rc<dyn Fn(PointerEvent)>>,
563 pub on_pointer_leave: Option<Rc<dyn Fn(PointerEvent)>>,
564 pub on_click: Option<Rc<dyn Fn()>>,
566 pub on_double_click: Option<Rc<dyn Fn()>>,
568 pub on_long_click: Option<Rc<dyn Fn()>>,
570 pub on_globally_positioned: Option<Rc<dyn Fn(crate::Rect)>>,
573 pub on_size_changed: Option<Rc<dyn Fn(crate::Vec2)>>,
576 pub on_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
579 pub on_preview_key_event: Option<Rc<dyn Fn(crate::input::KeyEvent) -> bool>>,
582 pub blur: Option<BlurStyle>,
587 pub layout: Option<Rc<dyn Fn(LayoutConstraints) -> (f32, f32)>>,
592 pub semantics: Option<crate::Semantics>,
593 pub alpha: Option<f32>,
594 pub graphics_layer: Option<f32>,
595 pub shadow: Option<ShadowSpec>,
596 pub transform: Option<Transform>,
597 pub grid: Option<GridConfig>,
598 pub grid_col_span: Option<u16>,
599 pub grid_row_span: Option<u16>,
600 pub position_type: Option<PositionType>,
601 pub offset_left: Option<f32>,
602 pub offset_right: Option<f32>,
603 pub offset_top: Option<f32>,
604 pub offset_bottom: Option<f32>,
605
606 pub margin_left: Option<f32>,
607 pub margin_right: Option<f32>,
608 pub margin_top: Option<f32>,
609 pub margin_bottom: Option<f32>,
610 pub aspect_ratio: Option<f32>,
611 pub intrinsic_width: Option<IntrinsicSize>,
613 pub intrinsic_height: Option<IntrinsicSize>,
615 pub painter: Option<Rc<dyn Fn(&mut crate::Scene, crate::Rect, f32)>>,
616
617 pub on_drag_start: Option<Rc<dyn Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload>>>,
619 pub on_drag_end: Option<Rc<dyn Fn(crate::dnd::DragEnd)>>,
620 pub on_drag_enter: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
621 pub on_drag_over: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
622 pub on_drag_leave: Option<Rc<dyn Fn(crate::dnd::DragOver)>>,
623 pub on_drop: Option<Rc<dyn Fn(crate::dnd::DropEvent) -> bool>>,
624
625 pub on_action: Option<Rc<dyn Fn(crate::shortcuts::Action) -> bool>>,
626
627 pub cursor: Option<crate::CursorIcon>,
629
630 pub animate_content_size: Option<AnimationSpec>,
633
634 pub focus_requester: Option<crate::runtime::FocusRequester>,
638
639 pub on_focus_changed: Option<Rc<dyn Fn(bool)>>,
642
643 pub interaction_source: Option<InteractionSource>,
650
651 pub text_input: Option<TextInputConfig>,
653
654 pub indication: Option<Rc<dyn IndicationNodeFactory>>,
656}
657
658impl std::fmt::Debug for Modifier {
659 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
660 let mut s = f.debug_struct("Modifier");
661
662 macro_rules! opt_val {
663 ($($name:ident),+ $(,)?) => {
664 $( if self.$name.is_some() { s.field(stringify!($name), &self.$name); } )+
665 };
666 }
667 if self.indication.is_some() {
668 s.field("indication", &"…");
669 }
670
671 opt_val!(
672 key,
673 size,
674 width,
675 height,
676 required_size,
677 padding,
678 padding_values,
679 min_width,
680 min_height,
681 max_width,
682 max_height,
683 required_min_width,
684 required_max_width,
685 required_min_height,
686 required_max_height,
687 default_min_width,
688 default_min_height,
689 fill_max,
690 fill_max_w,
691 fill_max_h,
692 background,
693 state_colors,
694 state_elevation,
695 border,
696 flex_grow,
697 flex_shrink,
698 flex_basis,
699 flex_wrap,
700 flex_dir,
701 gap,
702 row_gap,
703 column_gap,
704 align_self,
705 justify_content,
706 align_items_container,
707 align_content,
708 clip_rounded,
709 clip_rect,
710 render_z_index,
711 semantics,
712 alpha,
713 transform,
714 grid,
715 grid_col_span,
716 grid_row_span,
717 position_type,
718 offset_left,
719 offset_right,
720 offset_top,
721 offset_bottom,
722 margin_left,
723 margin_right,
724 margin_top,
725 margin_bottom,
726 aspect_ratio,
727 intrinsic_width,
728 intrinsic_height,
729 cursor,
730 animate_content_size,
731 blur,
732 );
733
734 macro_rules! opt_cb {
735 ($($name:ident),+ $(,)?) => {
736 $( if self.$name.is_some() { s.field(stringify!($name), &"…"); } )+
737 };
738 }
739 opt_cb!(
740 on_scroll,
741 scroll,
742 nested_scroll_connection,
743 on_pointer_down,
744 on_pointer_move,
745 on_pointer_up,
746 on_pointer_cancel,
747 on_pointer_enter,
748 on_pointer_leave,
749 on_click,
750 on_double_click,
751 on_long_click,
752 on_globally_positioned,
753 on_size_changed,
754 on_key_event,
755 on_preview_key_event,
756 painter,
757 on_drag_start,
758 on_drag_end,
759 on_drag_enter,
760 on_drag_over,
761 on_drag_leave,
762 on_drop,
763 on_action,
764 on_focus_changed,
765 interaction_source,
766 text_input,
767 layout,
768 );
769
770 macro_rules! flag {
771 ($($name:ident),+ $(,)?) => {
772 $( if self.$name { s.field(stringify!($name), &true); } )+
773 };
774 }
775 flag!(
776 hit_passthrough,
777 input_blocker,
778 repaint_boundary,
779 click,
780 disabled,
781 propagate_min,
782 focus_group,
783 );
784
785 if let Some(f) = self.focusable {
786 s.field("focusable", &f);
787 }
788 if self.z_index != 0.0 {
789 s.field("z_index", &self.z_index);
790 }
791
792 s.finish()
793 }
794}
795
796impl_option_fields!(Modifier);
797
798impl Modifier {
799 pub fn new() -> Self {
800 Self::default()
801 }
802
803 pub fn key(mut self, key: u64) -> Self {
806 self.key = Some(key);
807 self
808 }
809
810 pub fn size(mut self, w: f32, h: f32) -> Self {
811 self.size = Some(Size {
812 width: w,
813 height: h,
814 });
815 self
816 }
817 pub fn width(mut self, w: f32) -> Self {
818 self.width = Some(w);
819 self
820 }
821 pub fn height(mut self, h: f32) -> Self {
822 self.height = Some(h);
823 self
824 }
825 pub fn required_size(mut self, w: f32, h: f32) -> Self {
830 self.required_size = Some(Size {
831 width: w,
832 height: h,
833 });
834 self
835 }
836 pub fn required_width_in(mut self, min: f32, max: f32) -> Self {
837 self.required_min_width = Some(min.max(0.0));
838 self.required_max_width = Some(max.max(0.0));
839 self
840 }
841 pub fn required_height_in(mut self, min: f32, max: f32) -> Self {
842 self.required_min_height = Some(min.max(0.0));
843 self.required_max_height = Some(max.max(0.0));
844 self
845 }
846 pub fn required_min_width(mut self, w: f32) -> Self {
847 self.required_min_width = Some(w.max(0.0));
848 self
849 }
850 pub fn required_max_width(mut self, w: f32) -> Self {
851 self.required_max_width = Some(w.max(0.0));
852 self
853 }
854 pub fn required_min_height(mut self, h: f32) -> Self {
855 self.required_min_height = Some(h.max(0.0));
856 self
857 }
858 pub fn required_max_height(mut self, h: f32) -> Self {
859 self.required_max_height = Some(h.max(0.0));
860 self
861 }
862 pub fn default_min_size(mut self, w: f32, h: f32) -> Self {
864 self.default_min_width = Some(w.max(0.0));
865 self.default_min_height = Some(h.max(0.0));
866 self
867 }
868 pub fn fill_max_size(mut self) -> Self {
871 self.fill_max = Some(1.0);
872 self
873 }
874 pub fn fill_max_size_frac(mut self, fraction: f32) -> Self {
875 self.fill_max = Some(fraction.clamp(0.0, 1.0));
876 self
877 }
878 pub fn fill_max_width(mut self) -> Self {
880 self.fill_max_w = Some(1.0);
881 self
882 }
883 pub fn fill_max_width_frac(mut self, fraction: f32) -> Self {
884 self.fill_max_w = Some(fraction.clamp(0.0, 1.0));
885 self
886 }
887 pub fn fill_max_height(mut self) -> Self {
889 self.fill_max_h = Some(1.0);
890 self
891 }
892 pub fn fill_max_height_frac(mut self, fraction: f32) -> Self {
893 self.fill_max_h = Some(fraction.clamp(0.0, 1.0));
894 self
895 }
896 pub fn padding(mut self, v: f32) -> Self {
897 self.padding = Some(v);
898 self
899 }
900 pub fn padding_values(mut self, padding: PaddingValues) -> Self {
901 self.padding_values = Some(padding);
902 self
903 }
904 pub fn ime_padding(mut self) -> Self {
907 let insets = crate::locals::window_insets();
908 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
909 let mut p = self.padding_values.unwrap_or_default();
910 p.bottom += insets.ime_bottom / scale;
911 self.padding_values = Some(p);
912 self
913 }
914 pub fn system_bars_padding(mut self) -> Self {
916 let insets = crate::locals::window_insets();
917 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
918 let mut p = self.padding_values.unwrap_or_default();
919 p.top += insets.top / scale;
920 p.bottom += insets.bottom / scale;
921 self.padding_values = Some(p);
922 self
923 }
924 pub fn status_bars_padding(mut self) -> Self {
926 let insets = crate::locals::window_insets();
927 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
928 let mut p = self.padding_values.unwrap_or_default();
929 p.top += insets.top / scale;
930 self.padding_values = Some(p);
931 self
932 }
933 pub fn navigation_bars_padding(mut self) -> Self {
935 let insets = crate::locals::window_insets();
936 let scale = crate::locals::density().scale * crate::locals::ui_scale().0;
937 let mut p = self.padding_values.unwrap_or_default();
938 p.bottom += insets.bottom / scale;
939 self.padding_values = Some(p);
940 self
941 }
942 pub fn min_size(mut self, w: f32, h: f32) -> Self {
943 self.min_width = Some(w);
944 self.min_height = Some(h);
945 self
946 }
947 pub fn max_size(mut self, w: f32, h: f32) -> Self {
948 self.max_width = Some(w);
949 self.max_height = Some(h);
950 self
951 }
952 pub fn min_width(mut self, w: f32) -> Self {
953 self.min_width = Some(w);
954 self
955 }
956 pub fn min_height(mut self, h: f32) -> Self {
957 self.min_height = Some(h);
958 self
959 }
960 pub fn max_width(mut self, w: f32) -> Self {
961 self.max_width = Some(w);
962 self
963 }
964 pub fn max_height(mut self, h: f32) -> Self {
965 self.max_height = Some(h);
966 self
967 }
968 pub fn background(mut self, color: Color) -> Self {
970 self.background = Some(Brush::Solid(color));
971 self
972 }
973 pub fn background_brush(mut self, brush: Brush) -> Self {
975 self.background = Some(brush);
976 self
977 }
978 pub fn border(mut self, width: f32, color: Color, radius: f32) -> Self {
979 self.border = Some(Border {
980 width,
981 color,
982 radius: [radius; 4],
983 });
984 self
985 }
986 pub fn border_radii(mut self, width: f32, color: Color, radii: [f32; 4]) -> Self {
987 self.border = Some(Border {
988 width,
989 color,
990 radius: radii,
991 });
992 self
993 }
994 pub fn flex_grow(mut self, v: f32) -> Self {
995 self.flex_grow = Some(v);
996 self
997 }
998 pub fn flex_shrink(mut self, v: f32) -> Self {
999 self.flex_shrink = Some(v);
1000 self
1001 }
1002 pub fn flex_basis(mut self, v: f32) -> Self {
1003 self.flex_basis = Some(v);
1004 self
1005 }
1006 pub fn flex_wrap(mut self, w: FlexWrap) -> Self {
1007 self.flex_wrap = Some(w);
1008 self
1009 }
1010 pub fn flex_dir(mut self, d: FlexDirection) -> Self {
1011 self.flex_dir = Some(d);
1012 self
1013 }
1014 pub fn gap(mut self, v: f32) -> Self {
1015 let v = v.max(0.0);
1016 self.gap = Some(v);
1017 self.row_gap = Some(v);
1018 self.column_gap = Some(v);
1019 self
1020 }
1021 pub fn row_gap(mut self, v: f32) -> Self {
1022 self.row_gap = Some(v.max(0.0));
1023 self
1024 }
1025 pub fn column_gap(mut self, v: f32) -> Self {
1026 self.column_gap = Some(v.max(0.0));
1027 self
1028 }
1029 pub fn align_self(mut self, a: AlignSelf) -> Self {
1030 self.align_self = Some(a);
1031 self
1032 }
1033 pub fn align_self_center(mut self) -> Self {
1034 self.align_self = Some(AlignSelf::CENTER);
1035 self
1036 }
1037 pub fn justify_content(mut self, j: JustifyContent) -> Self {
1038 self.justify_content = Some(j);
1039 self
1040 }
1041 pub fn align_items(mut self, a: AlignItems) -> Self {
1042 self.align_items_container = Some(a);
1043 self
1044 }
1045 pub fn align_content(mut self, a: AlignContent) -> Self {
1046 self.align_content = Some(a);
1047 self
1048 }
1049 pub fn clip_rounded(mut self, radius: f32) -> Self {
1050 self.clip_rounded = Some([radius; 4]);
1051 self
1052 }
1053 pub fn clip_rounded_radii(mut self, radii: [f32; 4]) -> Self {
1054 self.clip_rounded = Some(radii);
1055 self
1056 }
1057 pub fn clip_rect(mut self, left: f32, top: f32, right: f32, bottom: f32, op: ClipOp) -> Self {
1060 self.clip_rect = Some(ClipRect {
1061 left,
1062 top,
1063 right,
1064 bottom,
1065 op,
1066 });
1067 self
1068 }
1069 pub fn overflow(mut self, overflow: Overflow) -> Self {
1070 self.overflow = Some(overflow);
1071 self
1072 }
1073 pub fn z_index(mut self, z: f32) -> Self {
1074 self.z_index = z;
1075 self
1076 }
1077
1078 pub fn render_z_index(mut self, z: f32) -> Self {
1081 self.render_z_index = Some(z);
1082 self
1083 }
1084
1085 pub fn input_blocker(mut self) -> Self {
1087 self.input_blocker = true;
1088 self
1089 }
1090
1091 pub fn hit_passthrough(mut self) -> Self {
1092 self.hit_passthrough = true;
1093 self
1094 }
1095 pub fn clickable(mut self) -> Self {
1096 self.click = true;
1097 self
1098 }
1099 pub fn clickable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1102 self.click = true;
1103 self.interaction_source = Some(source.source());
1104 self
1105 }
1106 pub fn state_colors(mut self, colors: StateColors) -> Self {
1109 self.state_colors = Some(colors);
1110 self
1111 }
1112 pub fn state_elevation(mut self, elev: StateElevation) -> Self {
1114 self.state_elevation = Some(elev);
1115 self
1116 }
1117 pub fn disabled(mut self) -> Self {
1119 self.disabled = true;
1120 self
1121 }
1122 pub fn enabled(mut self, enabled: bool) -> Self {
1124 self.disabled = !enabled;
1125 self
1126 }
1127 pub fn focusable(mut self, focusable: bool) -> Self {
1132 self.focusable = Some(focusable);
1133 self
1134 }
1135 pub fn focus_group(mut self) -> Self {
1138 self.focus_group = true;
1139 self
1140 }
1141 pub fn interaction_source(mut self, source: &MutableInteractionSource) -> Self {
1150 self.interaction_source = Some(source.source());
1151 self
1152 }
1153 pub fn hoverable(
1156 mut self,
1157 on_enter: impl Fn() + 'static,
1158 on_leave: impl Fn() + 'static,
1159 ) -> Self {
1160 self.on_pointer_enter = Some(Rc::new(move |_| on_enter()));
1161 self.on_pointer_leave = Some(Rc::new(move |_| on_leave()));
1162 self
1163 }
1164 pub fn hoverable_with_source(mut self, source: &MutableInteractionSource) -> Self {
1168 self.interaction_source = Some(source.source());
1169 self
1170 }
1171 pub fn propagate_min_constraints(mut self, propagate: bool) -> Self {
1174 self.propagate_min = propagate;
1175 self
1176 }
1177 pub fn on_scroll(mut self, f: impl Fn(Vec2) -> Vec2 + 'static) -> Self {
1178 self.on_scroll = Some(Rc::new(f));
1179 self
1180 }
1181 pub fn vertical_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1185 self.scroll = Some(crate::scroll::ScrollBinding::Vertical(binding));
1186 self
1187 }
1188 pub fn horizontal_scroll(mut self, binding: crate::scroll::ScrollAxisBinding) -> Self {
1190 self.scroll = Some(crate::scroll::ScrollBinding::Horizontal(binding));
1191 self
1192 }
1193 pub fn scrollable(mut self, binding: crate::scroll::ScrollBothBinding) -> Self {
1195 self.scroll = Some(crate::scroll::ScrollBinding::Both(binding));
1196 self
1197 }
1198 pub fn nested_scroll(mut self, conn: crate::nested_scroll::NestedScrollConnection) -> Self {
1205 self.nested_scroll_connection = Some(conn);
1206 self
1207 }
1208 pub fn on_pointer_down(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1209 self.on_pointer_down = Some(Rc::new(f));
1210 self
1211 }
1212 pub fn on_pointer_move(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1213 self.on_pointer_move = Some(Rc::new(f));
1214 self
1215 }
1216 pub fn on_pointer_up(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1217 self.on_pointer_up = Some(Rc::new(f));
1218 self
1219 }
1220 pub fn on_pointer_cancel(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1221 self.on_pointer_cancel = Some(Rc::new(f));
1222 self
1223 }
1224 pub fn on_pointer_enter(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1225 self.on_pointer_enter = Some(Rc::new(f));
1226 self
1227 }
1228 pub fn on_pointer_leave(mut self, f: impl Fn(PointerEvent) + 'static) -> Self {
1229 self.on_pointer_leave = Some(Rc::new(f));
1230 self
1231 }
1232 pub fn on_click(mut self, f: impl Fn() + 'static) -> Self {
1233 self.on_click = Some(Rc::new(f));
1234 self.click = true;
1235 self
1236 }
1237 pub fn on_double_click(mut self, f: impl Fn() + 'static) -> Self {
1238 self.on_double_click = Some(Rc::new(f));
1239 self
1240 }
1241 pub fn on_long_click(mut self, f: impl Fn() + 'static) -> Self {
1242 self.on_long_click = Some(Rc::new(f));
1243 self
1244 }
1245 pub fn semantics(mut self, s: crate::Semantics) -> Self {
1246 self.semantics = Some(s);
1247 self
1248 }
1249 pub fn alpha(mut self, a: f32) -> Self {
1250 self.alpha = Some(a);
1251 self
1252 }
1253 pub fn graphics_layer(mut self, alpha: f32) -> Self {
1258 self.graphics_layer = Some(alpha.clamp(0.0, 1.0));
1259 self
1260 }
1261 pub fn shadow(mut self, blur_radius: f32, offset_y: f32) -> Self {
1265 self.shadow = Some(ShadowSpec {
1266 blur_radius: blur_radius.max(0.0),
1267 offset_y,
1268 color: Color(0, 0, 0, 64),
1269 });
1270 self
1271 }
1272 pub fn shadow_with_color(mut self, blur_radius: f32, offset_y: f32, color: Color) -> Self {
1274 self.shadow = Some(ShadowSpec {
1275 blur_radius: blur_radius.max(0.0),
1276 offset_y,
1277 color,
1278 });
1279 self
1280 }
1281 pub fn elevation(mut self, level: f32) -> Self {
1285 if level <= 0.0 {
1286 self.shadow = None;
1287 return self;
1288 }
1289 self.shadow = Some(ShadowSpec {
1290 blur_radius: level * 2.0,
1291 offset_y: level * 0.5,
1292 color: Color(0, 0, 0, (level * 8.0).clamp(8.0, 80.0) as u8),
1293 });
1294 self
1295 }
1296 pub fn transform(mut self, t: Transform) -> Self {
1297 self.transform = Some(t);
1298 self
1299 }
1300 pub fn grid(mut self, columns: usize, row_gap: f32, column_gap: f32) -> Self {
1301 self.grid = Some(GridConfig {
1302 columns,
1303 row_gap,
1304 column_gap,
1305 });
1306 self
1307 }
1308 pub fn grid_span(mut self, col_span: u16, row_span: u16) -> Self {
1309 self.grid_col_span = Some(col_span);
1310 self.grid_row_span = Some(row_span);
1311 self
1312 }
1313 pub fn absolute(mut self) -> Self {
1314 self.position_type = Some(PositionType::Absolute);
1315 self
1316 }
1317 pub fn offset(
1318 mut self,
1319 left: Option<f32>,
1320 top: Option<f32>,
1321 right: Option<f32>,
1322 bottom: Option<f32>,
1323 ) -> Self {
1324 self.offset_left = left;
1325 self.offset_top = top;
1326 self.offset_right = right;
1327 self.offset_bottom = bottom;
1328 self
1329 }
1330 pub fn offset_left(mut self, v: f32) -> Self {
1331 self.offset_left = Some(v);
1332 self
1333 }
1334 pub fn offset_right(mut self, v: f32) -> Self {
1335 self.offset_right = Some(v);
1336 self
1337 }
1338 pub fn offset_top(mut self, v: f32) -> Self {
1339 self.offset_top = Some(v);
1340 self
1341 }
1342 pub fn offset_bottom(mut self, v: f32) -> Self {
1343 self.offset_bottom = Some(v);
1344 self
1345 }
1346 pub fn margin(mut self, v: f32) -> Self {
1347 self.margin_left = Some(v);
1348 self.margin_right = Some(v);
1349 self.margin_top = Some(v);
1350 self.margin_bottom = Some(v);
1351 self
1352 }
1353
1354 pub fn margin_horizontal(mut self, v: f32) -> Self {
1355 self.margin_left = Some(v);
1356 self.margin_right = Some(v);
1357 self
1358 }
1359
1360 pub fn margin_vertical(mut self, v: f32) -> Self {
1361 self.margin_top = Some(v);
1362 self.margin_bottom = Some(v);
1363 self
1364 }
1365 pub fn aspect_ratio(mut self, ratio: f32) -> Self {
1366 self.aspect_ratio = Some(ratio);
1367 self
1368 }
1369 pub fn intrinsic_width(mut self, mode: IntrinsicSize) -> Self {
1371 self.intrinsic_width = Some(mode);
1372 self
1373 }
1374 pub fn intrinsic_height(mut self, mode: IntrinsicSize) -> Self {
1376 self.intrinsic_height = Some(mode);
1377 self
1378 }
1379 pub fn painter(mut self, f: impl Fn(&mut crate::Scene, crate::Rect, f32) + 'static) -> Self {
1380 self.painter = Some(Rc::new(f));
1381 self
1382 }
1383 pub fn scale(self, s: f32) -> Self {
1384 self.scale2(s, s)
1385 }
1386 pub fn scale2(mut self, sx: f32, sy: f32) -> Self {
1387 let mut t = self.transform.unwrap_or_else(Transform::identity);
1388 t.scale_x *= sx;
1389 t.scale_y *= sy;
1390 self.transform = Some(t);
1391 self
1392 }
1393 pub fn translate(mut self, x: f32, y: f32) -> Self {
1394 let t = self.transform.unwrap_or_else(Transform::identity);
1395 self.transform = Some(t.combine(&Transform::translate(x, y)));
1396 self
1397 }
1398 pub fn translate_vec2(self, v: Vec2) -> Self {
1399 self.translate(v.x, v.y)
1400 }
1401 pub fn rotate(mut self, radians: f32) -> Self {
1402 let mut t = self.transform.unwrap_or_else(Transform::identity);
1403 t.rotate += radians;
1404 self.transform = Some(t);
1405 self
1406 }
1407 pub fn weight(mut self, w: f32) -> Self {
1408 let w = w.max(0.0);
1409 self.flex_grow = Some(w);
1410 self.flex_shrink = Some(1.0);
1411 self.flex_basis = Some(0.0);
1413 self
1414 }
1415 pub fn repaint_boundary(mut self) -> Self {
1419 self.repaint_boundary = true;
1420 self
1421 }
1422 pub fn on_action(mut self, f: impl Fn(crate::shortcuts::Action) -> bool + 'static) -> Self {
1423 self.on_action = Some(Rc::new(f));
1424 self
1425 }
1426
1427 pub fn on_drag_start(
1429 mut self,
1430 f: impl Fn(crate::dnd::DragStart) -> Option<crate::dnd::DragPayload> + 'static,
1431 ) -> Self {
1432 self.on_drag_start = Some(Rc::new(f));
1433 self
1434 }
1435
1436 pub fn on_drag_end(mut self, f: impl Fn(crate::dnd::DragEnd) + 'static) -> Self {
1438 self.on_drag_end = Some(Rc::new(f));
1439 self
1440 }
1441
1442 pub fn on_drag_enter(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1444 self.on_drag_enter = Some(Rc::new(f));
1445 self
1446 }
1447
1448 pub fn on_drag_over(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1450 self.on_drag_over = Some(Rc::new(f));
1451 self
1452 }
1453
1454 pub fn on_drag_leave(mut self, f: impl Fn(crate::dnd::DragOver) + 'static) -> Self {
1456 self.on_drag_leave = Some(Rc::new(f));
1457 self
1458 }
1459
1460 pub fn on_drop(mut self, f: impl Fn(crate::dnd::DropEvent) -> bool + 'static) -> Self {
1463 self.on_drop = Some(Rc::new(f));
1464 self
1465 }
1466
1467 pub fn cursor(mut self, c: crate::CursorIcon) -> Self {
1469 self.cursor = Some(c);
1470 self
1471 }
1472
1473 pub fn animate_content_size(mut self, spec: AnimationSpec) -> Self {
1477 self.animate_content_size = Some(spec);
1478 self
1479 }
1480
1481 pub fn focus_requester(mut self, fr: crate::runtime::FocusRequester) -> Self {
1484 self.focus_requester = Some(fr);
1485 self
1486 }
1487
1488 pub fn focus_target(mut self) -> Self {
1491 self.focusable = Some(true);
1492 self
1493 }
1494
1495 pub fn on_focus_changed(mut self, f: impl Fn(bool) + 'static) -> Self {
1498 self.on_focus_changed = Some(Rc::new(f));
1499 self
1500 }
1501
1502 pub fn on_globally_positioned(mut self, f: impl Fn(crate::Rect) + 'static) -> Self {
1506 self.on_globally_positioned = Some(Rc::new(f));
1507 self
1508 }
1509
1510 pub fn on_size_changed(mut self, f: impl Fn(crate::Vec2) + 'static) -> Self {
1513 self.on_size_changed = Some(Rc::new(f));
1514 self
1515 }
1516
1517 pub fn on_key_event(mut self, f: impl Fn(crate::input::KeyEvent) -> bool + 'static) -> Self {
1521 self.on_key_event = Some(Rc::new(f));
1522 self
1523 }
1524
1525 pub fn on_preview_key_event(
1529 mut self,
1530 f: impl Fn(crate::input::KeyEvent) -> bool + 'static,
1531 ) -> Self {
1532 self.on_preview_key_event = Some(Rc::new(f));
1533 self
1534 }
1535
1536 pub fn blur(mut self, radius_dp: f32) -> Self {
1543 self.blur = Some(BlurStyle {
1544 radius_x: radius_dp.max(0.0),
1545 radius_y: radius_dp.max(0.0),
1546 edge_treatment: BlurredEdgeTreatment::Rectangle,
1547 });
1548 self
1549 }
1550
1551 pub fn blur_with_edge(
1556 mut self,
1557 radius_x: f32,
1558 radius_y: f32,
1559 edge_treatment: BlurredEdgeTreatment,
1560 ) -> Self {
1561 self.blur = Some(BlurStyle {
1562 radius_x: radius_x.max(0.0),
1563 radius_y: radius_y.max(0.0),
1564 edge_treatment,
1565 });
1566 self
1567 }
1568
1569 pub fn layout(mut self, f: impl Fn(LayoutConstraints) -> (f32, f32) + 'static) -> Self {
1577 self.layout = Some(Rc::new(f));
1578 self
1579 }
1580
1581 pub fn text_input(mut self, config: TextInputConfig) -> Self {
1583 self.text_input = Some(config);
1584 self
1585 }
1586
1587 pub fn indication(mut self, factory: Rc<dyn IndicationNodeFactory>) -> Self {
1591 self.indication = Some(factory);
1592 self
1593 }
1594}