1use std::sync::{
17 atomic::{AtomicBool, Ordering},
18 Arc, Mutex,
19};
20
21use blinc_core::{
22 BlurQuality, BlurStyle, Brush, ClipPath, Color, CornerRadius, CornerShape, LayerEffect,
23 OverflowFade, Shadow, Transform,
24};
25use blinc_theme::ThemeState;
26use taffy::prelude::*;
27use taffy::Overflow;
28
29use crate::element::{
30 ElementBounds, GlassMaterial, Material, MetallicMaterial, RenderLayer, RenderProps,
31 WoodMaterial,
32};
33use crate::element_style::ElementStyle;
34use crate::tree::{LayoutNodeId, LayoutTree};
35
36type RefStorage<T> = Arc<Mutex<Option<T>>>;
42
43type DirtyFlag = Arc<AtomicBool>;
45
46type LayoutBoundsStorage = Arc<Mutex<Option<ElementBounds>>>;
75
76pub struct ElementRef<T> {
77 inner: RefStorage<T>,
78 dirty_flag: DirtyFlag,
80 layout_bounds: LayoutBoundsStorage,
82}
83
84impl<T> Clone for ElementRef<T> {
85 fn clone(&self) -> Self {
86 Self {
87 inner: Arc::clone(&self.inner),
88 dirty_flag: Arc::clone(&self.dirty_flag),
89 layout_bounds: Arc::clone(&self.layout_bounds),
90 }
91 }
92}
93
94impl<T> Default for ElementRef<T> {
95 fn default() -> Self {
96 Self::new()
97 }
98}
99
100impl<T> ElementRef<T> {
101 pub fn new() -> Self {
103 Self {
104 inner: Arc::new(Mutex::new(None)),
105 dirty_flag: Arc::new(AtomicBool::new(false)),
106 layout_bounds: Arc::new(Mutex::new(None)),
107 }
108 }
109
110 pub fn with_dirty_flag(dirty_flag: DirtyFlag) -> Self {
115 Self {
116 inner: Arc::new(Mutex::new(None)),
117 dirty_flag,
118 layout_bounds: Arc::new(Mutex::new(None)),
119 }
120 }
121
122 pub fn dirty_flag(&self) -> DirtyFlag {
124 Arc::clone(&self.dirty_flag)
125 }
126
127 pub fn take_dirty(&self) -> bool {
131 self.dirty_flag.swap(false, Ordering::SeqCst)
132 }
133
134 pub fn is_dirty(&self) -> bool {
136 self.dirty_flag.load(Ordering::SeqCst)
137 }
138
139 pub fn mark_dirty(&self) {
141 self.dirty_flag.store(true, Ordering::SeqCst);
142 }
143
144 pub fn is_bound(&self) -> bool {
146 self.inner.lock().unwrap().is_some()
147 }
148
149 pub fn storage(&self) -> RefStorage<T> {
154 Arc::clone(&self.inner)
155 }
156
157 pub fn set(&self, elem: T) {
159 *self.inner.lock().unwrap() = Some(elem);
160 }
161
162 pub fn with<F, R>(&self, f: F) -> Option<R>
172 where
173 F: FnOnce(&T) -> R,
174 {
175 self.inner.lock().unwrap().as_ref().map(f)
176 }
177
178 pub fn with_mut<F, R>(&self, f: F) -> Option<R>
200 where
201 F: FnOnce(&mut T) -> R,
202 {
203 let result = self.inner.lock().unwrap().as_mut().map(f);
204 if result.is_some() {
205 self.dirty_flag.store(true, Ordering::SeqCst);
207 }
208 result
209 }
210
211 pub fn get(&self) -> Option<T>
213 where
214 T: Clone,
215 {
216 self.inner.lock().unwrap().clone()
217 }
218
219 pub fn replace(&self, new_elem: T) -> Option<T> {
223 let old = self.inner.lock().unwrap().replace(new_elem);
224 self.dirty_flag.store(true, Ordering::SeqCst);
225 old
226 }
227
228 pub fn take(&self) -> Option<T> {
230 self.inner.lock().unwrap().take()
231 }
232
233 pub fn borrow(&self) -> ElementRefGuard<'_, T> {
248 ElementRefGuard {
249 guard: self.inner.lock().unwrap(),
250 }
251 }
252
253 pub fn borrow_mut(&self) -> ElementRefGuardMut<'_, T> {
272 ElementRefGuardMut {
273 guard: self.inner.lock().unwrap(),
274 dirty_flag: Arc::clone(&self.dirty_flag),
275 }
276 }
277
278 pub fn get_layout_bounds(&self) -> Option<ElementBounds> {
295 *self.layout_bounds.lock().unwrap()
296 }
297
298 pub fn set_layout_bounds(&self, bounds: ElementBounds) {
303 *self.layout_bounds.lock().unwrap() = Some(bounds);
304 }
305
306 pub fn clear_layout_bounds(&self) {
311 *self.layout_bounds.lock().unwrap() = None;
312 }
313
314 pub fn layout_bounds_storage(&self) -> LayoutBoundsStorage {
319 Arc::clone(&self.layout_bounds)
320 }
321}
322
323pub struct ElementRefGuard<'a, T> {
325 guard: std::sync::MutexGuard<'a, Option<T>>,
326}
327
328impl<T> std::ops::Deref for ElementRefGuard<'_, T> {
329 type Target = T;
330
331 fn deref(&self) -> &Self::Target {
332 self.guard.as_ref().expect("ElementRef not bound")
333 }
334}
335
336pub struct ElementRefGuardMut<'a, T> {
341 guard: std::sync::MutexGuard<'a, Option<T>>,
342 dirty_flag: DirtyFlag,
343}
344
345impl<T> std::ops::Deref for ElementRefGuardMut<'_, T> {
346 type Target = T;
347
348 fn deref(&self) -> &Self::Target {
349 self.guard.as_ref().expect("ElementRef not bound")
350 }
351}
352
353impl<T> std::ops::DerefMut for ElementRefGuardMut<'_, T> {
354 fn deref_mut(&mut self) -> &mut Self::Target {
355 self.guard.as_mut().expect("ElementRef not bound")
356 }
357}
358
359impl<T> Drop for ElementRefGuardMut<'_, T> {
360 fn drop(&mut self) {
361 self.dirty_flag.store(true, Ordering::SeqCst);
363 }
364}
365
366pub type DivRef = ElementRef<Div>;
368
369pub struct Div {
371 pub(crate) style: Style,
372 pub(crate) children: Vec<Box<dyn ElementBuilder>>,
373 pub(crate) background: Option<Brush>,
374 pub(crate) border_radius: CornerRadius,
375 pub(crate) border_radius_explicit: bool,
377 pub(crate) corner_shape: CornerShape,
378 pub(crate) border_color: Option<Color>,
379 pub(crate) border_width: f32,
380 pub(crate) border_sides: crate::element::BorderSides,
381 pub(crate) render_layer: RenderLayer,
382 pub(crate) material: Option<Material>,
383 pub(crate) shadow: Option<Shadow>,
384 pub(crate) transform: Option<Transform>,
385 pub(crate) opacity: f32,
386 pub(crate) cursor: Option<crate::element::CursorStyle>,
387 pub(crate) pointer_events_none: bool,
388 pub(crate) layer_effects: Vec<LayerEffect>,
390 pub(crate) is_stack_layer: bool,
392 pub(crate) event_handlers: crate::event_handler::EventHandlers,
393 pub(crate) element_id: Option<String>,
395 pub(crate) classes: Vec<String>,
397 pub(crate) rotate_x: Option<f32>,
399 pub(crate) rotate_y: Option<f32>,
400 pub(crate) perspective_3d: Option<f32>,
401 pub(crate) shape_3d: Option<f32>,
402 pub(crate) depth: Option<f32>,
403 pub(crate) light_direction: Option<[f32; 3]>,
404 pub(crate) light_intensity: Option<f32>,
405 pub(crate) ambient: Option<f32>,
406 pub(crate) specular: Option<f32>,
407 pub(crate) translate_z: Option<f32>,
408 pub(crate) op_3d: Option<f32>,
409 pub(crate) blend_3d: Option<f32>,
410 pub(crate) overflow_fade: OverflowFade,
412 pub(crate) clip_path: Option<ClipPath>,
414 pub(crate) flow_name: Option<String>,
416 pub(crate) flow_graph: Option<std::sync::Arc<blinc_core::FlowGraph>>,
418 pub(crate) is_fixed: bool,
420 pub(crate) is_sticky: bool,
422 pub(crate) sticky_top: Option<f32>,
424 pub(crate) outline_width: f32,
426 pub(crate) outline_color: Option<Color>,
428 pub(crate) outline_offset: f32,
430 pub(crate) z_index: i32,
432 pub(crate) scroll_physics: Option<crate::scroll::SharedScrollPhysics>,
434 pub(crate) layout_animation: Option<crate::layout_animation::LayoutAnimationConfig>,
436 pub(crate) visual_animation: Option<crate::visual_animation::VisualAnimationConfig>,
438 pub(crate) stateful_context_key: Option<String>,
443}
444
445impl Default for Div {
446 fn default() -> Self {
447 Self::new()
448 }
449}
450
451impl Div {
452 pub fn new() -> Self {
454 Self {
455 style: Style::default(),
456 children: Vec::new(),
457 background: None,
458 border_radius: CornerRadius::default(),
459 border_radius_explicit: false,
460 corner_shape: CornerShape::default(),
461 border_color: None,
462 border_width: 0.0,
463 border_sides: crate::element::BorderSides::default(),
464 render_layer: RenderLayer::default(),
465 material: None,
466 shadow: None,
467 transform: None,
468 opacity: 1.0,
469 cursor: None,
470 pointer_events_none: false,
471 layer_effects: Vec::new(),
472 is_stack_layer: false,
473 event_handlers: crate::event_handler::EventHandlers::new(),
474 element_id: None,
475 classes: Vec::new(),
476 rotate_x: None,
477 rotate_y: None,
478 perspective_3d: None,
479 shape_3d: None,
480 depth: None,
481 light_direction: None,
482 light_intensity: None,
483 ambient: None,
484 specular: None,
485 translate_z: None,
486 op_3d: None,
487 blend_3d: None,
488 overflow_fade: OverflowFade::default(),
489 clip_path: None,
490 flow_name: None,
491 flow_graph: None,
492 outline_width: 0.0,
493 outline_color: None,
494 outline_offset: 0.0,
495 is_fixed: false,
496 is_sticky: false,
497 sticky_top: None,
498 z_index: 0,
499 scroll_physics: None,
500 layout_animation: None,
501 visual_animation: None,
502 stateful_context_key: None,
503 }
504 }
505
506 pub fn with_style(style: Style) -> Self {
511 Self {
512 style,
513 children: Vec::new(),
514 background: None,
515 border_radius: CornerRadius::default(),
516 border_radius_explicit: false,
517 corner_shape: CornerShape::default(),
518 border_color: None,
519 border_width: 0.0,
520 border_sides: crate::element::BorderSides::default(),
521 render_layer: RenderLayer::default(),
522 material: None,
523 shadow: None,
524 transform: None,
525 opacity: 1.0,
526 cursor: None,
527 pointer_events_none: false,
528 layer_effects: Vec::new(),
529 is_stack_layer: false,
530 event_handlers: crate::event_handler::EventHandlers::new(),
531 element_id: None,
532 classes: Vec::new(),
533 rotate_x: None,
534 rotate_y: None,
535 perspective_3d: None,
536 shape_3d: None,
537 depth: None,
538 light_direction: None,
539 light_intensity: None,
540 ambient: None,
541 specular: None,
542 translate_z: None,
543 op_3d: None,
544 blend_3d: None,
545 overflow_fade: OverflowFade::default(),
546 clip_path: None,
547 flow_name: None,
548 flow_graph: None,
549 outline_width: 0.0,
550 outline_color: None,
551 outline_offset: 0.0,
552 is_fixed: false,
553 is_sticky: false,
554 sticky_top: None,
555 z_index: 0,
556 scroll_physics: None,
557 layout_animation: None,
558 visual_animation: None,
559 stateful_context_key: None,
560 }
561 }
562
563 pub fn id(mut self, id: impl Into<String>) -> Self {
575 self.element_id = Some(id.into());
576 self
577 }
578
579 pub fn element_id(&self) -> Option<&str> {
581 self.element_id.as_deref()
582 }
583
584 pub fn class(mut self, name: impl Into<String>) -> Self {
589 self.classes.push(name.into());
590 self
591 }
592
593 pub fn classes(&self) -> &[String] {
595 &self.classes
596 }
597
598 pub(crate) fn with_stateful_context(mut self, key: impl Into<String>) -> Self {
604 self.stateful_context_key = Some(key.into());
605 self
606 }
607
608 pub fn stateful_context_key(&self) -> Option<&str> {
610 self.stateful_context_key.as_deref()
611 }
612
613 #[deprecated(
643 since = "0.3.0",
644 note = "Use animate_bounds() instead. The old system modifies taffy which causes parent-child misalignment issues."
645 )]
646 pub fn animate_layout(
647 mut self,
648 config: crate::layout_animation::LayoutAnimationConfig,
649 ) -> Self {
650 let config = if let Some(ref ctx_key) = self.stateful_context_key {
652 if config.stable_key.is_none() {
653 let auto_key = format!("{}:layout_anim", ctx_key);
654 config.with_key(auto_key)
655 } else {
656 config
657 }
658 } else {
659 config
660 };
661 self.layout_animation = Some(config);
662 self
663 }
664
665 pub fn animate_bounds(
686 mut self,
687 config: crate::visual_animation::VisualAnimationConfig,
688 ) -> Self {
689 let config = if let Some(ref ctx_key) = self.stateful_context_key {
691 if config.key.is_none() {
692 let auto_key = format!("{}:visual_anim", ctx_key);
693 config.with_key(auto_key)
694 } else {
695 config
696 }
697 } else {
698 config
699 };
700 self.visual_animation = Some(config);
701 self
702 }
703
704 #[track_caller]
723 pub fn motion(self) -> crate::motion::Motion {
724 if let Some(ref ctx_key) = self.stateful_context_key {
725 let motion_key = format!("{}:motion", ctx_key);
727 crate::motion::motion_derived(&motion_key).child(self)
728 } else {
729 crate::motion::motion().child(self)
731 }
732 }
733
734 #[inline]
759 pub fn swap(&mut self) -> Self {
760 std::mem::take(self)
761 }
762
763 #[inline]
780 pub fn when<F>(self, condition: bool, f: F) -> Self
781 where
782 F: FnOnce(Self) -> Self,
783 {
784 if condition {
785 f(self)
786 } else {
787 self
788 }
789 }
790
791 #[inline]
796 pub fn set_bg(&mut self, color: impl Into<Brush>) {
797 self.background = Some(color.into());
798 }
799
800 #[inline]
802 pub fn set_rounded(&mut self, radius: f32) {
803 self.border_radius = CornerRadius::uniform(radius);
804 self.border_radius_explicit = true;
805 }
806
807 #[inline]
809 pub fn set_transform(&mut self, transform: Transform) {
810 self.transform = Some(transform);
811 }
812
813 #[inline]
815 pub fn set_shadow(&mut self, shadow: Shadow) {
816 self.shadow = Some(shadow);
817 }
818
819 #[inline]
821 pub fn set_opacity(&mut self, opacity: f32) {
822 self.opacity = opacity;
823 }
824
825 #[inline]
827 pub fn set_border(&mut self, width: f32, color: Color) {
828 self.border_width = width;
829 self.border_color = Some(color);
830 }
831
832 #[inline]
834 pub fn set_overflow_clip(&mut self, clip: bool) {
835 if clip {
836 self.style.overflow.x = taffy::Overflow::Hidden;
837 self.style.overflow.y = taffy::Overflow::Hidden;
838 } else {
839 self.style.overflow.x = taffy::Overflow::Visible;
840 self.style.overflow.y = taffy::Overflow::Visible;
841 }
842 }
843
844 #[inline]
846 pub fn set_padding_x(&mut self, px: f32) {
847 self.style.padding.left = taffy::LengthPercentage::Length(px);
848 self.style.padding.right = taffy::LengthPercentage::Length(px);
849 }
850
851 #[inline]
853 pub fn set_padding_y(&mut self, px: f32) {
854 self.style.padding.top = taffy::LengthPercentage::Length(px);
855 self.style.padding.bottom = taffy::LengthPercentage::Length(px);
856 }
857
858 #[inline]
860 pub fn set_child(&mut self, child: impl ElementBuilder + 'static) {
861 self.children.clear();
862 self.children.push(Box::new(child));
863 }
864
865 #[inline]
867 pub fn clear_children(&mut self) {
868 self.children.clear();
869 }
870
871 #[inline]
876 pub fn set_w(&mut self, px: f32) {
877 self.style.size.width = taffy::Dimension::Length(px);
878 }
879
880 #[inline]
882 pub fn set_h(&mut self, px: f32) {
883 self.style.size.height = taffy::Dimension::Length(px);
884 }
885
886 #[inline]
888 pub fn set_h_auto(&mut self) {
889 self.style.size.height = taffy::Dimension::Auto;
890 }
891
892 pub fn style(mut self, style: &ElementStyle) -> Self {
917 self.set_style(style);
918 self
919 }
920
921 #[inline]
934 pub fn set_style(&mut self, style: &ElementStyle) {
935 use crate::element_style::{
936 SpacingRect, StyleAlign, StyleDisplay, StyleFlexDirection, StyleJustify, StyleOverflow,
937 };
938
939 if let Some(ref bg) = style.background {
941 self.background = Some(bg.clone());
942 }
943 if let Some(radius) = style.corner_radius {
944 self.border_radius = radius;
945 }
946 if let Some(cs) = style.corner_shape {
947 self.corner_shape = cs;
948 }
949 if let Some(fade) = style.overflow_fade {
950 self.overflow_fade = fade;
951 }
952 if let Some(ref shadow) = style.shadow {
953 self.shadow = Some(*shadow);
954 }
955 if let Some(ref transform) = style.transform {
956 self.transform = Some(transform.clone());
957 }
958 if let Some(ref material) = style.material {
959 self.material = Some(material.clone());
960 }
961 if let Some(layer) = style.render_layer {
962 self.render_layer = layer;
963 }
964 if let Some(opacity) = style.opacity {
965 self.opacity = opacity;
966 }
967
968 if let Some(w) = style.width {
970 match w {
971 crate::element_style::StyleDimension::Length(px) => {
972 self.style.size.width = Dimension::Length(px);
973 }
974 crate::element_style::StyleDimension::Percent(p) => {
975 self.style.size.width = Dimension::Percent(p);
976 }
977 crate::element_style::StyleDimension::Auto => {
978 self.style.size.width = Dimension::Auto;
979 self.style.flex_basis = Dimension::Auto;
980 self.style.flex_grow = 0.0;
981 self.style.flex_shrink = 0.0;
982 }
983 }
984 }
985 if let Some(h) = style.height {
986 match h {
987 crate::element_style::StyleDimension::Length(px) => {
988 self.style.size.height = Dimension::Length(px);
989 }
990 crate::element_style::StyleDimension::Percent(p) => {
991 self.style.size.height = Dimension::Percent(p);
992 }
993 crate::element_style::StyleDimension::Auto => {
994 self.style.size.height = Dimension::Auto;
995 self.style.flex_basis = Dimension::Auto;
996 self.style.flex_grow = 0.0;
997 self.style.flex_shrink = 0.0;
998 }
999 }
1000 }
1001 if let Some(w) = style.min_width {
1002 self.style.min_size.width = Dimension::Length(w);
1003 }
1004 if let Some(h) = style.min_height {
1005 self.style.min_size.height = Dimension::Length(h);
1006 }
1007 if let Some(w) = style.max_width {
1008 self.style.max_size.width = Dimension::Length(w);
1009 }
1010 if let Some(h) = style.max_height {
1011 self.style.max_size.height = Dimension::Length(h);
1012 }
1013
1014 if let Some(display) = style.display {
1016 self.style.display = match display {
1017 StyleDisplay::Flex => Display::Flex,
1018 StyleDisplay::Block => Display::Block,
1019 StyleDisplay::None => Display::None,
1020 };
1021 }
1022 if let Some(dir) = style.flex_direction {
1023 self.style.flex_direction = match dir {
1024 StyleFlexDirection::Row => FlexDirection::Row,
1025 StyleFlexDirection::Column => FlexDirection::Column,
1026 StyleFlexDirection::RowReverse => FlexDirection::RowReverse,
1027 StyleFlexDirection::ColumnReverse => FlexDirection::ColumnReverse,
1028 };
1029 }
1030 if let Some(wrap) = style.flex_wrap {
1031 self.style.flex_wrap = if wrap {
1032 FlexWrap::Wrap
1033 } else {
1034 FlexWrap::NoWrap
1035 };
1036 }
1037 if let Some(grow) = style.flex_grow {
1038 self.style.flex_grow = grow;
1039 }
1040 if let Some(shrink) = style.flex_shrink {
1041 self.style.flex_shrink = shrink;
1042 }
1043
1044 if let Some(align) = style.align_items {
1046 self.style.align_items = Some(match align {
1047 StyleAlign::Start => AlignItems::Start,
1048 StyleAlign::Center => AlignItems::Center,
1049 StyleAlign::End => AlignItems::End,
1050 StyleAlign::Stretch => AlignItems::Stretch,
1051 StyleAlign::Baseline => AlignItems::Baseline,
1052 });
1053 }
1054 if let Some(justify) = style.justify_content {
1055 self.style.justify_content = Some(match justify {
1056 StyleJustify::Start => JustifyContent::Start,
1057 StyleJustify::Center => JustifyContent::Center,
1058 StyleJustify::End => JustifyContent::End,
1059 StyleJustify::SpaceBetween => JustifyContent::SpaceBetween,
1060 StyleJustify::SpaceAround => JustifyContent::SpaceAround,
1061 StyleJustify::SpaceEvenly => JustifyContent::SpaceEvenly,
1062 });
1063 }
1064 if let Some(align) = style.align_self {
1065 self.style.align_self = Some(match align {
1066 StyleAlign::Start => AlignSelf::Start,
1067 StyleAlign::Center => AlignSelf::Center,
1068 StyleAlign::End => AlignSelf::End,
1069 StyleAlign::Stretch => AlignSelf::Stretch,
1070 StyleAlign::Baseline => AlignSelf::Baseline,
1071 });
1072 }
1073
1074 if let Some(SpacingRect {
1076 top,
1077 right,
1078 bottom,
1079 left,
1080 }) = style.padding
1081 {
1082 self.style.padding = Rect {
1083 top: LengthPercentage::Length(top),
1084 right: LengthPercentage::Length(right),
1085 bottom: LengthPercentage::Length(bottom),
1086 left: LengthPercentage::Length(left),
1087 };
1088 }
1089 if let Some(SpacingRect {
1090 top,
1091 right,
1092 bottom,
1093 left,
1094 }) = style.margin
1095 {
1096 self.style.margin = Rect {
1097 top: LengthPercentageAuto::Length(top),
1098 right: LengthPercentageAuto::Length(right),
1099 bottom: LengthPercentageAuto::Length(bottom),
1100 left: LengthPercentageAuto::Length(left),
1101 };
1102 }
1103 if let Some(gap) = style.gap {
1104 self.style.gap = taffy::Size {
1105 width: LengthPercentage::Length(gap),
1106 height: LengthPercentage::Length(gap),
1107 };
1108 }
1109
1110 if let Some(overflow) = style.overflow {
1112 let val = match overflow {
1113 StyleOverflow::Visible => Overflow::Visible,
1114 StyleOverflow::Clip => Overflow::Clip,
1115 StyleOverflow::Scroll => Overflow::Scroll,
1116 };
1117 self.style.overflow.x = val;
1118 self.style.overflow.y = val;
1119 if overflow == StyleOverflow::Scroll {
1120 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Both);
1121 }
1122 }
1123 if let Some(ox) = style.overflow_x {
1125 let val = match ox {
1126 StyleOverflow::Visible => Overflow::Visible,
1127 StyleOverflow::Clip => Overflow::Clip,
1128 StyleOverflow::Scroll => Overflow::Scroll,
1129 };
1130 self.style.overflow.x = val;
1131 if ox == StyleOverflow::Scroll {
1132 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Horizontal);
1133 }
1134 }
1135 if let Some(oy) = style.overflow_y {
1136 let val = match oy {
1137 StyleOverflow::Visible => Overflow::Visible,
1138 StyleOverflow::Clip => Overflow::Clip,
1139 StyleOverflow::Scroll => Overflow::Scroll,
1140 };
1141 self.style.overflow.y = val;
1142 if oy == StyleOverflow::Scroll {
1143 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Vertical);
1144 }
1145 }
1146
1147 if let Some(width) = style.border_width {
1149 self.border_width = width;
1150 }
1151 if let Some(color) = style.border_color {
1152 self.border_color = Some(color);
1153 }
1154
1155 if let Some(v) = style.rotate_x {
1157 self.rotate_x = Some(v);
1158 }
1159 if let Some(v) = style.rotate_y {
1160 self.rotate_y = Some(v);
1161 }
1162 if let Some(v) = style.perspective {
1163 self.perspective_3d = Some(v);
1164 }
1165 if let Some(ref s) = style.shape_3d {
1166 self.shape_3d = Some(crate::css_parser::shape_3d_to_float(s));
1167 }
1168 if let Some(v) = style.depth {
1169 self.depth = Some(v);
1170 }
1171 if let Some(dir) = style.light_direction {
1172 self.light_direction = Some(dir);
1173 }
1174 if let Some(v) = style.light_intensity {
1175 self.light_intensity = Some(v);
1176 }
1177 if let Some(v) = style.ambient {
1178 self.ambient = Some(v);
1179 }
1180 if let Some(v) = style.specular {
1181 self.specular = Some(v);
1182 }
1183 if let Some(v) = style.translate_z {
1184 self.translate_z = Some(v);
1185 }
1186 if let Some(ref op) = style.op_3d {
1187 self.op_3d = Some(crate::css_parser::op_3d_to_float(op));
1188 }
1189 if let Some(v) = style.blend_3d {
1190 self.blend_3d = Some(v);
1191 }
1192 if let Some(ref cp) = style.clip_path {
1193 self.clip_path = Some(cp.clone());
1194 }
1195 if let Some(ref f) = style.flow {
1196 self.flow_name = Some(f.clone());
1197 }
1198 }
1199
1200 #[inline]
1211 pub fn merge(&mut self, other: Div) {
1212 let default = Div::new();
1214
1215 self.merge_style(&other.style, &default.style);
1218
1219 if other.background.is_some() {
1221 self.background = other.background;
1222 }
1223 if other.border_radius_explicit || other.border_radius != default.border_radius {
1224 self.border_radius = other.border_radius;
1225 self.border_radius_explicit = true;
1226 }
1227 if other.border_color.is_some() {
1228 self.border_color = other.border_color;
1229 }
1230 if other.border_width != default.border_width {
1231 self.border_width = other.border_width;
1232 }
1233 if other.render_layer != default.render_layer {
1234 self.render_layer = other.render_layer;
1235 }
1236 if other.material.is_some() {
1237 self.material = other.material;
1238 }
1239 if other.shadow.is_some() {
1240 self.shadow = other.shadow;
1241 }
1242 if other.transform.is_some() {
1243 self.transform = other.transform;
1244 }
1245 if other.opacity != default.opacity {
1246 self.opacity = other.opacity;
1247 }
1248 if other.cursor.is_some() {
1249 self.cursor = other.cursor;
1250 }
1251
1252 if other.element_id.is_some() {
1257 self.element_id = other.element_id;
1258 }
1259 if !other.classes.is_empty() {
1260 self.classes = other.classes;
1261 }
1262
1263 if !other.children.is_empty() {
1265 self.children = other.children;
1266 }
1267
1268 if other.stateful_context_key.is_some() {
1270 self.stateful_context_key = other.stateful_context_key;
1271 }
1272
1273 if other.visual_animation.is_some() {
1275 self.visual_animation = other.visual_animation;
1276 }
1277
1278 if other.layout_animation.is_some() {
1280 self.layout_animation = other.layout_animation;
1281 }
1282
1283 if other.rotate_x.is_some() {
1285 self.rotate_x = other.rotate_x;
1286 }
1287 if other.rotate_y.is_some() {
1288 self.rotate_y = other.rotate_y;
1289 }
1290 if other.perspective_3d.is_some() {
1291 self.perspective_3d = other.perspective_3d;
1292 }
1293 if other.shape_3d.is_some() {
1294 self.shape_3d = other.shape_3d;
1295 }
1296 if other.depth.is_some() {
1297 self.depth = other.depth;
1298 }
1299 if other.light_direction.is_some() {
1300 self.light_direction = other.light_direction;
1301 }
1302 if other.light_intensity.is_some() {
1303 self.light_intensity = other.light_intensity;
1304 }
1305 if other.ambient.is_some() {
1306 self.ambient = other.ambient;
1307 }
1308 if other.specular.is_some() {
1309 self.specular = other.specular;
1310 }
1311 if other.translate_z.is_some() {
1312 self.translate_z = other.translate_z;
1313 }
1314 if other.op_3d.is_some() {
1315 self.op_3d = other.op_3d;
1316 }
1317 if other.blend_3d.is_some() {
1318 self.blend_3d = other.blend_3d;
1319 }
1320 if other.clip_path.is_some() {
1321 self.clip_path = other.clip_path;
1322 }
1323 if other.flow_name.is_some() {
1324 self.flow_name = other.flow_name;
1325 self.flow_graph = other.flow_graph;
1326 }
1327
1328 if other.scroll_physics.is_some() {
1330 self.scroll_physics = other.scroll_physics;
1331 }
1332
1333 if !other.event_handlers.is_empty() {
1335 self.event_handlers.merge(other.event_handlers);
1336 }
1337 }
1338
1339 fn merge_style(&mut self, other: &Style, default: &Style) {
1341 if other.display != default.display {
1343 self.style.display = other.display;
1344 }
1345 if other.position != default.position {
1346 self.style.position = other.position;
1347 }
1348 if other.overflow != default.overflow {
1349 self.style.overflow = other.overflow;
1350 }
1351
1352 if other.flex_direction != default.flex_direction {
1354 self.style.flex_direction = other.flex_direction;
1355 }
1356 if other.flex_wrap != default.flex_wrap {
1357 self.style.flex_wrap = other.flex_wrap;
1358 }
1359 if other.justify_content != default.justify_content {
1360 self.style.justify_content = other.justify_content;
1361 }
1362 if other.align_items != default.align_items {
1363 self.style.align_items = other.align_items;
1364 }
1365 if other.align_content != default.align_content {
1366 self.style.align_content = other.align_content;
1367 }
1368 if other.gap.width != default.gap.width {
1370 self.style.gap.width = other.gap.width;
1371 }
1372 if other.gap.height != default.gap.height {
1373 self.style.gap.height = other.gap.height;
1374 }
1375
1376 if other.flex_grow != default.flex_grow {
1378 self.style.flex_grow = other.flex_grow;
1379 }
1380 if other.flex_shrink != default.flex_shrink {
1381 self.style.flex_shrink = other.flex_shrink;
1382 }
1383 if other.flex_basis != default.flex_basis {
1384 self.style.flex_basis = other.flex_basis;
1385 }
1386 if other.align_self != default.align_self {
1387 self.style.align_self = other.align_self;
1388 }
1389
1390 if other.size.width != default.size.width {
1392 self.style.size.width = other.size.width;
1393 }
1394 if other.size.height != default.size.height {
1395 self.style.size.height = other.size.height;
1396 }
1397 if other.min_size.width != default.min_size.width {
1398 self.style.min_size.width = other.min_size.width;
1399 }
1400 if other.min_size.height != default.min_size.height {
1401 self.style.min_size.height = other.min_size.height;
1402 }
1403 if other.max_size.width != default.max_size.width {
1404 self.style.max_size.width = other.max_size.width;
1405 }
1406 if other.max_size.height != default.max_size.height {
1407 self.style.max_size.height = other.max_size.height;
1408 }
1409 if other.aspect_ratio != default.aspect_ratio {
1410 self.style.aspect_ratio = other.aspect_ratio;
1411 }
1412
1413 if other.margin.left != default.margin.left {
1416 self.style.margin.left = other.margin.left;
1417 }
1418 if other.margin.right != default.margin.right {
1419 self.style.margin.right = other.margin.right;
1420 }
1421 if other.margin.top != default.margin.top {
1422 self.style.margin.top = other.margin.top;
1423 }
1424 if other.margin.bottom != default.margin.bottom {
1425 self.style.margin.bottom = other.margin.bottom;
1426 }
1427 if other.padding.left != default.padding.left {
1429 self.style.padding.left = other.padding.left;
1430 }
1431 if other.padding.right != default.padding.right {
1432 self.style.padding.right = other.padding.right;
1433 }
1434 if other.padding.top != default.padding.top {
1435 self.style.padding.top = other.padding.top;
1436 }
1437 if other.padding.bottom != default.padding.bottom {
1438 self.style.padding.bottom = other.padding.bottom;
1439 }
1440 if other.border.left != default.border.left {
1442 self.style.border.left = other.border.left;
1443 }
1444 if other.border.right != default.border.right {
1445 self.style.border.right = other.border.right;
1446 }
1447 if other.border.top != default.border.top {
1448 self.style.border.top = other.border.top;
1449 }
1450 if other.border.bottom != default.border.bottom {
1451 self.style.border.bottom = other.border.bottom;
1452 }
1453
1454 if other.inset.left != default.inset.left {
1456 self.style.inset.left = other.inset.left;
1457 }
1458 if other.inset.right != default.inset.right {
1459 self.style.inset.right = other.inset.right;
1460 }
1461 if other.inset.top != default.inset.top {
1462 self.style.inset.top = other.inset.top;
1463 }
1464 if other.inset.bottom != default.inset.bottom {
1465 self.style.inset.bottom = other.inset.bottom;
1466 }
1467 }
1468
1469 pub fn flex(mut self) -> Self {
1475 self.style.display = Display::Flex;
1476 self
1477 }
1478
1479 pub fn block(mut self) -> Self {
1481 self.style.display = Display::Block;
1482 self
1483 }
1484
1485 pub fn grid(mut self) -> Self {
1487 self.style.display = Display::Grid;
1488 self
1489 }
1490
1491 pub fn hidden(mut self) -> Self {
1493 self.style.display = Display::None;
1494 self
1495 }
1496
1497 pub fn flex_row(mut self) -> Self {
1499 self.style.display = Display::Flex;
1500 self.style.flex_direction = FlexDirection::Row;
1501 self
1502 }
1503
1504 pub fn flex_col(mut self) -> Self {
1506 self.style.display = Display::Flex;
1507 self.style.flex_direction = FlexDirection::Column;
1508 self
1509 }
1510
1511 pub fn flex_row_reverse(mut self) -> Self {
1513 self.style.display = Display::Flex;
1514 self.style.flex_direction = FlexDirection::RowReverse;
1515 self
1516 }
1517
1518 pub fn flex_col_reverse(mut self) -> Self {
1520 self.style.display = Display::Flex;
1521 self.style.flex_direction = FlexDirection::ColumnReverse;
1522 self
1523 }
1524
1525 pub fn flex_grow(mut self) -> Self {
1531 self.style.flex_grow = 1.0;
1532 self
1533 }
1534
1535 pub fn flex_grow_value(mut self, value: f32) -> Self {
1540 self.style.flex_grow = value;
1541 self
1542 }
1543
1544 pub fn flex_shrink(mut self) -> Self {
1546 self.style.flex_shrink = 1.0;
1547 self
1548 }
1549
1550 pub fn flex_shrink_0(mut self) -> Self {
1552 self.style.flex_shrink = 0.0;
1553 self
1554 }
1555
1556 pub fn flex_auto(mut self) -> Self {
1558 self.style.flex_grow = 1.0;
1559 self.style.flex_shrink = 1.0;
1560 self.style.flex_basis = Dimension::Auto;
1561 self
1562 }
1563
1564 pub fn flex_1(mut self) -> Self {
1566 self.style.flex_grow = 1.0;
1567 self.style.flex_shrink = 1.0;
1568 self.style.flex_basis = Dimension::Length(0.0);
1569 self
1570 }
1571
1572 pub fn flex_wrap(mut self) -> Self {
1574 self.style.flex_wrap = FlexWrap::Wrap;
1575 self
1576 }
1577
1578 pub fn items_center(mut self) -> Self {
1584 self.style.align_items = Some(AlignItems::Center);
1585 self
1586 }
1587
1588 pub fn items_start(mut self) -> Self {
1590 self.style.align_items = Some(AlignItems::Start);
1591 self
1592 }
1593
1594 pub fn items_end(mut self) -> Self {
1596 self.style.align_items = Some(AlignItems::End);
1597 self
1598 }
1599
1600 pub fn items_stretch(mut self) -> Self {
1602 self.style.align_items = Some(AlignItems::Stretch);
1603 self
1604 }
1605
1606 pub fn items_baseline(mut self) -> Self {
1608 self.style.align_items = Some(AlignItems::Baseline);
1609 self
1610 }
1611
1612 pub fn align_self_start(mut self) -> Self {
1614 self.style.align_self = Some(AlignSelf::Start);
1615 self
1616 }
1617
1618 pub fn align_self_center(mut self) -> Self {
1620 self.style.align_self = Some(AlignSelf::Center);
1621 self
1622 }
1623
1624 pub fn align_self_end(mut self) -> Self {
1626 self.style.align_self = Some(AlignSelf::End);
1627 self
1628 }
1629
1630 pub fn align_self_stretch(mut self) -> Self {
1632 self.style.align_self = Some(AlignSelf::Stretch);
1633 self
1634 }
1635
1636 pub fn justify_start(mut self) -> Self {
1638 self.style.justify_content = Some(JustifyContent::Start);
1639 self
1640 }
1641
1642 pub fn justify_center(mut self) -> Self {
1644 self.style.justify_content = Some(JustifyContent::Center);
1645 self
1646 }
1647
1648 pub fn justify_end(mut self) -> Self {
1650 self.style.justify_content = Some(JustifyContent::End);
1651 self
1652 }
1653
1654 pub fn justify_between(mut self) -> Self {
1656 self.style.justify_content = Some(JustifyContent::SpaceBetween);
1657 self
1658 }
1659
1660 pub fn justify_around(mut self) -> Self {
1662 self.style.justify_content = Some(JustifyContent::SpaceAround);
1663 self
1664 }
1665
1666 pub fn justify_evenly(mut self) -> Self {
1668 self.style.justify_content = Some(JustifyContent::SpaceEvenly);
1669 self
1670 }
1671
1672 pub fn content_start(mut self) -> Self {
1674 self.style.align_content = Some(taffy::AlignContent::Start);
1675 self
1676 }
1677
1678 pub fn content_center(mut self) -> Self {
1680 self.style.align_content = Some(taffy::AlignContent::Center);
1681 self
1682 }
1683
1684 pub fn content_end(mut self) -> Self {
1686 self.style.align_content = Some(taffy::AlignContent::End);
1687 self
1688 }
1689
1690 pub fn self_start(mut self) -> Self {
1695 self.style.align_self = Some(AlignSelf::FlexStart);
1696 self
1697 }
1698
1699 pub fn self_center(mut self) -> Self {
1701 self.style.align_self = Some(AlignSelf::Center);
1702 self
1703 }
1704
1705 pub fn self_end(mut self) -> Self {
1707 self.style.align_self = Some(AlignSelf::FlexEnd);
1708 self
1709 }
1710
1711 pub fn self_stretch(mut self) -> Self {
1713 self.style.align_self = Some(AlignSelf::Stretch);
1714 self
1715 }
1716
1717 pub fn w(mut self, px: f32) -> Self {
1723 self.style.size.width = Dimension::Length(px);
1724 self
1725 }
1726
1727 pub fn w_full(mut self) -> Self {
1729 self.style.size.width = Dimension::Percent(1.0);
1730 self
1731 }
1732
1733 pub fn w_auto(mut self) -> Self {
1735 self.style.size.width = Dimension::Auto;
1736 self
1737 }
1738
1739 pub fn w_fit(mut self) -> Self {
1744 self.style.size.width = Dimension::Auto;
1745 self.style.flex_basis = Dimension::Auto;
1746 self.style.flex_grow = 0.0;
1747 self.style.flex_shrink = 0.0;
1748 self
1749 }
1750
1751 pub fn h(mut self, px: f32) -> Self {
1753 self.style.size.height = Dimension::Length(px);
1754 self
1755 }
1756
1757 pub fn h_full(mut self) -> Self {
1759 self.style.size.height = Dimension::Percent(1.0);
1760 self
1761 }
1762
1763 pub fn h_auto(mut self) -> Self {
1765 self.style.size.height = Dimension::Auto;
1766 self
1767 }
1768
1769 pub fn h_fit(mut self) -> Self {
1774 self.style.size.height = Dimension::Auto;
1775 self.style.flex_basis = Dimension::Auto;
1776 self.style.flex_grow = 0.0;
1777 self.style.flex_shrink = 0.0;
1778 self
1779 }
1780
1781 pub fn size_fit(mut self) -> Self {
1785 self.style.size.width = Dimension::Auto;
1786 self.style.size.height = Dimension::Auto;
1787 self.style.flex_basis = Dimension::Auto;
1788 self.style.flex_grow = 0.0;
1789 self.style.flex_shrink = 0.0;
1790 self
1791 }
1792
1793 pub fn size(mut self, w: f32, h: f32) -> Self {
1795 self.style.size.width = Dimension::Length(w);
1796 self.style.size.height = Dimension::Length(h);
1797 self
1798 }
1799
1800 pub fn square(mut self, size: f32) -> Self {
1802 self.style.size.width = Dimension::Length(size);
1803 self.style.size.height = Dimension::Length(size);
1804 self
1805 }
1806
1807 pub fn min_w(mut self, px: f32) -> Self {
1809 self.style.min_size.width = Dimension::Length(px);
1810 self
1811 }
1812
1813 pub fn min_h(mut self, px: f32) -> Self {
1815 self.style.min_size.height = Dimension::Length(px);
1816 self
1817 }
1818
1819 pub fn max_w(mut self, px: f32) -> Self {
1821 self.style.max_size.width = Dimension::Length(px);
1822 self
1823 }
1824
1825 pub fn max_h(mut self, px: f32) -> Self {
1827 self.style.max_size.height = Dimension::Length(px);
1828 self
1829 }
1830
1831 pub fn gap(mut self, units: f32) -> Self {
1838 let px = units * 4.0;
1839 self.style.gap = taffy::Size {
1840 width: LengthPercentage::Length(px),
1841 height: LengthPercentage::Length(px),
1842 };
1843 self
1844 }
1845
1846 pub fn gap_px(mut self, px: f32) -> Self {
1848 self.style.gap = taffy::Size {
1849 width: LengthPercentage::Length(px),
1850 height: LengthPercentage::Length(px),
1851 };
1852 self
1853 }
1854
1855 pub fn gap_x(mut self, units: f32) -> Self {
1857 self.style.gap.width = LengthPercentage::Length(units * 4.0);
1858 self
1859 }
1860
1861 pub fn gap_y(mut self, units: f32) -> Self {
1863 self.style.gap.height = LengthPercentage::Length(units * 4.0);
1864 self
1865 }
1866
1867 pub fn gap_1(self) -> Self {
1873 self.gap_px(ThemeState::get().spacing().space_1)
1874 }
1875
1876 pub fn gap_2(self) -> Self {
1878 self.gap_px(ThemeState::get().spacing().space_2)
1879 }
1880
1881 pub fn gap_3(self) -> Self {
1883 self.gap_px(ThemeState::get().spacing().space_3)
1884 }
1885
1886 pub fn gap_4(self) -> Self {
1888 self.gap_px(ThemeState::get().spacing().space_4)
1889 }
1890
1891 pub fn gap_5(self) -> Self {
1893 self.gap_px(ThemeState::get().spacing().space_5)
1894 }
1895
1896 pub fn gap_6(self) -> Self {
1898 self.gap_px(ThemeState::get().spacing().space_6)
1899 }
1900
1901 pub fn gap_8(self) -> Self {
1903 self.gap_px(ThemeState::get().spacing().space_8)
1904 }
1905
1906 pub fn gap_10(self) -> Self {
1908 self.gap_px(ThemeState::get().spacing().space_10)
1909 }
1910
1911 pub fn gap_12(self) -> Self {
1913 self.gap_px(ThemeState::get().spacing().space_12)
1914 }
1915
1916 pub fn p(mut self, units: f32) -> Self {
1923 let px = LengthPercentage::Length(units * 4.0);
1924 self.style.padding = Rect {
1925 left: px,
1926 right: px,
1927 top: px,
1928 bottom: px,
1929 };
1930 self
1931 }
1932
1933 pub fn p_px(mut self, px: f32) -> Self {
1935 let val = LengthPercentage::Length(px);
1936 self.style.padding = Rect {
1937 left: val,
1938 right: val,
1939 top: val,
1940 bottom: val,
1941 };
1942 self
1943 }
1944
1945 pub fn px(mut self, units: f32) -> Self {
1947 let px = LengthPercentage::Length(units * 4.0);
1948 self.style.padding.left = px;
1949 self.style.padding.right = px;
1950 self
1951 }
1952
1953 pub fn py(mut self, units: f32) -> Self {
1955 let px = LengthPercentage::Length(units * 4.0);
1956 self.style.padding.top = px;
1957 self.style.padding.bottom = px;
1958 self
1959 }
1960
1961 pub fn pl(mut self, units: f32) -> Self {
1963 self.style.padding.left = LengthPercentage::Length(units * 4.0);
1964 self
1965 }
1966
1967 pub fn pr(mut self, units: f32) -> Self {
1969 self.style.padding.right = LengthPercentage::Length(units * 4.0);
1970 self
1971 }
1972
1973 pub fn pt(mut self, units: f32) -> Self {
1975 self.style.padding.top = LengthPercentage::Length(units * 4.0);
1976 self
1977 }
1978
1979 pub fn pb(mut self, units: f32) -> Self {
1981 self.style.padding.bottom = LengthPercentage::Length(units * 4.0);
1982 self
1983 }
1984
1985 pub fn p_1(self) -> Self {
1991 let px = ThemeState::get().spacing().space_1;
1992 self.padding(crate::units::Length::Px(px))
1993 }
1994
1995 pub fn p_2(self) -> Self {
1997 let px = ThemeState::get().spacing().space_2;
1998 self.padding(crate::units::Length::Px(px))
1999 }
2000
2001 pub fn p_3(self) -> Self {
2003 let px = ThemeState::get().spacing().space_3;
2004 self.padding(crate::units::Length::Px(px))
2005 }
2006
2007 pub fn p_4(self) -> Self {
2009 let px = ThemeState::get().spacing().space_4;
2010 self.padding(crate::units::Length::Px(px))
2011 }
2012
2013 pub fn p_5(self) -> Self {
2015 let px = ThemeState::get().spacing().space_5;
2016 self.padding(crate::units::Length::Px(px))
2017 }
2018
2019 pub fn p_6(self) -> Self {
2021 let px = ThemeState::get().spacing().space_6;
2022 self.padding(crate::units::Length::Px(px))
2023 }
2024
2025 pub fn p_8(self) -> Self {
2027 let px = ThemeState::get().spacing().space_8;
2028 self.padding(crate::units::Length::Px(px))
2029 }
2030
2031 pub fn p_10(self) -> Self {
2033 let px = ThemeState::get().spacing().space_10;
2034 self.padding(crate::units::Length::Px(px))
2035 }
2036
2037 pub fn p_12(self) -> Self {
2039 let px = ThemeState::get().spacing().space_12;
2040 self.padding(crate::units::Length::Px(px))
2041 }
2042
2043 pub fn padding_x_px(mut self, pixels: f32) -> Self {
2049 let px = LengthPercentage::Length(pixels);
2050 self.style.padding.left = px;
2051 self.style.padding.right = px;
2052 self
2053 }
2054
2055 pub fn padding_y_px(mut self, pixels: f32) -> Self {
2057 let px = LengthPercentage::Length(pixels);
2058 self.style.padding.top = px;
2059 self.style.padding.bottom = px;
2060 self
2061 }
2062
2063 pub fn padding(mut self, len: crate::units::Length) -> Self {
2077 let val: LengthPercentage = len.into();
2078 self.style.padding = Rect {
2079 left: val,
2080 right: val,
2081 top: val,
2082 bottom: val,
2083 };
2084 self
2085 }
2086
2087 pub fn padding_x(mut self, len: crate::units::Length) -> Self {
2089 let val: LengthPercentage = len.into();
2090 self.style.padding.left = val;
2091 self.style.padding.right = val;
2092 self
2093 }
2094
2095 pub fn padding_y(mut self, len: crate::units::Length) -> Self {
2097 let val: LengthPercentage = len.into();
2098 self.style.padding.top = val;
2099 self.style.padding.bottom = val;
2100 self
2101 }
2102
2103 pub fn m(mut self, units: f32) -> Self {
2105 let px = LengthPercentageAuto::Length(units * 4.0);
2106 self.style.margin = Rect {
2107 left: px,
2108 right: px,
2109 top: px,
2110 bottom: px,
2111 };
2112 self
2113 }
2114
2115 pub fn m_px(mut self, px: f32) -> Self {
2117 let val = LengthPercentageAuto::Length(px);
2118 self.style.margin = Rect {
2119 left: val,
2120 right: val,
2121 top: val,
2122 bottom: val,
2123 };
2124 self
2125 }
2126
2127 pub fn mx(mut self, units: f32) -> Self {
2129 let px = LengthPercentageAuto::Length(units * 4.0);
2130 self.style.margin.left = px;
2131 self.style.margin.right = px;
2132 self
2133 }
2134
2135 pub fn my(mut self, units: f32) -> Self {
2137 let px = LengthPercentageAuto::Length(units * 4.0);
2138 self.style.margin.top = px;
2139 self.style.margin.bottom = px;
2140 self
2141 }
2142
2143 pub fn mx_auto(mut self) -> Self {
2145 self.style.margin.left = LengthPercentageAuto::Auto;
2146 self.style.margin.right = LengthPercentageAuto::Auto;
2147 self
2148 }
2149
2150 pub fn ml(mut self, units: f32) -> Self {
2152 self.style.margin.left = LengthPercentageAuto::Length(units * 4.0);
2153 self
2154 }
2155
2156 pub fn mr(mut self, units: f32) -> Self {
2158 self.style.margin.right = LengthPercentageAuto::Length(units * 4.0);
2159 self
2160 }
2161
2162 pub fn mt(mut self, units: f32) -> Self {
2164 self.style.margin.top = LengthPercentageAuto::Length(units * 4.0);
2165 self
2166 }
2167
2168 pub fn mb(mut self, units: f32) -> Self {
2170 self.style.margin.bottom = LengthPercentageAuto::Length(units * 4.0);
2171 self
2172 }
2173
2174 pub fn m_1(self) -> Self {
2180 self.m_px(ThemeState::get().spacing().space_1)
2181 }
2182
2183 pub fn m_2(self) -> Self {
2185 self.m_px(ThemeState::get().spacing().space_2)
2186 }
2187
2188 pub fn m_3(self) -> Self {
2190 self.m_px(ThemeState::get().spacing().space_3)
2191 }
2192
2193 pub fn m_4(self) -> Self {
2195 self.m_px(ThemeState::get().spacing().space_4)
2196 }
2197
2198 pub fn m_5(self) -> Self {
2200 self.m_px(ThemeState::get().spacing().space_5)
2201 }
2202
2203 pub fn m_6(self) -> Self {
2205 self.m_px(ThemeState::get().spacing().space_6)
2206 }
2207
2208 pub fn m_8(self) -> Self {
2210 self.m_px(ThemeState::get().spacing().space_8)
2211 }
2212
2213 pub fn absolute(mut self) -> Self {
2219 self.style.position = Position::Absolute;
2220 self
2221 }
2222
2223 pub fn relative(mut self) -> Self {
2225 self.style.position = Position::Relative;
2226 self
2227 }
2228
2229 pub fn fixed(mut self) -> Self {
2231 self.style.position = Position::Absolute;
2232 self.is_fixed = true;
2233 self.is_sticky = false;
2234 self
2235 }
2236
2237 pub fn sticky(mut self, top: f32) -> Self {
2239 self.style.position = Position::Relative;
2240 self.is_sticky = true;
2241 self.is_fixed = false;
2242 self.sticky_top = Some(top);
2243 self
2244 }
2245
2246 pub fn inset(mut self, px: f32) -> Self {
2248 let val = LengthPercentageAuto::Length(px);
2249 self.style.inset = Rect {
2250 left: val,
2251 right: val,
2252 top: val,
2253 bottom: val,
2254 };
2255 self
2256 }
2257
2258 pub fn top(mut self, px: f32) -> Self {
2260 self.style.inset.top = LengthPercentageAuto::Length(px);
2261 self
2262 }
2263
2264 pub fn bottom(mut self, px: f32) -> Self {
2266 self.style.inset.bottom = LengthPercentageAuto::Length(px);
2267 self
2268 }
2269
2270 pub fn left(mut self, px: f32) -> Self {
2272 self.style.inset.left = LengthPercentageAuto::Length(px);
2273 self
2274 }
2275
2276 pub fn right(mut self, px: f32) -> Self {
2278 self.style.inset.right = LengthPercentageAuto::Length(px);
2279 self
2280 }
2281
2282 pub fn overflow_clip(mut self) -> Self {
2291 self.style.overflow.x = Overflow::Clip;
2292 self.style.overflow.y = Overflow::Clip;
2293 self
2294 }
2295
2296 pub fn overflow_visible(mut self) -> Self {
2298 self.style.overflow.x = Overflow::Visible;
2299 self.style.overflow.y = Overflow::Visible;
2300 self
2301 }
2302
2303 pub fn overflow_scroll(mut self) -> Self {
2308 self.style.overflow.x = Overflow::Scroll;
2309 self.style.overflow.y = Overflow::Scroll;
2310 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Both);
2311 self
2312 }
2313
2314 pub(crate) fn overflow_scroll_style_only(mut self) -> Self {
2318 self.style.overflow.x = Overflow::Scroll;
2319 self.style.overflow.y = Overflow::Scroll;
2320 self
2321 }
2322
2323 pub fn overflow_x(mut self, overflow: Overflow) -> Self {
2325 self.style.overflow.x = overflow;
2326 if overflow == Overflow::Scroll {
2327 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Horizontal);
2328 }
2329 self
2330 }
2331
2332 pub fn overflow_y(mut self, overflow: Overflow) -> Self {
2334 self.style.overflow.y = overflow;
2335 if overflow == Overflow::Scroll {
2336 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Vertical);
2337 }
2338 self
2339 }
2340
2341 pub fn overflow_x_scroll(mut self) -> Self {
2343 self.style.overflow.x = Overflow::Scroll;
2344 self.style.overflow.y = Overflow::Clip;
2345 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Horizontal);
2346 self
2347 }
2348
2349 pub fn overflow_y_scroll(mut self) -> Self {
2351 self.style.overflow.x = Overflow::Clip;
2352 self.style.overflow.y = Overflow::Scroll;
2353 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Vertical);
2354 self
2355 }
2356
2357 fn ensure_scroll_physics(&mut self, direction: crate::scroll::ScrollDirection) {
2359 if self.scroll_physics.is_none() {
2360 let config = crate::scroll::ScrollConfig {
2361 direction,
2362 ..Default::default()
2363 };
2364 let physics = std::sync::Arc::new(std::sync::Mutex::new(
2365 crate::scroll::ScrollPhysics::new(config),
2366 ));
2367 let handlers =
2368 crate::scroll::Scroll::create_internal_handlers(std::sync::Arc::clone(&physics));
2369 self.event_handlers.merge(handlers);
2371 self.scroll_physics = Some(physics);
2372 }
2373 }
2374
2375 pub fn bg(mut self, color: Color) -> Self {
2381 self.background = Some(Brush::Solid(color));
2382 self
2383 }
2384
2385 pub fn background(mut self, brush: impl Into<Brush>) -> Self {
2387 self.background = Some(brush.into());
2388 self
2389 }
2390
2391 pub fn backdrop_blur(self, radius: f32) -> Self {
2410 self.background(Brush::Blur(BlurStyle::with_radius(radius)))
2411 }
2412
2413 pub fn backdrop_blur_style(self, style: BlurStyle) -> Self {
2427 self.background(Brush::Blur(style))
2428 }
2429
2430 pub fn backdrop_blur_light(self) -> Self {
2432 self.background(Brush::Blur(BlurStyle::light()))
2433 }
2434
2435 pub fn backdrop_blur_medium(self) -> Self {
2437 self.background(Brush::Blur(BlurStyle::medium()))
2438 }
2439
2440 pub fn backdrop_blur_heavy(self) -> Self {
2442 self.background(Brush::Blur(BlurStyle::heavy()))
2443 }
2444
2445 pub fn backdrop_blur_max(self) -> Self {
2447 self.background(Brush::Blur(BlurStyle::max()))
2448 }
2449
2450 pub fn bg_primary(self) -> Self {
2456 self.bg(ThemeState::get().color(blinc_theme::ColorToken::Primary))
2457 }
2458
2459 pub fn bg_secondary(self) -> Self {
2461 self.bg(ThemeState::get().color(blinc_theme::ColorToken::Secondary))
2462 }
2463
2464 pub fn bg_background(self) -> Self {
2466 self.bg(ThemeState::get().color(blinc_theme::ColorToken::Background))
2467 }
2468
2469 pub fn bg_surface(self) -> Self {
2471 self.bg(ThemeState::get().color(blinc_theme::ColorToken::Surface))
2472 }
2473
2474 pub fn bg_surface_elevated(self) -> Self {
2476 self.bg(ThemeState::get().color(blinc_theme::ColorToken::SurfaceElevated))
2477 }
2478
2479 pub fn bg_success(self) -> Self {
2481 self.bg(ThemeState::get().color(blinc_theme::ColorToken::SuccessBg))
2482 }
2483
2484 pub fn bg_warning(self) -> Self {
2486 self.bg(ThemeState::get().color(blinc_theme::ColorToken::WarningBg))
2487 }
2488
2489 pub fn bg_error(self) -> Self {
2491 self.bg(ThemeState::get().color(blinc_theme::ColorToken::ErrorBg))
2492 }
2493
2494 pub fn bg_info(self) -> Self {
2496 self.bg(ThemeState::get().color(blinc_theme::ColorToken::InfoBg))
2497 }
2498
2499 pub fn bg_accent(self) -> Self {
2501 self.bg(ThemeState::get().color(blinc_theme::ColorToken::Accent))
2502 }
2503
2504 pub fn rounded(mut self, radius: f32) -> Self {
2510 self.border_radius = CornerRadius::uniform(radius);
2511 self.border_radius_explicit = true;
2512 self
2513 }
2514
2515 pub fn rounded_full(mut self) -> Self {
2517 self.border_radius = CornerRadius::uniform(9999.0);
2519 self.border_radius_explicit = true;
2520 self
2521 }
2522
2523 pub fn rounded_corners(mut self, tl: f32, tr: f32, br: f32, bl: f32) -> Self {
2525 self.border_radius = CornerRadius::new(tl, tr, br, bl);
2526 self.border_radius_explicit = true;
2527 self
2528 }
2529
2530 pub fn rounded_sm(self) -> Self {
2536 self.rounded(ThemeState::get().radii().radius_sm)
2537 }
2538
2539 pub fn rounded_default(self) -> Self {
2541 self.rounded(ThemeState::get().radii().radius_default)
2542 }
2543
2544 pub fn rounded_md(self) -> Self {
2546 self.rounded(ThemeState::get().radii().radius_md)
2547 }
2548
2549 pub fn rounded_lg(self) -> Self {
2551 self.rounded(ThemeState::get().radii().radius_lg)
2552 }
2553
2554 pub fn rounded_xl(self) -> Self {
2556 self.rounded(ThemeState::get().radii().radius_xl)
2557 }
2558
2559 pub fn rounded_2xl(self) -> Self {
2561 self.rounded(ThemeState::get().radii().radius_2xl)
2562 }
2563
2564 pub fn rounded_3xl(self) -> Self {
2566 self.rounded(ThemeState::get().radii().radius_3xl)
2567 }
2568
2569 pub fn rounded_none(self) -> Self {
2571 self.rounded(0.0)
2572 }
2573
2574 pub fn corner_shape(mut self, n: f32) -> Self {
2582 self.corner_shape = CornerShape::uniform(n);
2583 self
2584 }
2585
2586 pub fn corner_shapes(mut self, tl: f32, tr: f32, br: f32, bl: f32) -> Self {
2588 self.corner_shape = CornerShape::new(tl, tr, br, bl);
2589 self
2590 }
2591
2592 pub fn corner_bevel(self) -> Self {
2594 self.corner_shape(0.0)
2595 }
2596
2597 pub fn corner_squircle(self) -> Self {
2599 self.corner_shape(2.0)
2600 }
2601
2602 pub fn corner_scoop(self) -> Self {
2604 self.corner_shape(-1.0)
2605 }
2606
2607 pub fn overflow_fade(mut self, distance: f32) -> Self {
2613 self.overflow_fade = OverflowFade::uniform(distance);
2614 self
2615 }
2616
2617 pub fn overflow_fade_x(mut self, distance: f32) -> Self {
2619 self.overflow_fade = OverflowFade::horizontal(distance);
2620 self
2621 }
2622
2623 pub fn overflow_fade_y(mut self, distance: f32) -> Self {
2625 self.overflow_fade = OverflowFade::vertical(distance);
2626 self
2627 }
2628
2629 pub fn overflow_fade_edges(mut self, top: f32, right: f32, bottom: f32, left: f32) -> Self {
2631 self.overflow_fade = OverflowFade::new(top, right, bottom, left);
2632 self
2633 }
2634
2635 pub fn border(mut self, width: f32, color: Color) -> Self {
2641 self.border_width = width;
2642 self.border_color = Some(color);
2643 self
2644 }
2645
2646 pub fn border_color(mut self, color: Color) -> Self {
2648 self.border_color = Some(color);
2649 self
2650 }
2651
2652 pub fn border_width(mut self, width: f32) -> Self {
2654 self.border_width = width;
2655 self
2656 }
2657
2658 pub fn outline_width(mut self, width: f32) -> Self {
2660 self.outline_width = width;
2661 self
2662 }
2663
2664 pub fn outline_color(mut self, color: Color) -> Self {
2666 self.outline_color = Some(color);
2667 self
2668 }
2669
2670 pub fn outline_offset(mut self, offset: f32) -> Self {
2672 self.outline_offset = offset;
2673 self
2674 }
2675
2676 pub fn border_left(mut self, width: f32, color: Color) -> Self {
2685 self.inherit_uniform_border_to_sides();
2686 self.border_sides.left = Some(crate::element::BorderSide::new(width, color));
2687 self
2688 }
2689
2690 pub fn border_right(mut self, width: f32, color: Color) -> Self {
2694 self.inherit_uniform_border_to_sides();
2695 self.border_sides.right = Some(crate::element::BorderSide::new(width, color));
2696 self
2697 }
2698
2699 pub fn border_top(mut self, width: f32, color: Color) -> Self {
2703 self.inherit_uniform_border_to_sides();
2704 self.border_sides.top = Some(crate::element::BorderSide::new(width, color));
2705 self
2706 }
2707
2708 pub fn border_bottom(mut self, width: f32, color: Color) -> Self {
2712 self.inherit_uniform_border_to_sides();
2713 self.border_sides.bottom = Some(crate::element::BorderSide::new(width, color));
2714 self
2715 }
2716
2717 pub fn border_x(mut self, width: f32, color: Color) -> Self {
2721 self.inherit_uniform_border_to_sides();
2722 let side = crate::element::BorderSide::new(width, color);
2723 self.border_sides.left = Some(side);
2724 self.border_sides.right = Some(side);
2725 self
2726 }
2727
2728 pub fn border_y(mut self, width: f32, color: Color) -> Self {
2732 self.inherit_uniform_border_to_sides();
2733 let side = crate::element::BorderSide::new(width, color);
2734 self.border_sides.top = Some(side);
2735 self.border_sides.bottom = Some(side);
2736 self
2737 }
2738
2739 fn inherit_uniform_border_to_sides(&mut self) {
2744 if self.border_width > 0.0 && !self.border_sides.has_any() {
2746 if let Some(color) = self.border_color {
2747 let side = crate::element::BorderSide::new(self.border_width, color);
2748 self.border_sides.top = Some(side);
2749 self.border_sides.right = Some(side);
2750 self.border_sides.bottom = Some(side);
2751 self.border_sides.left = Some(side);
2752 }
2753 }
2754 }
2755
2756 pub fn borders<F>(mut self, f: F) -> Self
2774 where
2775 F: FnOnce(crate::element::BorderBuilder) -> crate::element::BorderBuilder,
2776 {
2777 let builder = f(crate::element::BorderBuilder::new());
2778 self.border_sides = builder.build();
2779 self
2780 }
2781
2782 pub fn layer(mut self, layer: RenderLayer) -> Self {
2788 self.render_layer = layer;
2789 self
2790 }
2791
2792 pub fn foreground(self) -> Self {
2794 self.layer(RenderLayer::Foreground)
2795 }
2796
2797 pub fn material(mut self, material: Material) -> Self {
2803 if matches!(material, Material::Glass(_)) {
2805 self.render_layer = RenderLayer::Glass;
2806 }
2807 self.material = Some(material);
2808 self
2809 }
2810
2811 pub fn effect(self, effect: impl Into<Material>) -> Self {
2825 self.material(effect.into())
2826 }
2827
2828 pub fn glass(self) -> Self {
2832 self.material(Material::Glass(GlassMaterial::new()))
2833 }
2834
2835 pub fn metallic(self) -> Self {
2837 self.material(Material::Metallic(MetallicMaterial::new()))
2838 }
2839
2840 pub fn chrome(self) -> Self {
2842 self.material(Material::Metallic(MetallicMaterial::chrome()))
2843 }
2844
2845 pub fn gold(self) -> Self {
2847 self.material(Material::Metallic(MetallicMaterial::gold()))
2848 }
2849
2850 pub fn wood(self) -> Self {
2852 self.material(Material::Wood(WoodMaterial::new()))
2853 }
2854
2855 pub fn shadow(mut self, shadow: Shadow) -> Self {
2861 self.shadow = Some(shadow);
2862 self
2863 }
2864
2865 pub fn shadow_params(self, offset_x: f32, offset_y: f32, blur: f32, color: Color) -> Self {
2867 self.shadow(Shadow::new(offset_x, offset_y, blur, color))
2868 }
2869
2870 pub fn shadow_sm(self) -> Self {
2872 self.shadow(ThemeState::get().shadows().shadow_sm.into())
2873 }
2874
2875 pub fn shadow_md(self) -> Self {
2877 self.shadow(ThemeState::get().shadows().shadow_md.into())
2878 }
2879
2880 pub fn shadow_lg(self) -> Self {
2882 self.shadow(ThemeState::get().shadows().shadow_lg.into())
2883 }
2884
2885 pub fn shadow_xl(self) -> Self {
2887 self.shadow(ThemeState::get().shadows().shadow_xl.into())
2888 }
2889
2890 pub fn transform(mut self, transform: Transform) -> Self {
2896 self.transform = Some(transform);
2897 self
2898 }
2899
2900 pub fn translate(self, x: f32, y: f32) -> Self {
2902 self.transform(Transform::translate(x, y))
2903 }
2904
2905 pub fn scale(self, factor: f32) -> Self {
2907 self.transform(Transform::scale(factor, factor))
2908 }
2909
2910 pub fn scale_xy(self, sx: f32, sy: f32) -> Self {
2912 self.transform(Transform::scale(sx, sy))
2913 }
2914
2915 pub fn rotate(self, angle: f32) -> Self {
2917 self.transform(Transform::rotate(angle))
2918 }
2919
2920 pub fn rotate_deg(self, degrees: f32) -> Self {
2922 self.rotate(degrees * std::f32::consts::PI / 180.0)
2923 }
2924
2925 pub fn opacity(mut self, opacity: f32) -> Self {
2931 self.opacity = opacity.clamp(0.0, 1.0);
2932 self
2933 }
2934
2935 pub fn opaque(self) -> Self {
2937 self.opacity(1.0)
2938 }
2939
2940 pub fn flow(mut self, f: impl Into<crate::element::FlowRef>) -> Self {
2953 match f.into() {
2954 crate::element::FlowRef::Name(name) => {
2955 self.flow_name = Some(name);
2956 }
2957 crate::element::FlowRef::Graph(g) => {
2958 self.flow_name = Some(g.name.clone());
2959 self.flow_graph = Some(g);
2960 }
2961 }
2962 self
2963 }
2964
2965 pub fn translucent(self) -> Self {
2967 self.opacity(0.5)
2968 }
2969
2970 pub fn invisible(self) -> Self {
2972 self.opacity(0.0)
2973 }
2974
2975 pub fn layer_effect(mut self, effect: LayerEffect) -> Self {
2996 self.layer_effects.push(effect);
2997 self
2998 }
2999
3000 pub fn blur(self, radius: f32) -> Self {
3011 self.layer_effect(LayerEffect::blur(radius))
3012 }
3013
3014 pub fn blur_with_quality(self, radius: f32, quality: BlurQuality) -> Self {
3021 self.layer_effect(LayerEffect::blur_with_quality(radius, quality))
3022 }
3023
3024 pub fn drop_shadow_effect(self, offset_x: f32, offset_y: f32, blur: f32, color: Color) -> Self {
3038 self.layer_effect(LayerEffect::drop_shadow(offset_x, offset_y, blur, color))
3039 }
3040
3041 pub fn glow_effect(self, color: Color, blur: f32, range: f32, opacity: f32) -> Self {
3060 self.layer_effect(LayerEffect::glow(color, blur, range, opacity))
3061 }
3062
3063 pub fn grayscale(self) -> Self {
3065 self.layer_effect(LayerEffect::grayscale())
3066 }
3067
3068 pub fn sepia(self) -> Self {
3070 self.layer_effect(LayerEffect::sepia())
3071 }
3072
3073 pub fn brightness(self, factor: f32) -> Self {
3075 self.layer_effect(LayerEffect::brightness(factor))
3076 }
3077
3078 pub fn contrast(self, factor: f32) -> Self {
3080 self.layer_effect(LayerEffect::contrast(factor))
3081 }
3082
3083 pub fn saturation(self, factor: f32) -> Self {
3085 self.layer_effect(LayerEffect::saturation(factor))
3086 }
3087
3088 pub fn cursor(mut self, cursor: crate::element::CursorStyle) -> Self {
3104 self.cursor = Some(cursor);
3105 self
3106 }
3107
3108 pub fn cursor_pointer(self) -> Self {
3110 self.cursor(crate::element::CursorStyle::Pointer)
3111 }
3112
3113 pub fn cursor_text(self) -> Self {
3115 self.cursor(crate::element::CursorStyle::Text)
3116 }
3117
3118 pub fn cursor_move(self) -> Self {
3120 self.cursor(crate::element::CursorStyle::Move)
3121 }
3122
3123 pub fn cursor_grab(self) -> Self {
3125 self.cursor(crate::element::CursorStyle::Grab)
3126 }
3127
3128 pub fn cursor_grabbing(self) -> Self {
3130 self.cursor(crate::element::CursorStyle::Grabbing)
3131 }
3132
3133 pub fn cursor_not_allowed(self) -> Self {
3135 self.cursor(crate::element::CursorStyle::NotAllowed)
3136 }
3137
3138 pub fn pointer_events_none(mut self) -> Self {
3144 self.pointer_events_none = true;
3145 self
3146 }
3147
3148 pub fn stack_layer(mut self) -> Self {
3156 self.is_stack_layer = true;
3157 self
3158 }
3159
3160 pub fn z_index(mut self, z: i32) -> Self {
3162 self.z_index = z;
3163 self
3164 }
3165
3166 pub fn child(mut self, child: impl ElementBuilder + 'static) -> Self {
3172 self.children.push(Box::new(child));
3173 self
3174 }
3175
3176 pub fn child_box(mut self, child: Box<dyn ElementBuilder>) -> Self {
3178 self.children.push(child);
3179 self
3180 }
3181
3182 pub fn children<I>(mut self, children: I) -> Self
3184 where
3185 I: IntoIterator,
3186 I::Item: ElementBuilder + 'static,
3187 {
3188 for child in children {
3189 self.children.push(Box::new(child));
3190 }
3191 self
3192 }
3193
3194 pub fn style_mut(&mut self) -> &mut Style {
3196 &mut self.style
3197 }
3198
3199 pub fn event_handlers(&self) -> &crate::event_handler::EventHandlers {
3205 &self.event_handlers
3206 }
3207
3208 pub fn event_handlers_mut(&mut self) -> &mut crate::event_handler::EventHandlers {
3210 &mut self.event_handlers
3211 }
3212
3213 pub fn on_click<F>(mut self, handler: F) -> Self
3226 where
3227 F: Fn(&crate::event_handler::EventContext) + 'static,
3228 {
3229 self.event_handlers.on_click(handler);
3230 self
3231 }
3232
3233 pub fn on_mouse_down<F>(mut self, handler: F) -> Self
3235 where
3236 F: Fn(&crate::event_handler::EventContext) + 'static,
3237 {
3238 self.event_handlers.on_mouse_down(handler);
3239 self
3240 }
3241
3242 pub fn on_mouse_up<F>(mut self, handler: F) -> Self
3244 where
3245 F: Fn(&crate::event_handler::EventContext) + 'static,
3246 {
3247 self.event_handlers.on_mouse_up(handler);
3248 self
3249 }
3250
3251 pub fn on_hover_enter<F>(mut self, handler: F) -> Self
3261 where
3262 F: Fn(&crate::event_handler::EventContext) + 'static,
3263 {
3264 self.event_handlers.on_hover_enter(handler);
3265 self
3266 }
3267
3268 pub fn on_hover_leave<F>(mut self, handler: F) -> Self
3270 where
3271 F: Fn(&crate::event_handler::EventContext) + 'static,
3272 {
3273 self.event_handlers.on_hover_leave(handler);
3274 self
3275 }
3276
3277 pub fn on_focus<F>(mut self, handler: F) -> Self
3279 where
3280 F: Fn(&crate::event_handler::EventContext) + 'static,
3281 {
3282 self.event_handlers.on_focus(handler);
3283 self
3284 }
3285
3286 pub fn on_blur<F>(mut self, handler: F) -> Self
3288 where
3289 F: Fn(&crate::event_handler::EventContext) + 'static,
3290 {
3291 self.event_handlers.on_blur(handler);
3292 self
3293 }
3294
3295 pub fn on_mount<F>(mut self, handler: F) -> Self
3297 where
3298 F: Fn(&crate::event_handler::EventContext) + 'static,
3299 {
3300 self.event_handlers.on_mount(handler);
3301 self
3302 }
3303
3304 pub fn on_unmount<F>(mut self, handler: F) -> Self
3306 where
3307 F: Fn(&crate::event_handler::EventContext) + 'static,
3308 {
3309 self.event_handlers.on_unmount(handler);
3310 self
3311 }
3312
3313 pub fn on_key_down<F>(mut self, handler: F) -> Self
3315 where
3316 F: Fn(&crate::event_handler::EventContext) + 'static,
3317 {
3318 self.event_handlers.on_key_down(handler);
3319 self
3320 }
3321
3322 pub fn on_key_up<F>(mut self, handler: F) -> Self
3324 where
3325 F: Fn(&crate::event_handler::EventContext) + 'static,
3326 {
3327 self.event_handlers.on_key_up(handler);
3328 self
3329 }
3330
3331 pub fn on_scroll<F>(mut self, handler: F) -> Self
3333 where
3334 F: Fn(&crate::event_handler::EventContext) + 'static,
3335 {
3336 self.event_handlers.on_scroll(handler);
3337 self
3338 }
3339
3340 pub fn on_mouse_move<F>(mut self, handler: F) -> Self
3342 where
3343 F: Fn(&crate::event_handler::EventContext) + 'static,
3344 {
3345 self.event_handlers
3346 .on(blinc_core::events::event_types::POINTER_MOVE, handler);
3347 self
3348 }
3349
3350 pub fn on_drag<F>(mut self, handler: F) -> Self
3352 where
3353 F: Fn(&crate::event_handler::EventContext) + 'static,
3354 {
3355 self.event_handlers
3356 .on(blinc_core::events::event_types::DRAG, handler);
3357 self
3358 }
3359
3360 pub fn on_drag_end<F>(mut self, handler: F) -> Self
3362 where
3363 F: Fn(&crate::event_handler::EventContext) + 'static,
3364 {
3365 self.event_handlers
3366 .on(blinc_core::events::event_types::DRAG_END, handler);
3367 self
3368 }
3369
3370 pub fn on_text_input<F>(mut self, handler: F) -> Self
3372 where
3373 F: Fn(&crate::event_handler::EventContext) + 'static,
3374 {
3375 self.event_handlers.on_text_input(handler);
3376 self
3377 }
3378
3379 pub fn on_resize<F>(mut self, handler: F) -> Self
3381 where
3382 F: Fn(&crate::event_handler::EventContext) + 'static,
3383 {
3384 self.event_handlers.on_resize(handler);
3385 self
3386 }
3387
3388 pub fn on_event<F>(mut self, event_type: blinc_core::events::EventType, handler: F) -> Self
3402 where
3403 F: Fn(&crate::event_handler::EventContext) + 'static,
3404 {
3405 self.event_handlers.on(event_type, handler);
3406 self
3407 }
3408}
3409
3410#[derive(Clone, Copy, Debug, PartialEq, Eq)]
3412pub enum ElementTypeId {
3413 Div,
3414 Text,
3415 StyledText,
3417 Svg,
3418 Image,
3419 Canvas,
3420 Motion,
3422}
3423
3424#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
3426pub enum TextAlign {
3427 #[default]
3429 Left,
3430 Center,
3432 Right,
3434}
3435
3436#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
3438pub enum FontWeight {
3439 Thin,
3441 ExtraLight,
3443 Light,
3445 #[default]
3447 Normal,
3448 Medium,
3450 SemiBold,
3452 Bold,
3454 ExtraBold,
3456 Black,
3458}
3459
3460impl FontWeight {
3461 pub fn weight(&self) -> u16 {
3463 match self {
3464 FontWeight::Thin => 100,
3465 FontWeight::ExtraLight => 200,
3466 FontWeight::Light => 300,
3467 FontWeight::Normal => 400,
3468 FontWeight::Medium => 500,
3469 FontWeight::SemiBold => 600,
3470 FontWeight::Bold => 700,
3471 FontWeight::ExtraBold => 800,
3472 FontWeight::Black => 900,
3473 }
3474 }
3475}
3476
3477#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
3479pub enum TextVerticalAlign {
3480 #[default]
3483 Top,
3484 Center,
3487 Baseline,
3491}
3492
3493#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
3495pub enum GenericFont {
3496 #[default]
3498 System,
3499 Monospace,
3501 Serif,
3503 SansSerif,
3505}
3506
3507#[derive(Debug, Clone, PartialEq, Eq, Default)]
3523pub struct FontFamily {
3524 pub name: Option<String>,
3526 pub generic: GenericFont,
3528}
3529
3530impl FontFamily {
3531 pub fn generic(generic: GenericFont) -> Self {
3533 Self {
3534 name: None,
3535 generic,
3536 }
3537 }
3538
3539 pub fn named(name: impl Into<String>) -> Self {
3541 Self {
3542 name: Some(name.into()),
3543 generic: GenericFont::System,
3544 }
3545 }
3546
3547 pub fn named_with_fallback(name: impl Into<String>, generic: GenericFont) -> Self {
3549 Self {
3550 name: Some(name.into()),
3551 generic,
3552 }
3553 }
3554
3555 pub fn system() -> Self {
3557 Self::generic(GenericFont::System)
3558 }
3559
3560 pub fn monospace() -> Self {
3562 Self::generic(GenericFont::Monospace)
3563 }
3564
3565 pub fn serif() -> Self {
3567 Self::generic(GenericFont::Serif)
3568 }
3569
3570 pub fn sans_serif() -> Self {
3572 Self::generic(GenericFont::SansSerif)
3573 }
3574}
3575
3576#[derive(Clone)]
3578pub struct TextRenderInfo {
3579 pub content: String,
3580 pub font_size: f32,
3581 pub color: [f32; 4],
3582 pub align: TextAlign,
3583 pub weight: FontWeight,
3584 pub italic: bool,
3586 pub v_align: TextVerticalAlign,
3587 pub wrap: bool,
3589 pub line_height: f32,
3591 pub measured_width: f32,
3594 pub font_family: FontFamily,
3596 pub word_spacing: f32,
3598 pub letter_spacing: f32,
3600 pub ascender: f32,
3603 pub strikethrough: bool,
3605 pub underline: bool,
3607}
3608
3609#[derive(Clone)]
3611pub struct StyledTextSpanInfo {
3612 pub start: usize,
3614 pub end: usize,
3616 pub color: [f32; 4],
3618 pub bold: bool,
3620 pub italic: bool,
3622 pub underline: bool,
3624 pub strikethrough: bool,
3626 pub link_url: Option<String>,
3628}
3629
3630#[derive(Clone)]
3632pub struct StyledTextRenderInfo {
3633 pub content: String,
3635 pub spans: Vec<StyledTextSpanInfo>,
3637 pub font_size: f32,
3639 pub default_color: [f32; 4],
3641 pub align: TextAlign,
3643 pub v_align: TextVerticalAlign,
3645 pub font_family: FontFamily,
3647 pub line_height: f32,
3649 pub weight: FontWeight,
3651 pub italic: bool,
3653 pub ascender: f32,
3655}
3656
3657#[derive(Clone)]
3659pub struct SvgRenderInfo {
3660 pub source: Arc<str>,
3661 pub tint: Option<blinc_core::Color>,
3662 pub fill: Option<blinc_core::Color>,
3663 pub stroke: Option<blinc_core::Color>,
3664 pub stroke_width: Option<f32>,
3665}
3666
3667#[derive(Clone)]
3669pub struct ImageRenderInfo {
3670 pub source: String,
3672 pub object_fit: u8,
3674 pub object_position: [f32; 2],
3676 pub opacity: f32,
3678 pub border_radius: f32,
3680 pub tint: [f32; 4],
3682 pub filter: [f32; 8],
3684 pub loading_strategy: u8,
3686 pub placeholder_type: u8,
3688 pub placeholder_color: [f32; 4],
3690 pub placeholder_image: Option<String>,
3692 pub fade_duration_ms: u32,
3694}
3695
3696impl Default for ImageRenderInfo {
3697 fn default() -> Self {
3698 Self {
3699 source: String::new(),
3700 object_fit: 0, object_position: [0.5, 0.5], opacity: 1.0,
3703 border_radius: 0.0,
3704 tint: [1.0, 1.0, 1.0, 1.0],
3705 filter: [0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0], loading_strategy: 0, placeholder_type: 1, placeholder_color: [0.15, 0.15, 0.15, 0.5], placeholder_image: None,
3710 fade_duration_ms: 200,
3711 }
3712 }
3713}
3714
3715pub trait ElementBuilder {
3719 fn build(&self, tree: &mut LayoutTree) -> LayoutNodeId;
3721
3722 fn render_props(&self) -> RenderProps;
3724
3725 fn children_builders(&self) -> &[Box<dyn ElementBuilder>];
3727
3728 fn element_type_id(&self) -> ElementTypeId {
3730 ElementTypeId::Div
3731 }
3732
3733 fn text_render_info(&self) -> Option<TextRenderInfo> {
3735 None
3736 }
3737
3738 fn styled_text_render_info(&self) -> Option<StyledTextRenderInfo> {
3740 None
3741 }
3742
3743 fn svg_render_info(&self) -> Option<SvgRenderInfo> {
3745 None
3746 }
3747
3748 fn image_render_info(&self) -> Option<ImageRenderInfo> {
3750 None
3751 }
3752
3753 fn canvas_render_info(&self) -> Option<crate::canvas::CanvasRenderFn> {
3755 None
3756 }
3757
3758 fn event_handlers(&self) -> Option<&crate::event_handler::EventHandlers> {
3763 None
3764 }
3765
3766 fn scroll_info(&self) -> Option<crate::scroll::ScrollRenderInfo> {
3768 None
3769 }
3770
3771 fn scroll_physics(&self) -> Option<crate::scroll::SharedScrollPhysics> {
3773 None
3774 }
3775
3776 fn motion_animation_for_child(
3781 &self,
3782 _child_index: usize,
3783 ) -> Option<crate::element::MotionAnimation> {
3784 None
3785 }
3786
3787 fn motion_bindings(&self) -> Option<crate::motion::MotionBindings> {
3792 None
3793 }
3794
3795 fn motion_stable_id(&self) -> Option<&str> {
3801 None
3802 }
3803
3804 fn motion_should_replay(&self) -> bool {
3809 false
3810 }
3811
3812 fn motion_is_suspended(&self) -> bool {
3817 false
3818 }
3819
3820 #[deprecated(
3829 since = "0.1.0",
3830 note = "Use query_motion(key).exit() to explicitly trigger motion exit"
3831 )]
3832 fn motion_is_exiting(&self) -> bool {
3833 false
3834 }
3835
3836 fn layout_style(&self) -> Option<&taffy::Style> {
3841 None
3842 }
3843
3844 fn layout_bounds_storage(&self) -> Option<crate::renderer::LayoutBoundsStorage> {
3849 None
3850 }
3851
3852 fn layout_bounds_callback(&self) -> Option<crate::renderer::LayoutBoundsCallback> {
3858 None
3859 }
3860
3861 fn semantic_type_name(&self) -> Option<&'static str> {
3866 None
3867 }
3868
3869 fn element_id(&self) -> Option<&str> {
3873 None
3874 }
3875
3876 fn set_auto_id(&mut self, _id: String) -> bool {
3881 false
3882 }
3883
3884 fn children_builders_mut(&mut self) -> &mut [Box<dyn ElementBuilder>] {
3886 &mut []
3887 }
3888
3889 fn element_classes(&self) -> &[String] {
3891 &[]
3892 }
3893
3894 fn bound_scroll_ref(&self) -> Option<&crate::selector::ScrollRef> {
3899 None
3900 }
3901
3902 fn motion_on_ready_callback(
3908 &self,
3909 ) -> Option<std::sync::Arc<dyn Fn(crate::element::ElementBounds) + Send + Sync>> {
3910 None
3911 }
3912
3913 fn layout_animation_config(&self) -> Option<crate::layout_animation::LayoutAnimationConfig> {
3922 None
3923 }
3924
3925 fn visual_animation_config(&self) -> Option<crate::visual_animation::VisualAnimationConfig> {
3930 None
3931 }
3932}
3933
3934impl ElementBuilder for Div {
3935 fn build(&self, tree: &mut LayoutTree) -> LayoutNodeId {
3936 let node = tree.create_node(self.style.clone());
3937
3938 for child in &self.children {
3940 let child_node = child.build(tree);
3941 tree.add_child(node, child_node);
3942 }
3943
3944 node
3945 }
3946
3947 #[allow(deprecated)]
3948 fn render_props(&self) -> RenderProps {
3949 let clips_content = !matches!(self.style.overflow.x, Overflow::Visible)
3952 || !matches!(self.style.overflow.y, Overflow::Visible);
3953
3954 RenderProps {
3955 background: self.background.clone(),
3956 border_radius: self.border_radius,
3957 border_radius_explicit: self.border_radius_explicit,
3958 corner_shape: self.corner_shape,
3959 border_color: self.border_color,
3960 border_width: self.border_width,
3961 border_sides: self.border_sides,
3962 layer: self.render_layer,
3963 material: self.material.clone(),
3964 shadow: self.shadow,
3965 transform: self.transform.clone(),
3966 opacity: self.opacity,
3967 clips_content,
3968 is_stack_layer: self.is_stack_layer,
3969 pointer_events_none: self.pointer_events_none,
3970 cursor: self.cursor,
3971 layer_effects: self.layer_effects.clone(),
3972 rotate_x: self.rotate_x,
3973 rotate_y: self.rotate_y,
3974 perspective: self.perspective_3d,
3975 shape_3d: self.shape_3d,
3976 depth: self.depth,
3977 light_direction: self.light_direction,
3978 light_intensity: self.light_intensity,
3979 ambient: self.ambient,
3980 specular: self.specular,
3981 translate_z: self.translate_z,
3982 op_3d: self.op_3d,
3983 blend_3d: self.blend_3d,
3984 clip_path: self.clip_path.clone(),
3985 overflow_fade: self.overflow_fade,
3986 flow: self.flow_name.clone(),
3987 flow_graph: self.flow_graph.clone(),
3988 outline_color: self.outline_color,
3989 outline_width: self.outline_width,
3990 outline_offset: self.outline_offset,
3991 is_fixed: self.is_fixed,
3992 is_sticky: self.is_sticky,
3993 sticky_top: self.sticky_top,
3994 z_index: self.z_index,
3995 ..Default::default()
3996 }
3997 }
3998
3999 fn children_builders(&self) -> &[Box<dyn ElementBuilder>] {
4000 &self.children
4001 }
4002
4003 fn event_handlers(&self) -> Option<&crate::event_handler::EventHandlers> {
4004 if self.event_handlers.is_empty() {
4005 None
4006 } else {
4007 Some(&self.event_handlers)
4008 }
4009 }
4010
4011 fn layout_style(&self) -> Option<&taffy::Style> {
4012 Some(&self.style)
4013 }
4014
4015 fn element_id(&self) -> Option<&str> {
4016 self.element_id.as_deref()
4017 }
4018
4019 fn set_auto_id(&mut self, id: String) -> bool {
4020 if self.element_id.is_none() {
4021 self.element_id = Some(id);
4022 true
4023 } else {
4024 false
4025 }
4026 }
4027
4028 fn children_builders_mut(&mut self) -> &mut [Box<dyn ElementBuilder>] {
4029 &mut self.children
4030 }
4031
4032 fn element_classes(&self) -> &[String] {
4033 &self.classes
4034 }
4035
4036 fn layout_animation_config(&self) -> Option<crate::layout_animation::LayoutAnimationConfig> {
4037 self.layout_animation.clone()
4038 }
4039
4040 fn visual_animation_config(&self) -> Option<crate::visual_animation::VisualAnimationConfig> {
4041 self.visual_animation.clone()
4042 }
4043
4044 fn scroll_physics(&self) -> Option<crate::scroll::SharedScrollPhysics> {
4045 self.scroll_physics.clone()
4046 }
4047}
4048
4049pub fn div() -> Div {
4051 Div::new()
4052}
4053
4054#[cfg(test)]
4057mod tests {
4058 use super::*;
4059 use crate::renderer::RenderTree;
4060
4061 #[test]
4062 fn test_div_builder() {
4063 let d = div().w(100.0).h(50.0).flex_row().gap(2.0).p(4.0);
4064
4065 assert!(matches!(d.style.display, Display::Flex));
4066 assert!(matches!(d.style.flex_direction, FlexDirection::Row));
4067 }
4068
4069 #[test]
4070 fn test_div_with_children() {
4071 let parent = div().flex_col().child(div().h(20.0)).child(div().h(30.0));
4072
4073 assert_eq!(parent.children.len(), 2);
4074 }
4075
4076 #[test]
4077 fn test_build_tree() {
4078 let ui = div().flex_col().child(div().h(20.0)).child(div().h(30.0));
4079
4080 let mut tree = LayoutTree::new();
4081 let root = ui.build(&mut tree);
4082
4083 assert_eq!(tree.len(), 3);
4084 assert_eq!(tree.children(root).len(), 2);
4085 }
4086
4087 #[test]
4088 fn test_layout_flex_row_with_fixed_children() {
4089 let ui = div()
4091 .w(300.0)
4092 .h(100.0)
4093 .flex_row()
4094 .child(div().w(50.0).h(100.0))
4095 .child(div().w(100.0).h(100.0))
4096 .child(div().w(50.0).h(100.0));
4097
4098 let mut tree = RenderTree::from_element(&ui);
4099 tree.compute_layout(300.0, 100.0);
4100
4101 let root = tree.root().unwrap();
4102 let children: Vec<_> = tree.layout_tree.children(root);
4103
4104 let first = tree
4106 .layout_tree
4107 .get_bounds(children[0], (0.0, 0.0))
4108 .unwrap();
4109 assert_eq!(first.x, 0.0);
4110 assert_eq!(first.width, 50.0);
4111
4112 let second = tree
4114 .layout_tree
4115 .get_bounds(children[1], (0.0, 0.0))
4116 .unwrap();
4117 assert_eq!(second.x, 50.0);
4118 assert_eq!(second.width, 100.0);
4119
4120 let third = tree
4122 .layout_tree
4123 .get_bounds(children[2], (0.0, 0.0))
4124 .unwrap();
4125 assert_eq!(third.x, 150.0);
4126 assert_eq!(third.width, 50.0);
4127 }
4128
4129 #[test]
4130 fn test_layout_flex_col_with_gap() {
4131 let ui = div()
4133 .w(100.0)
4134 .h(200.0)
4135 .flex_col()
4136 .gap_px(10.0) .child(div().w_full().h(40.0))
4138 .child(div().w_full().h(40.0))
4139 .child(div().w_full().h(40.0));
4140
4141 let mut tree = RenderTree::from_element(&ui);
4142 tree.compute_layout(100.0, 200.0);
4143
4144 let root = tree.root().unwrap();
4145 let children: Vec<_> = tree.layout_tree.children(root);
4146
4147 let first = tree
4149 .layout_tree
4150 .get_bounds(children[0], (0.0, 0.0))
4151 .unwrap();
4152 assert_eq!(first.y, 0.0);
4153 assert_eq!(first.height, 40.0);
4154
4155 let second = tree
4157 .layout_tree
4158 .get_bounds(children[1], (0.0, 0.0))
4159 .unwrap();
4160 assert_eq!(second.y, 50.0);
4161 assert_eq!(second.height, 40.0);
4162
4163 let third = tree
4165 .layout_tree
4166 .get_bounds(children[2], (0.0, 0.0))
4167 .unwrap();
4168 assert_eq!(third.y, 100.0);
4169 assert_eq!(third.height, 40.0);
4170 }
4171
4172 #[test]
4173 fn test_layout_flex_grow() {
4174 let ui = div()
4176 .w(200.0)
4177 .h(100.0)
4178 .flex_row()
4179 .child(div().w(50.0).h(100.0))
4180 .child(div().flex_grow().h(100.0));
4181
4182 let mut tree = RenderTree::from_element(&ui);
4183 tree.compute_layout(200.0, 100.0);
4184
4185 let root = tree.root().unwrap();
4186 let children: Vec<_> = tree.layout_tree.children(root);
4187
4188 let fixed = tree
4190 .layout_tree
4191 .get_bounds(children[0], (0.0, 0.0))
4192 .unwrap();
4193 assert_eq!(fixed.width, 50.0);
4194
4195 let growing = tree
4197 .layout_tree
4198 .get_bounds(children[1], (0.0, 0.0))
4199 .unwrap();
4200 assert_eq!(growing.x, 50.0);
4201 assert_eq!(growing.width, 150.0);
4202 }
4203
4204 #[test]
4205 fn test_layout_padding() {
4206 let ui = div()
4208 .w(100.0)
4209 .h(100.0)
4210 .p(2.0) .child(div().w_full().h_full());
4212
4213 let mut tree = RenderTree::from_element(&ui);
4214 tree.compute_layout(100.0, 100.0);
4215
4216 let root = tree.root().unwrap();
4217 let children: Vec<_> = tree.layout_tree.children(root);
4218
4219 let child = tree
4221 .layout_tree
4222 .get_bounds(children[0], (0.0, 0.0))
4223 .unwrap();
4224 assert_eq!(child.x, 8.0);
4225 assert_eq!(child.y, 8.0);
4226 assert_eq!(child.width, 84.0); assert_eq!(child.height, 84.0);
4228 }
4229
4230 #[test]
4231 fn test_layout_justify_between() {
4232 let ui = div()
4234 .w(200.0)
4235 .h(50.0)
4236 .flex_row()
4237 .justify_between()
4238 .child(div().w(30.0).h(50.0))
4239 .child(div().w(30.0).h(50.0))
4240 .child(div().w(30.0).h(50.0));
4241
4242 let mut tree = RenderTree::from_element(&ui);
4243 tree.compute_layout(200.0, 50.0);
4244
4245 let root = tree.root().unwrap();
4246 let children: Vec<_> = tree.layout_tree.children(root);
4247
4248 let first = tree
4250 .layout_tree
4251 .get_bounds(children[0], (0.0, 0.0))
4252 .unwrap();
4253 assert_eq!(first.x, 0.0);
4254
4255 let third = tree
4257 .layout_tree
4258 .get_bounds(children[2], (0.0, 0.0))
4259 .unwrap();
4260 assert_eq!(third.x, 170.0); let second = tree
4264 .layout_tree
4265 .get_bounds(children[1], (0.0, 0.0))
4266 .unwrap();
4267 assert_eq!(second.x, 85.0); }
4269
4270 #[test]
4271 fn test_nested_layout() {
4272 let ui = div()
4274 .w(200.0)
4275 .h(200.0)
4276 .flex_col()
4277 .child(
4278 div()
4279 .w_full()
4280 .h(50.0)
4281 .flex_row()
4282 .child(div().w(50.0).h(50.0))
4283 .child(div().flex_grow().h(50.0)),
4284 )
4285 .child(div().w_full().flex_grow());
4286
4287 let mut tree = RenderTree::from_element(&ui);
4288 tree.compute_layout(200.0, 200.0);
4289
4290 let root = tree.root().unwrap();
4291 let root_bounds = tree.get_bounds(root).unwrap();
4292 assert_eq!(root_bounds.width, 200.0);
4293 assert_eq!(root_bounds.height, 200.0);
4294
4295 let root_children: Vec<_> = tree.layout_tree.children(root);
4296
4297 let row = tree
4299 .layout_tree
4300 .get_bounds(root_children[0], (0.0, 0.0))
4301 .unwrap();
4302 assert_eq!(row.height, 50.0);
4303 assert_eq!(row.width, 200.0);
4304
4305 let bottom = tree
4307 .layout_tree
4308 .get_bounds(root_children[1], (0.0, 0.0))
4309 .unwrap();
4310 assert_eq!(bottom.y, 50.0);
4311 assert_eq!(bottom.height, 150.0);
4312 }
4313
4314 #[test]
4315 fn test_element_ref_basic() {
4316 let div_ref: ElementRef<Div> = ElementRef::new();
4318
4319 assert!(!div_ref.is_bound());
4320
4321 div_ref.set(div().w(100.0).h(50.0).bg(Color::BLUE));
4323
4324 assert!(div_ref.is_bound());
4325
4326 let width = div_ref.with(|d| d.style.size.width.clone());
4328 assert!(matches!(width, Some(Dimension::Length(100.0))));
4329 }
4330
4331 #[test]
4332 fn test_element_ref_with_mut() {
4333 let div_ref: ElementRef<Div> = ElementRef::new();
4334
4335 div_ref.set(div().w(100.0));
4336
4337 div_ref.with_mut(|d| {
4339 *d = d.swap().h(200.0).bg(Color::RED);
4340 });
4341
4342 let height = div_ref.with(|d| d.style.size.height.clone());
4344 assert!(matches!(height, Some(Dimension::Length(200.0))));
4345 }
4346
4347 #[test]
4348 fn test_element_ref_clone() {
4349 let div_ref: ElementRef<Div> = ElementRef::new();
4350 let div_ref_clone = div_ref.clone();
4351
4352 div_ref.set(div().w(100.0));
4354
4355 assert!(div_ref_clone.is_bound());
4357 let width = div_ref_clone.with(|d| d.style.size.width.clone());
4358 assert!(matches!(width, Some(Dimension::Length(100.0))));
4359 }
4360}