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) corner_shape: CornerShape,
376 pub(crate) border_color: Option<Color>,
377 pub(crate) border_width: f32,
378 pub(crate) border_sides: crate::element::BorderSides,
379 pub(crate) render_layer: RenderLayer,
380 pub(crate) material: Option<Material>,
381 pub(crate) shadow: Option<Shadow>,
382 pub(crate) transform: Option<Transform>,
383 pub(crate) opacity: f32,
384 pub(crate) cursor: Option<crate::element::CursorStyle>,
385 pub(crate) pointer_events_none: bool,
386 pub(crate) layer_effects: Vec<LayerEffect>,
388 pub(crate) is_stack_layer: bool,
390 pub(crate) event_handlers: crate::event_handler::EventHandlers,
391 pub(crate) element_id: Option<String>,
393 pub(crate) classes: Vec<String>,
395 pub(crate) rotate_x: Option<f32>,
397 pub(crate) rotate_y: Option<f32>,
398 pub(crate) perspective_3d: Option<f32>,
399 pub(crate) shape_3d: Option<f32>,
400 pub(crate) depth: Option<f32>,
401 pub(crate) light_direction: Option<[f32; 3]>,
402 pub(crate) light_intensity: Option<f32>,
403 pub(crate) ambient: Option<f32>,
404 pub(crate) specular: Option<f32>,
405 pub(crate) translate_z: Option<f32>,
406 pub(crate) op_3d: Option<f32>,
407 pub(crate) blend_3d: Option<f32>,
408 pub(crate) overflow_fade: OverflowFade,
410 pub(crate) clip_path: Option<ClipPath>,
412 pub(crate) flow_name: Option<String>,
414 pub(crate) flow_graph: Option<std::sync::Arc<blinc_core::FlowGraph>>,
416 pub(crate) is_fixed: bool,
418 pub(crate) is_sticky: bool,
420 pub(crate) sticky_top: Option<f32>,
422 pub(crate) outline_width: f32,
424 pub(crate) outline_color: Option<Color>,
426 pub(crate) outline_offset: f32,
428 pub(crate) z_index: i32,
430 pub(crate) scroll_physics: Option<crate::scroll::SharedScrollPhysics>,
432 pub(crate) layout_animation: Option<crate::layout_animation::LayoutAnimationConfig>,
434 pub(crate) visual_animation: Option<crate::visual_animation::VisualAnimationConfig>,
436 pub(crate) stateful_context_key: Option<String>,
441}
442
443impl Default for Div {
444 fn default() -> Self {
445 Self::new()
446 }
447}
448
449impl Div {
450 pub fn new() -> Self {
452 Self {
453 style: Style::default(),
454 children: Vec::new(),
455 background: None,
456 border_radius: CornerRadius::default(),
457 corner_shape: CornerShape::default(),
458 border_color: None,
459 border_width: 0.0,
460 border_sides: crate::element::BorderSides::default(),
461 render_layer: RenderLayer::default(),
462 material: None,
463 shadow: None,
464 transform: None,
465 opacity: 1.0,
466 cursor: None,
467 pointer_events_none: false,
468 layer_effects: Vec::new(),
469 is_stack_layer: false,
470 event_handlers: crate::event_handler::EventHandlers::new(),
471 element_id: None,
472 classes: Vec::new(),
473 rotate_x: None,
474 rotate_y: None,
475 perspective_3d: None,
476 shape_3d: None,
477 depth: None,
478 light_direction: None,
479 light_intensity: None,
480 ambient: None,
481 specular: None,
482 translate_z: None,
483 op_3d: None,
484 blend_3d: None,
485 overflow_fade: OverflowFade::default(),
486 clip_path: None,
487 flow_name: None,
488 flow_graph: None,
489 outline_width: 0.0,
490 outline_color: None,
491 outline_offset: 0.0,
492 is_fixed: false,
493 is_sticky: false,
494 sticky_top: None,
495 z_index: 0,
496 scroll_physics: None,
497 layout_animation: None,
498 visual_animation: None,
499 stateful_context_key: None,
500 }
501 }
502
503 pub fn with_style(style: Style) -> Self {
508 Self {
509 style,
510 children: Vec::new(),
511 background: None,
512 border_radius: CornerRadius::default(),
513 corner_shape: CornerShape::default(),
514 border_color: None,
515 border_width: 0.0,
516 border_sides: crate::element::BorderSides::default(),
517 render_layer: RenderLayer::default(),
518 material: None,
519 shadow: None,
520 transform: None,
521 opacity: 1.0,
522 cursor: None,
523 pointer_events_none: false,
524 layer_effects: Vec::new(),
525 is_stack_layer: false,
526 event_handlers: crate::event_handler::EventHandlers::new(),
527 element_id: None,
528 classes: Vec::new(),
529 rotate_x: None,
530 rotate_y: None,
531 perspective_3d: None,
532 shape_3d: None,
533 depth: None,
534 light_direction: None,
535 light_intensity: None,
536 ambient: None,
537 specular: None,
538 translate_z: None,
539 op_3d: None,
540 blend_3d: None,
541 overflow_fade: OverflowFade::default(),
542 clip_path: None,
543 flow_name: None,
544 flow_graph: None,
545 outline_width: 0.0,
546 outline_color: None,
547 outline_offset: 0.0,
548 is_fixed: false,
549 is_sticky: false,
550 sticky_top: None,
551 z_index: 0,
552 scroll_physics: None,
553 layout_animation: None,
554 visual_animation: None,
555 stateful_context_key: None,
556 }
557 }
558
559 pub fn id(mut self, id: impl Into<String>) -> Self {
571 self.element_id = Some(id.into());
572 self
573 }
574
575 pub fn element_id(&self) -> Option<&str> {
577 self.element_id.as_deref()
578 }
579
580 pub fn class(mut self, name: impl Into<String>) -> Self {
585 self.classes.push(name.into());
586 self
587 }
588
589 pub fn classes(&self) -> &[String] {
591 &self.classes
592 }
593
594 pub(crate) fn with_stateful_context(mut self, key: impl Into<String>) -> Self {
600 self.stateful_context_key = Some(key.into());
601 self
602 }
603
604 pub fn stateful_context_key(&self) -> Option<&str> {
606 self.stateful_context_key.as_deref()
607 }
608
609 #[deprecated(
639 since = "0.3.0",
640 note = "Use animate_bounds() instead. The old system modifies taffy which causes parent-child misalignment issues."
641 )]
642 pub fn animate_layout(
643 mut self,
644 config: crate::layout_animation::LayoutAnimationConfig,
645 ) -> Self {
646 let config = if let Some(ref ctx_key) = self.stateful_context_key {
648 if config.stable_key.is_none() {
649 let auto_key = format!("{}:layout_anim", ctx_key);
650 config.with_key(auto_key)
651 } else {
652 config
653 }
654 } else {
655 config
656 };
657 self.layout_animation = Some(config);
658 self
659 }
660
661 pub fn animate_bounds(
682 mut self,
683 config: crate::visual_animation::VisualAnimationConfig,
684 ) -> Self {
685 let config = if let Some(ref ctx_key) = self.stateful_context_key {
687 if config.key.is_none() {
688 let auto_key = format!("{}:visual_anim", ctx_key);
689 config.with_key(auto_key)
690 } else {
691 config
692 }
693 } else {
694 config
695 };
696 self.visual_animation = Some(config);
697 self
698 }
699
700 #[track_caller]
719 pub fn motion(self) -> crate::motion::Motion {
720 if let Some(ref ctx_key) = self.stateful_context_key {
721 let motion_key = format!("{}:motion", ctx_key);
723 crate::motion::motion_derived(&motion_key).child(self)
724 } else {
725 crate::motion::motion().child(self)
727 }
728 }
729
730 #[inline]
755 pub fn swap(&mut self) -> Self {
756 std::mem::take(self)
757 }
758
759 #[inline]
776 pub fn when<F>(self, condition: bool, f: F) -> Self
777 where
778 F: FnOnce(Self) -> Self,
779 {
780 if condition {
781 f(self)
782 } else {
783 self
784 }
785 }
786
787 #[inline]
792 pub fn set_bg(&mut self, color: impl Into<Brush>) {
793 self.background = Some(color.into());
794 }
795
796 #[inline]
798 pub fn set_rounded(&mut self, radius: f32) {
799 self.border_radius = CornerRadius::uniform(radius);
800 }
801
802 #[inline]
804 pub fn set_transform(&mut self, transform: Transform) {
805 self.transform = Some(transform);
806 }
807
808 #[inline]
810 pub fn set_shadow(&mut self, shadow: Shadow) {
811 self.shadow = Some(shadow);
812 }
813
814 #[inline]
816 pub fn set_opacity(&mut self, opacity: f32) {
817 self.opacity = opacity;
818 }
819
820 #[inline]
822 pub fn set_border(&mut self, width: f32, color: Color) {
823 self.border_width = width;
824 self.border_color = Some(color);
825 }
826
827 #[inline]
829 pub fn set_overflow_clip(&mut self, clip: bool) {
830 if clip {
831 self.style.overflow.x = taffy::Overflow::Hidden;
832 self.style.overflow.y = taffy::Overflow::Hidden;
833 } else {
834 self.style.overflow.x = taffy::Overflow::Visible;
835 self.style.overflow.y = taffy::Overflow::Visible;
836 }
837 }
838
839 #[inline]
841 pub fn set_padding_x(&mut self, px: f32) {
842 self.style.padding.left = taffy::LengthPercentage::Length(px);
843 self.style.padding.right = taffy::LengthPercentage::Length(px);
844 }
845
846 #[inline]
848 pub fn set_padding_y(&mut self, px: f32) {
849 self.style.padding.top = taffy::LengthPercentage::Length(px);
850 self.style.padding.bottom = taffy::LengthPercentage::Length(px);
851 }
852
853 #[inline]
855 pub fn set_child(&mut self, child: impl ElementBuilder + 'static) {
856 self.children.clear();
857 self.children.push(Box::new(child));
858 }
859
860 #[inline]
862 pub fn clear_children(&mut self) {
863 self.children.clear();
864 }
865
866 #[inline]
871 pub fn set_w(&mut self, px: f32) {
872 self.style.size.width = taffy::Dimension::Length(px);
873 }
874
875 #[inline]
877 pub fn set_h(&mut self, px: f32) {
878 self.style.size.height = taffy::Dimension::Length(px);
879 }
880
881 #[inline]
883 pub fn set_h_auto(&mut self) {
884 self.style.size.height = taffy::Dimension::Auto;
885 }
886
887 pub fn style(mut self, style: &ElementStyle) -> Self {
912 self.set_style(style);
913 self
914 }
915
916 #[inline]
929 pub fn set_style(&mut self, style: &ElementStyle) {
930 use crate::element_style::{
931 SpacingRect, StyleAlign, StyleDisplay, StyleFlexDirection, StyleJustify, StyleOverflow,
932 };
933
934 if let Some(ref bg) = style.background {
936 self.background = Some(bg.clone());
937 }
938 if let Some(radius) = style.corner_radius {
939 self.border_radius = radius;
940 }
941 if let Some(cs) = style.corner_shape {
942 self.corner_shape = cs;
943 }
944 if let Some(fade) = style.overflow_fade {
945 self.overflow_fade = fade;
946 }
947 if let Some(ref shadow) = style.shadow {
948 self.shadow = Some(*shadow);
949 }
950 if let Some(ref transform) = style.transform {
951 self.transform = Some(transform.clone());
952 }
953 if let Some(ref material) = style.material {
954 self.material = Some(material.clone());
955 }
956 if let Some(layer) = style.render_layer {
957 self.render_layer = layer;
958 }
959 if let Some(opacity) = style.opacity {
960 self.opacity = opacity;
961 }
962
963 if let Some(w) = style.width {
965 match w {
966 crate::element_style::StyleDimension::Length(px) => {
967 self.style.size.width = Dimension::Length(px);
968 }
969 crate::element_style::StyleDimension::Percent(p) => {
970 self.style.size.width = Dimension::Percent(p);
971 }
972 crate::element_style::StyleDimension::Auto => {
973 self.style.size.width = Dimension::Auto;
974 self.style.flex_basis = Dimension::Auto;
975 self.style.flex_grow = 0.0;
976 self.style.flex_shrink = 0.0;
977 }
978 }
979 }
980 if let Some(h) = style.height {
981 match h {
982 crate::element_style::StyleDimension::Length(px) => {
983 self.style.size.height = Dimension::Length(px);
984 }
985 crate::element_style::StyleDimension::Percent(p) => {
986 self.style.size.height = Dimension::Percent(p);
987 }
988 crate::element_style::StyleDimension::Auto => {
989 self.style.size.height = Dimension::Auto;
990 self.style.flex_basis = Dimension::Auto;
991 self.style.flex_grow = 0.0;
992 self.style.flex_shrink = 0.0;
993 }
994 }
995 }
996 if let Some(w) = style.min_width {
997 self.style.min_size.width = Dimension::Length(w);
998 }
999 if let Some(h) = style.min_height {
1000 self.style.min_size.height = Dimension::Length(h);
1001 }
1002 if let Some(w) = style.max_width {
1003 self.style.max_size.width = Dimension::Length(w);
1004 }
1005 if let Some(h) = style.max_height {
1006 self.style.max_size.height = Dimension::Length(h);
1007 }
1008
1009 if let Some(display) = style.display {
1011 self.style.display = match display {
1012 StyleDisplay::Flex => Display::Flex,
1013 StyleDisplay::Block => Display::Block,
1014 StyleDisplay::None => Display::None,
1015 };
1016 }
1017 if let Some(dir) = style.flex_direction {
1018 self.style.flex_direction = match dir {
1019 StyleFlexDirection::Row => FlexDirection::Row,
1020 StyleFlexDirection::Column => FlexDirection::Column,
1021 StyleFlexDirection::RowReverse => FlexDirection::RowReverse,
1022 StyleFlexDirection::ColumnReverse => FlexDirection::ColumnReverse,
1023 };
1024 }
1025 if let Some(wrap) = style.flex_wrap {
1026 self.style.flex_wrap = if wrap {
1027 FlexWrap::Wrap
1028 } else {
1029 FlexWrap::NoWrap
1030 };
1031 }
1032 if let Some(grow) = style.flex_grow {
1033 self.style.flex_grow = grow;
1034 }
1035 if let Some(shrink) = style.flex_shrink {
1036 self.style.flex_shrink = shrink;
1037 }
1038
1039 if let Some(align) = style.align_items {
1041 self.style.align_items = Some(match align {
1042 StyleAlign::Start => AlignItems::Start,
1043 StyleAlign::Center => AlignItems::Center,
1044 StyleAlign::End => AlignItems::End,
1045 StyleAlign::Stretch => AlignItems::Stretch,
1046 StyleAlign::Baseline => AlignItems::Baseline,
1047 });
1048 }
1049 if let Some(justify) = style.justify_content {
1050 self.style.justify_content = Some(match justify {
1051 StyleJustify::Start => JustifyContent::Start,
1052 StyleJustify::Center => JustifyContent::Center,
1053 StyleJustify::End => JustifyContent::End,
1054 StyleJustify::SpaceBetween => JustifyContent::SpaceBetween,
1055 StyleJustify::SpaceAround => JustifyContent::SpaceAround,
1056 StyleJustify::SpaceEvenly => JustifyContent::SpaceEvenly,
1057 });
1058 }
1059 if let Some(align) = style.align_self {
1060 self.style.align_self = Some(match align {
1061 StyleAlign::Start => AlignSelf::Start,
1062 StyleAlign::Center => AlignSelf::Center,
1063 StyleAlign::End => AlignSelf::End,
1064 StyleAlign::Stretch => AlignSelf::Stretch,
1065 StyleAlign::Baseline => AlignSelf::Baseline,
1066 });
1067 }
1068
1069 if let Some(SpacingRect {
1071 top,
1072 right,
1073 bottom,
1074 left,
1075 }) = style.padding
1076 {
1077 self.style.padding = Rect {
1078 top: LengthPercentage::Length(top),
1079 right: LengthPercentage::Length(right),
1080 bottom: LengthPercentage::Length(bottom),
1081 left: LengthPercentage::Length(left),
1082 };
1083 }
1084 if let Some(SpacingRect {
1085 top,
1086 right,
1087 bottom,
1088 left,
1089 }) = style.margin
1090 {
1091 self.style.margin = Rect {
1092 top: LengthPercentageAuto::Length(top),
1093 right: LengthPercentageAuto::Length(right),
1094 bottom: LengthPercentageAuto::Length(bottom),
1095 left: LengthPercentageAuto::Length(left),
1096 };
1097 }
1098 if let Some(gap) = style.gap {
1099 self.style.gap = taffy::Size {
1100 width: LengthPercentage::Length(gap),
1101 height: LengthPercentage::Length(gap),
1102 };
1103 }
1104
1105 if let Some(overflow) = style.overflow {
1107 let val = match overflow {
1108 StyleOverflow::Visible => Overflow::Visible,
1109 StyleOverflow::Clip => Overflow::Clip,
1110 StyleOverflow::Scroll => Overflow::Scroll,
1111 };
1112 self.style.overflow.x = val;
1113 self.style.overflow.y = val;
1114 if overflow == StyleOverflow::Scroll {
1115 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Both);
1116 }
1117 }
1118 if let Some(ox) = style.overflow_x {
1120 let val = match ox {
1121 StyleOverflow::Visible => Overflow::Visible,
1122 StyleOverflow::Clip => Overflow::Clip,
1123 StyleOverflow::Scroll => Overflow::Scroll,
1124 };
1125 self.style.overflow.x = val;
1126 if ox == StyleOverflow::Scroll {
1127 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Horizontal);
1128 }
1129 }
1130 if let Some(oy) = style.overflow_y {
1131 let val = match oy {
1132 StyleOverflow::Visible => Overflow::Visible,
1133 StyleOverflow::Clip => Overflow::Clip,
1134 StyleOverflow::Scroll => Overflow::Scroll,
1135 };
1136 self.style.overflow.y = val;
1137 if oy == StyleOverflow::Scroll {
1138 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Vertical);
1139 }
1140 }
1141
1142 if let Some(width) = style.border_width {
1144 self.border_width = width;
1145 }
1146 if let Some(color) = style.border_color {
1147 self.border_color = Some(color);
1148 }
1149
1150 if let Some(v) = style.rotate_x {
1152 self.rotate_x = Some(v);
1153 }
1154 if let Some(v) = style.rotate_y {
1155 self.rotate_y = Some(v);
1156 }
1157 if let Some(v) = style.perspective {
1158 self.perspective_3d = Some(v);
1159 }
1160 if let Some(ref s) = style.shape_3d {
1161 self.shape_3d = Some(crate::css_parser::shape_3d_to_float(s));
1162 }
1163 if let Some(v) = style.depth {
1164 self.depth = Some(v);
1165 }
1166 if let Some(dir) = style.light_direction {
1167 self.light_direction = Some(dir);
1168 }
1169 if let Some(v) = style.light_intensity {
1170 self.light_intensity = Some(v);
1171 }
1172 if let Some(v) = style.ambient {
1173 self.ambient = Some(v);
1174 }
1175 if let Some(v) = style.specular {
1176 self.specular = Some(v);
1177 }
1178 if let Some(v) = style.translate_z {
1179 self.translate_z = Some(v);
1180 }
1181 if let Some(ref op) = style.op_3d {
1182 self.op_3d = Some(crate::css_parser::op_3d_to_float(op));
1183 }
1184 if let Some(v) = style.blend_3d {
1185 self.blend_3d = Some(v);
1186 }
1187 if let Some(ref cp) = style.clip_path {
1188 self.clip_path = Some(cp.clone());
1189 }
1190 if let Some(ref f) = style.flow {
1191 self.flow_name = Some(f.clone());
1192 }
1193 }
1194
1195 #[inline]
1206 pub fn merge(&mut self, other: Div) {
1207 let default = Div::new();
1209
1210 self.merge_style(&other.style, &default.style);
1213
1214 if other.background.is_some() {
1216 self.background = other.background;
1217 }
1218 if other.border_radius != default.border_radius {
1219 self.border_radius = other.border_radius;
1220 }
1221 if other.border_color.is_some() {
1222 self.border_color = other.border_color;
1223 }
1224 if other.border_width != default.border_width {
1225 self.border_width = other.border_width;
1226 }
1227 if other.render_layer != default.render_layer {
1228 self.render_layer = other.render_layer;
1229 }
1230 if other.material.is_some() {
1231 self.material = other.material;
1232 }
1233 if other.shadow.is_some() {
1234 self.shadow = other.shadow;
1235 }
1236 if other.transform.is_some() {
1237 self.transform = other.transform;
1238 }
1239 if other.opacity != default.opacity {
1240 self.opacity = other.opacity;
1241 }
1242 if other.cursor.is_some() {
1243 self.cursor = other.cursor;
1244 }
1245
1246 if !other.children.is_empty() {
1248 self.children = other.children;
1249 }
1250
1251 if other.stateful_context_key.is_some() {
1253 self.stateful_context_key = other.stateful_context_key;
1254 }
1255
1256 if other.visual_animation.is_some() {
1258 self.visual_animation = other.visual_animation;
1259 }
1260
1261 if other.layout_animation.is_some() {
1263 self.layout_animation = other.layout_animation;
1264 }
1265
1266 if other.rotate_x.is_some() {
1268 self.rotate_x = other.rotate_x;
1269 }
1270 if other.rotate_y.is_some() {
1271 self.rotate_y = other.rotate_y;
1272 }
1273 if other.perspective_3d.is_some() {
1274 self.perspective_3d = other.perspective_3d;
1275 }
1276 if other.shape_3d.is_some() {
1277 self.shape_3d = other.shape_3d;
1278 }
1279 if other.depth.is_some() {
1280 self.depth = other.depth;
1281 }
1282 if other.light_direction.is_some() {
1283 self.light_direction = other.light_direction;
1284 }
1285 if other.light_intensity.is_some() {
1286 self.light_intensity = other.light_intensity;
1287 }
1288 if other.ambient.is_some() {
1289 self.ambient = other.ambient;
1290 }
1291 if other.specular.is_some() {
1292 self.specular = other.specular;
1293 }
1294 if other.translate_z.is_some() {
1295 self.translate_z = other.translate_z;
1296 }
1297 if other.op_3d.is_some() {
1298 self.op_3d = other.op_3d;
1299 }
1300 if other.blend_3d.is_some() {
1301 self.blend_3d = other.blend_3d;
1302 }
1303 if other.clip_path.is_some() {
1304 self.clip_path = other.clip_path;
1305 }
1306 if other.flow_name.is_some() {
1307 self.flow_name = other.flow_name;
1308 self.flow_graph = other.flow_graph;
1309 }
1310
1311 }
1313
1314 fn merge_style(&mut self, other: &Style, default: &Style) {
1316 if other.display != default.display {
1318 self.style.display = other.display;
1319 }
1320 if other.position != default.position {
1321 self.style.position = other.position;
1322 }
1323 if other.overflow != default.overflow {
1324 self.style.overflow = other.overflow;
1325 }
1326
1327 if other.flex_direction != default.flex_direction {
1329 self.style.flex_direction = other.flex_direction;
1330 }
1331 if other.flex_wrap != default.flex_wrap {
1332 self.style.flex_wrap = other.flex_wrap;
1333 }
1334 if other.justify_content != default.justify_content {
1335 self.style.justify_content = other.justify_content;
1336 }
1337 if other.align_items != default.align_items {
1338 self.style.align_items = other.align_items;
1339 }
1340 if other.align_content != default.align_content {
1341 self.style.align_content = other.align_content;
1342 }
1343 if other.gap.width != default.gap.width {
1345 self.style.gap.width = other.gap.width;
1346 }
1347 if other.gap.height != default.gap.height {
1348 self.style.gap.height = other.gap.height;
1349 }
1350
1351 if other.flex_grow != default.flex_grow {
1353 self.style.flex_grow = other.flex_grow;
1354 }
1355 if other.flex_shrink != default.flex_shrink {
1356 self.style.flex_shrink = other.flex_shrink;
1357 }
1358 if other.flex_basis != default.flex_basis {
1359 self.style.flex_basis = other.flex_basis;
1360 }
1361 if other.align_self != default.align_self {
1362 self.style.align_self = other.align_self;
1363 }
1364
1365 if other.size.width != default.size.width {
1367 self.style.size.width = other.size.width;
1368 }
1369 if other.size.height != default.size.height {
1370 self.style.size.height = other.size.height;
1371 }
1372 if other.min_size.width != default.min_size.width {
1373 self.style.min_size.width = other.min_size.width;
1374 }
1375 if other.min_size.height != default.min_size.height {
1376 self.style.min_size.height = other.min_size.height;
1377 }
1378 if other.max_size.width != default.max_size.width {
1379 self.style.max_size.width = other.max_size.width;
1380 }
1381 if other.max_size.height != default.max_size.height {
1382 self.style.max_size.height = other.max_size.height;
1383 }
1384 if other.aspect_ratio != default.aspect_ratio {
1385 self.style.aspect_ratio = other.aspect_ratio;
1386 }
1387
1388 if other.margin.left != default.margin.left {
1391 self.style.margin.left = other.margin.left;
1392 }
1393 if other.margin.right != default.margin.right {
1394 self.style.margin.right = other.margin.right;
1395 }
1396 if other.margin.top != default.margin.top {
1397 self.style.margin.top = other.margin.top;
1398 }
1399 if other.margin.bottom != default.margin.bottom {
1400 self.style.margin.bottom = other.margin.bottom;
1401 }
1402 if other.padding.left != default.padding.left {
1404 self.style.padding.left = other.padding.left;
1405 }
1406 if other.padding.right != default.padding.right {
1407 self.style.padding.right = other.padding.right;
1408 }
1409 if other.padding.top != default.padding.top {
1410 self.style.padding.top = other.padding.top;
1411 }
1412 if other.padding.bottom != default.padding.bottom {
1413 self.style.padding.bottom = other.padding.bottom;
1414 }
1415 if other.border.left != default.border.left {
1417 self.style.border.left = other.border.left;
1418 }
1419 if other.border.right != default.border.right {
1420 self.style.border.right = other.border.right;
1421 }
1422 if other.border.top != default.border.top {
1423 self.style.border.top = other.border.top;
1424 }
1425 if other.border.bottom != default.border.bottom {
1426 self.style.border.bottom = other.border.bottom;
1427 }
1428
1429 if other.inset.left != default.inset.left {
1431 self.style.inset.left = other.inset.left;
1432 }
1433 if other.inset.right != default.inset.right {
1434 self.style.inset.right = other.inset.right;
1435 }
1436 if other.inset.top != default.inset.top {
1437 self.style.inset.top = other.inset.top;
1438 }
1439 if other.inset.bottom != default.inset.bottom {
1440 self.style.inset.bottom = other.inset.bottom;
1441 }
1442 }
1443
1444 pub fn flex(mut self) -> Self {
1450 self.style.display = Display::Flex;
1451 self
1452 }
1453
1454 pub fn block(mut self) -> Self {
1456 self.style.display = Display::Block;
1457 self
1458 }
1459
1460 pub fn grid(mut self) -> Self {
1462 self.style.display = Display::Grid;
1463 self
1464 }
1465
1466 pub fn hidden(mut self) -> Self {
1468 self.style.display = Display::None;
1469 self
1470 }
1471
1472 pub fn flex_row(mut self) -> Self {
1474 self.style.display = Display::Flex;
1475 self.style.flex_direction = FlexDirection::Row;
1476 self
1477 }
1478
1479 pub fn flex_col(mut self) -> Self {
1481 self.style.display = Display::Flex;
1482 self.style.flex_direction = FlexDirection::Column;
1483 self
1484 }
1485
1486 pub fn flex_row_reverse(mut self) -> Self {
1488 self.style.display = Display::Flex;
1489 self.style.flex_direction = FlexDirection::RowReverse;
1490 self
1491 }
1492
1493 pub fn flex_col_reverse(mut self) -> Self {
1495 self.style.display = Display::Flex;
1496 self.style.flex_direction = FlexDirection::ColumnReverse;
1497 self
1498 }
1499
1500 pub fn flex_grow(mut self) -> Self {
1506 self.style.flex_grow = 1.0;
1507 self
1508 }
1509
1510 pub fn flex_grow_value(mut self, value: f32) -> Self {
1515 self.style.flex_grow = value;
1516 self
1517 }
1518
1519 pub fn flex_shrink(mut self) -> Self {
1521 self.style.flex_shrink = 1.0;
1522 self
1523 }
1524
1525 pub fn flex_shrink_0(mut self) -> Self {
1527 self.style.flex_shrink = 0.0;
1528 self
1529 }
1530
1531 pub fn flex_auto(mut self) -> Self {
1533 self.style.flex_grow = 1.0;
1534 self.style.flex_shrink = 1.0;
1535 self.style.flex_basis = Dimension::Auto;
1536 self
1537 }
1538
1539 pub fn flex_1(mut self) -> Self {
1541 self.style.flex_grow = 1.0;
1542 self.style.flex_shrink = 1.0;
1543 self.style.flex_basis = Dimension::Length(0.0);
1544 self
1545 }
1546
1547 pub fn flex_wrap(mut self) -> Self {
1549 self.style.flex_wrap = FlexWrap::Wrap;
1550 self
1551 }
1552
1553 pub fn items_center(mut self) -> Self {
1559 self.style.align_items = Some(AlignItems::Center);
1560 self
1561 }
1562
1563 pub fn items_start(mut self) -> Self {
1565 self.style.align_items = Some(AlignItems::Start);
1566 self
1567 }
1568
1569 pub fn items_end(mut self) -> Self {
1571 self.style.align_items = Some(AlignItems::End);
1572 self
1573 }
1574
1575 pub fn items_stretch(mut self) -> Self {
1577 self.style.align_items = Some(AlignItems::Stretch);
1578 self
1579 }
1580
1581 pub fn items_baseline(mut self) -> Self {
1583 self.style.align_items = Some(AlignItems::Baseline);
1584 self
1585 }
1586
1587 pub fn align_self_start(mut self) -> Self {
1589 self.style.align_self = Some(AlignSelf::Start);
1590 self
1591 }
1592
1593 pub fn align_self_center(mut self) -> Self {
1595 self.style.align_self = Some(AlignSelf::Center);
1596 self
1597 }
1598
1599 pub fn align_self_end(mut self) -> Self {
1601 self.style.align_self = Some(AlignSelf::End);
1602 self
1603 }
1604
1605 pub fn align_self_stretch(mut self) -> Self {
1607 self.style.align_self = Some(AlignSelf::Stretch);
1608 self
1609 }
1610
1611 pub fn justify_start(mut self) -> Self {
1613 self.style.justify_content = Some(JustifyContent::Start);
1614 self
1615 }
1616
1617 pub fn justify_center(mut self) -> Self {
1619 self.style.justify_content = Some(JustifyContent::Center);
1620 self
1621 }
1622
1623 pub fn justify_end(mut self) -> Self {
1625 self.style.justify_content = Some(JustifyContent::End);
1626 self
1627 }
1628
1629 pub fn justify_between(mut self) -> Self {
1631 self.style.justify_content = Some(JustifyContent::SpaceBetween);
1632 self
1633 }
1634
1635 pub fn justify_around(mut self) -> Self {
1637 self.style.justify_content = Some(JustifyContent::SpaceAround);
1638 self
1639 }
1640
1641 pub fn justify_evenly(mut self) -> Self {
1643 self.style.justify_content = Some(JustifyContent::SpaceEvenly);
1644 self
1645 }
1646
1647 pub fn content_start(mut self) -> Self {
1649 self.style.align_content = Some(taffy::AlignContent::Start);
1650 self
1651 }
1652
1653 pub fn content_center(mut self) -> Self {
1655 self.style.align_content = Some(taffy::AlignContent::Center);
1656 self
1657 }
1658
1659 pub fn content_end(mut self) -> Self {
1661 self.style.align_content = Some(taffy::AlignContent::End);
1662 self
1663 }
1664
1665 pub fn self_start(mut self) -> Self {
1670 self.style.align_self = Some(AlignSelf::FlexStart);
1671 self
1672 }
1673
1674 pub fn self_center(mut self) -> Self {
1676 self.style.align_self = Some(AlignSelf::Center);
1677 self
1678 }
1679
1680 pub fn self_end(mut self) -> Self {
1682 self.style.align_self = Some(AlignSelf::FlexEnd);
1683 self
1684 }
1685
1686 pub fn self_stretch(mut self) -> Self {
1688 self.style.align_self = Some(AlignSelf::Stretch);
1689 self
1690 }
1691
1692 pub fn w(mut self, px: f32) -> Self {
1698 self.style.size.width = Dimension::Length(px);
1699 self
1700 }
1701
1702 pub fn w_full(mut self) -> Self {
1704 self.style.size.width = Dimension::Percent(1.0);
1705 self
1706 }
1707
1708 pub fn w_auto(mut self) -> Self {
1710 self.style.size.width = Dimension::Auto;
1711 self
1712 }
1713
1714 pub fn w_fit(mut self) -> Self {
1719 self.style.size.width = Dimension::Auto;
1720 self.style.flex_basis = Dimension::Auto;
1721 self.style.flex_grow = 0.0;
1722 self.style.flex_shrink = 0.0;
1723 self
1724 }
1725
1726 pub fn h(mut self, px: f32) -> Self {
1728 self.style.size.height = Dimension::Length(px);
1729 self
1730 }
1731
1732 pub fn h_full(mut self) -> Self {
1734 self.style.size.height = Dimension::Percent(1.0);
1735 self
1736 }
1737
1738 pub fn h_auto(mut self) -> Self {
1740 self.style.size.height = Dimension::Auto;
1741 self
1742 }
1743
1744 pub fn h_fit(mut self) -> Self {
1749 self.style.size.height = Dimension::Auto;
1750 self.style.flex_basis = Dimension::Auto;
1751 self.style.flex_grow = 0.0;
1752 self.style.flex_shrink = 0.0;
1753 self
1754 }
1755
1756 pub fn size_fit(mut self) -> Self {
1760 self.style.size.width = Dimension::Auto;
1761 self.style.size.height = Dimension::Auto;
1762 self.style.flex_basis = Dimension::Auto;
1763 self.style.flex_grow = 0.0;
1764 self.style.flex_shrink = 0.0;
1765 self
1766 }
1767
1768 pub fn size(mut self, w: f32, h: f32) -> Self {
1770 self.style.size.width = Dimension::Length(w);
1771 self.style.size.height = Dimension::Length(h);
1772 self
1773 }
1774
1775 pub fn square(mut self, size: f32) -> Self {
1777 self.style.size.width = Dimension::Length(size);
1778 self.style.size.height = Dimension::Length(size);
1779 self
1780 }
1781
1782 pub fn min_w(mut self, px: f32) -> Self {
1784 self.style.min_size.width = Dimension::Length(px);
1785 self
1786 }
1787
1788 pub fn min_h(mut self, px: f32) -> Self {
1790 self.style.min_size.height = Dimension::Length(px);
1791 self
1792 }
1793
1794 pub fn max_w(mut self, px: f32) -> Self {
1796 self.style.max_size.width = Dimension::Length(px);
1797 self
1798 }
1799
1800 pub fn max_h(mut self, px: f32) -> Self {
1802 self.style.max_size.height = Dimension::Length(px);
1803 self
1804 }
1805
1806 pub fn gap(mut self, units: f32) -> Self {
1813 let px = units * 4.0;
1814 self.style.gap = taffy::Size {
1815 width: LengthPercentage::Length(px),
1816 height: LengthPercentage::Length(px),
1817 };
1818 self
1819 }
1820
1821 pub fn gap_px(mut self, px: f32) -> Self {
1823 self.style.gap = taffy::Size {
1824 width: LengthPercentage::Length(px),
1825 height: LengthPercentage::Length(px),
1826 };
1827 self
1828 }
1829
1830 pub fn gap_x(mut self, units: f32) -> Self {
1832 self.style.gap.width = LengthPercentage::Length(units * 4.0);
1833 self
1834 }
1835
1836 pub fn gap_y(mut self, units: f32) -> Self {
1838 self.style.gap.height = LengthPercentage::Length(units * 4.0);
1839 self
1840 }
1841
1842 pub fn gap_1(self) -> Self {
1848 self.gap_px(ThemeState::get().spacing().space_1)
1849 }
1850
1851 pub fn gap_2(self) -> Self {
1853 self.gap_px(ThemeState::get().spacing().space_2)
1854 }
1855
1856 pub fn gap_3(self) -> Self {
1858 self.gap_px(ThemeState::get().spacing().space_3)
1859 }
1860
1861 pub fn gap_4(self) -> Self {
1863 self.gap_px(ThemeState::get().spacing().space_4)
1864 }
1865
1866 pub fn gap_5(self) -> Self {
1868 self.gap_px(ThemeState::get().spacing().space_5)
1869 }
1870
1871 pub fn gap_6(self) -> Self {
1873 self.gap_px(ThemeState::get().spacing().space_6)
1874 }
1875
1876 pub fn gap_8(self) -> Self {
1878 self.gap_px(ThemeState::get().spacing().space_8)
1879 }
1880
1881 pub fn gap_10(self) -> Self {
1883 self.gap_px(ThemeState::get().spacing().space_10)
1884 }
1885
1886 pub fn gap_12(self) -> Self {
1888 self.gap_px(ThemeState::get().spacing().space_12)
1889 }
1890
1891 pub fn p(mut self, units: f32) -> Self {
1898 let px = LengthPercentage::Length(units * 4.0);
1899 self.style.padding = Rect {
1900 left: px,
1901 right: px,
1902 top: px,
1903 bottom: px,
1904 };
1905 self
1906 }
1907
1908 pub fn p_px(mut self, px: f32) -> Self {
1910 let val = LengthPercentage::Length(px);
1911 self.style.padding = Rect {
1912 left: val,
1913 right: val,
1914 top: val,
1915 bottom: val,
1916 };
1917 self
1918 }
1919
1920 pub fn px(mut self, units: f32) -> Self {
1922 let px = LengthPercentage::Length(units * 4.0);
1923 self.style.padding.left = px;
1924 self.style.padding.right = px;
1925 self
1926 }
1927
1928 pub fn py(mut self, units: f32) -> Self {
1930 let px = LengthPercentage::Length(units * 4.0);
1931 self.style.padding.top = px;
1932 self.style.padding.bottom = px;
1933 self
1934 }
1935
1936 pub fn pl(mut self, units: f32) -> Self {
1938 self.style.padding.left = LengthPercentage::Length(units * 4.0);
1939 self
1940 }
1941
1942 pub fn pr(mut self, units: f32) -> Self {
1944 self.style.padding.right = LengthPercentage::Length(units * 4.0);
1945 self
1946 }
1947
1948 pub fn pt(mut self, units: f32) -> Self {
1950 self.style.padding.top = LengthPercentage::Length(units * 4.0);
1951 self
1952 }
1953
1954 pub fn pb(mut self, units: f32) -> Self {
1956 self.style.padding.bottom = LengthPercentage::Length(units * 4.0);
1957 self
1958 }
1959
1960 pub fn p_1(self) -> Self {
1966 let px = ThemeState::get().spacing().space_1;
1967 self.padding(crate::units::Length::Px(px))
1968 }
1969
1970 pub fn p_2(self) -> Self {
1972 let px = ThemeState::get().spacing().space_2;
1973 self.padding(crate::units::Length::Px(px))
1974 }
1975
1976 pub fn p_3(self) -> Self {
1978 let px = ThemeState::get().spacing().space_3;
1979 self.padding(crate::units::Length::Px(px))
1980 }
1981
1982 pub fn p_4(self) -> Self {
1984 let px = ThemeState::get().spacing().space_4;
1985 self.padding(crate::units::Length::Px(px))
1986 }
1987
1988 pub fn p_5(self) -> Self {
1990 let px = ThemeState::get().spacing().space_5;
1991 self.padding(crate::units::Length::Px(px))
1992 }
1993
1994 pub fn p_6(self) -> Self {
1996 let px = ThemeState::get().spacing().space_6;
1997 self.padding(crate::units::Length::Px(px))
1998 }
1999
2000 pub fn p_8(self) -> Self {
2002 let px = ThemeState::get().spacing().space_8;
2003 self.padding(crate::units::Length::Px(px))
2004 }
2005
2006 pub fn p_10(self) -> Self {
2008 let px = ThemeState::get().spacing().space_10;
2009 self.padding(crate::units::Length::Px(px))
2010 }
2011
2012 pub fn p_12(self) -> Self {
2014 let px = ThemeState::get().spacing().space_12;
2015 self.padding(crate::units::Length::Px(px))
2016 }
2017
2018 pub fn padding_x_px(mut self, pixels: f32) -> Self {
2024 let px = LengthPercentage::Length(pixels);
2025 self.style.padding.left = px;
2026 self.style.padding.right = px;
2027 self
2028 }
2029
2030 pub fn padding_y_px(mut self, pixels: f32) -> Self {
2032 let px = LengthPercentage::Length(pixels);
2033 self.style.padding.top = px;
2034 self.style.padding.bottom = px;
2035 self
2036 }
2037
2038 pub fn padding(mut self, len: crate::units::Length) -> Self {
2052 let val: LengthPercentage = len.into();
2053 self.style.padding = Rect {
2054 left: val,
2055 right: val,
2056 top: val,
2057 bottom: val,
2058 };
2059 self
2060 }
2061
2062 pub fn padding_x(mut self, len: crate::units::Length) -> Self {
2064 let val: LengthPercentage = len.into();
2065 self.style.padding.left = val;
2066 self.style.padding.right = val;
2067 self
2068 }
2069
2070 pub fn padding_y(mut self, len: crate::units::Length) -> Self {
2072 let val: LengthPercentage = len.into();
2073 self.style.padding.top = val;
2074 self.style.padding.bottom = val;
2075 self
2076 }
2077
2078 pub fn m(mut self, units: f32) -> Self {
2080 let px = LengthPercentageAuto::Length(units * 4.0);
2081 self.style.margin = Rect {
2082 left: px,
2083 right: px,
2084 top: px,
2085 bottom: px,
2086 };
2087 self
2088 }
2089
2090 pub fn m_px(mut self, px: f32) -> Self {
2092 let val = LengthPercentageAuto::Length(px);
2093 self.style.margin = Rect {
2094 left: val,
2095 right: val,
2096 top: val,
2097 bottom: val,
2098 };
2099 self
2100 }
2101
2102 pub fn mx(mut self, units: f32) -> Self {
2104 let px = LengthPercentageAuto::Length(units * 4.0);
2105 self.style.margin.left = px;
2106 self.style.margin.right = px;
2107 self
2108 }
2109
2110 pub fn my(mut self, units: f32) -> Self {
2112 let px = LengthPercentageAuto::Length(units * 4.0);
2113 self.style.margin.top = px;
2114 self.style.margin.bottom = px;
2115 self
2116 }
2117
2118 pub fn mx_auto(mut self) -> Self {
2120 self.style.margin.left = LengthPercentageAuto::Auto;
2121 self.style.margin.right = LengthPercentageAuto::Auto;
2122 self
2123 }
2124
2125 pub fn ml(mut self, units: f32) -> Self {
2127 self.style.margin.left = LengthPercentageAuto::Length(units * 4.0);
2128 self
2129 }
2130
2131 pub fn mr(mut self, units: f32) -> Self {
2133 self.style.margin.right = LengthPercentageAuto::Length(units * 4.0);
2134 self
2135 }
2136
2137 pub fn mt(mut self, units: f32) -> Self {
2139 self.style.margin.top = LengthPercentageAuto::Length(units * 4.0);
2140 self
2141 }
2142
2143 pub fn mb(mut self, units: f32) -> Self {
2145 self.style.margin.bottom = LengthPercentageAuto::Length(units * 4.0);
2146 self
2147 }
2148
2149 pub fn m_1(self) -> Self {
2155 self.m_px(ThemeState::get().spacing().space_1)
2156 }
2157
2158 pub fn m_2(self) -> Self {
2160 self.m_px(ThemeState::get().spacing().space_2)
2161 }
2162
2163 pub fn m_3(self) -> Self {
2165 self.m_px(ThemeState::get().spacing().space_3)
2166 }
2167
2168 pub fn m_4(self) -> Self {
2170 self.m_px(ThemeState::get().spacing().space_4)
2171 }
2172
2173 pub fn m_5(self) -> Self {
2175 self.m_px(ThemeState::get().spacing().space_5)
2176 }
2177
2178 pub fn m_6(self) -> Self {
2180 self.m_px(ThemeState::get().spacing().space_6)
2181 }
2182
2183 pub fn m_8(self) -> Self {
2185 self.m_px(ThemeState::get().spacing().space_8)
2186 }
2187
2188 pub fn absolute(mut self) -> Self {
2194 self.style.position = Position::Absolute;
2195 self
2196 }
2197
2198 pub fn relative(mut self) -> Self {
2200 self.style.position = Position::Relative;
2201 self
2202 }
2203
2204 pub fn fixed(mut self) -> Self {
2206 self.style.position = Position::Absolute;
2207 self.is_fixed = true;
2208 self.is_sticky = false;
2209 self
2210 }
2211
2212 pub fn sticky(mut self, top: f32) -> Self {
2214 self.style.position = Position::Relative;
2215 self.is_sticky = true;
2216 self.is_fixed = false;
2217 self.sticky_top = Some(top);
2218 self
2219 }
2220
2221 pub fn inset(mut self, px: f32) -> Self {
2223 let val = LengthPercentageAuto::Length(px);
2224 self.style.inset = Rect {
2225 left: val,
2226 right: val,
2227 top: val,
2228 bottom: val,
2229 };
2230 self
2231 }
2232
2233 pub fn top(mut self, px: f32) -> Self {
2235 self.style.inset.top = LengthPercentageAuto::Length(px);
2236 self
2237 }
2238
2239 pub fn bottom(mut self, px: f32) -> Self {
2241 self.style.inset.bottom = LengthPercentageAuto::Length(px);
2242 self
2243 }
2244
2245 pub fn left(mut self, px: f32) -> Self {
2247 self.style.inset.left = LengthPercentageAuto::Length(px);
2248 self
2249 }
2250
2251 pub fn right(mut self, px: f32) -> Self {
2253 self.style.inset.right = LengthPercentageAuto::Length(px);
2254 self
2255 }
2256
2257 pub fn overflow_clip(mut self) -> Self {
2266 self.style.overflow.x = Overflow::Clip;
2267 self.style.overflow.y = Overflow::Clip;
2268 self
2269 }
2270
2271 pub fn overflow_visible(mut self) -> Self {
2273 self.style.overflow.x = Overflow::Visible;
2274 self.style.overflow.y = Overflow::Visible;
2275 self
2276 }
2277
2278 pub fn overflow_scroll(mut self) -> Self {
2283 self.style.overflow.x = Overflow::Scroll;
2284 self.style.overflow.y = Overflow::Scroll;
2285 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Both);
2286 self
2287 }
2288
2289 pub(crate) fn overflow_scroll_style_only(mut self) -> Self {
2293 self.style.overflow.x = Overflow::Scroll;
2294 self.style.overflow.y = Overflow::Scroll;
2295 self
2296 }
2297
2298 pub fn overflow_x(mut self, overflow: Overflow) -> Self {
2300 self.style.overflow.x = overflow;
2301 if overflow == Overflow::Scroll {
2302 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Horizontal);
2303 }
2304 self
2305 }
2306
2307 pub fn overflow_y(mut self, overflow: Overflow) -> Self {
2309 self.style.overflow.y = overflow;
2310 if overflow == Overflow::Scroll {
2311 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Vertical);
2312 }
2313 self
2314 }
2315
2316 pub fn overflow_x_scroll(mut self) -> Self {
2318 self.style.overflow.x = Overflow::Scroll;
2319 self.style.overflow.y = Overflow::Clip;
2320 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Horizontal);
2321 self
2322 }
2323
2324 pub fn overflow_y_scroll(mut self) -> Self {
2326 self.style.overflow.x = Overflow::Clip;
2327 self.style.overflow.y = Overflow::Scroll;
2328 self.ensure_scroll_physics(crate::scroll::ScrollDirection::Vertical);
2329 self
2330 }
2331
2332 fn ensure_scroll_physics(&mut self, direction: crate::scroll::ScrollDirection) {
2334 if self.scroll_physics.is_none() {
2335 let config = crate::scroll::ScrollConfig {
2336 direction,
2337 ..Default::default()
2338 };
2339 let physics = std::sync::Arc::new(std::sync::Mutex::new(
2340 crate::scroll::ScrollPhysics::new(config),
2341 ));
2342 let handlers =
2343 crate::scroll::Scroll::create_internal_handlers(std::sync::Arc::clone(&physics));
2344 self.event_handlers.merge(handlers);
2346 self.scroll_physics = Some(physics);
2347 }
2348 }
2349
2350 pub fn bg(mut self, color: Color) -> Self {
2356 self.background = Some(Brush::Solid(color));
2357 self
2358 }
2359
2360 pub fn background(mut self, brush: impl Into<Brush>) -> Self {
2362 self.background = Some(brush.into());
2363 self
2364 }
2365
2366 pub fn backdrop_blur(self, radius: f32) -> Self {
2385 self.background(Brush::Blur(BlurStyle::with_radius(radius)))
2386 }
2387
2388 pub fn backdrop_blur_style(self, style: BlurStyle) -> Self {
2402 self.background(Brush::Blur(style))
2403 }
2404
2405 pub fn backdrop_blur_light(self) -> Self {
2407 self.background(Brush::Blur(BlurStyle::light()))
2408 }
2409
2410 pub fn backdrop_blur_medium(self) -> Self {
2412 self.background(Brush::Blur(BlurStyle::medium()))
2413 }
2414
2415 pub fn backdrop_blur_heavy(self) -> Self {
2417 self.background(Brush::Blur(BlurStyle::heavy()))
2418 }
2419
2420 pub fn backdrop_blur_max(self) -> Self {
2422 self.background(Brush::Blur(BlurStyle::max()))
2423 }
2424
2425 pub fn bg_primary(self) -> Self {
2431 self.bg(ThemeState::get().color(blinc_theme::ColorToken::Primary))
2432 }
2433
2434 pub fn bg_secondary(self) -> Self {
2436 self.bg(ThemeState::get().color(blinc_theme::ColorToken::Secondary))
2437 }
2438
2439 pub fn bg_background(self) -> Self {
2441 self.bg(ThemeState::get().color(blinc_theme::ColorToken::Background))
2442 }
2443
2444 pub fn bg_surface(self) -> Self {
2446 self.bg(ThemeState::get().color(blinc_theme::ColorToken::Surface))
2447 }
2448
2449 pub fn bg_surface_elevated(self) -> Self {
2451 self.bg(ThemeState::get().color(blinc_theme::ColorToken::SurfaceElevated))
2452 }
2453
2454 pub fn bg_success(self) -> Self {
2456 self.bg(ThemeState::get().color(blinc_theme::ColorToken::SuccessBg))
2457 }
2458
2459 pub fn bg_warning(self) -> Self {
2461 self.bg(ThemeState::get().color(blinc_theme::ColorToken::WarningBg))
2462 }
2463
2464 pub fn bg_error(self) -> Self {
2466 self.bg(ThemeState::get().color(blinc_theme::ColorToken::ErrorBg))
2467 }
2468
2469 pub fn bg_info(self) -> Self {
2471 self.bg(ThemeState::get().color(blinc_theme::ColorToken::InfoBg))
2472 }
2473
2474 pub fn bg_accent(self) -> Self {
2476 self.bg(ThemeState::get().color(blinc_theme::ColorToken::Accent))
2477 }
2478
2479 pub fn rounded(mut self, radius: f32) -> Self {
2485 self.border_radius = CornerRadius::uniform(radius);
2486 self
2487 }
2488
2489 pub fn rounded_full(mut self) -> Self {
2491 self.border_radius = CornerRadius::uniform(9999.0);
2493 self
2494 }
2495
2496 pub fn rounded_corners(mut self, tl: f32, tr: f32, br: f32, bl: f32) -> Self {
2498 self.border_radius = CornerRadius::new(tl, tr, br, bl);
2499 self
2500 }
2501
2502 pub fn rounded_sm(self) -> Self {
2508 self.rounded(ThemeState::get().radii().radius_sm)
2509 }
2510
2511 pub fn rounded_default(self) -> Self {
2513 self.rounded(ThemeState::get().radii().radius_default)
2514 }
2515
2516 pub fn rounded_md(self) -> Self {
2518 self.rounded(ThemeState::get().radii().radius_md)
2519 }
2520
2521 pub fn rounded_lg(self) -> Self {
2523 self.rounded(ThemeState::get().radii().radius_lg)
2524 }
2525
2526 pub fn rounded_xl(self) -> Self {
2528 self.rounded(ThemeState::get().radii().radius_xl)
2529 }
2530
2531 pub fn rounded_2xl(self) -> Self {
2533 self.rounded(ThemeState::get().radii().radius_2xl)
2534 }
2535
2536 pub fn rounded_3xl(self) -> Self {
2538 self.rounded(ThemeState::get().radii().radius_3xl)
2539 }
2540
2541 pub fn rounded_none(self) -> Self {
2543 self.rounded(0.0)
2544 }
2545
2546 pub fn corner_shape(mut self, n: f32) -> Self {
2554 self.corner_shape = CornerShape::uniform(n);
2555 self
2556 }
2557
2558 pub fn corner_shapes(mut self, tl: f32, tr: f32, br: f32, bl: f32) -> Self {
2560 self.corner_shape = CornerShape::new(tl, tr, br, bl);
2561 self
2562 }
2563
2564 pub fn corner_bevel(self) -> Self {
2566 self.corner_shape(0.0)
2567 }
2568
2569 pub fn corner_squircle(self) -> Self {
2571 self.corner_shape(2.0)
2572 }
2573
2574 pub fn corner_scoop(self) -> Self {
2576 self.corner_shape(-1.0)
2577 }
2578
2579 pub fn overflow_fade(mut self, distance: f32) -> Self {
2585 self.overflow_fade = OverflowFade::uniform(distance);
2586 self
2587 }
2588
2589 pub fn overflow_fade_x(mut self, distance: f32) -> Self {
2591 self.overflow_fade = OverflowFade::horizontal(distance);
2592 self
2593 }
2594
2595 pub fn overflow_fade_y(mut self, distance: f32) -> Self {
2597 self.overflow_fade = OverflowFade::vertical(distance);
2598 self
2599 }
2600
2601 pub fn overflow_fade_edges(mut self, top: f32, right: f32, bottom: f32, left: f32) -> Self {
2603 self.overflow_fade = OverflowFade::new(top, right, bottom, left);
2604 self
2605 }
2606
2607 pub fn border(mut self, width: f32, color: Color) -> Self {
2613 self.border_width = width;
2614 self.border_color = Some(color);
2615 self
2616 }
2617
2618 pub fn border_color(mut self, color: Color) -> Self {
2620 self.border_color = Some(color);
2621 self
2622 }
2623
2624 pub fn border_width(mut self, width: f32) -> Self {
2626 self.border_width = width;
2627 self
2628 }
2629
2630 pub fn outline_width(mut self, width: f32) -> Self {
2632 self.outline_width = width;
2633 self
2634 }
2635
2636 pub fn outline_color(mut self, color: Color) -> Self {
2638 self.outline_color = Some(color);
2639 self
2640 }
2641
2642 pub fn outline_offset(mut self, offset: f32) -> Self {
2644 self.outline_offset = offset;
2645 self
2646 }
2647
2648 pub fn border_left(mut self, width: f32, color: Color) -> Self {
2657 self.inherit_uniform_border_to_sides();
2658 self.border_sides.left = Some(crate::element::BorderSide::new(width, color));
2659 self
2660 }
2661
2662 pub fn border_right(mut self, width: f32, color: Color) -> Self {
2666 self.inherit_uniform_border_to_sides();
2667 self.border_sides.right = Some(crate::element::BorderSide::new(width, color));
2668 self
2669 }
2670
2671 pub fn border_top(mut self, width: f32, color: Color) -> Self {
2675 self.inherit_uniform_border_to_sides();
2676 self.border_sides.top = Some(crate::element::BorderSide::new(width, color));
2677 self
2678 }
2679
2680 pub fn border_bottom(mut self, width: f32, color: Color) -> Self {
2684 self.inherit_uniform_border_to_sides();
2685 self.border_sides.bottom = Some(crate::element::BorderSide::new(width, color));
2686 self
2687 }
2688
2689 pub fn border_x(mut self, width: f32, color: Color) -> Self {
2693 self.inherit_uniform_border_to_sides();
2694 let side = crate::element::BorderSide::new(width, color);
2695 self.border_sides.left = Some(side);
2696 self.border_sides.right = Some(side);
2697 self
2698 }
2699
2700 pub fn border_y(mut self, width: f32, color: Color) -> Self {
2704 self.inherit_uniform_border_to_sides();
2705 let side = crate::element::BorderSide::new(width, color);
2706 self.border_sides.top = Some(side);
2707 self.border_sides.bottom = Some(side);
2708 self
2709 }
2710
2711 fn inherit_uniform_border_to_sides(&mut self) {
2716 if self.border_width > 0.0 && !self.border_sides.has_any() {
2718 if let Some(color) = self.border_color {
2719 let side = crate::element::BorderSide::new(self.border_width, color);
2720 self.border_sides.top = Some(side);
2721 self.border_sides.right = Some(side);
2722 self.border_sides.bottom = Some(side);
2723 self.border_sides.left = Some(side);
2724 }
2725 }
2726 }
2727
2728 pub fn borders<F>(mut self, f: F) -> Self
2746 where
2747 F: FnOnce(crate::element::BorderBuilder) -> crate::element::BorderBuilder,
2748 {
2749 let builder = f(crate::element::BorderBuilder::new());
2750 self.border_sides = builder.build();
2751 self
2752 }
2753
2754 pub fn layer(mut self, layer: RenderLayer) -> Self {
2760 self.render_layer = layer;
2761 self
2762 }
2763
2764 pub fn foreground(self) -> Self {
2766 self.layer(RenderLayer::Foreground)
2767 }
2768
2769 pub fn material(mut self, material: Material) -> Self {
2775 if matches!(material, Material::Glass(_)) {
2777 self.render_layer = RenderLayer::Glass;
2778 }
2779 self.material = Some(material);
2780 self
2781 }
2782
2783 pub fn effect(self, effect: impl Into<Material>) -> Self {
2797 self.material(effect.into())
2798 }
2799
2800 pub fn glass(self) -> Self {
2804 self.material(Material::Glass(GlassMaterial::new()))
2805 }
2806
2807 pub fn metallic(self) -> Self {
2809 self.material(Material::Metallic(MetallicMaterial::new()))
2810 }
2811
2812 pub fn chrome(self) -> Self {
2814 self.material(Material::Metallic(MetallicMaterial::chrome()))
2815 }
2816
2817 pub fn gold(self) -> Self {
2819 self.material(Material::Metallic(MetallicMaterial::gold()))
2820 }
2821
2822 pub fn wood(self) -> Self {
2824 self.material(Material::Wood(WoodMaterial::new()))
2825 }
2826
2827 pub fn shadow(mut self, shadow: Shadow) -> Self {
2833 self.shadow = Some(shadow);
2834 self
2835 }
2836
2837 pub fn shadow_params(self, offset_x: f32, offset_y: f32, blur: f32, color: Color) -> Self {
2839 self.shadow(Shadow::new(offset_x, offset_y, blur, color))
2840 }
2841
2842 pub fn shadow_sm(self) -> Self {
2844 self.shadow(ThemeState::get().shadows().shadow_sm.into())
2845 }
2846
2847 pub fn shadow_md(self) -> Self {
2849 self.shadow(ThemeState::get().shadows().shadow_md.into())
2850 }
2851
2852 pub fn shadow_lg(self) -> Self {
2854 self.shadow(ThemeState::get().shadows().shadow_lg.into())
2855 }
2856
2857 pub fn shadow_xl(self) -> Self {
2859 self.shadow(ThemeState::get().shadows().shadow_xl.into())
2860 }
2861
2862 pub fn transform(mut self, transform: Transform) -> Self {
2868 self.transform = Some(transform);
2869 self
2870 }
2871
2872 pub fn translate(self, x: f32, y: f32) -> Self {
2874 self.transform(Transform::translate(x, y))
2875 }
2876
2877 pub fn scale(self, factor: f32) -> Self {
2879 self.transform(Transform::scale(factor, factor))
2880 }
2881
2882 pub fn scale_xy(self, sx: f32, sy: f32) -> Self {
2884 self.transform(Transform::scale(sx, sy))
2885 }
2886
2887 pub fn rotate(self, angle: f32) -> Self {
2889 self.transform(Transform::rotate(angle))
2890 }
2891
2892 pub fn rotate_deg(self, degrees: f32) -> Self {
2894 self.rotate(degrees * std::f32::consts::PI / 180.0)
2895 }
2896
2897 pub fn opacity(mut self, opacity: f32) -> Self {
2903 self.opacity = opacity.clamp(0.0, 1.0);
2904 self
2905 }
2906
2907 pub fn opaque(self) -> Self {
2909 self.opacity(1.0)
2910 }
2911
2912 pub fn flow(mut self, f: impl Into<crate::element::FlowRef>) -> Self {
2925 match f.into() {
2926 crate::element::FlowRef::Name(name) => {
2927 self.flow_name = Some(name);
2928 }
2929 crate::element::FlowRef::Graph(g) => {
2930 self.flow_name = Some(g.name.clone());
2931 self.flow_graph = Some(g);
2932 }
2933 }
2934 self
2935 }
2936
2937 pub fn translucent(self) -> Self {
2939 self.opacity(0.5)
2940 }
2941
2942 pub fn invisible(self) -> Self {
2944 self.opacity(0.0)
2945 }
2946
2947 pub fn layer_effect(mut self, effect: LayerEffect) -> Self {
2968 self.layer_effects.push(effect);
2969 self
2970 }
2971
2972 pub fn blur(self, radius: f32) -> Self {
2983 self.layer_effect(LayerEffect::blur(radius))
2984 }
2985
2986 pub fn blur_with_quality(self, radius: f32, quality: BlurQuality) -> Self {
2993 self.layer_effect(LayerEffect::blur_with_quality(radius, quality))
2994 }
2995
2996 pub fn drop_shadow_effect(self, offset_x: f32, offset_y: f32, blur: f32, color: Color) -> Self {
3010 self.layer_effect(LayerEffect::drop_shadow(offset_x, offset_y, blur, color))
3011 }
3012
3013 pub fn glow_effect(self, color: Color, blur: f32, range: f32, opacity: f32) -> Self {
3032 self.layer_effect(LayerEffect::glow(color, blur, range, opacity))
3033 }
3034
3035 pub fn grayscale(self) -> Self {
3037 self.layer_effect(LayerEffect::grayscale())
3038 }
3039
3040 pub fn sepia(self) -> Self {
3042 self.layer_effect(LayerEffect::sepia())
3043 }
3044
3045 pub fn brightness(self, factor: f32) -> Self {
3047 self.layer_effect(LayerEffect::brightness(factor))
3048 }
3049
3050 pub fn contrast(self, factor: f32) -> Self {
3052 self.layer_effect(LayerEffect::contrast(factor))
3053 }
3054
3055 pub fn saturation(self, factor: f32) -> Self {
3057 self.layer_effect(LayerEffect::saturation(factor))
3058 }
3059
3060 pub fn cursor(mut self, cursor: crate::element::CursorStyle) -> Self {
3076 self.cursor = Some(cursor);
3077 self
3078 }
3079
3080 pub fn cursor_pointer(self) -> Self {
3082 self.cursor(crate::element::CursorStyle::Pointer)
3083 }
3084
3085 pub fn cursor_text(self) -> Self {
3087 self.cursor(crate::element::CursorStyle::Text)
3088 }
3089
3090 pub fn cursor_move(self) -> Self {
3092 self.cursor(crate::element::CursorStyle::Move)
3093 }
3094
3095 pub fn cursor_grab(self) -> Self {
3097 self.cursor(crate::element::CursorStyle::Grab)
3098 }
3099
3100 pub fn cursor_grabbing(self) -> Self {
3102 self.cursor(crate::element::CursorStyle::Grabbing)
3103 }
3104
3105 pub fn cursor_not_allowed(self) -> Self {
3107 self.cursor(crate::element::CursorStyle::NotAllowed)
3108 }
3109
3110 pub fn pointer_events_none(mut self) -> Self {
3116 self.pointer_events_none = true;
3117 self
3118 }
3119
3120 pub fn stack_layer(mut self) -> Self {
3128 self.is_stack_layer = true;
3129 self
3130 }
3131
3132 pub fn z_index(mut self, z: i32) -> Self {
3134 self.z_index = z;
3135 self
3136 }
3137
3138 pub fn child(mut self, child: impl ElementBuilder + 'static) -> Self {
3144 self.children.push(Box::new(child));
3145 self
3146 }
3147
3148 pub fn child_box(mut self, child: Box<dyn ElementBuilder>) -> Self {
3150 self.children.push(child);
3151 self
3152 }
3153
3154 pub fn children<I>(mut self, children: I) -> Self
3156 where
3157 I: IntoIterator,
3158 I::Item: ElementBuilder + 'static,
3159 {
3160 for child in children {
3161 self.children.push(Box::new(child));
3162 }
3163 self
3164 }
3165
3166 pub fn style_mut(&mut self) -> &mut Style {
3168 &mut self.style
3169 }
3170
3171 pub fn event_handlers(&self) -> &crate::event_handler::EventHandlers {
3177 &self.event_handlers
3178 }
3179
3180 pub fn event_handlers_mut(&mut self) -> &mut crate::event_handler::EventHandlers {
3182 &mut self.event_handlers
3183 }
3184
3185 pub fn on_click<F>(mut self, handler: F) -> Self
3198 where
3199 F: Fn(&crate::event_handler::EventContext) + 'static,
3200 {
3201 self.event_handlers.on_click(handler);
3202 self
3203 }
3204
3205 pub fn on_mouse_down<F>(mut self, handler: F) -> Self
3207 where
3208 F: Fn(&crate::event_handler::EventContext) + 'static,
3209 {
3210 self.event_handlers.on_mouse_down(handler);
3211 self
3212 }
3213
3214 pub fn on_mouse_up<F>(mut self, handler: F) -> Self
3216 where
3217 F: Fn(&crate::event_handler::EventContext) + 'static,
3218 {
3219 self.event_handlers.on_mouse_up(handler);
3220 self
3221 }
3222
3223 pub fn on_hover_enter<F>(mut self, handler: F) -> Self
3233 where
3234 F: Fn(&crate::event_handler::EventContext) + 'static,
3235 {
3236 self.event_handlers.on_hover_enter(handler);
3237 self
3238 }
3239
3240 pub fn on_hover_leave<F>(mut self, handler: F) -> Self
3242 where
3243 F: Fn(&crate::event_handler::EventContext) + 'static,
3244 {
3245 self.event_handlers.on_hover_leave(handler);
3246 self
3247 }
3248
3249 pub fn on_focus<F>(mut self, handler: F) -> Self
3251 where
3252 F: Fn(&crate::event_handler::EventContext) + 'static,
3253 {
3254 self.event_handlers.on_focus(handler);
3255 self
3256 }
3257
3258 pub fn on_blur<F>(mut self, handler: F) -> Self
3260 where
3261 F: Fn(&crate::event_handler::EventContext) + 'static,
3262 {
3263 self.event_handlers.on_blur(handler);
3264 self
3265 }
3266
3267 pub fn on_mount<F>(mut self, handler: F) -> Self
3269 where
3270 F: Fn(&crate::event_handler::EventContext) + 'static,
3271 {
3272 self.event_handlers.on_mount(handler);
3273 self
3274 }
3275
3276 pub fn on_unmount<F>(mut self, handler: F) -> Self
3278 where
3279 F: Fn(&crate::event_handler::EventContext) + 'static,
3280 {
3281 self.event_handlers.on_unmount(handler);
3282 self
3283 }
3284
3285 pub fn on_key_down<F>(mut self, handler: F) -> Self
3287 where
3288 F: Fn(&crate::event_handler::EventContext) + 'static,
3289 {
3290 self.event_handlers.on_key_down(handler);
3291 self
3292 }
3293
3294 pub fn on_key_up<F>(mut self, handler: F) -> Self
3296 where
3297 F: Fn(&crate::event_handler::EventContext) + 'static,
3298 {
3299 self.event_handlers.on_key_up(handler);
3300 self
3301 }
3302
3303 pub fn on_scroll<F>(mut self, handler: F) -> Self
3305 where
3306 F: Fn(&crate::event_handler::EventContext) + 'static,
3307 {
3308 self.event_handlers.on_scroll(handler);
3309 self
3310 }
3311
3312 pub fn on_mouse_move<F>(mut self, handler: F) -> Self
3314 where
3315 F: Fn(&crate::event_handler::EventContext) + 'static,
3316 {
3317 self.event_handlers
3318 .on(blinc_core::events::event_types::POINTER_MOVE, handler);
3319 self
3320 }
3321
3322 pub fn on_drag<F>(mut self, handler: F) -> Self
3324 where
3325 F: Fn(&crate::event_handler::EventContext) + 'static,
3326 {
3327 self.event_handlers
3328 .on(blinc_core::events::event_types::DRAG, handler);
3329 self
3330 }
3331
3332 pub fn on_drag_end<F>(mut self, handler: F) -> Self
3334 where
3335 F: Fn(&crate::event_handler::EventContext) + 'static,
3336 {
3337 self.event_handlers
3338 .on(blinc_core::events::event_types::DRAG_END, handler);
3339 self
3340 }
3341
3342 pub fn on_text_input<F>(mut self, handler: F) -> Self
3344 where
3345 F: Fn(&crate::event_handler::EventContext) + 'static,
3346 {
3347 self.event_handlers.on_text_input(handler);
3348 self
3349 }
3350
3351 pub fn on_resize<F>(mut self, handler: F) -> Self
3353 where
3354 F: Fn(&crate::event_handler::EventContext) + 'static,
3355 {
3356 self.event_handlers.on_resize(handler);
3357 self
3358 }
3359
3360 pub fn on_event<F>(mut self, event_type: blinc_core::events::EventType, handler: F) -> Self
3374 where
3375 F: Fn(&crate::event_handler::EventContext) + 'static,
3376 {
3377 self.event_handlers.on(event_type, handler);
3378 self
3379 }
3380}
3381
3382#[derive(Clone, Copy, Debug, PartialEq, Eq)]
3384pub enum ElementTypeId {
3385 Div,
3386 Text,
3387 StyledText,
3389 Svg,
3390 Image,
3391 Canvas,
3392 Motion,
3394}
3395
3396#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
3398pub enum TextAlign {
3399 #[default]
3401 Left,
3402 Center,
3404 Right,
3406}
3407
3408#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
3410pub enum FontWeight {
3411 Thin,
3413 ExtraLight,
3415 Light,
3417 #[default]
3419 Normal,
3420 Medium,
3422 SemiBold,
3424 Bold,
3426 ExtraBold,
3428 Black,
3430}
3431
3432impl FontWeight {
3433 pub fn weight(&self) -> u16 {
3435 match self {
3436 FontWeight::Thin => 100,
3437 FontWeight::ExtraLight => 200,
3438 FontWeight::Light => 300,
3439 FontWeight::Normal => 400,
3440 FontWeight::Medium => 500,
3441 FontWeight::SemiBold => 600,
3442 FontWeight::Bold => 700,
3443 FontWeight::ExtraBold => 800,
3444 FontWeight::Black => 900,
3445 }
3446 }
3447}
3448
3449#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
3451pub enum TextVerticalAlign {
3452 #[default]
3455 Top,
3456 Center,
3459 Baseline,
3463}
3464
3465#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
3467pub enum GenericFont {
3468 #[default]
3470 System,
3471 Monospace,
3473 Serif,
3475 SansSerif,
3477}
3478
3479#[derive(Debug, Clone, PartialEq, Eq, Default)]
3495pub struct FontFamily {
3496 pub name: Option<String>,
3498 pub generic: GenericFont,
3500}
3501
3502impl FontFamily {
3503 pub fn generic(generic: GenericFont) -> Self {
3505 Self {
3506 name: None,
3507 generic,
3508 }
3509 }
3510
3511 pub fn named(name: impl Into<String>) -> Self {
3513 Self {
3514 name: Some(name.into()),
3515 generic: GenericFont::System,
3516 }
3517 }
3518
3519 pub fn named_with_fallback(name: impl Into<String>, generic: GenericFont) -> Self {
3521 Self {
3522 name: Some(name.into()),
3523 generic,
3524 }
3525 }
3526
3527 pub fn system() -> Self {
3529 Self::generic(GenericFont::System)
3530 }
3531
3532 pub fn monospace() -> Self {
3534 Self::generic(GenericFont::Monospace)
3535 }
3536
3537 pub fn serif() -> Self {
3539 Self::generic(GenericFont::Serif)
3540 }
3541
3542 pub fn sans_serif() -> Self {
3544 Self::generic(GenericFont::SansSerif)
3545 }
3546}
3547
3548#[derive(Clone)]
3550pub struct TextRenderInfo {
3551 pub content: String,
3552 pub font_size: f32,
3553 pub color: [f32; 4],
3554 pub align: TextAlign,
3555 pub weight: FontWeight,
3556 pub italic: bool,
3558 pub v_align: TextVerticalAlign,
3559 pub wrap: bool,
3561 pub line_height: f32,
3563 pub measured_width: f32,
3566 pub font_family: FontFamily,
3568 pub word_spacing: f32,
3570 pub letter_spacing: f32,
3572 pub ascender: f32,
3575 pub strikethrough: bool,
3577 pub underline: bool,
3579}
3580
3581#[derive(Clone)]
3583pub struct StyledTextSpanInfo {
3584 pub start: usize,
3586 pub end: usize,
3588 pub color: [f32; 4],
3590 pub bold: bool,
3592 pub italic: bool,
3594 pub underline: bool,
3596 pub strikethrough: bool,
3598 pub link_url: Option<String>,
3600}
3601
3602#[derive(Clone)]
3604pub struct StyledTextRenderInfo {
3605 pub content: String,
3607 pub spans: Vec<StyledTextSpanInfo>,
3609 pub font_size: f32,
3611 pub default_color: [f32; 4],
3613 pub align: TextAlign,
3615 pub v_align: TextVerticalAlign,
3617 pub font_family: FontFamily,
3619 pub line_height: f32,
3621 pub weight: FontWeight,
3623 pub italic: bool,
3625 pub ascender: f32,
3627}
3628
3629#[derive(Clone)]
3631pub struct SvgRenderInfo {
3632 pub source: String,
3633 pub tint: Option<blinc_core::Color>,
3634 pub fill: Option<blinc_core::Color>,
3635 pub stroke: Option<blinc_core::Color>,
3636 pub stroke_width: Option<f32>,
3637}
3638
3639#[derive(Clone)]
3641pub struct ImageRenderInfo {
3642 pub source: String,
3644 pub object_fit: u8,
3646 pub object_position: [f32; 2],
3648 pub opacity: f32,
3650 pub border_radius: f32,
3652 pub tint: [f32; 4],
3654 pub filter: [f32; 8],
3656 pub loading_strategy: u8,
3658 pub placeholder_type: u8,
3660 pub placeholder_color: [f32; 4],
3662 pub placeholder_image: Option<String>,
3664 pub fade_duration_ms: u32,
3666}
3667
3668impl Default for ImageRenderInfo {
3669 fn default() -> Self {
3670 Self {
3671 source: String::new(),
3672 object_fit: 0, object_position: [0.5, 0.5], opacity: 1.0,
3675 border_radius: 0.0,
3676 tint: [1.0, 1.0, 1.0, 1.0],
3677 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,
3682 fade_duration_ms: 200,
3683 }
3684 }
3685}
3686
3687pub trait ElementBuilder {
3691 fn build(&self, tree: &mut LayoutTree) -> LayoutNodeId;
3693
3694 fn render_props(&self) -> RenderProps;
3696
3697 fn children_builders(&self) -> &[Box<dyn ElementBuilder>];
3699
3700 fn element_type_id(&self) -> ElementTypeId {
3702 ElementTypeId::Div
3703 }
3704
3705 fn text_render_info(&self) -> Option<TextRenderInfo> {
3707 None
3708 }
3709
3710 fn styled_text_render_info(&self) -> Option<StyledTextRenderInfo> {
3712 None
3713 }
3714
3715 fn svg_render_info(&self) -> Option<SvgRenderInfo> {
3717 None
3718 }
3719
3720 fn image_render_info(&self) -> Option<ImageRenderInfo> {
3722 None
3723 }
3724
3725 fn canvas_render_info(&self) -> Option<crate::canvas::CanvasRenderFn> {
3727 None
3728 }
3729
3730 fn event_handlers(&self) -> Option<&crate::event_handler::EventHandlers> {
3735 None
3736 }
3737
3738 fn scroll_info(&self) -> Option<crate::scroll::ScrollRenderInfo> {
3740 None
3741 }
3742
3743 fn scroll_physics(&self) -> Option<crate::scroll::SharedScrollPhysics> {
3745 None
3746 }
3747
3748 fn motion_animation_for_child(
3753 &self,
3754 _child_index: usize,
3755 ) -> Option<crate::element::MotionAnimation> {
3756 None
3757 }
3758
3759 fn motion_bindings(&self) -> Option<crate::motion::MotionBindings> {
3764 None
3765 }
3766
3767 fn motion_stable_id(&self) -> Option<&str> {
3773 None
3774 }
3775
3776 fn motion_should_replay(&self) -> bool {
3781 false
3782 }
3783
3784 fn motion_is_suspended(&self) -> bool {
3789 false
3790 }
3791
3792 #[deprecated(
3801 since = "0.1.0",
3802 note = "Use query_motion(key).exit() to explicitly trigger motion exit"
3803 )]
3804 fn motion_is_exiting(&self) -> bool {
3805 false
3806 }
3807
3808 fn layout_style(&self) -> Option<&taffy::Style> {
3813 None
3814 }
3815
3816 fn layout_bounds_storage(&self) -> Option<crate::renderer::LayoutBoundsStorage> {
3821 None
3822 }
3823
3824 fn layout_bounds_callback(&self) -> Option<crate::renderer::LayoutBoundsCallback> {
3830 None
3831 }
3832
3833 fn semantic_type_name(&self) -> Option<&'static str> {
3838 None
3839 }
3840
3841 fn element_id(&self) -> Option<&str> {
3845 None
3846 }
3847
3848 fn element_classes(&self) -> &[String] {
3850 &[]
3851 }
3852
3853 fn bound_scroll_ref(&self) -> Option<&crate::selector::ScrollRef> {
3858 None
3859 }
3860
3861 fn motion_on_ready_callback(
3867 &self,
3868 ) -> Option<std::sync::Arc<dyn Fn(crate::element::ElementBounds) + Send + Sync>> {
3869 None
3870 }
3871
3872 fn layout_animation_config(&self) -> Option<crate::layout_animation::LayoutAnimationConfig> {
3881 None
3882 }
3883
3884 fn visual_animation_config(&self) -> Option<crate::visual_animation::VisualAnimationConfig> {
3889 None
3890 }
3891}
3892
3893impl ElementBuilder for Div {
3894 fn build(&self, tree: &mut LayoutTree) -> LayoutNodeId {
3895 let node = tree.create_node(self.style.clone());
3896
3897 for child in &self.children {
3899 let child_node = child.build(tree);
3900 tree.add_child(node, child_node);
3901 }
3902
3903 node
3904 }
3905
3906 #[allow(deprecated)]
3907 fn render_props(&self) -> RenderProps {
3908 let clips_content = !matches!(self.style.overflow.x, Overflow::Visible)
3911 || !matches!(self.style.overflow.y, Overflow::Visible);
3912
3913 RenderProps {
3914 background: self.background.clone(),
3915 border_radius: self.border_radius,
3916 corner_shape: self.corner_shape,
3917 border_color: self.border_color,
3918 border_width: self.border_width,
3919 border_sides: self.border_sides,
3920 layer: self.render_layer,
3921 material: self.material.clone(),
3922 shadow: self.shadow,
3923 transform: self.transform.clone(),
3924 opacity: self.opacity,
3925 clips_content,
3926 is_stack_layer: self.is_stack_layer,
3927 pointer_events_none: self.pointer_events_none,
3928 cursor: self.cursor,
3929 layer_effects: self.layer_effects.clone(),
3930 rotate_x: self.rotate_x,
3931 rotate_y: self.rotate_y,
3932 perspective: self.perspective_3d,
3933 shape_3d: self.shape_3d,
3934 depth: self.depth,
3935 light_direction: self.light_direction,
3936 light_intensity: self.light_intensity,
3937 ambient: self.ambient,
3938 specular: self.specular,
3939 translate_z: self.translate_z,
3940 op_3d: self.op_3d,
3941 blend_3d: self.blend_3d,
3942 clip_path: self.clip_path.clone(),
3943 overflow_fade: self.overflow_fade,
3944 flow: self.flow_name.clone(),
3945 flow_graph: self.flow_graph.clone(),
3946 outline_color: self.outline_color,
3947 outline_width: self.outline_width,
3948 outline_offset: self.outline_offset,
3949 is_fixed: self.is_fixed,
3950 is_sticky: self.is_sticky,
3951 sticky_top: self.sticky_top,
3952 z_index: self.z_index,
3953 ..Default::default()
3954 }
3955 }
3956
3957 fn children_builders(&self) -> &[Box<dyn ElementBuilder>] {
3958 &self.children
3959 }
3960
3961 fn event_handlers(&self) -> Option<&crate::event_handler::EventHandlers> {
3962 if self.event_handlers.is_empty() {
3963 None
3964 } else {
3965 Some(&self.event_handlers)
3966 }
3967 }
3968
3969 fn layout_style(&self) -> Option<&taffy::Style> {
3970 Some(&self.style)
3971 }
3972
3973 fn element_id(&self) -> Option<&str> {
3974 self.element_id.as_deref()
3975 }
3976
3977 fn element_classes(&self) -> &[String] {
3978 &self.classes
3979 }
3980
3981 fn layout_animation_config(&self) -> Option<crate::layout_animation::LayoutAnimationConfig> {
3982 self.layout_animation.clone()
3983 }
3984
3985 fn visual_animation_config(&self) -> Option<crate::visual_animation::VisualAnimationConfig> {
3986 self.visual_animation.clone()
3987 }
3988
3989 fn scroll_physics(&self) -> Option<crate::scroll::SharedScrollPhysics> {
3990 self.scroll_physics.clone()
3991 }
3992}
3993
3994pub fn div() -> Div {
3996 Div::new()
3997}
3998
3999#[cfg(test)]
4002mod tests {
4003 use super::*;
4004 use crate::renderer::RenderTree;
4005
4006 #[test]
4007 fn test_div_builder() {
4008 let d = div().w(100.0).h(50.0).flex_row().gap(2.0).p(4.0);
4009
4010 assert!(matches!(d.style.display, Display::Flex));
4011 assert!(matches!(d.style.flex_direction, FlexDirection::Row));
4012 }
4013
4014 #[test]
4015 fn test_div_with_children() {
4016 let parent = div().flex_col().child(div().h(20.0)).child(div().h(30.0));
4017
4018 assert_eq!(parent.children.len(), 2);
4019 }
4020
4021 #[test]
4022 fn test_build_tree() {
4023 let ui = div().flex_col().child(div().h(20.0)).child(div().h(30.0));
4024
4025 let mut tree = LayoutTree::new();
4026 let root = ui.build(&mut tree);
4027
4028 assert_eq!(tree.len(), 3);
4029 assert_eq!(tree.children(root).len(), 2);
4030 }
4031
4032 #[test]
4033 fn test_layout_flex_row_with_fixed_children() {
4034 let ui = div()
4036 .w(300.0)
4037 .h(100.0)
4038 .flex_row()
4039 .child(div().w(50.0).h(100.0))
4040 .child(div().w(100.0).h(100.0))
4041 .child(div().w(50.0).h(100.0));
4042
4043 let mut tree = RenderTree::from_element(&ui);
4044 tree.compute_layout(300.0, 100.0);
4045
4046 let root = tree.root().unwrap();
4047 let children: Vec<_> = tree.layout_tree.children(root);
4048
4049 let first = tree
4051 .layout_tree
4052 .get_bounds(children[0], (0.0, 0.0))
4053 .unwrap();
4054 assert_eq!(first.x, 0.0);
4055 assert_eq!(first.width, 50.0);
4056
4057 let second = tree
4059 .layout_tree
4060 .get_bounds(children[1], (0.0, 0.0))
4061 .unwrap();
4062 assert_eq!(second.x, 50.0);
4063 assert_eq!(second.width, 100.0);
4064
4065 let third = tree
4067 .layout_tree
4068 .get_bounds(children[2], (0.0, 0.0))
4069 .unwrap();
4070 assert_eq!(third.x, 150.0);
4071 assert_eq!(third.width, 50.0);
4072 }
4073
4074 #[test]
4075 fn test_layout_flex_col_with_gap() {
4076 let ui = div()
4078 .w(100.0)
4079 .h(200.0)
4080 .flex_col()
4081 .gap_px(10.0) .child(div().w_full().h(40.0))
4083 .child(div().w_full().h(40.0))
4084 .child(div().w_full().h(40.0));
4085
4086 let mut tree = RenderTree::from_element(&ui);
4087 tree.compute_layout(100.0, 200.0);
4088
4089 let root = tree.root().unwrap();
4090 let children: Vec<_> = tree.layout_tree.children(root);
4091
4092 let first = tree
4094 .layout_tree
4095 .get_bounds(children[0], (0.0, 0.0))
4096 .unwrap();
4097 assert_eq!(first.y, 0.0);
4098 assert_eq!(first.height, 40.0);
4099
4100 let second = tree
4102 .layout_tree
4103 .get_bounds(children[1], (0.0, 0.0))
4104 .unwrap();
4105 assert_eq!(second.y, 50.0);
4106 assert_eq!(second.height, 40.0);
4107
4108 let third = tree
4110 .layout_tree
4111 .get_bounds(children[2], (0.0, 0.0))
4112 .unwrap();
4113 assert_eq!(third.y, 100.0);
4114 assert_eq!(third.height, 40.0);
4115 }
4116
4117 #[test]
4118 fn test_layout_flex_grow() {
4119 let ui = div()
4121 .w(200.0)
4122 .h(100.0)
4123 .flex_row()
4124 .child(div().w(50.0).h(100.0))
4125 .child(div().flex_grow().h(100.0));
4126
4127 let mut tree = RenderTree::from_element(&ui);
4128 tree.compute_layout(200.0, 100.0);
4129
4130 let root = tree.root().unwrap();
4131 let children: Vec<_> = tree.layout_tree.children(root);
4132
4133 let fixed = tree
4135 .layout_tree
4136 .get_bounds(children[0], (0.0, 0.0))
4137 .unwrap();
4138 assert_eq!(fixed.width, 50.0);
4139
4140 let growing = tree
4142 .layout_tree
4143 .get_bounds(children[1], (0.0, 0.0))
4144 .unwrap();
4145 assert_eq!(growing.x, 50.0);
4146 assert_eq!(growing.width, 150.0);
4147 }
4148
4149 #[test]
4150 fn test_layout_padding() {
4151 let ui = div()
4153 .w(100.0)
4154 .h(100.0)
4155 .p(2.0) .child(div().w_full().h_full());
4157
4158 let mut tree = RenderTree::from_element(&ui);
4159 tree.compute_layout(100.0, 100.0);
4160
4161 let root = tree.root().unwrap();
4162 let children: Vec<_> = tree.layout_tree.children(root);
4163
4164 let child = tree
4166 .layout_tree
4167 .get_bounds(children[0], (0.0, 0.0))
4168 .unwrap();
4169 assert_eq!(child.x, 8.0);
4170 assert_eq!(child.y, 8.0);
4171 assert_eq!(child.width, 84.0); assert_eq!(child.height, 84.0);
4173 }
4174
4175 #[test]
4176 fn test_layout_justify_between() {
4177 let ui = div()
4179 .w(200.0)
4180 .h(50.0)
4181 .flex_row()
4182 .justify_between()
4183 .child(div().w(30.0).h(50.0))
4184 .child(div().w(30.0).h(50.0))
4185 .child(div().w(30.0).h(50.0));
4186
4187 let mut tree = RenderTree::from_element(&ui);
4188 tree.compute_layout(200.0, 50.0);
4189
4190 let root = tree.root().unwrap();
4191 let children: Vec<_> = tree.layout_tree.children(root);
4192
4193 let first = tree
4195 .layout_tree
4196 .get_bounds(children[0], (0.0, 0.0))
4197 .unwrap();
4198 assert_eq!(first.x, 0.0);
4199
4200 let third = tree
4202 .layout_tree
4203 .get_bounds(children[2], (0.0, 0.0))
4204 .unwrap();
4205 assert_eq!(third.x, 170.0); let second = tree
4209 .layout_tree
4210 .get_bounds(children[1], (0.0, 0.0))
4211 .unwrap();
4212 assert_eq!(second.x, 85.0); }
4214
4215 #[test]
4216 fn test_nested_layout() {
4217 let ui = div()
4219 .w(200.0)
4220 .h(200.0)
4221 .flex_col()
4222 .child(
4223 div()
4224 .w_full()
4225 .h(50.0)
4226 .flex_row()
4227 .child(div().w(50.0).h(50.0))
4228 .child(div().flex_grow().h(50.0)),
4229 )
4230 .child(div().w_full().flex_grow());
4231
4232 let mut tree = RenderTree::from_element(&ui);
4233 tree.compute_layout(200.0, 200.0);
4234
4235 let root = tree.root().unwrap();
4236 let root_bounds = tree.get_bounds(root).unwrap();
4237 assert_eq!(root_bounds.width, 200.0);
4238 assert_eq!(root_bounds.height, 200.0);
4239
4240 let root_children: Vec<_> = tree.layout_tree.children(root);
4241
4242 let row = tree
4244 .layout_tree
4245 .get_bounds(root_children[0], (0.0, 0.0))
4246 .unwrap();
4247 assert_eq!(row.height, 50.0);
4248 assert_eq!(row.width, 200.0);
4249
4250 let bottom = tree
4252 .layout_tree
4253 .get_bounds(root_children[1], (0.0, 0.0))
4254 .unwrap();
4255 assert_eq!(bottom.y, 50.0);
4256 assert_eq!(bottom.height, 150.0);
4257 }
4258
4259 #[test]
4260 fn test_element_ref_basic() {
4261 let div_ref: ElementRef<Div> = ElementRef::new();
4263
4264 assert!(!div_ref.is_bound());
4265
4266 div_ref.set(div().w(100.0).h(50.0).bg(Color::BLUE));
4268
4269 assert!(div_ref.is_bound());
4270
4271 let width = div_ref.with(|d| d.style.size.width.clone());
4273 assert!(matches!(width, Some(Dimension::Length(100.0))));
4274 }
4275
4276 #[test]
4277 fn test_element_ref_with_mut() {
4278 let div_ref: ElementRef<Div> = ElementRef::new();
4279
4280 div_ref.set(div().w(100.0));
4281
4282 div_ref.with_mut(|d| {
4284 *d = d.swap().h(200.0).bg(Color::RED);
4285 });
4286
4287 let height = div_ref.with(|d| d.style.size.height.clone());
4289 assert!(matches!(height, Some(Dimension::Length(200.0))));
4290 }
4291
4292 #[test]
4293 fn test_element_ref_clone() {
4294 let div_ref: ElementRef<Div> = ElementRef::new();
4295 let div_ref_clone = div_ref.clone();
4296
4297 div_ref.set(div().w(100.0));
4299
4300 assert!(div_ref_clone.is_bound());
4302 let width = div_ref_clone.with(|d| d.style.size.width.clone());
4303 assert!(matches!(width, Some(Dimension::Length(100.0))));
4304 }
4305}